001/* 002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others 003 * 004 * This program and the accompanying materials are made available under the 005 * terms of the Eclipse Public License 2.0 which is available at 006 * http://www.eclipse.org/legal/epl-2.0. 007 * 008 * SPDX-License-Identifier: EPL-2.0 009 */ 010 011package gololang.ir; 012 013import java.io.PrintStream; 014 015public class IrTreeDumper implements GoloIrVisitor { 016 017 private final PrintStream out; 018 private int spacing = 0; 019 private GoloModule currentModule; 020 021 public IrTreeDumper() { 022 this(System.out); 023 } 024 025 public IrTreeDumper(PrintStream out) { 026 this.out = out; 027 } 028 029 private void space() { 030 this.out.print("# "); 031 for (int i = 0; i < spacing; i++) { 032 this.out.print(" "); 033 } 034 } 035 036 private void incr() { 037 spacing += 2; 038 } 039 040 private void decr() { 041 spacing -= 2; 042 } 043 044 @Override 045 public void visitModule(GoloModule module) { 046 if (currentModule == module) { 047 incr(); 048 space(); 049 this.out.println("current module"); 050 decr(); 051 return; 052 } 053 currentModule = module; 054 space(); 055 this.out.print(module.getPackageAndClass()); 056 this.out.print(" [Local References: "); 057 this.out.print(System.identityHashCode(module.getReferenceTable())); 058 this.out.println("]"); 059 module.walk(this); 060 } 061 062 @Override 063 public void visitModuleImport(ModuleImport moduleImport) { 064 incr(); 065 space(); 066 this.out.append(" - ").println(moduleImport); 067 moduleImport.walk(this); 068 decr(); 069 } 070 071 @Override 072 public void visitNamedAugmentation(NamedAugmentation namedAugmentation) { 073 incr(); 074 space(); 075 this.out.append("Named Augmentation ").println(namedAugmentation.getName()); 076 namedAugmentation.walk(this); 077 decr(); 078 } 079 080 @Override 081 public void visitAugmentation(Augmentation augmentation) { 082 incr(); 083 space(); 084 this.out.append("Augmentation on ").println(augmentation.getTarget()); 085 if (augmentation.hasNames()) { 086 incr(); 087 for (String name : augmentation.getNames()) { 088 space(); 089 this.out.append("Named Augmentation ").println(name); 090 } 091 decr(); 092 } 093 augmentation.walk(this); 094 decr(); 095 } 096 097 @Override 098 public void visitStruct(Struct struct) { 099 incr(); 100 space(); 101 this.out.append("Struct ").println(struct.getPackageAndClass().className()); 102 space(); 103 this.out.append(" - target class = ").println(struct.getPackageAndClass()); 104 incr(); 105 space(); 106 this.out.println("Members: "); 107 struct.walk(this); 108 decr(); 109 decr(); 110 } 111 112 @Override 113 public void visitUnion(Union union) { 114 incr(); 115 space(); 116 this.out.append("Union ").println(union.getPackageAndClass().className()); 117 space(); 118 this.out.append(" - target class = ").println(union.getPackageAndClass()); 119 union.walk(this); 120 decr(); 121 } 122 123 @Override 124 public void visitUnionValue(UnionValue value) { 125 incr(); 126 space(); 127 this.out.append("Value ").println(value.getPackageAndClass().className()); 128 space(); 129 this.out.append(" - target class = ").println(value.getPackageAndClass()); 130 if (value.hasMembers()) { 131 incr(); 132 space(); 133 this.out.println("Members: "); 134 value.walk(this); 135 decr(); 136 } 137 decr(); 138 } 139 140 @Override 141 public void visitFunction(GoloFunction function) { 142 incr(); 143 space(); 144 if (function.isLocal()) { 145 this.out.print("Local function "); 146 } else { 147 this.out.print("Function "); 148 } 149 this.out.append(function.getName()).append(" = "); 150 visitFunctionDefinition(function); 151 decr(); 152 } 153 154 private void visitFunctionDefinition(GoloFunction function) { 155 this.out.print("|"); 156 boolean first = true; 157 for (String param : function.getParameterNames()) { 158 if (first) { 159 first = false; 160 } else { 161 this.out.print(", "); 162 } 163 this.out.print(param); 164 } 165 this.out.print("|"); 166 if (function.isVarargs()) { 167 this.out.print(" (varargs)"); 168 } 169 if (function.isSynthetic()) { 170 this.out.format(" (synthetic, %s synthetic parameters)", 171 function.getSyntheticParameterCount()); 172 if (function.getSyntheticSelfName() != null) { 173 this.out.append(" (selfname: ") 174 .append(function.getSyntheticSelfName()).append(")"); 175 } 176 } 177 this.out.println(); 178 function.walk(this); 179 } 180 181 @Override 182 public void visitDecorator(Decorator decorator) { 183 incr(); 184 space(); 185 this.out.println("@Decorator"); 186 decorator.walk(this); 187 decr(); 188 } 189 190 @Override 191 public void visitBlock(Block block) { 192 if (block.isEmpty()) { return; } 193 incr(); 194 space(); 195 this.out.print("Block"); 196 this.out.print(" [Local References: "); 197 this.out.print(System.identityHashCode(block.getReferenceTable())); 198 this.out.print(" -> "); 199 this.out.print(System.identityHashCode(block.getReferenceTable().parent())); 200 this.out.println("]"); 201 block.walk(this); 202 decr(); 203 } 204 205 @Override 206 public void visitLocalReference(LocalReference ref) { 207 incr(); 208 space(); 209 this.out.append(" - ").println(ref); 210 decr(); 211 } 212 213 @Override 214 public void visitConstantStatement(ConstantStatement constantStatement) { 215 incr(); 216 space(); 217 Object v = constantStatement.value(); 218 this.out.append("Constant = ").print(v); 219 if (v != null) { 220 this.out.append(" (").append(v.getClass().getName()).append(")"); 221 } 222 this.out.println(); 223 decr(); 224 } 225 226 @Override 227 public void visitReturnStatement(ReturnStatement returnStatement) { 228 incr(); 229 space(); 230 this.out.println("Return"); 231 returnStatement.walk(this); 232 decr(); 233 } 234 235 @Override 236 public void visitFunctionInvocation(FunctionInvocation functionInvocation) { 237 incr(); 238 space(); 239 this.out.append("Function call: ").print(functionInvocation.getName()); 240 this.out.append(", on reference? -> ").print(functionInvocation.isOnReference()); 241 this.out.append(", on module state? -> ").print(functionInvocation.isOnModuleState()); 242 this.out.append(", anonymous? -> ").print(functionInvocation.isAnonymous()); 243 this.out.append(", constant? -> ").print(functionInvocation.isConstant()); 244 this.out.append(", named arguments? -> ").println(functionInvocation.usesNamedArguments()); 245 functionInvocation.walk(this); 246 printLocalDeclarations(functionInvocation); 247 decr(); 248 } 249 250 @Override 251 public void visitAssignmentStatement(AssignmentStatement assignmentStatement) { 252 incr(); 253 space(); 254 this.out.append("Assignment: ") 255 .append(assignmentStatement.getLocalReference().toString()) 256 .println(assignmentStatement.isDeclaring() ? " (declaring)" : ""); 257 assignmentStatement.walk(this); 258 decr(); 259 } 260 261 @Override 262 public void visitDestructuringAssignment(DestructuringAssignment assignment) { 263 incr(); 264 space(); 265 this.out.format( 266 "Destructuring assignement: {declaring=%s, varargs=%s}%n", 267 assignment.isDeclaring(), 268 assignment.isVarargs()); 269 assignment.walk(this); 270 decr(); 271 } 272 273 @Override 274 public void visitReferenceLookup(ReferenceLookup referenceLookup) { 275 incr(); 276 space(); 277 this.out.append("Reference lookup: ").println(referenceLookup.getName()); 278 printLocalDeclarations(referenceLookup); 279 decr(); 280 } 281 282 @Override 283 public void visitConditionalBranching(ConditionalBranching conditionalBranching) { 284 incr(); 285 space(); 286 this.out.println("Conditional"); 287 conditionalBranching.walk(this); 288 decr(); 289 } 290 291 @Override 292 public void visitCaseStatement(CaseStatement caseStatement) { 293 incr(); 294 space(); 295 this.out.println("Case"); 296 incr(); 297 for (WhenClause<Block> c : caseStatement.getClauses()) { 298 c.accept(this); 299 } 300 space(); 301 this.out.println("Otherwise"); 302 caseStatement.getOtherwise().accept(this); 303 decr(); 304 } 305 306 @Override 307 public void visitMatchExpression(MatchExpression matchExpression) { 308 incr(); 309 space(); 310 this.out.println("Match"); 311 incr(); 312 for (WhenClause<?> c : matchExpression.getClauses()) { 313 c.accept(this); 314 } 315 space(); 316 this.out.println("Otherwise"); 317 matchExpression.getOtherwise().accept(this); 318 printLocalDeclarations(matchExpression); 319 decr(); 320 } 321 322 @Override 323 public void visitWhenClause(WhenClause<?> whenClause) { 324 space(); 325 this.out.println("When"); 326 incr(); 327 whenClause.walk(this); 328 decr(); 329 } 330 331 @Override 332 public void visitBinaryOperation(BinaryOperation binaryOperation) { 333 incr(); 334 space(); 335 this.out.append("Binary operator: ").println(binaryOperation.getType()); 336 binaryOperation.walk(this); 337 printLocalDeclarations(binaryOperation); 338 decr(); 339 } 340 341 @Override 342 public void visitUnaryOperation(UnaryOperation unaryOperation) { 343 incr(); 344 space(); 345 this.out.append("Unary operator: ").println(unaryOperation.getType()); 346 unaryOperation.walk(this); 347 printLocalDeclarations(unaryOperation); 348 decr(); 349 } 350 351 @Override 352 public void visitLoopStatement(LoopStatement loopStatement) { 353 incr(); 354 space(); 355 this.out.println("Loop"); 356 loopStatement.walk(this); 357 decr(); 358 } 359 360 @Override 361 public void visitForEachLoopStatement(ForEachLoopStatement foreachStatement) { 362 incr(); 363 space(); 364 this.out.println("Foreach"); 365 incr(); 366 for (LocalReference ref : foreachStatement.getReferences()) { 367 ref.accept(this); 368 } 369 foreachStatement.getIterable().accept(this); 370 if (foreachStatement.hasWhenClause()) { 371 space(); 372 this.out.println("When:"); 373 foreachStatement.getWhenClause().accept(this); 374 } 375 foreachStatement.getBlock().accept(this); 376 decr(); 377 decr(); 378 } 379 380 @Override 381 public void visitMethodInvocation(MethodInvocation methodInvocation) { 382 incr(); 383 space(); 384 this.out.format("Method invocation: %s, null safe? -> %s%n", 385 methodInvocation.getName(), 386 methodInvocation.isNullSafeGuarded()); 387 methodInvocation.walk(this); 388 printLocalDeclarations(methodInvocation); 389 decr(); 390 } 391 392 @Override 393 public void visitThrowStatement(ThrowStatement throwStatement) { 394 incr(); 395 space(); 396 this.out.println("Throw"); 397 throwStatement.walk(this); 398 decr(); 399 } 400 401 @Override 402 public void visitTryCatchFinally(TryCatchFinally tryCatchFinally) { 403 incr(); 404 space(); 405 this.out.println("Try"); 406 tryCatchFinally.getTryBlock().accept(this); 407 if (tryCatchFinally.hasCatchBlock()) { 408 space(); 409 this.out.append("Catch: ").println(tryCatchFinally.getExceptionId()); 410 tryCatchFinally.getCatchBlock().accept(this); 411 } 412 if (tryCatchFinally.hasFinallyBlock()) { 413 space(); 414 this.out.println("Finally"); 415 tryCatchFinally.getFinallyBlock().accept(this); 416 } 417 decr(); 418 } 419 420 @Override 421 public void visitClosureReference(ClosureReference closureReference) { 422 GoloFunction target = closureReference.getTarget(); 423 incr(); 424 space(); 425 if (target.isAnonymous()) { 426 this.out.print("Closure: "); 427 incr(); 428 visitFunctionDefinition(target); 429 decr(); 430 } else { 431 this.out.printf( 432 "Closure reference: %s, regular arguments at index %d%n", 433 target.getName(), 434 target.getSyntheticParameterCount()); 435 incr(); 436 for (String refName : closureReference.getCapturedReferenceNames()) { 437 space(); 438 this.out.append("- capture: ").println(refName); 439 } 440 decr(); 441 } 442 decr(); 443 } 444 445 @Override 446 public void visitLoopBreakFlowStatement(LoopBreakFlowStatement loopBreakFlowStatement) { 447 incr(); 448 space(); 449 this.out.append("Loop break flow: ").println(loopBreakFlowStatement.getType().name()); 450 decr(); 451 } 452 453 @Override 454 public void visitCollectionLiteral(CollectionLiteral collectionLiteral) { 455 incr(); 456 space(); 457 this.out.append("Collection literal of type: ").println(collectionLiteral.getType()); 458 collectionLiteral.walk(this); 459 printLocalDeclarations(collectionLiteral); 460 decr(); 461 } 462 463 @Override 464 public void visitCollectionComprehension(CollectionComprehension collectionComprehension) { 465 incr(); 466 space(); 467 this.out.append("Collection comprehension of type: ").println(collectionComprehension.getType()); 468 incr(); 469 space(); 470 this.out.println("Expression: "); 471 collectionComprehension.expression().accept(this); 472 space(); 473 this.out.println("Comprehension: "); 474 for (GoloStatement<?> b : collectionComprehension.loops()) { 475 b.accept(this); 476 } 477 printLocalDeclarations(collectionComprehension); 478 decr(); 479 decr(); 480 } 481 482 @Override 483 public void visitNamedArgument(NamedArgument namedArgument) { 484 incr(); 485 space(); 486 this.out.append("Named argument: ").println(namedArgument.getName()); 487 namedArgument.expression().accept(this); 488 decr(); 489 } 490 491 @Override 492 public void visitMember(Member member) { 493 space(); 494 this.out.print(" - "); 495 this.out.print(member.getName()); 496 this.out.println(); 497 } 498 499 private void printLocalDeclarations(ExpressionStatement<?> expr) { 500 if (expr.hasLocalDeclarations()) { 501 incr(); 502 space(); 503 System.out.println("Local declaration:"); 504 for (GoloAssignment<?> a : expr.declarations()) { 505 a.accept(this); 506 } 507 decr(); 508 } 509 } 510 511 @Override 512 public void visitNoop(Noop noop) { 513 incr(); 514 space(); 515 this.out.append("Noop: ").println(noop.comment()); 516 decr(); 517 } 518 519 @Override 520 public void visitToplevelElements(ToplevelElements toplevel) { 521 toplevel.walk(this); 522 } 523}