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