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