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    import java.util.*;
011    import java.util.ArrayList;
012    
013    aspect ConstructScope {
014      inh Collection ConstructorAccess.lookupConstructor();
015      eq Program.getChild().lookupConstructor() = Collections.EMPTY_LIST;
016      eq TypeDecl.getBodyDecl().lookupConstructor() = constructors();
017      eq AbstractDot.getRight().lookupConstructor() = getLeft().type().constructors();
018    
019      inh Collection SuperConstructorAccess.lookupSuperConstructor();
020      eq TypeDecl.getBodyDecl().lookupSuperConstructor() = lookupSuperConstructor();
021      syn Collection TypeDecl.lookupSuperConstructor() = Collections.EMPTY_LIST;
022      eq ClassDecl.lookupSuperConstructor() = hasSuperclass() ? superclass().constructors() : Collections.EMPTY_LIST;
023      eq InterfaceDecl.lookupSuperConstructor() = typeObject().constructors();
024      eq Program.getChild().lookupSuperConstructor() = Collections.EMPTY_LIST;
025      eq AbstractDot.getRight().lookupSuperConstructor() = getLeft().type().lookupSuperConstructor();
026    
027      inh TypeDecl ClassInstanceExpr.typeObject();
028      
029      // compute the most specific constructor in a collection
030      // the constructor is invoked with the arguments specified in argList
031      // the curent context (this) is used to evaluate the hostType for accessibility
032      syn SimpleSet Expr.mostSpecificConstructor(Collection constructors) {
033        SimpleSet maxSpecific = SimpleSet.emptySet;
034        for(Iterator iter = constructors.iterator(); iter.hasNext(); ) {
035          ConstructorDecl decl = (ConstructorDecl)iter.next();
036          if(applicableAndAccessible(decl)) {
037            if(maxSpecific.isEmpty())
038              maxSpecific = maxSpecific.add(decl);
039            else {
040              if(decl.moreSpecificThan((ConstructorDecl)maxSpecific.iterator().next()))
041                maxSpecific = SimpleSet.emptySet.add(decl);
042              else if(!((ConstructorDecl)maxSpecific.iterator().next()).moreSpecificThan(decl))
043                maxSpecific = maxSpecific.add(decl);
044            }
045          }
046        }
047        return maxSpecific;
048      }
049    
050      syn boolean Expr.applicableAndAccessible(ConstructorDecl decl) = false;
051      eq ConstructorAccess.applicableAndAccessible(ConstructorDecl decl) =
052        decl.applicable(getArgList()) && decl.accessibleFrom(hostType());
053      eq ClassInstanceExpr.applicableAndAccessible(ConstructorDecl decl) = 
054        decl.applicable(getArgList()) && decl.accessibleFrom(hostType()) && 
055        (!decl.isProtected() || hasTypeDecl() || decl.hostPackage().equals(hostPackage()));
056      
057      syn lazy SimpleSet ConstructorAccess.decls() = mostSpecificConstructor(lookupConstructor());
058      
059      syn lazy SimpleSet SuperConstructorAccess.decls() {
060        Collection c = hasPrevExpr() && !prevExpr().isTypeAccess() ?
061          hostType().lookupSuperConstructor() : lookupSuperConstructor();
062        return mostSpecificConstructor(c);
063      }
064      
065      syn lazy ConstructorDecl ConstructorAccess.decl() {
066        SimpleSet decls = decls();
067        if(decls.size() == 1)
068          return (ConstructorDecl)decls.iterator().next();
069        return unknownConstructor();
070      }
071      inh ConstructorDecl ConstructorAccess.unknownConstructor();
072    
073      syn lazy SimpleSet ClassInstanceExpr.decls() {
074        TypeDecl typeDecl = hasTypeDecl() ? getTypeDecl() : getAccess().type();
075        return mostSpecificConstructor(typeDecl.constructors());
076      }
077      
078      syn lazy ConstructorDecl ClassInstanceExpr.decl() {
079        SimpleSet decls = decls();
080        if(decls.size() == 1)
081          return (ConstructorDecl)decls.iterator().next();
082        return unknownConstructor();
083      }
084      inh ConstructorDecl ClassInstanceExpr.unknownConstructor();
085    }
086    
087    aspect ConstructorLookup {
088      public ConstructorDecl TypeDecl.lookupConstructor(ConstructorDecl signature) {
089        for(Iterator iter = constructors().iterator(); iter.hasNext(); ) {
090          ConstructorDecl decl = (ConstructorDecl)iter.next();
091          if(decl.sameSignature(signature)) {
092            return decl;
093          }
094        }
095        return null;
096      }
097    
098      syn lazy Collection TypeDecl.constructors() {
099        Collection c = new ArrayList();
100        for(int i = 0; i < getNumBodyDecl(); i++) {
101          if(getBodyDecl(i) instanceof ConstructorDecl) {
102            c.add(getBodyDecl(i));
103          }
104        }
105        return c;
106      }
107    }
108    
109    aspect ConstructorDecl {
110      syn lazy String ConstructorDecl.name() = getID();
111      // 8.8.2
112      syn lazy String ConstructorDecl.signature() {
113        StringBuffer s = new StringBuffer();
114        s.append(name() + "(");
115        for(int i = 0; i < getNumParameter(); i++) {
116          s.append(getParameter(i));
117          if(i != getNumParameter() - 1)
118            s.append(", ");
119        }
120        s.append(")");
121        return s.toString();
122      }
123    
124      // 8.8.2
125      syn lazy boolean ConstructorDecl.sameSignature(ConstructorDecl c) {
126        if(!name().equals(c.name()))
127          return false;
128        if(c.getNumParameter() != getNumParameter())
129          return false;
130        for(int i = 0; i < getNumParameter(); i++)
131          if(!c.getParameter(i).type().equals(getParameter(i).type()))
132            return false;
133        return true;
134      }
135    
136      syn lazy boolean ConstructorDecl.moreSpecificThan(ConstructorDecl m) {
137        for(int i = 0; i < getNumParameter(); i++) {
138          if(!getParameter(i).type().instanceOf(m.getParameter(i).type()))
139            return false;
140        }
141        return true;
142      }
143    
144      public boolean ConstructorDecl.applicable(List argList) {
145        if(getNumParameter() != argList.getNumChild())
146          return false;
147        for(int i = 0; i < getNumParameter(); i++) {
148          TypeDecl arg = ((Expr)argList.getChild(i)).type();
149          TypeDecl parameter = getParameter(i).type();
150          if(!arg.instanceOf(parameter)) {
151            return false;
152          }  
153        }
154        return true;
155      }
156    }
157    aspect ImplicitConstructor {
158      syn boolean List.requiresDefaultConstructor() {
159        if(getParent() instanceof ClassDecl) {
160          ClassDecl c = (ClassDecl)getParent();
161          return c.noConstructor() && c.getBodyDeclListNoTransform() == this && !(c instanceof AnonymousDecl);
162        }
163        return false;
164      }
165    
166      /**
167       * Flag to indicate if this constructor is an auto-generated
168       * default constructor. Default constructors are not pretty
169       * printed.
170       */
171      private boolean ConstructorDecl.isDefaultConstructor = false;
172      /**
173       * Set the default constructor flag. Causes this constructor
174       * to not be pretty printed.
175       */
176      public void ConstructorDecl.setDefaultConstructor() {
177        isDefaultConstructor = true;
178      }
179      /**
180       * @return true if this is an auto-generated default constructor
181       */
182      syn boolean ConstructorDecl.isDefaultConstructor() =
183        isDefaultConstructor;
184        
185      rewrite List {
186        when(requiresDefaultConstructor())
187        to List {
188          ClassDecl c = (ClassDecl)getParent();
189          Modifiers m = new Modifiers();
190          if(c.isPublic()) m.addModifier(new Modifier("public"));
191          else if(c.isProtected()) m.addModifier(new Modifier("protected"));
192          else if(c.isPrivate()) m.addModifier(new Modifier("private"));
193          ConstructorDecl constructor = new ConstructorDecl(
194                m,
195                c.name(),
196                new List(),
197                new List(),
198                new Opt(),
199                new Block()
200          );
201          constructor.setDefaultConstructor();
202          c.addBodyDecl(constructor);
203          return this;
204        }
205      }
206    
207      syn boolean ClassDecl.noConstructor() {
208        if(!compilationUnit().fromSource())
209          return false;
210        for(int i = 0; i < getNumBodyDecl(); i++)
211          if(getBodyDecl(i) instanceof ConstructorDecl)
212            return false;
213        return true;
214      }
215      
216      // 8.8.5
217      rewrite ConstructorDecl {
218        when(!hasConstructorInvocation() && !hostType().isObject())
219        to ConstructorDecl {
220          setConstructorInvocation(
221            new ExprStmt(
222              new SuperConstructorAccess("super", new List())
223              )
224            );
225          return this;
226        }
227      }
228    }
229    
230