1 35 package org.jruby.parser; 36 37 import java.util.Iterator ; 38 39 import org.jruby.ast.AndNode; 40 import org.jruby.ast.ArgsCatNode; 41 import org.jruby.ast.ArgsPushNode; 42 import org.jruby.ast.ArrayNode; 43 import org.jruby.ast.AssignableNode; 44 import org.jruby.ast.AttrAssignNode; 45 import org.jruby.ast.BackRefNode; 46 import org.jruby.ast.BeginNode; 47 import org.jruby.ast.BignumNode; 48 import org.jruby.ast.BlockNode; 49 import org.jruby.ast.BlockPassNode; 50 import org.jruby.ast.BreakNode; 51 import org.jruby.ast.CallNode; 52 import org.jruby.ast.ClassVarAsgnNode; 53 import org.jruby.ast.ClassVarDeclNode; 54 import org.jruby.ast.ClassVarNode; 55 import org.jruby.ast.ConstDeclNode; 56 import org.jruby.ast.ConstNode; 57 import org.jruby.ast.DAsgnNode; 58 import org.jruby.ast.DRegexpNode; 59 import org.jruby.ast.DStrNode; 60 import org.jruby.ast.DotNode; 61 import org.jruby.ast.EvStrNode; 62 import org.jruby.ast.FCallNode; 63 import org.jruby.ast.FalseNode; 64 import org.jruby.ast.FixnumNode; 65 import org.jruby.ast.FlipNode; 66 import org.jruby.ast.FloatNode; 67 import org.jruby.ast.GlobalAsgnNode; 68 import org.jruby.ast.GlobalVarNode; 69 import org.jruby.ast.IArgumentNode; 70 import org.jruby.ast.IfNode; 71 import org.jruby.ast.InstAsgnNode; 72 import org.jruby.ast.InstVarNode; 73 import org.jruby.ast.ListNode; 74 import org.jruby.ast.LocalAsgnNode; 75 import org.jruby.ast.Match2Node; 76 import org.jruby.ast.Match3Node; 77 import org.jruby.ast.MatchNode; 78 import org.jruby.ast.MultipleAsgnNode; 79 import org.jruby.ast.NewlineNode; 80 import org.jruby.ast.NilNode; 81 import org.jruby.ast.Node; 82 import org.jruby.ast.NodeTypes; 83 import org.jruby.ast.NthRefNode; 84 import org.jruby.ast.OptNNode; 85 import org.jruby.ast.OrNode; 86 import org.jruby.ast.RegexpNode; 87 import org.jruby.ast.RootNode; 88 import org.jruby.ast.SValueNode; 89 import org.jruby.ast.SelfNode; 90 import org.jruby.ast.SplatNode; 91 import org.jruby.ast.StrNode; 92 import org.jruby.ast.SuperNode; 93 import org.jruby.ast.TrueNode; 94 import org.jruby.ast.YieldNode; 95 import org.jruby.ast.types.ILiteralNode; 96 import org.jruby.common.IRubyWarnings; 97 import org.jruby.lexer.yacc.ISourcePosition; 98 import org.jruby.lexer.yacc.ISourcePositionHolder; 99 import org.jruby.lexer.yacc.SourcePosition; 100 import org.jruby.lexer.yacc.SyntaxException; 101 import org.jruby.lexer.yacc.Token; 102 import org.jruby.runtime.DynamicScope; 103 import org.jruby.util.ByteList; 104 import org.jruby.util.IdUtil; 105 106 109 public class ParserSupport { 110 private StaticScope currentScope; 112 113 private int inSingleton; 115 116 private boolean inDefinition; 118 119 private IRubyWarnings warnings; 120 121 private RubyParserConfiguration configuration; 122 private RubyParserResult result; 123 124 public void reset() { 125 inSingleton = 0; 126 inDefinition = false; 127 } 128 129 public StaticScope getCurrentScope() { 130 return currentScope; 131 } 132 133 public void popCurrentScope() { 134 currentScope = currentScope.getEnclosingScope(); 135 } 136 137 public void pushBlockScope() { 138 currentScope = new BlockStaticScope(currentScope); 139 } 140 141 public void pushLocalScope() { 142 currentScope = new LocalStaticScope(currentScope); 143 } 144 145 public Node arg_concat(ISourcePosition position, Node node1, Node node2) { 146 return node2 == null ? node1 : new ArgsCatNode(position, node1, node2); 147 } 148 149 public Node arg_blk_pass(Node firstNode, BlockPassNode secondNode) { 150 if (secondNode != null) { 151 secondNode.setArgsNode(firstNode); 152 return secondNode; 153 } 154 return firstNode; 155 } 156 157 public Node appendPrintToBlock(Node block) { 158 ISourcePosition position = block.getPosition(); 159 return appendToBlock(block, new FCallNode(position, "print", 160 new ArrayNode(position).add(new GlobalVarNode(position, "$_")))); 161 } 162 163 public Node appendWhileLoopToBlock(Node block, boolean chop, boolean split) { 164 ISourcePosition position = block.getPosition(); 165 if (split) { 166 block = appendToBlock(new GlobalAsgnNode(position, "$F", 167 new CallNode(position, new GlobalVarNode(position, "$_"), "split", null)), block); 168 } 169 if (chop) { 170 block = appendToBlock(new CallNode(position, new GlobalVarNode(position, "$_"), "chop!", null), block); 171 } 172 return new OptNNode(position, block); 173 } 174 175 182 public Node gettable2(String id, ISourcePosition position) { 183 switch (IdUtil.getVarType(id)) { 184 case IdUtil.LOCAL_VAR: 185 return currentScope.declare(position, id); 186 case IdUtil.CONSTANT: 187 return new ConstNode(position, id); 188 case IdUtil.INSTANCE_VAR: 189 return new InstVarNode(position, id); 190 case IdUtil.CLASS_VAR: 191 return new ClassVarNode(position, id); 192 case IdUtil.GLOBAL_VAR: 193 return new GlobalVarNode(position, id); 194 } 195 196 throw new SyntaxException(position, "identifier " + id + " is not valid"); 197 } 198 199 206 public Node gettable(String id, ISourcePosition position) { 207 if (id.equals("self")) { 208 return new SelfNode(position); 209 } else if (id.equals("nil")) { 210 return new NilNode(position); 211 } else if (id.equals("true")) { 212 return new TrueNode(position); 213 } else if (id.equals("false")) { 214 return new FalseNode(position); 215 } else if (id.equals("__FILE__")) { 216 return new StrNode(position, ByteList.create(position.getFile())); 217 } else if (id.equals("__LINE__")) { 218 return new FixnumNode(position, position.getEndLine()+1); 219 } 220 221 return gettable2(id, position); 222 } 223 224 public AssignableNode assignable(Token lhs, Node value) { 225 checkExpression(value); 226 227 String id = (String ) lhs.getValue(); 228 229 if ("self".equals(id)) { 230 throw new SyntaxException(lhs.getPosition(), "Can't change the value of self"); 231 } else if ("nil".equals(id)) { 232 throw new SyntaxException(lhs.getPosition(), "Can't assign to nil"); 233 } else if ("true".equals(id)) { 234 throw new SyntaxException(lhs.getPosition(), "Can't assign to true"); 235 } else if ("false".equals(id)) { 236 throw new SyntaxException(lhs.getPosition(), "Can't assign to false"); 237 } else if ("__FILE__".equals(id)) { 238 throw new SyntaxException(lhs.getPosition(), "Can't assign to __FILE__"); 239 } else if ("__LINE__".equals(id)) { 240 throw new SyntaxException(lhs.getPosition(), "Can't assign to __LINE__"); 241 } else { 242 switch (IdUtil.getVarType(id)) { 243 case IdUtil.LOCAL_VAR: 244 return currentScope.assign(value != null ? union(lhs, value) : lhs.getPosition(), id, value); 245 case IdUtil.CONSTANT: 246 if (isInDef() || isInSingle()) { 247 throw new SyntaxException(lhs.getPosition(), "dynamic constant assignment"); 248 } 249 return new ConstDeclNode(lhs.getPosition(), id, null, value); 250 case IdUtil.INSTANCE_VAR: 251 return new InstAsgnNode(lhs.getPosition(), id, value); 252 case IdUtil.CLASS_VAR: 253 if (isInDef() || isInSingle()) { 254 return new ClassVarAsgnNode(lhs.getPosition(), id, value); 255 } 256 return new ClassVarDeclNode(lhs.getPosition(), id, value); 257 case IdUtil.GLOBAL_VAR: 258 return new GlobalAsgnNode(lhs.getPosition(), id, value); 259 } 260 } 261 262 throw new SyntaxException(lhs.getPosition(), "identifier " + id + " is not valid"); 263 } 264 265 271 public Node newline_node(Node node, ISourcePosition position) { 272 if (node == null) return null; 273 274 return node instanceof NewlineNode ? node : new NewlineNode(position, node); 275 } 276 277 public ISourcePosition union(ISourcePositionHolder first, ISourcePositionHolder second) { 278 while (first instanceof NewlineNode) { 279 first = ((NewlineNode) first).getNextNode(); 280 } 281 282 while (second instanceof NewlineNode) { 283 second = ((NewlineNode) second).getNextNode(); 284 } 285 286 if(second == null) { 287 return first.getPosition(); 288 } 289 290 return first.getPosition().union(second.getPosition()); 291 } 292 293 public ISourcePosition union(ISourcePosition first, ISourcePosition second) { 294 assert first.getFile().equals(second.getFile()); 295 296 if (first.getStartOffset() < second.getStartOffset()) { 297 return new SourcePosition(first.getFile(), first.getStartLine(), 298 second.getEndLine(), first.getStartOffset(), second.getEndOffset()); 299 } else { 300 return new SourcePosition(first.getFile(), second.getStartLine(), 301 first.getEndLine(), second.getStartOffset(), first.getEndOffset()); 302 } 303 } 304 305 public Node addRootNode(Node topOfAST) { 306 RootNode root = new RootNode(topOfAST != null ? topOfAST.getPosition() : null, result.getScope(), 309 appendToBlock(result.getAST(), topOfAST)); 310 311 313 return root; 314 315 } 316 317 public Node appendToBlock(Node head, Node tail) { 318 if (tail == null) return head; 319 if (head == null) return tail; 320 321 326 if (!(head instanceof BlockNode)) { 327 head = new BlockNode(head.getPosition()).add(head); 328 } 329 330 if (warnings.isVerbose() && isBreakStatement(((ListNode) head).getLast())) { 331 warnings.warning(tail.getPosition(), "Statement not reached."); 332 } 333 334 ((ListNode) head).addAll(tail); 336 head.setPosition(union(head, tail)); 337 return head; 338 } 339 340 public Node getOperatorCallNode(Node firstNode, String operator) { 341 checkExpression(firstNode); 342 343 return new CallNode(firstNode.getPosition(), firstNode, operator, null); 344 } 345 346 public Node getOperatorCallNode(Node firstNode, String operator, Node secondNode) { 347 checkExpression(firstNode); 348 checkExpression(secondNode); 349 350 return new CallNode(union(firstNode.getPosition(), secondNode.getPosition()), firstNode, operator, new ArrayNode(secondNode.getPosition()).add(secondNode)); 351 } 352 353 public Node getMatchNode(Node firstNode, Node secondNode) { 354 if (firstNode instanceof DRegexpNode || firstNode instanceof RegexpNode) { 355 return new Match2Node(firstNode.getPosition(), firstNode, secondNode); 356 } else if (secondNode instanceof DRegexpNode || secondNode instanceof RegexpNode) { 357 return new Match3Node(firstNode.getPosition(), secondNode, firstNode); 358 } 359 360 return getOperatorCallNode(firstNode, "=~", secondNode); 361 } 362 363 370 public Node aryset(Node receiver, Node index) { 371 checkExpression(receiver); 372 373 return new AttrAssignNode(receiver.getPosition(), receiver, "[]=", index); 374 } 375 376 383 public Node attrset(Node receiver, String name) { 384 checkExpression(receiver); 385 386 return new AttrAssignNode(receiver.getPosition(), receiver, name + "=", null); 387 } 388 389 public void backrefAssignError(Node node) { 390 if (node instanceof NthRefNode) { 391 throw new SyntaxException(node.getPosition(), "Can't set variable $" + ((NthRefNode) node).getMatchNumber() + '.'); 392 } else if (node instanceof BackRefNode) { 393 throw new SyntaxException(node.getPosition(), "Can't set variable $" + ((BackRefNode) node).getType() + '.'); 394 } 395 } 396 397 public Node arg_add(ISourcePosition position, Node node1, Node node2) { 398 if (node1 == null) return new ArrayNode(position, node2); 399 if (node1 instanceof ArrayNode) return ((ArrayNode) node1).add(node2); 400 401 return new ArgsPushNode(position, node1, node2); 402 } 403 404 407 public Node node_assign(Node lhs, Node rhs) { 408 if (lhs == null) { 409 return null; 410 } 411 Node newNode = lhs; 412 413 checkExpression(rhs); 414 if (lhs instanceof AssignableNode) { 415 ((AssignableNode) lhs).setValueNode(rhs); 416 lhs.setPosition(union(lhs, rhs)); 417 } else if (lhs instanceof IArgumentNode) { 418 IArgumentNode invokableNode = (IArgumentNode) lhs; 419 420 invokableNode.setArgsNode(arg_add(lhs.getPosition(), invokableNode.getArgsNode(), rhs)); 421 } 422 423 return newNode; 424 } 425 426 public Node ret_args(Node node, ISourcePosition position) { 427 if (node != null) { 428 if (node instanceof BlockPassNode) { 429 throw new SyntaxException(position, "Dynamic constant assignment."); 430 } else if (node instanceof ArrayNode && ((ArrayNode)node).size() == 1) { 431 node = (Node) ((ArrayNode)node).iterator().next(); 432 } else if (node instanceof SplatNode) { 433 node = new SValueNode(position, node); 434 } 435 } 436 437 return node; 438 } 439 440 446 public boolean isBreakStatement(Node node) { 447 breakLoop: do { 448 if (node == null) return false; 449 450 switch (node.nodeId) { 451 case NodeTypes.NEWLINENODE: 452 node = ((NewlineNode) node).getNextNode(); 453 continue breakLoop; 454 case NodeTypes.BREAKNODE: case NodeTypes.NEXTNODE: case NodeTypes.REDONODE: 455 case NodeTypes.RETRYNODE: case NodeTypes.RETURNNODE: 456 return true; 457 default: 458 return false; 459 } 460 } while (true); 461 } 462 463 468 public void checkExpression(Node node) { 469 if (!isExpression(node)) { 470 warnings.warning(node.getPosition(), "void value expression"); 471 } 472 } 473 474 private boolean isExpression(Node node) { 475 expressionLoop: do { 476 if (node == null) return true; 477 478 switch (node.nodeId) { 479 case NodeTypes.BEGINNODE: 480 node = ((BeginNode) node).getBodyNode(); 481 continue expressionLoop; 482 case NodeTypes.BLOCKNODE: 483 node = ((BlockNode) node).getLast(); 484 continue expressionLoop; 485 case NodeTypes.BREAKNODE: 486 node = ((BreakNode) node).getValueNode(); 487 continue expressionLoop; 488 case NodeTypes.CLASSNODE: case NodeTypes.DEFNNODE: case NodeTypes.DEFSNODE: 489 case NodeTypes.MODULENODE: case NodeTypes.NEXTNODE: case NodeTypes.REDONODE: 490 case NodeTypes.RETRYNODE: case NodeTypes.RETURNNODE: case NodeTypes.UNTILNODE: 491 case NodeTypes.WHILENODE: 492 return false; 493 case NodeTypes.IFNODE: 494 return isExpression(((IfNode) node).getThenBody()) && 495 isExpression(((IfNode) node).getElseBody()); 496 case NodeTypes.NEWLINENODE: 497 node = ((NewlineNode) node).getNextNode(); 498 continue expressionLoop; 499 default: return true; 501 } 502 } while (true); 503 } 504 505 private void handleUselessWarn(Node node, String useless) { 506 warnings.warn(node.getPosition(), "Useless use of " + useless + " in void context."); 507 } 508 509 514 public void checkUselessStatement(Node node) { 515 if (!warnings.isVerbose()) return; 516 517 uselessLoop: do { 518 if (node == null) return; 519 520 switch (node.nodeId) { 521 case NodeTypes.NEWLINENODE: 522 node = ((NewlineNode) node).getNextNode(); 523 continue uselessLoop; 524 case NodeTypes.CALLNODE: { 525 String name = ((CallNode) node).getName().intern(); 526 527 if (name == "+" || name == "-" || name == "*" || name == "/" || name == "%" || 528 name == "**" || name == "+@" || name == "-@" || name == "|" || name == "^" || 529 name == "&" || name == "<=>" || name == ">" || name == ">=" || name == "<" || 530 name == "<=" || name == "==" || name == "!=") { 531 handleUselessWarn(node, name); 532 } 533 return; 534 } 535 case NodeTypes.BACKREFNODE: case NodeTypes.DVARNODE: case NodeTypes.GLOBALVARNODE: 536 case NodeTypes.LOCALVARNODE: case NodeTypes.NTHREFNODE: case NodeTypes.CLASSVARNODE: 537 case NodeTypes.INSTVARNODE: 538 handleUselessWarn(node, "a variable"); return; 539 542 case NodeTypes.BIGNUMNODE: case NodeTypes.DREGEXPNODE: case NodeTypes.DSTRNODE: 543 case NodeTypes.FIXNUMNODE: case NodeTypes.FLOATNODE: case NodeTypes.REGEXPNODE: 544 case NodeTypes.STRNODE: case NodeTypes.SYMBOLNODE: 545 handleUselessWarn(node, "a literal"); return; 546 549 case NodeTypes.DOTNODE: 550 handleUselessWarn(node, ((DotNode) node).isExclusive() ? "..." : ".."); return; 551 case NodeTypes.DEFINEDNODE: 552 handleUselessWarn(node, "defined?"); return; 553 case NodeTypes.FALSENODE: 554 handleUselessWarn(node, "false"); return; 555 case NodeTypes.NILNODE: 556 handleUselessWarn(node, "nil"); return; 557 560 case NodeTypes.TRUENODE: 561 handleUselessWarn(node, "true"); return; 562 default: return; 563 } 564 } while (true); 565 } 566 567 572 public void checkUselessStatements(BlockNode blockNode) { 573 if (warnings.isVerbose()) { 574 Node lastNode = blockNode.getLast(); 575 576 for (Iterator iterator = blockNode.iterator(); iterator.hasNext(); ) { 577 Node currentNode = (Node) iterator.next(); 578 579 if (lastNode != currentNode ) { 580 checkUselessStatement(currentNode); 581 } 582 } 583 } 584 } 585 586 589 private boolean checkAssignmentInCondition(Node node) { 590 if (node instanceof MultipleAsgnNode) { 591 throw new SyntaxException(node.getPosition(), "Multiple assignment in conditional."); 592 } else if (node instanceof LocalAsgnNode || node instanceof DAsgnNode || node instanceof GlobalAsgnNode || node instanceof InstAsgnNode) { 593 Node valueNode = ((AssignableNode) node).getValueNode(); 594 if (valueNode instanceof ILiteralNode || valueNode instanceof NilNode || valueNode instanceof TrueNode || valueNode instanceof FalseNode) { 595 warnings.warn(node.getPosition(), "Found '=' in conditional, should be '=='."); 596 } 597 return true; 598 } 599 600 return false; 601 } 602 603 private Node cond0(Node node) { 604 checkAssignmentInCondition(node); 605 606 if (node instanceof DRegexpNode) { 607 ISourcePosition position = node.getPosition(); 608 609 return new Match2Node(position, node, new GlobalVarNode(position, "$_")); 610 } else if (node instanceof DotNode) { 611 int slot = currentScope.getLocalScope().addVariable(""); 612 return new FlipNode(node.getPosition(), 613 getFlipConditionNode(((DotNode) node).getBeginNode()), 614 getFlipConditionNode(((DotNode) node).getEndNode()), 615 ((DotNode) node).isExclusive(), slot); 616 } else if (node instanceof RegexpNode) { 617 return new MatchNode(node.getPosition(), node); 618 } else if (node instanceof StrNode) { 619 ISourcePosition position = node.getPosition(); 620 621 return new MatchNode(position, new RegexpNode(position, (ByteList) ((StrNode) node).getValue().clone(), 0)); 622 } 623 624 return node; 625 } 626 627 public Node getConditionNode(Node node) { 628 if (node == null) return null; 629 630 if (node instanceof NewlineNode) { 631 return new NewlineNode(node.getPosition(), cond0(((NewlineNode) node).getNextNode())); 632 } 633 634 return cond0(node); 635 } 636 637 private Node getFlipConditionNode(Node node) { 638 node = getConditionNode(node); 639 640 if (node instanceof NewlineNode) return ((NewlineNode) node).getNextNode(); 641 642 if (node instanceof FixnumNode) { 643 return getOperatorCallNode(node, "==", new GlobalVarNode(node.getPosition(), "$.")); 644 } 645 646 return node; 647 } 648 649 public AndNode newAndNode(Node left, Node right) { 650 checkExpression(left); 651 652 return new AndNode(union(left, right), left, right); 653 } 654 655 public OrNode newOrNode(Node left, Node right) { 656 checkExpression(left); 657 658 return new OrNode(union(left, right), left, right); 659 } 660 661 public Node getReturnArgsNode(Node node) { 662 if (node instanceof ArrayNode && ((ArrayNode) node).size() == 1) { 663 return (Node) ((ListNode) node).iterator().next(); 664 } else if (node instanceof BlockPassNode) { 665 throw new SyntaxException(node.getPosition(), "Block argument should not be given."); 666 } 667 return node; 668 } 669 670 public Node new_call(Node receiver, Token name, Node args, Node iter) { 671 if (args == null) { 672 return new CallNode(union(receiver, name), receiver,(String ) name.getValue(), null, iter); 673 } 674 675 if (args instanceof BlockPassNode) { 676 if (iter != null) { 678 throw new SyntaxException(iter.getPosition(), "Both block arg and actual block given."); 679 } 680 681 return new CallNode(union(receiver, args), receiver, (String ) name.getValue(), 682 ((BlockPassNode) args).getArgsNode(), args); 683 } 684 685 return new CallNode(union(receiver, args), receiver,(String ) name.getValue(), args, iter); 686 } 687 688 public Node new_fcall(Token operation, Node args, Node iter) { 689 String name = (String ) operation.getValue(); 690 691 if (args == null) return new FCallNode(operation.getPosition(), name, args, iter); 692 693 if (args instanceof BlockPassNode) { 694 if (iter != null) { 695 throw new SyntaxException(iter.getPosition(), "Both block arg and actual block given."); 696 } 697 return new FCallNode(union(operation, args), name, ((BlockPassNode) args).getArgsNode(), args); 698 } 699 700 return new FCallNode(union(operation, args), name, args, iter); 701 } 702 703 public Node new_super(Node args, Token operation) { 704 if (args != null && args instanceof BlockPassNode) { 705 return new SuperNode(union(operation, args), ((BlockPassNode) args).getArgsNode(), args); 706 } 707 return new SuperNode(operation.getPosition(), args); 708 } 709 710 713 public void initTopLocalVariables() { 714 DynamicScope scope = configuration.getScope(); 715 currentScope = scope.getStaticScope(); 716 717 result.setScope(scope); 718 } 719 720 723 public boolean isInSingle() { 724 return inSingleton != 0; 725 } 726 727 730 public void setInSingle(int inSingle) { 731 this.inSingleton = inSingle; 732 } 733 734 public boolean isInDef() { 735 return inDefinition; 736 } 737 738 public void setInDef(boolean inDef) { 739 this.inDefinition = inDef; 740 } 741 742 745 public int getInSingle() { 746 return inSingleton; 747 } 748 749 753 public RubyParserResult getResult() { 754 return result; 755 } 756 757 761 public void setResult(RubyParserResult result) { 762 this.result = result; 763 } 764 765 769 public void setConfiguration(RubyParserConfiguration configuration) { 770 this.configuration = configuration; 771 } 772 773 public void setWarnings(IRubyWarnings warnings) { 774 this.warnings = warnings; 775 } 776 777 public Node literal_concat(ISourcePosition position, Node head, Node tail) { 778 if (head == null) return tail; 779 if (tail == null) return head; 780 781 if (head instanceof EvStrNode) { 782 head = new DStrNode(union(head.getPosition(), position)).add(head); 783 } 784 785 if (tail instanceof StrNode) { 786 if (head instanceof StrNode) { 787 return new StrNode(union(head, tail), (StrNode) head, (StrNode) tail); 788 } 789 head.setPosition(union(head, tail)); 790 return ((ListNode) head).add(tail); 791 792 } else if (tail instanceof DStrNode) { 793 if (head instanceof StrNode){ 794 ((DStrNode)tail).childNodes().add(0, head); 795 return tail; 796 } 797 798 return ((ListNode) head).addAll(tail); 799 } 800 801 if (head instanceof StrNode) { 803 804 if(((StrNode) head).getValue().length() == 0) { 806 head = new DStrNode(head.getPosition()); 807 } else { 808 head.getPosition().adjustStartOffset(-1); 810 head = new DStrNode(head.getPosition()).add(head); 811 } 812 } 813 return ((DStrNode) head).add(tail); 814 } 815 816 public Node newEvStrNode(ISourcePosition position, Node node) { 817 Node head = node; 818 while (true) { 819 if (node == null) break; 820 821 if (node instanceof StrNode || node instanceof DStrNode || node instanceof EvStrNode) { 822 return node; 823 } 824 825 if (!(node instanceof NewlineNode)) break; 826 827 node = ((NewlineNode) node).getNextNode(); 828 } 829 830 return new EvStrNode(position, head); 831 } 832 833 public Node new_yield(ISourcePosition position, Node node) { 834 boolean state = true; 835 836 if (node != null) { 837 if (node instanceof BlockPassNode) { 838 throw new SyntaxException(node.getPosition(), "Block argument should not be given."); 839 } 840 841 if (node instanceof ArrayNode && ((ArrayNode)node).size() == 1) { 842 node = (Node) ((ArrayNode)node).iterator().next(); 843 state = false; 844 } 845 846 if (node != null && node instanceof SplatNode) { 847 state = true; 848 } 849 } else { 850 state = false; 851 } 852 853 return new YieldNode(position, node, state); 854 } 855 856 public Node negateInteger(Node integerNode) { 857 if (integerNode instanceof FixnumNode) { 858 FixnumNode fixnumNode = (FixnumNode) integerNode; 859 860 fixnumNode.setValue(-fixnumNode.getValue()); 861 return fixnumNode; 862 } else if (integerNode instanceof BignumNode) { 863 BignumNode bignumNode = (BignumNode) integerNode; 864 865 bignumNode.setValue(bignumNode.getValue().negate()); 866 } 867 868 return integerNode; 869 } 870 871 public FloatNode negateFloat(FloatNode floatNode) { 872 floatNode.setValue(-floatNode.getValue()); 873 874 return floatNode; 875 } 876 877 public Node unwrapNewlineNode(Node node) { 878 if(node instanceof NewlineNode) { 879 return ((NewlineNode) node).getNextNode(); 880 } 881 return node; 882 } 883 } 884 | Popular Tags |