package me.tomassetti.turin.parser.ast.relations; import com.google.common.collect.ImmutableList; import me.tomassetti.jvm.JvmNameUtils; import me.tomassetti.turin.definitions.TypeDefinition; import me.tomassetti.turin.resolvers.SymbolResolver; import me.tomassetti.turin.resolvers.jdk.ReflectionTypeDefinitionFactory; import me.tomassetti.turin.parser.ast.FormalParameterNode; import me.tomassetti.turin.parser.ast.Node; import me.tomassetti.turin.parser.ast.typeusage.TypeUsageNode; import me.tomassetti.turin.typesystem.ReferenceTypeUsage; import me.tomassetti.turin.typesystem.TypeUsage; import me.tomassetti.turin.util.StringUtils; import turin.relations.Relation; import java.util.ArrayList; import java.util.List; public class RelationFieldDefinition extends Node { private String name; private TypeUsageNode type; public boolean isApplicableTo(TypeDefinition typeDefinition, SymbolResolver resolver) { if ((type.getParent() instanceof FormalParameterNode) && type.getParent().getParent() == null){ throw new UnsupportedOperationException(); } ReferenceTypeUsage referenceTypeUsage = new ReferenceTypeUsage(typeDefinition); return referenceTypeUsage.canBeAssignedTo(type); } public RelationDefinition getRelationDefinition() { return (RelationDefinition)getParent(); } public String methodDescriptor(SymbolResolver resolver) { if (cardinality == Cardinality.SINGLE) { return "(" + otherField().getType().jvmType().getDescriptor() + ")" + JvmNameUtils.descriptor(Relation.ReferenceSingleEndpoint.class); } else if (cardinality == Cardinality.MANY) { return "(" + otherField().getType().jvmType().getDescriptor() + ")" + JvmNameUtils.descriptor(Relation.ReferenceMultipleEndpoint.class); } else { throw new UnsupportedOperationException(); } } public enum Cardinality { SINGLE, MANY } @Override public TypeUsage calcType() { if (cardinality == Cardinality.SINGLE) { List<TypeUsage> typeParams = new ArrayList<>(getParentOfType(RelationDefinition.class).getTypeParameters()); TypeDefinition referenceSingleEndpointTD = symbolResolver().getTypeDefinitionIn(Relation.ReferenceSingleEndpoint.class.getCanonicalName(), this); ReferenceTypeUsage res = new ReferenceTypeUsage(referenceSingleEndpointTD, typeParams); return res; } else if (cardinality == Cardinality.MANY) { List<TypeUsage> typeParams = new ArrayList<>(getParentOfType(RelationDefinition.class).getTypeParameters()); TypeDefinition referenceMultipleEndpointTD = symbolResolver().getTypeDefinitionIn(Relation.ReferenceMultipleEndpoint.class.getCanonicalName(), this); ReferenceTypeUsage res = new ReferenceTypeUsage(referenceMultipleEndpointTD, typeParams); return res; } else { throw new UnsupportedOperationException(); } } public String getName() { return name; } public TypeUsageNode getType() { return type; } public Cardinality getCardinality() { return cardinality; } private Cardinality cardinality; public RelationFieldDefinition(Cardinality cardinality, String name, TypeUsageNode type) { this.cardinality = cardinality; this.name = name; this.type = type; this.type.setParent(this); } @Override public Iterable<Node> getChildren() { return ImmutableList.of(type); } private RelationFieldDefinition otherField() { RelationDefinition relationDefinition = (RelationDefinition)getParent(); if (relationDefinition.firstField() == this) { return relationDefinition.secondField(); } else if (relationDefinition.secondField() == this) { return relationDefinition.firstField(); } else { throw new UnsupportedOperationException(); } } public String methodName() { if (otherField().getCardinality() == Cardinality.SINGLE) { return getName() + "For" + StringUtils.capitalize(otherField().getName()); } else if (otherField().getCardinality() == Cardinality.MANY) { return getName() + "For" + StringUtils.capitalize(otherField().getName()) + "Element"; } else { throw new UnsupportedOperationException(); } } }