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