001/* 002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 */ 009 010package org.eclipse.golo.compiler; 011 012import org.eclipse.golo.runtime.OperatorType; 013import org.eclipse.golo.compiler.ir.*; 014import org.eclipse.golo.compiler.parser.*; 015 016import java.util.Collections; 017import java.util.Deque; 018import java.util.LinkedList; 019import java.util.List; 020import java.util.stream.Collectors; 021 022import static org.eclipse.golo.compiler.ir.Builders.*; 023import static java.util.Collections.nCopies; 024import static org.eclipse.golo.compiler.GoloCompilationException.Problem.Type.*; 025import static gololang.Messages.message; 026 027public class ParseTreeToGoloIrVisitor implements GoloParserVisitor { 028 029 public ParseTreeToGoloIrVisitor() { } 030 031 @Override 032 public Object visit(ASTerror node, Object data) { 033 return null; 034 } 035 036 private static final class Context { 037 public GoloModule module; 038 private Deque<FunctionContainer> functionContainersStack = new LinkedList<>(); 039 private Deque<Object> objectStack = new LinkedList<>(); 040 private Deque<ReferenceTable> referenceTableStack = new LinkedList<>(); 041 private GoloCompilationException.Builder exceptionBuilder; 042 043 public void push(Object object) { 044 objectStack.push(object); 045 } 046 047 public Object peek() { 048 return objectStack.peek(); 049 } 050 051 public Object pop() { 052 return objectStack.pop(); 053 } 054 055 public Block enterScope() { 056 ReferenceTable blockReferenceTable = referenceTableStack.peek().fork(); 057 referenceTableStack.push(blockReferenceTable); 058 return block().ref(blockReferenceTable); 059 } 060 061 public void leaveScope() { 062 referenceTableStack.pop(); 063 } 064 065 public GoloModule createModule(String name) { 066 ReferenceTable global = new ReferenceTable(); 067 referenceTableStack.push(global); 068 module = new GoloModule(PackageAndClass.fromString(name), global); 069 functionContainersStack.push(module); 070 return module; 071 } 072 073 public void enterAugmentation(ASTAugmentDeclaration node) { 074 functionContainersStack.push(this.module.addAugmentation( 075 augment(node.getTarget()).with(node.getAugmentationNames()).ofAST(node))); 076 } 077 078 public void leaveAugmentation() { 079 functionContainersStack.pop(); 080 } 081 082 public void enterNamedAugmentation(ASTNamedAugmentationDeclaration node) { 083 NamedAugmentation namedAugmentation = augmentation(node.getName()).ofAST(node); 084 functionContainersStack.push(namedAugmentation); 085 this.module.addNamedAugmentation(namedAugmentation); 086 } 087 088 public void leaveNamedAugmentation() { 089 functionContainersStack.pop(); 090 } 091 092 public void addFunction(GoloFunction function) { 093 FunctionContainer container = this.functionContainersStack.peek(); 094 if (container.getFunctions().contains(function)) { 095 GoloFunction firstDeclaration = null; 096 for (GoloFunction f : container.getFunctions()) { 097 if (function.equals(f)) { 098 firstDeclaration = f; 099 } 100 } 101 errorMessage(AMBIGUOUS_DECLARATION, function.getASTNode(), 102 message("ambiguous_function_declaration", 103 function.getName(), 104 firstDeclaration == null ? "unknown" : firstDeclaration.getASTNode().getPositionInSourceCode())); 105 } 106 container.addFunction(function); 107 } 108 109 public boolean checkExistingSubtype(GoloASTNode node, String name) { 110 GoloElement existing = module.getSubtypeByName(name); 111 if (existing != null) { 112 errorMessage(AMBIGUOUS_DECLARATION, node, 113 message("ambiguous_type_declaration", 114 name, existing.getASTNode().getPositionInSourceCode())); 115 return true; 116 } 117 return false; 118 } 119 120 public GoloFunction getOrCreateFunction() { 121 if (!(objectStack.peek() instanceof GoloFunction)) { 122 objectStack.push(functionDeclaration().synthetic().local().asClosure()); 123 } 124 return (GoloFunction) objectStack.peek(); 125 } 126 127 private LocalReference.Kind referenceKindOf(ASTLetOrVar.Type type, boolean moduleState) { 128 if (moduleState) { 129 return type == ASTLetOrVar.Type.LET 130 ? LocalReference.Kind.MODULE_CONSTANT 131 : LocalReference.Kind.MODULE_VARIABLE; 132 } else { 133 return type == ASTLetOrVar.Type.LET 134 ? LocalReference.Kind.CONSTANT 135 : LocalReference.Kind.VARIABLE; 136 } 137 } 138 139 public LocalReference getOrCreateReference(ASTLetOrVar node) { 140 return getOrCreateReference(node.getType(), node.getName(), node.isModuleState(), node); 141 } 142 143 public LocalReference getOrCreateReference(ASTDestructuringAssignment node, String name) { 144 return getOrCreateReference(node.getType(), name, false, node); 145 } 146 147 public LocalReference getReference(String name, GoloASTNode node) { 148 return referenceTableStack.peek().get(name); 149 } 150 151 private LocalReference getOrCreateReference(ASTLetOrVar.Type type, String name, boolean module, GoloASTNode node) { 152 if (type != null) { 153 LocalReference val = localRef(name).kind(referenceKindOf(type, module)).ofAST(node); 154 referenceTableStack.peek().add(val); 155 return val; 156 } 157 return getReference(name, node); 158 } 159 160 public void setExceptionBuilder(GoloCompilationException.Builder builder) { 161 exceptionBuilder = builder; 162 } 163 164 public GoloCompilationException.Builder getExceptionBuilder() { 165 return exceptionBuilder; 166 } 167 168 private GoloCompilationException.Builder getOrCreateExceptionBuilder() { 169 if (exceptionBuilder == null) { 170 exceptionBuilder = new GoloCompilationException.Builder(module.getPackageAndClass().toString()); 171 } 172 return exceptionBuilder; 173 } 174 175 public void errorMessage(GoloCompilationException.Problem.Type type, 176 GoloASTNode node, 177 String message) { 178 String errorMessage = message + ' ' + message("source_position", 179 node.getPositionInSourceCode().getLine(), 180 node.getPositionInSourceCode().getColumn()); 181 getOrCreateExceptionBuilder().report(type, node, errorMessage); 182 } 183 184 } 185 186 public GoloModule transform(ASTCompilationUnit compilationUnit, GoloCompilationException.Builder builder) { 187 Context context = new Context(); 188 context.setExceptionBuilder(builder); 189 visit(compilationUnit, context); 190 return context.module; 191 } 192 193 @Override 194 public Object visit(SimpleNode node, Object data) { 195 throw new IllegalStateException("visit(SimpleNode) shall never be invoked: " + node.getClass()); 196 } 197 198 @Override 199 public Object visit(ASTCompilationUnit node, Object data) { 200 return node.childrenAccept(this, data); 201 } 202 203 @Override 204 public Object visit(ASTModuleDeclaration node, Object data) { 205 Context context = (Context) data; 206 context.createModule(node.getName()).ofAST(node); 207 return node.childrenAccept(this, data); 208 } 209 210 @Override 211 public Object visit(ASTImportDeclaration node, Object data) { 212 Context context = (Context) data; 213 PackageAndClass name; 214 if (node.isRelative()) { 215 name = context.module.getPackageAndClass().createSiblingClass(node.getName()); 216 } else { 217 name = PackageAndClass.fromString(node.getName()); 218 } 219 if (node.getMultiple().isEmpty()) { 220 context.module.addImport(moduleImport(name).ofAST(node)); 221 } else { 222 for (String sub : node.getMultiple()) { 223 context.module.addImport(moduleImport(name.createSubPackage(sub)).ofAST(node)); 224 } 225 } 226 return node.childrenAccept(this, data); 227 } 228 229 @Override 230 public Object visit(ASTToplevelDeclaration node, Object data) { 231 return node.childrenAccept(this, data); 232 } 233 234 @Override 235 public Object visit(ASTMemberDeclaration node, Object data) { 236 Context context = (Context) data; 237 context.push(member(node.getName()).ofAST(node)); 238 return context; 239 } 240 241 @Override 242 public Object visit(ASTStructDeclaration node, Object data) { 243 Context context = (Context) data; 244 if (!context.checkExistingSubtype(node, node.getName())) { 245 Struct theStruct = structure(node.getName()).ofAST(node); 246 for (int i = 0; i < node.jjtGetNumChildren(); i++) { 247 node.jjtGetChild(i).jjtAccept(this, context); 248 theStruct.withMember(context.pop()); 249 } 250 context.module.addStruct(theStruct); 251 } 252 return context; 253 } 254 255 @Override 256 public Object visit(ASTUnionDeclaration node, Object data) { 257 Context context = (Context) data; 258 if (!context.checkExistingSubtype(node, node.getName())) { 259 context.push(union(node.getName()).ofAST(node)); 260 node.childrenAccept(this, data); 261 context.module.addUnion((Union) context.pop()); 262 } 263 return data; 264 } 265 266 @Override 267 public Object visit(ASTUnionValue node, Object data) { 268 Context context = (Context) data; 269 Union currentUnion = (Union) context.peek(); 270 UnionValue value = currentUnion.createValue(node.getName()).ofAST(node); 271 for (int i = 0; i < node.jjtGetNumChildren(); i++) { 272 node.jjtGetChild(i).jjtAccept(this, context); 273 value.withMember(context.pop()); 274 } 275 276 if (!currentUnion.addValue(value)) { 277 context.errorMessage(AMBIGUOUS_DECLARATION, node, 278 message("ambiguous_unionvalue_declaration", node.getName())); 279 } 280 return data; 281 } 282 283 @Override 284 public Object visit(ASTAugmentDeclaration node, Object data) { 285 Context context = (Context) data; 286 context.enterAugmentation(node); 287 node.childrenAccept(this, data); 288 context.leaveAugmentation(); 289 return data; 290 } 291 292 @Override 293 public Object visit(ASTDecoratorDeclaration node, Object data) { 294 Context context = (Context) data; 295 node.childrenAccept(this, data); 296 context.push( 297 decorator(context.pop()) 298 .constant(node.isConstant()) 299 .ofAST(node)); 300 return data; 301 } 302 303 @Override 304 public Object visit(ASTNamedAugmentationDeclaration node, Object data) { 305 Context context = (Context) data; 306 context.enterNamedAugmentation(node); 307 node.childrenAccept(this, data); 308 context.leaveNamedAugmentation(); 309 return data; 310 } 311 312 @Override 313 public Object visit(ASTFunctionDeclaration node, Object data) { 314 Context context = (Context) data; 315 GoloFunction function = functionDeclaration().ofAST(node) 316 .name(node.getName()) 317 .local(node.isLocal()) 318 .inAugment(node.isAugmentation()) 319 .decorator(node.isDecorator()); 320 while (context.peek() instanceof Decorator) { 321 function.decoratedWith(context.pop()); 322 } 323 context.push(function); 324 node.childrenAccept(this, data); 325 context.pop(); 326 return data; 327 } 328 329 @Override 330 public Object visit(ASTContinue node, Object data) { 331 Context context = (Context) data; 332 LoopBreakFlowStatement statement = LoopBreakFlowStatement.newContinue(); 333 node.setIrElement(statement); 334 context.push(statement); 335 return data; 336 } 337 338 @Override 339 public Object visit(ASTBreak node, Object data) { 340 Context context = (Context) data; 341 LoopBreakFlowStatement statement = LoopBreakFlowStatement.newBreak(); 342 node.setIrElement(statement); 343 context.push(statement); 344 return data; 345 } 346 347 @Override 348 public Object visit(ASTFunction node, Object data) { 349 Context context = (Context) data; 350 GoloFunction function = context.getOrCreateFunction() 351 .ofAST(node) 352 .varargs(node.isVarargs()) 353 .withParameters(node.getParameters()); 354 355 if (node.isCompactForm()) { 356 // TODO: refactor 357 Node astChild = node.jjtGetChild(0); 358 ASTReturn astReturn = new ASTReturn(0); 359 astReturn.jjtAddChild(astChild, 0); 360 ASTBlock astBlock = new ASTBlock(0); 361 astBlock.jjtAddChild(astReturn, 0); 362 astBlock.jjtAccept(this, data); 363 // XXX 364 // if (function.isSynthetic()) { 365 // context.pop(); 366 // } 367 // node.jjtGetChild(0).jjtAccept(this, data); 368 // function.block(returns(context.pop())); 369 // context.push(function.getBlock()); 370 } else { 371 node.childrenAccept(this, data); 372 } 373 if (function.isSynthetic()) { 374 context.pop(); 375 context.push(function.asClosureReference()); 376 } else { 377 context.addFunction(function); 378 context.pop(); 379 } 380 return data; 381 } 382 383 @Override 384 public Object visit(ASTUnaryExpression node, Object data) { 385 Context context = (Context) data; 386 node.childrenAccept(this, data); 387 context.push( 388 not((ExpressionStatement) context.pop()).ofAST(node)); 389 return data; 390 } 391 392 @Override 393 public Object visit(ASTLiteral node, Object data) { 394 Context context = (Context) data; 395 ConstantStatement constantStatement = constant(node.getLiteralValue()); 396 context.push(constantStatement); 397 node.setIrElement(constantStatement); 398 return data; 399 } 400 401 @Override 402 public Object visit(ASTCollectionLiteral node, Object data) { 403 if (node.isComprehension()) { 404 return createCollectionComprehension(node, (Context) data); 405 } 406 return createCollectionLiteral(node, (Context) data); 407 } 408 409 private Object createCollectionLiteral(ASTCollectionLiteral node, Context context) { 410 CollectionLiteral collection = collection(node.getType()).ofAST(node); 411 for (int i = 0; i < node.jjtGetNumChildren(); i++) { 412 node.jjtGetChild(i).jjtAccept(this, context); 413 collection.add(context.pop()); 414 } 415 context.push(collection); 416 return context; 417 } 418 419 private Object createCollectionComprehension(ASTCollectionLiteral node, Context context) { 420 CollectionComprehension col = collectionComprehension(node.getType()).ofAST(node); 421 node.jjtGetChild(0).jjtAccept(this, context); 422 col.expression(context.pop()); 423 for (int i = 1; i < node.jjtGetNumChildren(); i++) { 424 node.jjtGetChild(i).jjtAccept(this, context); 425 col.loop(context.pop()); 426 } 427 context.push(col); 428 return context; 429 } 430 431 @Override 432 public Object visit(ASTReference node, Object data) { 433 ((Context) data).push(refLookup(node.getName()).ofAST(node)); 434 return data; 435 } 436 437 @Override 438 public Object visit(ASTLetOrVar node, Object data) { 439 Context context = (Context) data; 440 node.childrenAccept(this, data); 441 AssignmentStatement assignmentStatement = define(context.getOrCreateReference(node)) 442 .as(context.pop()) 443 .ofAST(node); 444 if (node.isModuleState()) { 445 context.module.addModuleStateInitializer(assignmentStatement); 446 } else { 447 context.push(assignmentStatement); 448 } 449 return data; 450 } 451 452 @Override 453 public Object visit(ASTAssignment node, Object data) { 454 Context context = (Context) data; 455 LocalReference reference = context.getReference(node.getName(), node); 456 node.childrenAccept(this, data); 457 if (reference == null) { 458 context.errorMessage(UNDECLARED_REFERENCE, node, 459 message("undeclared_reference", node.getName())); 460 } else { 461 AssignmentStatement assignmentStatement = assign(context.pop()).to(reference).ofAST(node); 462 context.push(assignmentStatement); 463 } 464 return data; 465 } 466 467 @Override 468 public Object visit(ASTDestructuringAssignment node, Object data) { 469 Context context = (Context) data; 470 node.jjtGetChild(0).jjtAccept(this, data); 471 472 DestructuringAssignment builder = destruct().ofAST(node) 473 .declaring(node.getType() != null) 474 .varargs(node.isVarargs()) 475 .expression(context.pop()); 476 477 for (String name : node.getNames()) { 478 LocalReference val = context.getOrCreateReference(node, name); 479 if (val != null) { 480 builder.to(val); 481 } 482 } 483 context.push(builder); 484 return data; 485 } 486 487 @Override 488 public Object visit(ASTReturn node, Object data) { 489 Context context = (Context) data; 490 if (node.jjtGetNumChildren() > 0) { 491 node.childrenAccept(this, data); 492 } else { 493 context.push(constant(null)); 494 } 495 context.push(returns(context.pop()).ofAST(node)); 496 return data; 497 } 498 499 @Override 500 public Object visit(ASTArgument node, Object data) { 501 Context context = (Context) data; 502 node.childrenAccept(this, data); 503 context.push( 504 node.isNamed() 505 ? namedArgument(node.getName()).value(context.pop()) 506 : (ExpressionStatement) context.pop()); 507 return data; 508 } 509 510 @Override 511 public Object visit(ASTThrow node, Object data) { 512 Context context = (Context) data; 513 node.childrenAccept(this, data); 514 context.push(raise(context.pop()).ofAST(node)); 515 return data; 516 } 517 518 @Override 519 public Object visit(ASTBlock node, Object data) { 520 Context context = (Context) data; 521 Block block = context.enterScope(); 522 node.setIrElement(block); 523 if (context.peek() instanceof GoloFunction) { 524 GoloFunction function = (GoloFunction) context.peek(); 525 function.block(block); 526 if (function.isSynthetic()) { 527 context.pop(); 528 } 529 } 530 context.push(block); 531 for (int i = 0; i < node.jjtGetNumChildren(); i++) { 532 GoloASTNode child = (GoloASTNode) node.jjtGetChild(i); 533 child.jjtAccept(this, data); 534 GoloStatement statement = (GoloStatement) context.pop(); 535 block.addStatement(statement); 536 } 537 context.leaveScope(); 538 return data; 539 } 540 541 @Override 542 public Object visit(ASTFunctionInvocation node, Object data) { 543 Context context = (Context) data; 544 context.push(visitAbstractInvocation(data, node, call(node.getName()).constant(node.isConstant()))); 545 return data; 546 } 547 548 @Override 549 public Object visit(ASTMethodInvocation node, Object data) { 550 Context context = (Context) data; 551 context.push(visitAbstractInvocation(data, node, invoke(node.getName()))); 552 return data; 553 } 554 555 @Override 556 public Object visit(ASTAnonymousFunctionInvocation node, Object data) { 557 Context context = (Context) data; 558 ExpressionStatement result = visitAbstractInvocation(data, node, functionInvocation().constant(node.isConstant())); 559 if (node.isOnExpression()) { 560 context.push(anonCall(context.pop(), result)); 561 } else { 562 context.push(result); 563 } 564 return data; 565 } 566 567 private void checkNamedArgument(Context context, GoloASTNode node, AbstractInvocation invocation, ExpressionStatement statement) { 568 if (statement instanceof NamedArgument) { 569 if (!invocation.namedArgumentsComplete()) { 570 context.errorMessage(INCOMPLETE_NAMED_ARGUMENTS_USAGE, node, 571 message("incomplete_named_arguments_usage", 572 invocation.getClass(), invocation.getName())); 573 } 574 invocation.withNamedArguments(); 575 } 576 } 577 578 private ExpressionStatement visitAbstractInvocation(Object data, GoloASTNode node, AbstractInvocation invocation) { 579 Context context = (Context) data; 580 invocation.ofAST(node); 581 int i = 0; 582 final int numChildren = node.jjtGetNumChildren(); 583 for (i = 0; i < numChildren; i++) { 584 GoloASTNode argumentNode = (GoloASTNode) node.jjtGetChild(i); 585 if (argumentNode instanceof ASTAnonymousFunctionInvocation) { 586 break; 587 } 588 argumentNode.jjtAccept(this, context); 589 ExpressionStatement statement = (ExpressionStatement) context.pop(); 590 checkNamedArgument(context, node, invocation, statement); 591 invocation.withArgs(statement); 592 } 593 ExpressionStatement result = invocation; 594 if (i < numChildren) { 595 for (; i < numChildren; i++) { 596 node.jjtGetChild(i).jjtAccept(this, context); 597 result = anonCall(result, context.pop()); 598 } 599 } 600 return result; 601 } 602 603 @Override 604 public Object visit(ASTConditionalBranching node, Object data) { 605 Context context = (Context) data; 606 node.jjtGetChild(1).jjtAccept(this, data); 607 node.jjtGetChild(0).jjtAccept(this, data); 608 609 ConditionalBranching conditionalBranching = branch().ofAST(node) 610 .condition(context.pop()) 611 .whenTrue(context.pop()); 612 613 if (node.jjtGetNumChildren() > 2) { 614 node.jjtGetChild(2).jjtAccept(this, data); 615 conditionalBranching.otherwise(context.pop()); 616 } 617 context.push(conditionalBranching); 618 return data; 619 } 620 621 private Object visitAlternatives(Object data, GoloASTNode node, Alternatives<?> alternatives) { 622 Context context = (Context) data; 623 final int lastWhen = node.jjtGetNumChildren() - 1; 624 for (int i = 0; i < lastWhen; i = i + 2) { 625 node.jjtGetChild(i).jjtAccept(this, data); 626 alternatives.when(context.pop()); 627 node.jjtGetChild(i + 1).jjtAccept(this, data); 628 alternatives.then(context.pop()); 629 } 630 node.jjtGetChild(lastWhen).jjtAccept(this, data); 631 alternatives.otherwise(context.pop()); 632 context.push(alternatives); 633 return data; 634 } 635 636 @Override 637 public Object visit(ASTCase node, Object data) { 638 return visitAlternatives(data, node, cases().ofAST(node)); 639 } 640 641 @Override 642 public Object visit(ASTMatch node, Object data) { 643 return visitAlternatives(data, node, match().ofAST(node)); 644 } 645 646 @Override 647 public Object visit(ASTWhileLoop node, Object data) { 648 Context context = (Context) data; 649 node.jjtGetChild(1).jjtAccept(this, data); 650 node.jjtGetChild(0).jjtAccept(this, data); 651 context.push( 652 whileLoop(context.pop()).ofAST(node) 653 .block((Block) context.pop())); 654 return data; 655 } 656 657 @Override 658 public Object visit(ASTForLoop node, Object data) { 659 Context context = (Context) data; 660 Block block = context.enterScope(); 661 662 node.jjtGetChild(0).jjtAccept(this, data); 663 node.jjtGetChild(1).jjtAccept(this, data); 664 node.jjtGetChild(2).jjtAccept(this, data); 665 666 LoopStatement loopStatement = loop().ofAST(node) 667 .post(context.pop()) 668 .condition(context.pop()) 669 .init(context.pop()); 670 671 if (node.jjtGetNumChildren() == 4) { 672 node.jjtGetChild(3).jjtAccept(this, data); 673 loopStatement.block((Block) context.pop()); 674 } 675 context.push(block.add(loopStatement)); 676 context.leaveScope(); 677 return data; 678 } 679 680 @Override 681 public Object visit(ASTForEachLoop node, Object data) { 682 Context context = (Context) data; 683 Block block = context.enterScope(); 684 685 node.jjtGetChild(0).jjtAccept(this, data); 686 687 ForEachLoopStatement foreach = foreach().ofAST(node) 688 .varargs(node.isVarargs()) 689 .on(context.pop()); 690 691 if (node.getElementIdentifier() != null) { 692 foreach.var(node.getElementIdentifier()); 693 } else { 694 for (String name : node.getNames()) { 695 foreach.var(name); 696 } 697 } 698 699 // there may be no block if we are in a collection comprehension, checking what we have... 700 int numChildren = node.jjtGetNumChildren(); 701 if (numChildren > 2) { 702 // when and block: it's a regular loop with a when clause 703 node.jjtGetChild(2).jjtAccept(this, data); 704 node.jjtGetChild(1).jjtAccept(this, data); 705 foreach.when(context.pop()).block(context.pop()); 706 } else if (numChildren == 2) { 707 // either a when and no block in collection comprehension or no when an block in regular loop 708 node.jjtGetChild(1).jjtAccept(this, data); 709 Object child = context.pop(); 710 if (child instanceof Block) { 711 foreach.block(child); 712 } else if (child instanceof ExpressionStatement) { 713 foreach.when(child); 714 } else { 715 context.errorMessage(PARSING, node, message("syntax_foreach")); 716 } 717 } 718 context.push(block.add(foreach)); 719 context.leaveScope(); 720 return data; 721 } 722 723 @Override 724 public Object visit(ASTTryCatchFinally node, Object data) { 725 Context context = (Context) data; 726 boolean hasCatchBlock = (node.getExceptionId() != null); 727 TryCatchFinally tryCatchFinally = tryCatch(node.getExceptionId()).ofAST(node); 728 729 context.enterScope(); 730 node.jjtGetChild(0).jjtAccept(this, data); 731 tryCatchFinally.trying(context.pop()); 732 context.leaveScope(); 733 734 context.enterScope(); 735 node.jjtGetChild(1).jjtAccept(this, data); 736 if (hasCatchBlock) { 737 tryCatchFinally.catching(context.pop()); 738 } else { 739 tryCatchFinally.finalizing(context.pop()); 740 } 741 context.leaveScope(); 742 743 if (hasCatchBlock && node.jjtGetNumChildren() > 2) { 744 context.enterScope(); 745 node.jjtGetChild(2).jjtAccept(this, data); 746 tryCatchFinally.finalizing(context.pop()); 747 context.leaveScope(); 748 } 749 750 context.push(tryCatchFinally); 751 return data; 752 } 753 754 @Override 755 public Object visit(ASTExpressionStatement node, Object data) { 756 node.childrenAccept(this, data); 757 return data; 758 } 759 760 @Override 761 public Object visit(ASTInvocationExpression node, Object data) { 762 Context context = (Context) data; 763 node.childrenAccept(this, context); 764 BinaryOperation current = null; 765 ExpressionStatement left; 766 ExpressionStatement right = null; 767 List<String> operators = node.getOperators(); 768 Collections.reverse(operators); 769 for (String symbol : operators) { 770 OperatorType operator = OperatorType.fromString(symbol); 771 if (right == null) { 772 right = (ExpressionStatement) context.pop(); 773 if (operator == OperatorType.ELVIS_METHOD_CALL) { 774 ((MethodInvocation) right).setNullSafeGuarded(true); 775 } 776 } else if (operator == OperatorType.ELVIS_METHOD_CALL) { 777 BinaryOperation rOp = (BinaryOperation) right; 778 ((MethodInvocation) rOp.getLeftExpression()).setNullSafeGuarded(true); 779 } 780 left = (ExpressionStatement) context.pop(); 781 right = current = binaryOperation(operator, left, right); 782 } 783 context.push(current); 784 node.setIrElement(current); 785 return data; 786 } 787 788 private BinaryOperation assembleBinaryOperation(List<ExpressionStatement> statements, List<OperatorType> operators) { 789 BinaryOperation current = null; 790 int i = 2; 791 for (OperatorType operator : operators) { 792 if (current == null) { 793 current = binaryOperation(operator, statements.get(0), statements.get(1)); 794 } else { 795 current = binaryOperation(operator, current, statements.get(i)); 796 i = i + 1; 797 } 798 } 799 return current; 800 } 801 802 private List<ExpressionStatement> operatorStatements(Context context, int operatorsCount) { 803 LinkedList<ExpressionStatement> statements = new LinkedList<>(); 804 for (int i = 0; i < operatorsCount + 1; i++) { 805 statements.addFirst((ExpressionStatement) context.pop()); 806 } 807 return statements; 808 } 809 810 @Override 811 public Object visit(ASTMultiplicativeExpression node, Object data) { 812 Context context = (Context) data; 813 node.childrenAccept(this, context); 814 List<OperatorType> operators = node.getOperators() 815 .stream() 816 .map(OperatorType::fromString) 817 .collect(Collectors.toList()); 818 List<ExpressionStatement> statements = operatorStatements(context, operators.size()); 819 ExpressionStatement operation = assembleBinaryOperation(statements, operators); 820 context.push(operation); 821 node.setIrElement(operation); 822 return data; 823 } 824 825 @Override 826 public Object visit(ASTAdditiveExpression node, Object data) { 827 Context context = (Context) data; 828 node.childrenAccept(this, context); 829 List<OperatorType> operators = node.getOperators() 830 .stream() 831 .map(OperatorType::fromString) 832 .collect(Collectors.toList()); 833 List<ExpressionStatement> statements = operatorStatements(context, operators.size()); 834 ExpressionStatement operation = assembleBinaryOperation(statements, operators); 835 context.push(operation); 836 node.setIrElement(operation); 837 return data; 838 } 839 840 @Override 841 public Object visit(ASTRelationalExpression node, Object data) { 842 Context context = (Context) data; 843 node.childrenAccept(this, data); 844 BinaryOperation operation = binaryOperation(node.getOperator()) 845 .right(context.pop()) 846 .left(context.pop()); 847 context.push(operation); 848 node.setIrElement(operation); 849 return data; 850 } 851 852 @Override 853 public Object visit(ASTEqualityExpression node, Object data) { 854 Context context = (Context) data; 855 node.childrenAccept(this, data); 856 BinaryOperation operation = binaryOperation(node.getOperator()) 857 .right(context.pop()) 858 .left(context.pop()); 859 context.push(operation); 860 node.setIrElement(operation); 861 return data; 862 } 863 864 @Override 865 public Object visit(ASTAndExpression node, Object data) { 866 Context context = (Context) data; 867 node.childrenAccept(this, context); 868 List<ExpressionStatement> statements = operatorStatements(context, node.count()); 869 BinaryOperation operation = assembleBinaryOperation(statements, nCopies(node.count(), OperatorType.AND)); 870 context.push(operation); 871 node.setIrElement(operation); 872 return data; 873 } 874 875 @Override 876 public Object visit(ASTOrExpression node, Object data) { 877 Context context = (Context) data; 878 node.childrenAccept(this, context); 879 List<ExpressionStatement> statements = operatorStatements(context, node.count()); 880 BinaryOperation operation = assembleBinaryOperation(statements, nCopies(node.count(), OperatorType.OR)); 881 context.push(operation); 882 node.setIrElement(operation); 883 return data; 884 } 885 886 @Override 887 public Object visit(ASTOrIfNullExpression node, Object data) { 888 Context context = (Context) data; 889 node.childrenAccept(this, context); 890 List<ExpressionStatement> statements = operatorStatements(context, node.count()); 891 BinaryOperation operation = assembleBinaryOperation(statements, nCopies(node.count(), OperatorType.ORIFNULL)); 892 context.push(operation); 893 node.setIrElement(operation); 894 return data; 895 } 896}