/* the names of fresh variables are guaranteed not to clash * with the names of other variables */ aspect FreshVariables { interface FreshVariable extends Variable { String pickFreshName(); } FreshParameter implements FreshVariable; FreshLocalVariable implements FreshVariable; FreshField implements FreshVariable; public FreshParameter.FreshParameter(Access type, String name) { this(new Modifiers(new List()), type, name); } public FreshLocalVariable.FreshLocalVariable(Access type, String name) { this(new Modifiers(new List()), type, name, new Opt()); } public boolean FreshVariable.canIntroduceLocal(String name) { return true; } public String FreshVariable.name() { return "#fresh#" + super.name(); } eq FreshVariable.refreshVariable() = this; public static LanguageExtension ASTNode.FRESH_VARIABLES = new LanguageExtension("fresh variables") { public void eliminateOn(ASTNode n) { n.eliminateFreshVariables(); n.flushCaches(); } }; public void ASTNode.eliminateFreshVariables() { for(int i=0;i decls = hostBodyDecl().allDecls(); if(conflicts(fresh_name, decls)) { for(int i=0;;++i) { fresh_name = getID()+i; if(!conflicts(fresh_name, decls)) break; } } return fresh_name; } // duplicate of the preceding method public String FreshLocalVariable.pickFreshName() { String fresh_name = getID(); Collection decls = hostBodyDecl().allDecls(); if(conflicts(fresh_name, decls)) { for(int i=0;;++i) { fresh_name = getID()+i; if(!conflicts(fresh_name, decls)) break; } } return fresh_name; } // check whether the name conflicts with any of the decls public boolean FreshVariable.conflicts(String name, Collection decls) { for(Declaration decl : decls) if(decl != this && !(decl instanceof MethodDecl) && decl.name().equals(name)) return true; return false; } // collect all declarations made or referenced in a subtree public Collection ASTNode.allDecls() { HashSet res = new HashSet(); collectAllDecls(res); return res; } public void ASTNode.collectAllDecls(Collection res) { for(int i=0;i res) { res.add(this); super.collectAllDecls(res); } // this shouldn't really be necessary, but JastAdd doesn't propagate through // more than one interface public void Variable.collectAllDecls(Collection res) { res.add(this); super.collectAllDecls(res); } public void PackageAccess.collectAllDecls(Collection res) { res.add(lookupPackage(getTopLevelPackage())); super.collectAllDecls(res); } public void TypeAccess.collectAllDecls(Collection res) { if(!getPackage().equals("")) res.add(lookupPackage(getTopLevelPackage())); res.add(decl()); super.collectAllDecls(res); } public void VarAccess.collectAllDecls(Collection res) { res.add(decl()); super.collectAllDecls(res); } public void MethodAccess.collectAllDecls(Collection res) { res.add(decl()); super.collectAllDecls(res); } // replace all declarations in this subtree by their fresh counterparts public void ASTNode.freshenAllDeclarations() { freshenDeclaration(); for(int i=0;i uses = allUses(); FreshParameter fp = new FreshParameter(getModifiers(), getTypeAccess(), getID()); for(VarAccess va : uses) va.lock(fp); replaceWith(fp); } public void VariableDeclaration.freshenDeclaration() { Collection uses = allUses(); FreshLocalVariable fv = new FreshLocalVariable(getModifiers(), getTypeAccess(), getID(), getInitOpt()); for(VarAccess va : uses) va.lock(fv); replaceWith(fv); } public FreshLocalVariable ParameterDeclaration.asFreshVariableDeclaration() { Collection uses = allUses(); FreshLocalVariable fv = new FreshLocalVariable(getModifiers(), getTypeAccess(), getID(), new Opt()); for(VarAccess va : uses) va.lock(fv); return fv; } }