package scotch.compiler.syntax.definition; import static org.apache.commons.lang.StringUtils.capitalize; import static scotch.compiler.syntax.builder.BuilderUtil.require; import static scotch.symbol.Symbol.symbol; import static scotch.symbol.Symbol.toJavaName; import static scotch.symbol.descriptor.DataFieldDescriptor.field; import java.util.Optional; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import scotch.compiler.intermediate.IntermediateField; import scotch.compiler.intermediate.IntermediateGenerator; import scotch.compiler.intermediate.Intermediates; import scotch.compiler.syntax.builder.SyntaxBuilder; import scotch.compiler.syntax.value.Argument; import scotch.compiler.syntax.value.Identifier; import scotch.compiler.syntax.value.Value; import scotch.compiler.text.SourceLocation; import scotch.runtime.Callable; import scotch.symbol.Symbol; import scotch.symbol.descriptor.DataFieldDescriptor; import scotch.compiler.syntax.type.Type; import scotch.compiler.syntax.type.TypeQualifier; @AllArgsConstructor @EqualsAndHashCode(callSuper = false) public class DataFieldDefinition implements Comparable<DataFieldDefinition> { public static Builder builder() { return new Builder(); } private final SourceLocation sourceLocation; private final int ordinal; private final String name; private final Type type; @Override public int compareTo(DataFieldDefinition o) { return ordinal - o.ordinal; } public IntermediateField generateIntermediateCode(IntermediateGenerator state) { return Intermediates.field(name, type); } public DataFieldDescriptor getDescriptor() { return field(ordinal, name, "get" + capitalize(toJavaName(name)), type.toDescriptor()); } public String getJavaName() { return Symbol.toJavaName(name); } public Class<?> getJavaType() { return Callable.class; } public String getName() { return name; } public Type getType() { return type; } public DataFieldDefinition qualifyNames(TypeQualifier state) { return withType(type.qualifyNames(state)); } public Argument toArgument() { return Argument.builder() .withName(name) .withSourceLocation(sourceLocation) .withType(type) .build(); } @Override public String toString() { return name + " :: " + type; } public Value toValue() { return Identifier.builder() .withSymbol(symbol(name)) .withType(type) .withSourceLocation(sourceLocation) .build(); } private DataFieldDefinition withType(Type type) { return new DataFieldDefinition(sourceLocation, ordinal, name, type); } public static final class Builder implements SyntaxBuilder<DataFieldDefinition> { private Optional<SourceLocation> sourceLocation = Optional.empty(); private Optional<Integer> ordinal = Optional.empty(); private Optional<String> name = Optional.empty(); private Optional<Type> type = Optional.empty(); public DataFieldDefinition build() { return new DataFieldDefinition( require(sourceLocation, "Source location"), require(ordinal, "Ordinal"), require(name, "Field name"), require(type, "Field type") ); } public Builder withName(String name) { this.name = Optional.of(name); return this; } public Builder withOrdinal(int ordinal) { this.ordinal = Optional.of(ordinal); return this; } @Override public Builder withSourceLocation(SourceLocation sourceLocation) { this.sourceLocation = Optional.of(sourceLocation); return this; } public Builder withType(Type type) { this.type = Optional.of(type); return this; } } }