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