aspect ASTGrammarAnalysis { // lazy build a map ASTDecl -> ASTDecl* // map an ASTDecl to all left hand sides in productions private HashMap Program.astParentMap = null; private HashMap Program.astParentMap() { if(astParentMap == null) { astParentMap = new HashMap(); collectAstParentMap(astParentMap); } return astParentMap; } protected void ASTNode.collectAstParentMap(HashMap map) { for(int i = 0; i < getNumChild(); i++) getChild(i).collectAstParentMap(map); } protected void ASTDecl.collectAstParentMap(HashMap map) { for(Iterator iter = components().iterator(); iter.hasNext(); ) { ASTChild child = (ASTChild)iter.next(); if(!(child instanceof ASTTokenChild)) { TypeDecl typeDecl = child.type(); if(!map.containsKey(typeDecl)) map.put(typeDecl, new HashSet(4)); Collection c = (Collection)map.get(typeDecl); c.add(this); } } } eq Program.getCompilationUnit(int i).parents(TypeDecl typeDecl) = astParentMap().containsKey(typeDecl) ? (Collection)astParentMap().get(typeDecl) : new ArrayList(0); inh Collection ASTDecl.parents(TypeDecl typeDecl); syn lazy Collection ASTDecl.parents() { if(superclass() instanceof ASTDecl) { HashSet set = new HashSet(); set.addAll(parents(this)); set.addAll(((ASTDecl)superclass()).parents()); return set; } else return parents(this); } syn boolean ASTDecl.isRootNode() = parents().isEmpty(); inh TypeDecl ASTChild.hostType(); eq ASTDecl.getASTChild(int i).hostType() = this; public void NTAListChild.nameCheck() { super.nameCheck(); if(hostType().memberMethods("get" + name() + "List").isEmpty()) error("Missing equation for NTA " + name() + " in " + hostType().typeName()); } public void NTAOptionalChild.nameCheck() { super.nameCheck(); if(hostType().memberMethods("get" + name() + "Opt").isEmpty()) error("Missing equation for NTA " + name() + " in " + hostType().typeName()); } public void NTAElementChild.nameCheck() { super.nameCheck(); if(hostType().memberMethods("get" + name()).isEmpty()) error("Missing equation for NTA " + name() + " in " + hostType().typeName()); } public void NTATokenChild.nameCheck() { super.nameCheck(); if(hostType().memberMethods("get" + name()).isEmpty()) error("Missing equation for NTA " + name() + " in " + hostType().typeName()); } public void ASTChild.nameCheck() { super.nameCheck(); if(lookupASTChild(name()) != this) error("AST child " + name() + " is multiply declared"); } inh ASTChild ASTChild.lookupASTChild(String name); eq ASTDecl.getASTChild(int i).lookupASTChild(String name) = lookupChild(name); }