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    
012    aspect AccessTypes {
013      syn boolean Expr.isTypeAccess() = false;
014      eq TypeAccess.isTypeAccess() = true;
015      eq AbstractDot.isTypeAccess() = getRight().isTypeAccess();
016    
017      syn boolean Expr.isMethodAccess() = false;
018      eq AbstractDot.isMethodAccess() = getRight().isMethodAccess();
019      eq MethodAccess.isMethodAccess() = true;
020    
021      syn boolean Expr.isFieldAccess() = false;
022      eq AbstractDot.isFieldAccess() = getRight().isFieldAccess();
023      syn lazy boolean VarAccess.isFieldAccess() = decl().isClassVariable() || decl().isInstanceVariable();
024    
025      syn boolean Expr.isSuperAccess() = false;
026      eq AbstractDot.isSuperAccess() = getRight().isSuperAccess();
027      eq SuperAccess.isSuperAccess() = true;
028      eq ParExpr.isSuperAccess() = getExpr().isSuperAccess();
029      eq CastExpr.isSuperAccess() = getExpr().isSuperAccess();
030    
031      syn boolean Expr.isThisAccess() = false;
032      eq AbstractDot.isThisAccess() = getRight().isThisAccess();
033      eq ThisAccess.isThisAccess() = true;
034      eq ParExpr.isThisAccess() = getExpr().isThisAccess();
035      eq CastExpr.isThisAccess() = getExpr().isThisAccess();
036    
037      syn boolean Expr.isPackageAccess() = false;
038      eq AbstractDot.isPackageAccess() = getRight().isPackageAccess();
039      eq PackageAccess.isPackageAccess() = true;
040    
041      syn boolean Expr.isArrayAccess() = false;
042      eq AbstractDot.isArrayAccess() = getRight().isArrayAccess();
043      eq ArrayAccess.isArrayAccess() = true;
044      
045      syn boolean Expr.isClassAccess() = false;
046      eq AbstractDot.isClassAccess() = getRight().isClassAccess();
047      eq ClassAccess.isClassAccess() = true;
048     
049      syn boolean Expr.isSuperConstructorAccess() = false;
050      eq AbstractDot.isSuperConstructorAccess() = getRight().isSuperConstructorAccess();
051      eq SuperConstructorAccess.isSuperConstructorAccess() = true;
052    }
053    
054    aspect QualifiedNames {
055      syn boolean Expr.isLeftChildOfDot() = hasParentDot() && parentDot().getLeft() == this;
056      syn boolean Expr.isRightChildOfDot() = hasParentDot() && parentDot().getRight() == this;
057      
058      syn boolean Access.isQualified() = hasPrevExpr();
059      eq AbstractDot.isQualified() = hasParentDot();
060    
061      syn Expr Access.qualifier() = prevExpr();
062      
063      syn Expr AbstractDot.leftSide() = getLeft();
064      syn Access AbstractDot.rightSide() = getRight/*NoTransform*/() instanceof AbstractDot ? (Access)((AbstractDot)getRight/*NoTransform*/()).getLeft() : (Access)getRight();
065    
066      syn Access Access.lastAccess() = this;
067      eq AbstractDot.lastAccess() = getRight().lastAccess();
068    
069      syn AbstractDot Expr.parentDot() = getParent() instanceof AbstractDot ? (AbstractDot)getParent() : null;
070      syn boolean Expr.hasParentDot() = parentDot() != null;
071    
072      syn Access Expr.nextAccess() = parentDot().nextAccess();
073      syn boolean Expr.hasNextAccess() = isLeftChildOfDot();
074      
075      syn Access AbstractDot.nextAccess() = rightSide();
076      
077      syn Expr AbstractDot.prevExpr() = leftSide();
078      syn lazy Expr Access.prevExpr() {
079        if(isLeftChildOfDot()) {
080          if(parentDot().isRightChildOfDot())
081            return parentDot().parentDot().leftSide();
082        }
083        else if(isRightChildOfDot())
084          return parentDot().leftSide();
085        throw new Error(this + " does not have a previous expression");
086      }
087    
088      syn boolean AbstractDot.hasPrevExpr() = true;
089      syn lazy boolean Access.hasPrevExpr() {
090        if(isLeftChildOfDot()) {
091          if(parentDot().isRightChildOfDot())
092            return true;
093        }
094        else if(isRightChildOfDot())
095          return true;
096        return false;
097      }
098    
099      public Dot Dot.lastDot() {
100        Dot node = this;
101        while(node.getRightNoTransform() instanceof Dot)
102          node = (Dot)node.getRightNoTransform();
103        return node;
104      }
105    
106      public Dot Expr.qualifiesAccess(Access access) {
107        Dot dot = new Dot(this, access);
108        dot.setStart(this.getStart());
109        dot.setEnd(access.getEnd());
110        return dot;
111      }
112      
113      public Dot Dot.qualifiesAccess(Access access) {
114         Dot lastDot = lastDot();
115         Expr l = lastDot.getRightNoTransform();
116         Dot dot = new Dot(lastDot.getRightNoTransform(), access);
117         dot.setStart(l.getStart());
118         dot.setEnd(access.getEnd());
119         lastDot.setRight(dot);
120         return this;
121      }
122      
123      // Used when replacing pairs from a list to concatenate the result to the tail of the current location.
124      private Access Dot.qualifyTailWith(Access expr) {
125        if(getRight/*NoTransform*/() instanceof AbstractDot) {
126          AbstractDot dot = (AbstractDot)getRight/*NoTransform*/();
127          return expr.qualifiesAccess(dot.getRight/*NoTransform*/());
128        }
129        return expr;
130      }
131    
132    
133      // These are used by the parser to extract the last name which
134      // will be replaced by a method name
135      public Access AbstractDot.extractLast() {
136        return getRightNoTransform();
137     }
138      public void AbstractDot.replaceLast(Access access) {
139        setRight(access);
140      }
141      public Access Dot.extractLast() {
142        return lastDot().getRightNoTransform();
143      }
144      public void Dot.replaceLast(Access access) {
145        lastDot().setRight(access);
146      }
147    
148      public Access Access.addArrayDims(List list) {
149        Access a = this;
150        for(int i = 0; i < list.getNumChildNoTransform(); i++) {
151          Dims dims = (Dims)list.getChildNoTransform(i);
152          Opt opt = dims.getExprOpt();
153          if(opt.getNumChildNoTransform() == 1)
154            a = new ArrayTypeWithSizeAccess(a, (Expr)opt.getChildNoTransform(0));
155          else
156            a = new ArrayTypeAccess(a);
157          a.setStart(dims.start());
158          a.setEnd(dims.end());
159        }
160        return a;
161      }
162    
163    }
164    
165    aspect NameResolution {
166     
167      // Resolve Package or Type name
168      rewrite PackageOrTypeAccess {
169        /*
170        when(!lookupType(name()).isEmpty())
171        to Access new TypeAccess(name());
172        when(hasPackage(name()))
173        to Access new PackageAccess(name());
174        */
175        when(!duringSyntacticClassification())
176        to Access{
177          if(!lookupType(name()).isEmpty())
178            return new TypeAccess(name(), start(), end());
179          else
180            return new PackageAccess(name(), start(), end());
181        }
182      }
183    
184      // Resolve Ambiguous name
185      rewrite AmbiguousAccess {
186        /*
187        when(!lookupVariable(name()).isEmpty())
188        to Access new VarAccess(name());
189        when(!lookupType(name()).isEmpty())
190        to Access new TypeAccess(name());
191        when(hasPackage(name()))
192        to Access new PackageAccess(name());
193        */
194        when(!duringSyntacticClassification())
195        to Access {
196          if(!lookupVariable(name()).isEmpty()) {
197            return new VarAccess(name(), start(), end());
198          }
199          else if(!lookupType(name()).isEmpty()) {
200            return new TypeAccess(name(), start(), end());
201          }
202          else {
203            return new PackageAccess(name(), start(), end());
204          }
205        }
206      }
207    
208      // combine two package access into one node
209      rewrite Dot {
210        when(!duringSyntacticClassification() && leftSide().isPackageAccess() && rightSide().isPackageAccess())
211        to Access {
212          PackageAccess left = (PackageAccess)leftSide();
213          PackageAccess right = (PackageAccess)rightSide();
214          left.setPackage(left.getPackage() + "." + right.getPackage());
215          left.setEnd(right.end());
216          return qualifyTailWith(left);
217        }
218      }
219            
220      // combine PackageAccess + TypeAccess into one qualified TypeAccess
221      rewrite Dot {
222        when(!duringSyntacticClassification() && leftSide().isPackageAccess() && !((Access)leftSide()).hasPrevExpr() && rightSide() instanceof TypeAccess)
223        to Access {
224          PackageAccess left = (PackageAccess)leftSide();
225          TypeAccess right = (TypeAccess)rightSide();
226          right.setPackage(left.getPackage());
227          right.setStart(left.start());
228          return qualifyTailWith(right);
229        }
230      }
231    }