001    /* Copyright (c) 2005-2008, Torbjorn Ekman
002     *                    2015, Jesper Öqvist <jesper.oqvist@cs.lth.se>
003     * All rights reserved.
004     *
005     * Redistribution and use in source and binary forms, with or without
006     * modification, are permitted provided that the following conditions are met:
007     *
008     * 1. Redistributions of source code must retain the above copyright notice,
009     * this list of conditions and the following disclaimer.
010     *
011     * 2. Redistributions in binary form must reproduce the above copyright notice,
012     * this list of conditions and the following disclaimer in the documentation
013     * and/or other materials provided with the distribution.
014     *
015     * 3. Neither the name of the copyright holder nor the names of its
016     * contributors may be used to endorse or promote products derived from this
017     * software without specific prior written permission.
018     *
019     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
021     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
023     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
024     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
025     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
026     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
027     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
029     * POSSIBILITY OF SUCH DAMAGE.
030     */
031    
032    import java.util.*;
033    
034    aspect AccessTypes {
035      syn boolean Expr.isTypeAccess() = false;
036      eq TypeAccess.isTypeAccess() = true;
037      eq AbstractDot.isTypeAccess() = getRight().isTypeAccess();
038    
039      syn boolean Expr.isMethodAccess() = false;
040      eq AbstractDot.isMethodAccess() = getRight().isMethodAccess();
041      eq MethodAccess.isMethodAccess() = true;
042    
043      syn boolean Expr.isFieldAccess() = false;
044      eq AbstractDot.isFieldAccess() = getRight().isFieldAccess();
045      syn lazy boolean VarAccess.isFieldAccess() = decl().isClassVariable() || decl().isInstanceVariable();
046    
047      syn boolean Expr.isSuperAccess() = false;
048      eq AbstractDot.isSuperAccess() = getRight().isSuperAccess();
049      eq SuperAccess.isSuperAccess() = true;
050      eq ParExpr.isSuperAccess() = getExpr().isSuperAccess();
051      eq CastExpr.isSuperAccess() = getExpr().isSuperAccess();
052    
053      syn boolean Expr.isThisAccess() = false;
054      eq AbstractDot.isThisAccess() = getRight().isThisAccess();
055      eq ThisAccess.isThisAccess() = true;
056      eq ParExpr.isThisAccess() = getExpr().isThisAccess();
057      eq CastExpr.isThisAccess() = getExpr().isThisAccess();
058    
059      syn boolean Expr.isPackageAccess() = false;
060      eq AbstractDot.isPackageAccess() = getRight().isPackageAccess();
061      eq PackageAccess.isPackageAccess() = true;
062    
063      syn boolean Expr.isArrayAccess() = false;
064      eq AbstractDot.isArrayAccess() = getRight().isArrayAccess();
065      eq ArrayAccess.isArrayAccess() = true;
066    
067      syn boolean Expr.isClassAccess() = false;
068      eq AbstractDot.isClassAccess() = getRight().isClassAccess();
069      eq ClassAccess.isClassAccess() = true;
070    
071      syn boolean Expr.isSuperConstructorAccess() = false;
072      eq AbstractDot.isSuperConstructorAccess() = getRight().isSuperConstructorAccess();
073      eq SuperConstructorAccess.isSuperConstructorAccess() = true;
074    }
075    
076    aspect QualifiedNames {
077      syn boolean Expr.isLeftChildOfDot() = hasParentDot() && parentDot().getLeft() == this;
078      syn boolean Expr.isRightChildOfDot() = hasParentDot() && parentDot().getRight() == this;
079    
080      syn boolean Access.isQualified() = hasPrevExpr();
081      eq AbstractDot.isQualified() = hasParentDot();
082    
083      syn Expr Access.qualifier() = prevExpr();
084    
085      syn Expr AbstractDot.leftSide() = getLeft();
086      syn Access AbstractDot.rightSide() = getRight() instanceof AbstractDot ?
087        (Access)((AbstractDot) getRight()).getLeft() : (Access) getRight();
088    
089      syn Access Access.lastAccess() = this;
090      eq AbstractDot.lastAccess() = getRight().lastAccess();
091    
092      syn AbstractDot Expr.parentDot() = getParent() instanceof AbstractDot ?
093        (AbstractDot) getParent() : null;
094      syn boolean Expr.hasParentDot() = parentDot() != null;
095    
096      syn Access Expr.nextAccess() = parentDot().nextAccess();
097      syn boolean Expr.hasNextAccess() = isLeftChildOfDot();
098    
099      syn Access AbstractDot.nextAccess() = rightSide();
100    
101      syn Expr AbstractDot.prevExpr() = leftSide();
102      syn lazy Expr Access.prevExpr() {
103        if (isLeftChildOfDot()) {
104          if (parentDot().isRightChildOfDot()) {
105            return parentDot().parentDot().leftSide();
106          }
107        } else if (isRightChildOfDot()) {
108          return parentDot().leftSide();
109        }
110        throw new Error(this + " does not have a previous expression");
111      }
112    
113      syn boolean AbstractDot.hasPrevExpr() = true;
114      syn lazy boolean Access.hasPrevExpr() {
115        if (isLeftChildOfDot()) {
116          if (parentDot().isRightChildOfDot()) {
117            return true;
118          }
119        } else if (isRightChildOfDot()) {
120          return true;
121        }
122        return false;
123      }
124    
125      public Dot Dot.lastDot() {
126        Dot node = this;
127        while (node.getRightNoTransform() instanceof Dot) {
128          node = (Dot) node.getRightNoTransform();
129        }
130        return node;
131      }
132    
133      /**
134       * Creates a qualified expression. This will not be subject to rewriting.
135       */
136      public Dot Expr.qualifiesAccess(Access access) {
137        Dot dot = new Dot(this, access);
138        dot.setStart(this.getStart());
139        dot.setEnd(access.getEnd());
140        return dot;
141      }
142    
143      public Dot Dot.qualifiesAccess(Access access) {
144        Dot lastDot = lastDot();
145        Expr l = lastDot.getRightNoTransform();
146        Dot dot = new Dot(lastDot.getRightNoTransform(), access);
147        dot.setStart(l.getStart());
148        dot.setEnd(access.getEnd());
149        lastDot.setRight(dot);
150        return this;
151      }
152    
153      // Used when replacing pairs from a list to concatenate the result to the tail of the current location.
154      private Access Dot.qualifyTailWith(Access expr) {
155        if (getRight/*NoTransform*/() instanceof AbstractDot) {
156          AbstractDot dot = (AbstractDot) getRight/*NoTransform*/();
157          return expr.qualifiesAccess(dot.getRight/*NoTransform*/());
158        }
159        return expr;
160      }
161    
162    
163      // These are used by the parser to extract the last name which
164      // will be replaced by a method name
165      public Access AbstractDot.extractLast() {
166        return getRightNoTransform();
167      }
168    
169      public void AbstractDot.replaceLast(Access access) {
170        setRight(access);
171      }
172    
173      public Access Dot.extractLast() {
174        return lastDot().getRightNoTransform();
175      }
176    
177      public void Dot.replaceLast(Access access) {
178        lastDot().setRight(access);
179      }
180    
181      public Access Access.addArrayDims(List list) {
182        Access a = this;
183        for (int i = 0; i < list.getNumChildNoTransform(); i++) {
184          Dims dims = (Dims) list.getChildNoTransform(i);
185          Opt opt = dims.getExprOpt();
186          if (opt.getNumChildNoTransform() == 1) {
187            a = new ArrayTypeWithSizeAccess(a, (Expr) opt.getChildNoTransform(0));
188          } else {
189            a = new ArrayTypeAccess(a);
190          }
191          a.setStart(dims.start());
192          a.setEnd(dims.end());
193        }
194        return a;
195      }
196    
197    }
198    
199    aspect NameResolution {
200    
201      // Replace the parsed name with a name reclassified according to context
202      // This is done upon first access to a name node
203    
204      rewrite ParseName {
205        to Access {
206          switch (nameType()) {
207            case PACKAGE_NAME:
208              return new PackageAccess(name(), start, end);
209            case TYPE_NAME:
210              return new TypeAccess(name(), start, end);
211            case PACKAGE_OR_TYPE_NAME:
212              if (lookupType(name()).isEmpty()) {
213                return new PackageAccess(name(), start, end);
214              } else {
215                return new TypeAccess(name(), start, end);
216              }
217            case AMBIGUOUS_NAME:
218              if (!lookupVariable(name()).isEmpty()) {
219                return new VarAccess(name(), start(), end());
220              } else {
221                if (lookupType(name()).isEmpty()) {
222                  return new PackageAccess(name(), start(), end());
223                } else {
224                  return new TypeAccess(name(), start(), end());
225                }
226              }
227            case EXPRESSION_NAME:
228              return new VarAccess(name(), start, end);
229            case NOT_CLASSIFIED:
230            default:
231              throw new Error("Failure in name classification: unknown name type encountered");
232          }
233        }
234      }
235    
236      rewrite Dot {
237        // NB: leftSide() and rightSide() are allowed to trigger rewrites, and in
238        // fact it is necessary in order to trigger rewrites on parse name leafs of
239        // this qualified expression.
240        // - Jesper 2015
241    
242        // collapse package accesses
243        when (leftSide().isPackageAccess() && rightSide().isPackageAccess())
244        to Access {
245          PackageAccess left = (PackageAccess) leftSide();
246          PackageAccess right = (PackageAccess) rightSide();
247          left.setPackage(left.getPackage() + "." + right.getPackage());
248          left.setEnd(right.end());
249          return qualifyTailWith(left);
250        }
251    
252        // collapse package with type access
253        when (leftSide().isPackageAccess() && !((Access) leftSide()).hasPrevExpr() && rightSide() instanceof TypeAccess)
254        to Access {
255          PackageAccess left = (PackageAccess) leftSide();
256          TypeAccess right = (TypeAccess) rightSide();
257          right.setPackage(left.getPackage());
258          right.setStart(left.start());
259          return qualifyTailWith(right);
260        }
261      }
262    
263    }
264