001    /*
002     * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered
003     * by the modified BSD License. You should have received a copy of the
004     * modified BSD license with this compiler.
005     * 
006     * Copyright (c) 2005-2008, Torbjorn Ekman
007     * All rights reserved.
008     */
009    
010    aspect BoundNames {
011      public Access FieldDeclaration.createQualifiedBoundAccess() {
012        if(isStatic())
013          return hostType().createQualifiedAccess().qualifiesAccess(new BoundFieldAccess(this));
014        else
015          return new ThisAccess("this").qualifiesAccess(
016            new BoundFieldAccess(this));
017      }
018    
019      // The memberMethods(String name) attribute is used to lookup member methods.
020      // It uses the methodsNameMap() map where a name is mapped to a list of member
021      // methods. We extend the map with the declaration m by either appending
022      // it to an existing list of declarations or adding a new list. That list
023      // will be used to name bind a new qualified name access.
024      public MethodDecl TypeDecl.addMemberMethod(MethodDecl m) {
025        addBodyDecl(m);
026        return (MethodDecl)getBodyDecl(getNumBodyDecl()-1);
027        /*
028        HashMap map = methodsNameMap();
029        ArrayList list = (ArrayList)map.get(m.name());
030        if(list == null) {
031          list = new ArrayList(4);
032          map.put(m.name(), list);
033        }
034        list.add(m);
035        if(!memberMethods(m.name()).contains(m))
036          throw new Error("The method " + m.signature() + " added to " + typeName() + " can not be found using lookupMemberMethod");
037        */
038      }
039    
040      public ConstructorDecl TypeDecl.addConstructor(ConstructorDecl c) {
041        addBodyDecl(c);
042        return (ConstructorDecl)getBodyDecl(getNumBodyDecl()-1);
043      }
044    
045      public ClassDecl TypeDecl.addMemberClass(ClassDecl c) {
046        addBodyDecl(new MemberClassDecl(c));
047        return ((MemberClassDecl)getBodyDecl(getNumBodyDecl()-1)).getClassDecl();
048      }
049    
050    
051      // the new field must be unique otherwise an error occurs
052      public FieldDeclaration TypeDecl.addMemberField(FieldDeclaration f) {
053        addBodyDecl(f);
054        return (FieldDeclaration)getBodyDecl(getNumBodyDecl()-1);
055        //if(!memberFields(f.name()).contains(f))
056        //  throw new Error("The field " + f.name() + " added to " + typeName() + " can not be found using lookupMemberField");
057      }
058    
059      // A BoundMethodAccess is a MethodAccess where the name analysis is bypassed by explicitly setting the desired binding
060      // this is useful when name binding is cached and recomputation is undesired
061      public BoundMethodAccess.BoundMethodAccess(String name, List args, MethodDecl methodDecl) {
062        this(name, args);
063        this.methodDecl = methodDecl;
064      }
065      private MethodDecl BoundMethodAccess.methodDecl;
066      eq BoundMethodAccess.decl() = methodDecl;
067    
068      public BoundFieldAccess.BoundFieldAccess(FieldDeclaration f) {
069        this(f.name(), f);
070      }
071    
072      eq BoundFieldAccess.decl() = getFieldDeclaration();
073      public boolean BoundFieldAccess.isExactVarAccess() {
074        return false;
075      }
076    
077      public Access MethodDecl.createBoundAccess(List args) {
078        if(isStatic()) {
079          return hostType().createQualifiedAccess().qualifiesAccess(
080            new BoundMethodAccess(name(), args, this)
081          );
082        }
083        return new BoundMethodAccess(name(), args, this);
084      }
085    
086      public Access FieldDeclaration.createBoundFieldAccess() {
087        return createQualifiedBoundAccess();
088      }
089    
090      public TypeAccess TypeDecl.createBoundAccess() {
091        return new BoundTypeAccess("", name(), this);
092      }
093      eq BoundTypeAccess.decls() = SimpleSet.emptySet.add(getTypeDecl());
094    
095      rewrite BytecodeTypeAccess {
096        to Access {
097          if(name().indexOf("$") == -1)
098            return new TypeAccess(packageName(), name());
099          else {
100            String[] names = name().split("\\$");
101            Access a = null; // the resulting access
102            String newName = null; // the subname to try
103            TypeDecl type = null; // qualifying type if one
104            for(int i = 0; i < names.length; i++) {
105              newName = newName == null ? names[i] : (newName + "$" + names[i]);
106              SimpleSet set;
107              if(type != null)
108                set = type.memberTypes(newName);
109              else if(packageName().equals(""))
110                set = lookupType(newName);
111              else {
112                TypeDecl typeDecl = lookupType(packageName(), newName);
113                set = SimpleSet.emptySet;
114                if(typeDecl != null)
115                  set = set.add(typeDecl);
116              }
117              if(!set.isEmpty()) {
118                a = a == null ? (Access)new TypeAccess(packageName(), newName) : (Access)a.qualifiesAccess(new TypeAccess(newName));
119                type = (TypeDecl)set.iterator().next();
120                newName = null; // reset subname
121              }
122            }
123            if(a == null) {
124              a = new TypeAccess(packageName(), name());
125            }
126            return a;
127          }
128        }
129      }
130    }