import java.util.*; aspect TypeAnalysis { public abstract TypeUse Component.getTypeUse(); //--- lookupType --- syn TypeDecl TypeUse.decl() = lookupType(getID()); inh TypeDecl TypeUse.lookupType(String name); inh TypeDecl TypeDecl.lookupType(String name); eq Program.getChild().lookupType(String name) { for (TypeDecl td : getTypeDecls()) { if (td.getID().equals(name)) { return td; } } return null; } //--- isAlreadyDeclared --- syn boolean TypeDecl.isAlreadyDeclared() = lookupType(getID()) != this; } aspect ComponentAnalysis { //--- isTargetOfDirectedRelation --- inh boolean Component.isTargetOfDirectedRelation(); eq Relation.getRight().isTargetOfDirectedRelation() = getDirection() instanceof RightDirection; eq Program.getChild().isTargetOfDirectedRelation() = false; //--- name --- syn String Component.name() = getID(); //--- enclosingTypeDecl --- inh TypeDecl Component.enclosingTypeDecl(); eq TypeDecl.getChild().enclosingTypeDecl() = this; eq Program.getChild().enclosingTypeDecl() = null; //--- otherSide --- inh RelationComponent RelationComponent.opposite(); eq Relation.getLeft().opposite() = getRight(); eq Relation.getRight().opposite() = getLeft(); eq Program.getChild().opposite() = null; //--- ofTypeDecl --- syn TypeDecl RelationComponent.ofTypeDecl() = opposite().getTypeUse().decl(); //--- isAlreadyDeclared --- /** * Check, if role with the same name is already declared on the same nonterminal */ syn boolean RelationComponent.isAlreadyDeclared() = !isTargetOfDirectedRelation() /* if unnamed in relation, there is no role name, so no error */ && getTypeUse().decl() != null /* nonterminal type of role is defined */ && findComponent(getTypeUse().decl(), name()) != this; /* there is another role defined previously with the same name */ //--- findComponent --- /** Search for either a component on the RHS of the given type with the given name, * or a relation part for the given type and a role with the given name */ inh Component Component.findComponent(TypeDecl td, String name); eq Program.getChild().findComponent(TypeDecl td, String name) = findComponentSyn(td, name); syn Component Program.findComponentSyn(TypeDecl td, String name) { for (Component c: td.getComponents()) { if (c.name().equals(name)) { return c; } } for (Relation r : getRelations()) { if (r.getLeft().matches(td, name)) return r.getLeft(); if (r.getRight().matches(td, name)) return r.getRight(); } return null; } //--- isInvalidRedefinition --- /** * Check, if a component with the same name is already declared in some supertype */ syn boolean Component.isInvalidRedefinition() = invalidRedefinition() != null; /** * Check, if a component with the same name is already declared in some supertype, and return it, if any */ syn Component Component.invalidRedefinition() = null; eq TokenComponent.invalidRedefinition() = invalidRedefinitionOn(enclosingTypeDecl()); eq RelationComponent.invalidRedefinition() = invalidRedefinitionOn(getTypeUse().decl()); syn Component Component.invalidRedefinitionOn(TypeDecl td) { if (td == null) return null; while (td.hasSuper() && td.getSuper().decl() != null) { td = td.getSuper().decl(); // find a matching component on the RHS of the (current) super type Component c = findComponent(td, getID()); if (c != null && !this.isEqual(c)) return c; } return null; } //--- isEqual --- syn boolean Component.isEqual(Component c) = this.getClass() == c.getClass() && getTypeUse().isEqual(c.getTypeUse()); /** * TokenComponents may be specialized by NTATokenComponents and vice versa */ eq TokenComponent.isEqual(Component c) = (c instanceof TokenComponent) && getTypeUse().isEqual(c.getTypeUse()); syn boolean TypeUse.isEqual(TypeUse u); eq SimpleTypeUse.isEqual(TypeUse u) = u instanceof SimpleTypeUse && getID().equals(u.getID()); eq ParameterizedTypeUse.isEqual(TypeUse u) { if (!getID().equals(u.getID())) return false; if (!(u instanceof ParameterizedTypeUse)) return false; ParameterizedTypeUse pu = (ParameterizedTypeUse) u; if (getNumTypeUse() != pu.getNumTypeUse()) return false; for (int i = 0; i < getNumTypeUse(); i++) { if (!getTypeUse(i).isEqual(pu.getTypeUse(i))) return false; } return true; } //--- matches --- /** * @return true, if the component has both type and role, its type matches the given typeDecl and its name matches the given name */ syn boolean RelationComponent.matches(TypeDecl td, String name) = !isTargetOfDirectedRelation() && getTypeUse().decl() == td && name().equals(name); //--- relationComponents --- coll Set TypeDecl.relationComponents() [new HashSet()] root Program; RelationComponent contributes this when !isTargetOfDirectedRelation() && getTypeUse().decl() != null to TypeDecl.relationComponents() for getTypeUse().decl(); //--- relationComponentsTransitive --- syn Collection TypeDecl.relationComponentsTransitive() { ArrayList list = new ArrayList<>(); if (hasSuper() && getSuper().decl() != null) { list.addAll(getSuper().decl().relationComponentsTransitive()); } list.addAll(relationComponents()); return list; } //--- oneRelationComponents --- syn Set TypeDecl.oneRelationComponents() { Set set = new HashSet<>(); for (RelationComponent rc: relationComponents()) { if (rc instanceof OneRelationComponent) { set.add((OneRelationComponent) rc); } } return set; } //--- needUnresolvedClass --- syn boolean TypeDecl.needUnresolvedClass() { // a TypeDecl needs an unresolved class, if it can appear in a relation // TODO return true; } //--- isList --- syn boolean Component.isList() = false; eq ListComponent.isList() = true; eq NTAListComponent.isList() = true; eq ManyRelationComponent.isList() = true; //--- isOpt --- syn boolean Component.isOpt() = false; eq OptComponent.isOpt() = true; eq NTAOptComponent.isOpt() = true; eq OptionalRelationComponent.isOpt() = true; //--- isNullable --- syn boolean Component.isNullable() = false; eq TokenComponent.isNullable() = !"float double int short long char byte boolean".contains(getTypeUse().getID()); } aspect InstanceSupplier { //--- program --- inh Program TypeDecl.program(); eq Program.getTypeDecl(int i).program() = this; //--- subTypeDecls --- syn Collection TypeDecl.subTypeDecls() { java.util.List subDecls = new ArrayList(); for (TypeDecl decl : program().getTypeDeclList()) { if (decl.hasSuper() && decl.getSuper().getID().equals(getID())) { subDecls.add(decl); } } return subDecls; } //--- instantiableSubType --- syn TypeDecl TypeDecl.instantiableSubType() { if (getAbstract() == false) { return this; } else { for (TypeDecl sub : subTypeDecls()) { if (sub.getAbstract() == false) { return sub; } else { TypeDecl subInstance = sub.instantiableSubType(); if (subInstance != null) { return subInstance; } } } } return null; } } aspect Constructors { //--- componentsTransitive --- syn Collection TypeDecl.componentsTransitive() { ArrayList list = new ArrayList<>(); if (hasSuper() && getSuper().decl() != null) { list.addAll(getSuper().decl().componentsTransitive()); } for (Component c: getComponents()) { if (c.inConstructor()) { list.add(c); } } return list; } //--- needsConstructor --- syn boolean TypeDecl.needsConstructor() = !componentsTransitive().isEmpty() && !relationComponentsTransitive().isEmpty(); //--- inConstructor --- /** * @return true, if the component should be added to the constructor (i.e., is not an NTA) */ syn boolean Component.inConstructor() = true; eq NTAComponent.inConstructor() = false; eq NTAOptComponent.inConstructor() = false; eq NTAListComponent.inConstructor() = false; eq NTATokenComponent.inConstructor() = false; } aspect Utils { //--- toString --- public String SimpleTypeUse.toString() { return getID(); } public String ParameterizedTypeUse.toString() { StringBuilder sb = new StringBuilder(); sb.append(getID()).append("<"); boolean first = true; for (TypeUse u: getTypeUses()) { if (first) { first = false; } else { sb.append(", "); } sb.append(u.toString()); } sb.append(">"); return sb.toString(); } public String TypeDecl.toString() { return getID(); } }