001 /* Copyright (c) 2015, Jesper Öqvist <jesper.oqvist@cs.lth.se> 002 * All rights reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * 1. Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * 010 * 2. Redistributions in binary form must reproduce the above copyright notice, 011 * this list of conditions and the following disclaimer in the documentation 012 * and/or other materials provided with the distribution. 013 * 014 * 3. Neither the name of the copyright holder nor the names of its 015 * contributors may be used to endorse or promote products derived from this 016 * software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 * POSSIBILITY OF SUCH DAMAGE. 029 */ 030 031 import org.jastadd.util.PrettyPrintable; 032 import org.jastadd.util.PrettyPrinter; 033 034 aspect PrettyPrintUtil { 035 ASTNode implements PrettyPrintable; 036 037 /** 038 * Pretty-print this ASTNode. 039 * @return pretty-printed representation of this AST node 040 */ 041 public String ASTNode.prettyPrint() { 042 ByteArrayOutputStream buf = new ByteArrayOutputStream(); 043 prettyPrint(new PrettyPrinter(" ", new PrintStream(buf))); 044 return buf.toString(); 045 } 046 047 /** 048 * Pretty print this AST node to the target PrintStream. 049 * @param out target for pretty printing 050 */ 051 public void ASTNode.prettyPrint(PrintStream out) { 052 prettyPrint(new PrettyPrinter(" ", out)); 053 } 054 055 /** 056 * @return the name of the class implementing this AST node 057 */ 058 public String ASTNode.toString() { 059 return getClass().getName(); 060 } 061 062 public void ASTNode.prettyPrint(PrettyPrinter out) { 063 } 064 065 /** Pretty-print Opt nodes only if they are not empty. */ 066 public void Opt.prettyPrint(PrettyPrinter out) { 067 if (getNumChild() > 0) { 068 getChild(0).prettyPrint(out); 069 } 070 } 071 072 /** Default list pretty printing prints all list elements. */ 073 public void List.prettyPrint(PrettyPrinter out) { 074 for (int i = 0; i < getNumChild(); ++i) { 075 getChild(i).prettyPrint(out); 076 } 077 } 078 079 public void Program.prettyPrint(PrettyPrinter out) { 080 for (Iterator iter = compilationUnitIterator(); iter.hasNext(); ) { 081 CompilationUnit cu = (CompilationUnit) iter.next(); 082 if (cu.fromSource()) { 083 out.print(cu); 084 } 085 } 086 } 087 088 /** 089 * Manually implemented because it is too complex for a template. 090 */ 091 public void ForStmt.prettyPrint(PrettyPrinter out) { 092 out.print("for ("); 093 if (getNumInitStmt() > 0) { 094 if (getInitStmt(0) instanceof VarDeclStmt) { 095 VarDeclStmt var = (VarDeclStmt) getInitStmt(0); 096 int minDimension = Integer.MAX_VALUE; 097 for (VariableDeclaration decl : var.getSingleDeclList()) { 098 minDimension = Math.min(minDimension, decl.type().dimension()); 099 } 100 101 // Print type. 102 out.print(var.getModifiers()); 103 out.print(var.type().elementType().typeName()); 104 for (int i = minDimension; i > 0; i--) { 105 out.print("[]"); 106 } 107 108 // Print individual declarations. 109 for (int i = 0; i < var.getNumSingleDecl(); ++i) { 110 if (i != 0) { 111 out.print(","); 112 } 113 VariableDeclaration decl = var.getSingleDecl(i); 114 out.print(" " + decl.name()); 115 for (int j = decl.type().dimension() - minDimension; j > 0; j -= 1) { 116 out.print("[]"); 117 } 118 if (decl.hasInit()) { 119 out.print(" = "); 120 out.print(decl.getInit()); 121 } 122 } 123 } else if (getInitStmt(0) instanceof ExprStmt) { 124 ExprStmt stmt = (ExprStmt) getInitStmt(0); 125 out.print(stmt.getExpr()); 126 for (int i = 1; i < getNumInitStmt(); i++) { 127 out.print(", "); 128 stmt = (ExprStmt)getInitStmt(i); 129 out.print(stmt.getExpr()); 130 } 131 } else { 132 throw new Error("Unexpected initializer in for loop: " + getInitStmt(0)); 133 } 134 } 135 136 out.print("; "); 137 if (hasCondition()) { 138 out.print(getCondition()); 139 } 140 out.print("; "); 141 142 // Print update statements. 143 for (int i = 0; i < getNumUpdateStmt(); i++) { 144 if (i > 0) { 145 out.print(", "); 146 } 147 ExprStmt update = (ExprStmt) getUpdateStmt(i); 148 out.print(update.getExpr()); 149 } 150 151 out.print(") "); 152 if (getStmt() instanceof Block) { 153 out.print(getStmt()); 154 } else { 155 out.print("{"); 156 out.println(); 157 out.indent(1); 158 out.print(getStmt()); 159 out.println(); 160 out.print("}"); 161 } 162 } 163 164 public void IfStmt.prettyPrint(PrettyPrinter out) { 165 out.print("if ("); 166 out.print(getCondition()); 167 out.print(") "); 168 if (getThen() instanceof Block) { 169 out.print(getThen()); 170 } else { 171 out.print("{"); 172 out.println(); 173 out.indent(1); 174 out.print(getThen()); 175 out.indent(0); 176 out.println(); 177 out.print("}"); 178 } 179 if (hasElse()) { 180 out.print(" else "); 181 if (getElse() instanceof Block) { 182 out.print(getElse()); 183 } else { 184 out.print("{"); 185 out.println(); 186 out.indent(1); 187 out.print(getElse()); 188 out.println(); 189 out.print("}"); 190 } 191 } 192 } 193 194 public void WhileStmt.prettyPrint(PrettyPrinter out) { 195 out.print("while ("); 196 out.print(getCondition()); 197 out.print(") "); 198 if (getStmt() instanceof Block) { 199 out.print(getStmt()); 200 } else { 201 out.print("{"); 202 out.println(); 203 out.indent(1); 204 out.print(getStmt()); 205 out.println(); 206 out.print("}"); 207 } 208 } 209 210 /** 211 * Has package name (not @primitive) 212 */ 213 syn boolean TypeAccess.hasPackage() = decl().isReferenceType() && !getPackage().isEmpty(); 214 215 syn boolean InstanceInitializer.blockIsEmpty() = getBlock().getNumStmt() == 0; 216 217 syn boolean StaticInitializer.blockIsEmpty() = getBlock().getNumStmt() == 0; 218 219 syn boolean Block.hasStmts() = getNumStmt() > 0; 220 221 /** 222 * @return <code>true</code> if there is any printable body decl 223 */ 224 syn boolean ClassInstanceExpr.hasPrintableBodyDecl() { 225 TypeDecl decl = getTypeDecl(); 226 for (int i = 0; i < decl.getNumBodyDecl(); ++i) { 227 if (decl.getBodyDecl(i) instanceof ConstructorDecl) { 228 ConstructorDecl cd = (ConstructorDecl) decl.getBodyDecl(i); 229 if (!cd.isImplicitConstructor()) { 230 return true; 231 } 232 } else { 233 return true; 234 } 235 } 236 return false; 237 } 238 239 syn List<BodyDecl> ClassInstanceExpr.bodyDecls() = getTypeDecl().getBodyDeclList(); 240 241 syn boolean ClassDecl.hasModifiers() = getModifiers().getNumModifier() > 0; 242 243 syn boolean InterfaceDecl.hasModifiers() = getModifiers().getNumModifier() > 0; 244 245 syn boolean ConstructorDecl.hasModifiers() = getModifiers().getNumModifier() > 0; 246 247 syn boolean MethodDecl.hasModifiers() = getModifiers().getNumModifier() > 0; 248 249 syn boolean FieldDeclaration.hasModifiers() = getModifiers().getNumModifier() > 0; 250 251 syn boolean VariableDeclaration.hasModifiers() = getModifiers().getNumModifier() > 0; 252 253 syn boolean ParameterDeclaration.hasModifiers() = getModifiers().getNumModifier() > 0; 254 255 syn boolean ConstructorDecl.hasExceptions() = getNumException() > 0; 256 257 syn List<Stmt> ConstructorDecl.blockStmts() = getBlock().getStmtList(); 258 259 syn boolean MethodDecl.hasExceptions() = getNumException() > 0; 260 261 syn boolean CompilationUnit.hasPackageDecl() = !getPackageDecl().isEmpty(); 262 263 syn String StringLiteral.escapedLiteral() = escape(getLITERAL()); 264 265 syn String CharacterLiteral.escapedLiteral() = escape(getLITERAL()); 266 267 syn boolean AbstractDot.needsDot() = !(getRight() instanceof ArrayAccess); 268 269 /** The operator string used for pretty printing this expression. */ 270 syn String Binary.printOp(); 271 eq MulExpr.printOp() = "*"; 272 eq DivExpr.printOp() = "/"; 273 eq ModExpr.printOp() = "%"; 274 eq AddExpr.printOp() = "+"; 275 eq SubExpr.printOp() = "-"; 276 eq LShiftExpr.printOp() = "<<"; 277 eq RShiftExpr.printOp() = ">>"; 278 eq URShiftExpr.printOp() = ">>>"; 279 eq AndBitwiseExpr.printOp() = "&"; 280 eq OrBitwiseExpr.printOp() = "|"; 281 eq XorBitwiseExpr.printOp() = "^"; 282 eq AndLogicalExpr.printOp() = "&&"; 283 eq OrLogicalExpr.printOp() = "||"; 284 eq LTExpr.printOp() = "<"; 285 eq GTExpr.printOp() = ">"; 286 eq LEExpr.printOp() = "<="; 287 eq GEExpr.printOp() = ">="; 288 eq EQExpr.printOp() = "=="; 289 eq NEExpr.printOp() = "!="; 290 291 /** The operator string used for pretty printing this expression. */ 292 syn String AssignExpr.printOp(); 293 eq AssignSimpleExpr.printOp() = "="; 294 eq AssignMulExpr.printOp() = "*="; 295 eq AssignDivExpr.printOp() = "/="; 296 eq AssignModExpr.printOp() = "%="; 297 eq AssignPlusExpr.printOp() = "+="; 298 eq AssignMinusExpr.printOp() = "-="; 299 eq AssignLShiftExpr.printOp() = "<<="; 300 eq AssignRShiftExpr.printOp() = ">>="; 301 eq AssignURShiftExpr.printOp() = ">>>="; 302 eq AssignAndExpr.printOp() = "&="; 303 eq AssignXorExpr.printOp() = "^="; 304 eq AssignOrExpr.printOp() = "|="; 305 306 syn String Unary.printPostOp() = ""; 307 eq PostIncExpr.printPostOp() = "++"; 308 eq PostDecExpr.printPostOp() = "--"; 309 310 syn String Unary.printPreOp() = ""; 311 eq PreIncExpr.printPreOp() = "++"; 312 eq PreDecExpr.printPreOp() = "--"; 313 eq MinusExpr.printPreOp() = "-"; 314 eq PlusExpr.printPreOp() = "+"; 315 eq BitNotExpr.printPreOp() = "~"; 316 eq LogNotExpr.printPreOp() = "!"; 317 318 /** 319 * Escapes a string literal. 320 * @param s string to escape 321 * @return escaped string literal 322 */ 323 protected static String Literal.escape(String s) { 324 StringBuffer result = new StringBuffer(); 325 for (int i=0; i < s.length(); i++) { 326 switch(s.charAt(i)) { 327 case '\b': 328 result.append("\\b"); 329 break; 330 case '\t': 331 result.append("\\t"); 332 break; 333 case '\n': 334 result.append("\\n"); 335 break; 336 case '\f': 337 result.append("\\f"); 338 break; 339 case '\r': 340 result.append("\\r"); 341 break; 342 case '\"': 343 result.append("\\\""); 344 break; 345 case '\'': 346 result.append("\\\'"); 347 break; 348 case '\\': 349 result.append("\\\\"); 350 break; 351 default: 352 int value = (int)s.charAt(i); 353 if (value < 0x20 || (value > 0x7e)) { 354 result.append(asEscape(value)); 355 } else { 356 result.append(s.charAt(i)); 357 } 358 } 359 } 360 return result.toString(); 361 } 362 363 protected static String Literal.asEscape(int value) { 364 StringBuffer s = new StringBuffer("\\u"); 365 String hex = Integer.toHexString(value); 366 for (int i = 0; i < 4-hex.length(); i++) { 367 s.append("0"); 368 } 369 s.append(hex); 370 return s.toString(); 371 } 372 373 }