Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    ***** BEGIN LICENSE BLOCK *****
    * Version: EPL 1.0/GPL 2.0/LGPL 2.1
    *
    * The contents of this file are subject to the Eclipse Public
    * License Version 1.0 (the "License"); you may not use this file
    * except in compliance with the License. You may obtain a copy of
    * the License at http://www.eclipse.org/legal/epl-v10.html
    *
   * Software distributed under the License is distributed on an "AS
   * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
   * implied. See the License for the specific language governing
   * rights and limitations under the License.
   *
   * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
   * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
   * Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
   * Copyright (C) 2004 Charles O Nutter <headius@headius.com>
   * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
   * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
   * Copyright (C) 2006-2007 Mirko Stocker <me@misto.ch>
   * Copyright (C) 2006 Thomas Corbat <tcorbat@hsr.ch>
   * 
   * Alternatively, the contents of this file may be used under the terms of
   * either of the GNU General Public License Version 2 or later (the "GPL"),
   * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
   * in which case the provisions of the GPL or the LGPL are applicable instead
   * of those above. If you wish to allow use of your version of this file only
   * under the terms of either the GPL or the LGPL, and not to allow others to
   * use your version of this file under the terms of the EPL, indicate your
   * decision by deleting the provisions above and replace them with the notice
   * and other provisions required by the GPL or the LGPL. If you do not delete
   * the provisions above, a recipient may use your version of this file under
   * the terms of any one of the EPL, the GPL or the LGPL.
   ***** END LICENSE BLOCK *****/
  package org.jruby.parser;
  
  import org.jruby.ast.*;
  
  public class ParserSupport {
      // Parser states:
      protected StaticScope currentScope;
  
      protected RubyYaccLexer lexer;
      
      // Is the parser current within a singleton (value is number of nested singletons)
      private int inSingleton;
      
      // Is the parser currently within a method definition
      private boolean inDefinition;
  
      protected IRubyWarnings warnings;
  
      protected ParserConfiguration configuration;
      private RubyParserResult result;
  
      public void reset() {
           = 0;
           = false;
      }
      
      public void allowDubyExtension(ISourcePosition position) {
          throw new SyntaxException(.position,
                  .getCurrentLine(), "Duby extensions not configured");
      }
      
      public StaticScope getCurrentScope() {
          return ;
      }
      
      public ParserConfiguration getConfiguration() {
          return ;
      }
      
      public void popCurrentScope() {
           = .getEnclosingScope();
     }
     
     public void pushBlockScope() {
     }
     
     public void pushLocalScope() {
     }
     
     public Node arg_concat(ISourcePosition positionNode node1Node node2) {
         return node2 == null ? node1 : new ArgsCatNode(positionnode1node2);
     }
 
     public Node arg_blk_pass(Node firstNodeBlockPassNode secondNode) {
         if (secondNode != null) {
             secondNode.setArgsNode(firstNode);
             return secondNode;
         }
         return firstNode;
     }

    
We know for callers of this that it cannot be any of the specials checked in gettable.

Parameters:
node to check its variable type
Returns:
an AST node representing this new variable
 
     public Node gettable2(Node node) {
         switch (node.getNodeType()) {
         case // LOCALVAR
         case :
             return .declare(node.getPosition(), ((INameNodenode).getName());
         case // CONSTANT
             return new ConstNode(node.getPosition(), ((INameNodenode).getName());
         case // INSTANCE VARIABLE
             return new InstVarNode(node.getPosition(), ((INameNodenode).getName());
         case :
         case :
             return new ClassVarNode(node.getPosition(), ((INameNodenode).getName());
         case :
             return new GlobalVarNode(node.getPosition(), ((INameNodenode).getName());
         }
 
         getterIdentifierError(node.getPosition(), ((INameNodenode).getName());
         return null;
     }
    
    
Create AST node representing variable type it represents.

Parameters:
token to check its variable type
Returns:
an AST node representing this new variable
 
     public Node gettable(Token token) {
         switch (token.getType()) {
         case .:
             return new SelfNode(token.getPosition());
         case .:
             return new NilNode(token.getPosition());
         case .:
             return new TrueNode(token.getPosition());
         case .:
             return new FalseNode(token.getPosition());
         case .:
             return new FileNode(token.getPosition(), new ByteList(token.getPosition().getFile().getBytes(),
                     getConfiguration().getRuntime().getEncodingService().getLocaleEncoding()));
         case .:
             return new FixnumNode(token.getPosition(), token.getPosition().getStartLine()+1);
         case .:
             return new EncodingNode(token.getPosition(), .getEncoding());
         case .:
             return .declare(token.getPosition(), (Stringtoken.getValue());
         case .:
             return new ConstNode(token.getPosition(), (Stringtoken.getValue());
         case .:
             return new InstVarNode(token.getPosition(), (Stringtoken.getValue());
         case .:
             return new ClassVarNode(token.getPosition(), (Stringtoken.getValue());
         case .:
             return new GlobalVarNode(token.getPosition(), (Stringtoken.getValue());
         }
 
         getterIdentifierError(token.getPosition(), (Stringtoken.getValue());
         return null;
     }
     
     protected void getterIdentifierError(ISourcePosition positionString identifier) {
         throw new SyntaxException(.position.getCurrentLine(),
                 "identifier " + identifier + " is not valid"identifier);
     }
     
     public AssignableNode assignable(Token lhsNode value) {
         checkExpression(value);
 
         switch (lhs.getType()) {
             case .:
                 throw new SyntaxException(.lhs.getPosition(),
                         .getCurrentLine(), "Can't change the value of self");
             case .:
                 throw new SyntaxException(.lhs.getPosition(),
                         .getCurrentLine(), "Can't assign to nil""nil");
             case .:
                 throw new SyntaxException(.lhs.getPosition(),
                         .getCurrentLine(), "Can't assign to true""true");
             case .:
                 throw new SyntaxException(.lhs.getPosition(),
                         .getCurrentLine(), "Can't assign to false""false");
             case .:
                 throw new SyntaxException(.lhs.getPosition(),
                         .getCurrentLine(), "Can't assign to __FILE__""__FILE__");
             case .:
                 throw new SyntaxException(.lhs.getPosition(),
                         .getCurrentLine(), "Can't assign to __LINE__""__LINE__");
             case .:
                 return .assign(lhs.getPosition(), (Stringlhs.getValue(), makeNullNil(value));
             case .:
                 if (isInDef() || isInSingle()) {
                     throw new SyntaxException(.lhs.getPosition(),
                             .getCurrentLine(), "dynamic constant assignment");
                 }
                 return new ConstDeclNode(lhs.getPosition(), (Stringlhs.getValue(), nullvalue);
             case .:
                 return new InstAsgnNode(lhs.getPosition(), (Stringlhs.getValue(), value);
             case .:
                 if (isInDef() || isInSingle()) {
                     return new ClassVarAsgnNode(lhs.getPosition(), (Stringlhs.getValue(), value);
                 }
                 return new ClassVarDeclNode(lhs.getPosition(), (Stringlhs.getValue(), value);
             case .:
                 return new GlobalAsgnNode(lhs.getPosition(), (Stringlhs.getValue(), value);
         }
 
         throw new SyntaxException(.lhs.getPosition(), .getCurrentLine(),
                 "identifier " + (Stringlhs.getValue() + " is not valid"lhs.getValue());
     }

    
Wraps node with NEWLINE node.

Parameters:
node
Returns:
a NewlineNode or null if node is null.
 
     public Node newline_node(Node nodeISourcePosition position) {
         if (node == nullreturn null;
 
         .coverLine(position.getStartLine());
         
         return node instanceof NewlineNode ? node : new NewlineNode(positionnode); 
     }
     
     public Node addRootNode(Node topOfASTISourcePosition position) {
         position = topOfAST != null ? topOfAST.getPosition() : position;
 
         if (.getBeginNodes().isEmpty()) {
             if (topOfAST == nulltopOfAST = .;
             
             return new RootNode(position.getScope(), topOfAST);
         }
         
         BlockNode newTopOfAST = new BlockNode(position);
         for (Node beginNode.getBeginNodes()) {
             appendToBlock(newTopOfASTbeginNode);
         }
         
         // Add real top to new top (unless this top is empty [only begin/end nodes or truly empty])
         if (topOfAST != nullnewTopOfAST.add(topOfAST);
         
         return new RootNode(position.getScope(), newTopOfAST);
     }
     
     /* MRI: block_append */
     public Node appendToBlock(Node headNode tail) {
         if (tail == nullreturn head;
         if (head == nullreturn tail;
 
         // Reduces overhead in interp by not set position every single line we encounter. 
         if (!.hasExtraPositionInformation()) {
             head = compactNewlines(head);
         }
 
         if (!(head instanceof BlockNode)) {
             head = new BlockNode(head.getPosition()).add(head);
         }
 
         if (.isVerbose() && isBreakStatement(((ListNodehead).getLast())) {
             .warning(.tail.getPosition(), "Statement not reached.");
         }
 
         // Assumption: tail is never a list node
         ((ListNodehead).addAll(tail);
         return head;
     }
 
     public Node getOperatorCallNode(Node firstNodeString operator) {
         checkExpression(firstNode);
 
         return new CallNoArgNode(firstNode.getPosition(), firstNodeoperator);
     }
     
     public Node getOperatorCallNode(Node firstNodeString operatorNode secondNode) {
         return getOperatorCallNode(firstNodeoperatorsecondNodenull);
     }
 
     public Node getOperatorCallNode(Node firstNodeString operatorNode secondNodeISourcePosition defaultPosition) {
         if (defaultPosition != null) {
             firstNode = checkForNilNode(firstNodedefaultPosition);
             secondNode = checkForNilNode(secondNodedefaultPosition);
         }
         
         checkExpression(firstNode);
         checkExpression(secondNode);
 
         return new_call_one_arg(firstNode.getPosition(), firstNodeoperatorsecondNode);
 //        return new CallOneArgNode(firstNode.getPosition(), firstNode, operator, new ArrayNode(secondNode.getPosition(), secondNode));
     }
 
     public Node getMatchNode(Node firstNodeNode secondNode) {
         if (firstNode instanceof DRegexpNode || firstNode instanceof RegexpNode) {
             return new Match2Node(firstNode.getPosition(), firstNodesecondNode);
         } else if (secondNode instanceof DRegexpNode || secondNode instanceof RegexpNode) {
             return new Match3Node(firstNode.getPosition(), secondNodefirstNode);
         } 
 
         return getOperatorCallNode(firstNode"=~"secondNode);
     }

    
Define an array set condition so we can return lhs

Parameters:
receiver array being set
index node which should evalute to index of array set
Returns:
an AttrAssignNode
 
     public Node aryset(Node receiverNode index) {
         checkExpression(receiver);
 
         return new_attrassign(receiver.getPosition(), receiver"[]="index);
     }

    
Define an attribute set condition so we can return lhs

Parameters:
receiver object which contains attribute
name of the attribute being set
Returns:
an AttrAssignNode
 
     public Node attrset(Node receiverString name) {
         checkExpression(receiver);
 
         return new_attrassign(receiver.getPosition(), receivername + "="null);
     }
 
     public void backrefAssignError(Node node) {
         if (node instanceof NthRefNode) {
             String varName = "$" + ((NthRefNodenode).getMatchNumber();
             throw new SyntaxException(.node.getPosition(), 
                     "Can't set variable " + varName + '.'varName);
         } else if (node instanceof BackRefNode) {
             String varName = "$" + ((BackRefNodenode).getType();
             throw new SyntaxException(.node.getPosition(), "Can't set variable " + varName + '.'varName);
         }
     }
 
     public Node arg_add(ISourcePosition positionNode node1Node node2) {
         if (node1 == null) {
             if (node2 == null) {
                 return new ArrayNode(position.);
             } else {
                 return new ArrayNode(node2.getPosition(), node2);
             }
         }
         if (node1 instanceof ArrayNodereturn ((ArrayNodenode1).add(node2);
         
         return new ArgsPushNode(positionnode1node2);
     }
    

Fixme:
position
 
     public Node node_assign(Node lhsNode rhs) {
         if (lhs == nullreturn null;
 
         Node newNode = lhs;
 
         checkExpression(rhs);
         if (lhs instanceof AssignableNode) {
     	    ((AssignableNodelhs).setValueNode(rhs);
         } else if (lhs instanceof IArgumentNode) {
             IArgumentNode invokableNode = (IArgumentNodelhs;
             
             return invokableNode.setArgsNode(arg_add(lhs.getPosition(), invokableNode.getArgsNode(), rhs));
         }
         
         return newNode;
     }
     
     public Node ret_args(Node nodeISourcePosition position) {
         if (node != null) {
             if (node instanceof BlockPassNode) {
                 throw new SyntaxException(.position,
                         .getCurrentLine(), "block argument should not be given");
             } else if (node instanceof ArrayNode && ((ArrayNode)node).size() == 1) {
                 node = ((ArrayNode)node).get(0);
             } else if (node instanceof SplatNode) {
                 node = newSValueNode(positionnode);
             }
         }
         
         return node;
     }

    
Is the supplied node a break/control statement?

Parameters:
node to be checked
Returns:
true if a control node, false otherwise
 
     public boolean isBreakStatement(Node node) {
         breakLoop: do {
             if (node == nullreturn false;
 
             switch (node.getNodeType()) {
             case :
                 node = ((NewlineNodenode).getNextNode();
                 continue breakLoop;
             case case case :
             case case :
                 return true;
             default:
                 return false;
             }
         } while (true);                    
     }
     
     public void warnUnlessEOption(ID idNode nodeString message) {
         if (!.isInlineSource()) {
             .warn(idnode.getPosition(), message);
         }
     }
 
     public void warningUnlessEOption(ID idNode nodeString message) {
         if (.isVerbose() && !.isInlineSource()) {
             .warning(idnode.getPosition(), message);
         }
     }
 
     private Node compactNewlines(Node head) {
         while (head instanceof NewlineNode) {
             Node nextNode = ((NewlineNodehead).getNextNode();
 
             if (!(nextNode instanceof NewlineNode)) {
                 break;
             }
             head = nextNode;
         }
         return head;
     }
 
     // logical equivalent to value_expr in MRI
     public boolean checkExpression(Node node) {
         boolean conditional = false;
 
         while (node != null) {
             switch (node.getNodeType()) {
             case case :
                 .warning(.node.getPosition(),
                         "void value expression");
                 return false;
             case case case case :
             case :
                 if (!conditional) {
                     throw new SyntaxException(.,
                             node.getPosition(), .getCurrentLine(),
                             "void value expression");
                 }
                 return false;
             case :
                 node = ((BlockNodenode).getLast();
                 break;
             case :
                 node = ((BeginNodenode).getBodyNode();
                 break;
             case :
                 if (!checkExpression(((IfNodenode).getThenBody())) return false;
                 node = ((IfNodenode).getElseBody();
                 break;
             case case :
                 conditional = true;
                 node = ((BinaryOperatorNodenode).getSecondNode();
                 break;
             case :
                 node = ((NewlineNodenode).getNextNode();
                 break;
             default// Node
                 return true;
             }
         }
 
         return true;
     }
    
    
Is this a literal in the sense that MRI has a NODE_LIT for. This is different than ILiteralNode. We should pick a different name since ILiteralNode is something we created which is similiar but used for a slightly different condition (can I do singleton things).

Parameters:
node to be tested
Returns:
true if it is a literal
 
     public boolean isLiteral(Node node) {
         return node != null && (node instanceof FixnumNode || node instanceof BignumNode || 
                 node instanceof FloatNode || node instanceof SymbolNode || 
                 (node instanceof RegexpNode && ((RegexpNodenode).getOptions().toJoniOptions() == 0));
     }
 
     private void handleUselessWarn(Node nodeString useless) {
         .warn(.node.getPosition(), "Useless use of " + useless + " in void context.");
     }

    
Check to see if current node is an useless statement. If useless a warning if printed.

Parameters:
node to be checked.
 
     public void checkUselessStatement(Node node) {
         if (!.isVerbose() || (!.isInlineSource() && .isEvalParse())) return;
         
         uselessLoop: do {
             if (node == nullreturn;
             
             switch (node.getNodeType()) {
             case :
                 node = ((NewlineNodenode).getNextNode();
                 continue uselessLoop;
             case : {
                 String name = ((CallNodenode).getName();
                 
                 if (name == "+" || name == "-" || name == "*" || name == "/" || name == "%" || 
                     name == "**" || name == "+@" || name == "-@" || name == "|" || name == "^" || 
                     name == "&" || name == "<=>" || name == ">" || name == ">=" || name == "<" || 
                     name == "<=" || name == "==" || name == "!=") {
                     handleUselessWarn(nodename);
                 }
                 return;
             }
             case case case :
             case case case :
             case :
                 handleUselessWarn(node"a variable"); return;
             // FIXME: Temporarily disabling because this fires way too much running Rails tests. JRUBY-518
             /*case CONSTNODE:
                 handleUselessWarn(node, "a constant"); return;*/
             case case case case :
             case case case :
             case case :
                 handleUselessWarn(node"a literal"); return;
             // FIXME: Temporarily disabling because this fires way too much running Rails tests. JRUBY-518
             /*case CLASSNODE: case COLON2NODE:
                 handleUselessWarn(node, "::"); return;*/
             case :
                 handleUselessWarn(node, ((DotNodenode).isExclusive() ? "..." : ".."); return;
             case :
                 handleUselessWarn(node"defined?"); return;
             case :
                 handleUselessWarn(node"false"); return;
             case 
                 handleUselessWarn(node"nil"); return;
             // FIXME: Temporarily disabling because this fires way too much running Rails tests. JRUBY-518
             /*case SELFNODE:
                 handleUselessWarn(node, "self"); return;*/
             case :
                 handleUselessWarn(node"true"); return;
             defaultreturn;
             }
         } while (true);
     }

    
Check all nodes but the last one in a BlockNode for useless (void context) statements.

Parameters:
blockNode to be checked.
 
     public void checkUselessStatements(BlockNode blockNode) {
         if (.isVerbose()) {
             Node lastNode = blockNode.getLast();
 
             for (int i = 0; i < blockNode.size(); i++) {
                 Node currentNode = blockNode.get(i);
         		
                 if (lastNode != currentNode ) {
                     checkUselessStatement(currentNode);
                 }
             }
         }
     }

assign_in_cond
 
     private boolean checkAssignmentInCondition(Node node) {
         if (node instanceof MultipleAsgnNode) {
             throw new SyntaxException(.node.getPosition(),
                     .getCurrentLine(), "Multiple assignment in conditional.");
         } else if (node instanceof LocalAsgnNode || node instanceof DAsgnNode || node instanceof GlobalAsgnNode || node instanceof InstAsgnNode) {
             Node valueNode = ((AssignableNodenode).getValueNode();
             if (valueNode instanceof ILiteralNode || valueNode instanceof NilNode || valueNode instanceof TrueNode || valueNode instanceof FalseNode) {
                 .warn(.node.getPosition(), "Found '=' in conditional, should be '=='.");
             }
             return true;
         } 
 
         return false;
     }
     
     protected Node makeNullNil(Node node) {
         return node == null ? . : node;
     }
 
     private Node cond0(Node node) {
         checkAssignmentInCondition(node);
         
         Node leftNode = null;
         Node rightNode = null;
 
         // FIXME: DSTR,EVSTR,STR: warning "string literal in condition"
         switch(node.getNodeType()) {
         case : {
             ISourcePosition position = node.getPosition();
 
             return new Match2Node(positionnodenew GlobalVarNode(position"$_"));
         }
         case :
             leftNode = cond0(((AndNodenode).getFirstNode());
             rightNode = cond0(((AndNodenode).getSecondNode());
             
             return new AndNode(node.getPosition(), makeNullNil(leftNode), makeNullNil(rightNode));
         case :
             leftNode = cond0(((OrNodenode).getFirstNode());
             rightNode = cond0(((OrNodenode).getSecondNode());
             
             return new OrNode(node.getPosition(), makeNullNil(leftNode), makeNullNil(rightNode));
         case : {
             DotNode dotNode = (DotNodenode;
             if (dotNode.isLiteral()) return node
             
             String label = String.valueOf("FLIP" + node.hashCode());
             .getLocalScope().addVariable(label);
             int slot = .isDefined(label);
             
             return new FlipNode(node.getPosition(),
                     getFlipConditionNode(((DotNodenode).getBeginNode()),
                     getFlipConditionNode(((DotNodenode).getEndNode()),
                     dotNode.isExclusive(), slot);
         }
         case :
             warningUnlessEOption(.node"regex literal in condition");
             
             return new MatchNode(node.getPosition(), node);
         }
 
         return node;
     }
 
     public Node getConditionNode(Node node) {
         if (node == nullreturn .;
 
         if (node instanceof NewlineNode) {
             return new NewlineNode(node.getPosition(), cond0(((NewlineNodenode).getNextNode()));
         } 
 
         return cond0(node);
     }
 
     /* MRI: range_op */
     private Node getFlipConditionNode(Node node) {
         if (!.isInlineSource()) return node;
         
         node = getConditionNode(node);
 
         if (node instanceof NewlineNodereturn ((NewlineNodenode).getNextNode();
         
         if (node instanceof FixnumNode) {
             warnUnlessEOption(.node"integer literal in conditional range");
             return getOperatorCallNode(node"=="new GlobalVarNode(node.getPosition(), "$."));
         } 
 
         return node;
     }
 
     public SValueNode newSValueNode(ISourcePosition positionNode node) {
         return new SValueNode(positionnode);
     }
     
     public SplatNode newSplatNode(ISourcePosition positionNode node) {
         return new SplatNode(positionmakeNullNil(node));
     }
     
     public ArrayNode newArrayNode(ISourcePosition positionNode firstNode) {
         return new ArrayNode(positionmakeNullNil(firstNode));
     }
 
         return one == null ? two.getPosition() : one.getPosition();
     }
 
     public AndNode newAndNode(ISourcePosition positionNode leftNode right) {
         checkExpression(left);
         
         if (left == null && right == nullreturn new AndNode(positionmakeNullNil(left), makeNullNil(right));
         
         return new AndNode(position(leftright), makeNullNil(left), makeNullNil(right));
     }
 
     public OrNode newOrNode(ISourcePosition positionNode leftNode right) {
         checkExpression(left);
 
         if (left == null && right == nullreturn new OrNode(positionmakeNullNil(left), makeNullNil(right));
         
         return new OrNode(position(leftright), makeNullNil(left), makeNullNil(right));
     }

    
Ok I admit that this is somewhat ugly. We post-process a chain of when nodes and analyze them to re-insert them back into our new CaseNode the way we want. The grammar is being difficult and until I go back into the depths of that this is where things are.

Parameters:
expression of the case node (e.g. case foo)
firstWhenNode first when (which could also be the else)
Returns:
a new case node
 
     public CaseNode newCaseNode(ISourcePosition positionNode expressionNode firstWhenNode) {
         ArrayNode cases = new ArrayNode(firstWhenNode != null ? firstWhenNode.getPosition() : position);
         CaseNode caseNode = new CaseNode(positionexpressioncases);
 
         for (Node current = firstWhenNodecurrent != nullcurrent = ((WhenNodecurrent).getNextCase()) {
             if (current instanceof WhenOneArgNode) {
                 cases.add(current);
             } else if (current instanceof WhenNode) {
                 simplifyMultipleArgumentWhenNodes((WhenNodecurrentcases);
             } else {
                 caseNode.setElseNode(current);
                 break;
             }
         }
 
         return caseNode;
     }
 
     /*
      * This method exists for us to break up multiple expression when nodes (e.g. when 1,2,3:)
      * into individual whenNodes.  The primary reason for this is to ensure lazy evaluation of
      * the arguments (when foo,bar,gar:) to prevent side-effects.  In the old code this was done
      * using nested when statements, which was awful for interpreter and compilation.
      *
      * Notes: This has semantic equivalence but will not be lexically equivalent.  Compiler
      * needs to detect same bodies to simplify bytecode generated.
      */
     private void simplifyMultipleArgumentWhenNodes(WhenNode sourceWhenArrayNode cases) {
         Node expressionNodes = sourceWhen.getExpressionNodes();
 
         if (expressionNodes instanceof SplatNode || expressionNodes instanceof ArgsCatNode) {
             cases.add(sourceWhen);
             return;
         }
 
         if (expressionNodes instanceof ListNode) {
             ListNode list = (ListNodeexpressionNodes;
             ISourcePosition position = sourceWhen.getPosition();
             Node bodyNode = sourceWhen.getBodyNode();
 
             for (int i = 0; i < list.size(); i++) {
                 Node expression = list.get(i);
 
                 if (expression instanceof SplatNode || expression instanceof ArgsCatNode) {
                     cases.add(new WhenNode(positionexpressionbodyNodenull));
                 } else {
                     cases.add(new WhenOneArgNode(positionexpressionbodyNodenull));
                 }
             }
         } else {
             cases.add(sourceWhen);
         }
     }
     
     public WhenNode newWhenNode(ISourcePosition positionNode expressionNodesNode bodyNodeNode nextCase) {
         if (bodyNode == nullbodyNode = .;
 
         if (expressionNodes instanceof SplatNode || expressionNodes instanceof ArgsCatNode || expressionNodes instanceof ArgsPushNode) {
             return new WhenNode(positionexpressionNodesbodyNodenextCase);
         }
 
         ListNode list = (ListNodeexpressionNodes;
 
         if (list.size() == 1) {
             Node element = list.get(0);
             
             if (!(element instanceof SplatNode)) {
                 return new WhenOneArgNode(positionelementbodyNodenextCase);
             }
         }
 
         return new WhenNode(positionexpressionNodesbodyNodenextCase);
     }
 
     public Node getReturnArgsNode(Node node) {
         if (node instanceof ArrayNode && ((ArrayNodenode).size() == 1) { 
             return ((ListNodenode).get(0);
         } else if (node instanceof BlockPassNode) {
             throw new SyntaxException(.node.getPosition(),
                     .getCurrentLine(), "Block argument should not be given.");
         }
         return node;
     }
     
     public Node new_opAssign(AssignableNode lhsString asgnOpNode rhs) {
         checkExpression(rhs);
 
         ISourcePosition pos = lhs.getPosition();
         
         if (asgnOp.equals("||")) {
             lhs.setValueNode(rhs);
             return new OpAsgnOrNode(posgettable2(lhs), lhs);
         } else if (asgnOp.equals("&&")) {
             lhs.setValueNode(rhs);
             return new OpAsgnAndNode(posgettable2(lhs), lhs);
         }
         
         lhs.setValueNode(getOperatorCallNode(gettable2(lhs), asgnOprhs));
         lhs.setPosition(pos);
         
         return lhs;
     }
     
     public Node new_opElementAsgnNode(ISourcePosition positionNode receiverNodeString operatorNameNode argsNodeNode valueNode) {
         if (argsNode instanceof ArrayNode) {
             ArrayNode array = (ArrayNodeargsNode;
             
             if (array.size() == 1) {
                 if (operatorName.equals("||")) {
                     return new OpElementOneArgOrAsgnNode(positionreceiverNodeoperatorNamearrayvalueNode);
                 } else if (operatorName.equals("&&")) {
                     return new OpElementOneArgAndAsgnNode(positionreceiverNodeoperatorNamearrayvalueNode);                    
                 } else {
                     return new OpElementOneArgAsgnNode(positionreceiverNodeoperatorNamearrayvalueNode);
                 }
             }
         }
         return new OpElementAsgnNode(positionreceiverNodeoperatorNameargsNodevalueNode);
     }
     
     public Node new_attrassign(ISourcePosition positionNode receiverString nameNode args) {
         if (!(args instanceof ArrayNode)) return new AttrAssignNode(positionreceivernameargs);
         
         ArrayNode argsNode = (ArrayNodeargs;
         
         switch (argsNode.size()) {
             case 1:
                 return new AttrAssignOneArgNode(positionreceivernameargsNode);
             case 2:
                 return new AttrAssignTwoArgNode(positionreceivernameargsNode);
             case 3:
                 return new AttrAssignThreeArgNode(positionreceivernameargsNode);
             default:
                 return new AttrAssignNode(positionreceivernameargsNode);
         }
     }
     
     private Node new_call_noargs(Node receiverToken nameIterNode iter) {
         ISourcePosition position = position(receivername);
         
         if (receiver == nullreceiver = .;
         
         if (iter != nullreturn new CallNoArgBlockNode(positionreceiver, (Stringname.getValue(), iter);
         
         return new CallNoArgNode(positionreceiver, (Stringname.getValue());
     }
     
     private Node new_call_complexargs(Node receiverToken nameNode argsNode iter) {
         if (args instanceof BlockPassNode) {
             // Block and block pass passed in at same time....uh oh
             if (iter != null) {
                 throw new SyntaxException(.iter.getPosition(),
                         .getCurrentLine(), "Both block arg and actual block given.");
             }
 
             return new_call_blockpass(receivername, (BlockPassNodeargs);
         }
 
         if (iter != nullreturn new CallSpecialArgBlockNode(position(receiverargs), receiver,(Stringname.getValue(), args, (IterNodeiter);
 
         return new CallSpecialArgNode(position(receiverargs), receiver, (Stringname.getValue(), args);
     }
     
     private Node new_call_blockpass(Node receiverToken operationBlockPassNode blockPass) {
         ISourcePosition position = position(receiverblockPass);
         String name = (Stringoperation.getValue();
         Node args = blockPass.getArgsNode();
         
         if (args == nullreturn new CallNoArgBlockPassNode(positionreceivernameargsblockPass);
         if (!(args instanceof ArrayNode)) return new CallSpecialArgBlockPassNode(positionreceivernameargsblockPass);
         
         switch (((ArrayNodeargs).size()) {
             case 0:  // foo()
                 return new CallNoArgBlockPassNode(positionreceivernameargsblockPass);
             case 1:
                 return new CallOneArgBlockPassNode(positionreceivername, (ArrayNodeargsblockPass);
             case 2:
                 return new CallTwoArgBlockPassNode(positionreceivername, (ArrayNodeargsblockPass);
             case 3:
                 return new CallThreeArgBlockPassNode(positionreceivername, (ArrayNodeargsblockPass);
             default:
                 return new CallManyArgsBlockPassNode(positionreceivernameargsblockPass);
         } 
     }
     
     private boolean isNumericOperator(String name) {
         if (name.length() == 1) {
             switch (name.charAt(0)) {
                 case '+'case '-'case '*'case '/'case '<'case '>':
                     return true;
             }
         } else if (name.length() == 2) {
             switch (name.charAt(0)) {
             case '<'case '>'case '=':
                 switch (name.charAt(1)) {
                 case '='case '<':
                     return true;
                 }
             }
         }
         
         return false;
     }
 
     private Node new_call_one_arg(ISourcePosition positionNode receiverString nameNode first) {
         if (first instanceof FixnumNode && isNumericOperator(name)) {
             return new CallOneArgFixnumNode(positionreceivernamenew ArrayNode(positionfirst));
         }
 
         return new CallOneArgNode(positionreceivernamenew ArrayNode(positionfirst));
     }
 
     public Node new_call(Node receiverToken nameNode argsNodeNode iter) {
         if (argsNode == nullreturn new_call_noargs(receivername, (IterNodeiter);
         if (!(argsNode instanceof ArrayNode)) return new_call_complexargs(receivernameargsNodeiter);
         
         ArrayNode args = (ArrayNodeargsNode;
 
         switch (args.size()) {
             case 0:
                 if (iter != nullreturn new CallNoArgBlockNode(position(receiverargs), receiver, (Stringname.getValue(), args, (IterNodeiter);
                     
                 return new CallNoArgNode(position(receiverargs), receiverargs, (Stringname.getValue());
             case 1:
                 if (iter != nullreturn new CallOneArgBlockNode(position(receiverargs), receiver, (Stringname.getValue(), args, (IterNodeiter);
 
                 return new CallOneArgNode(position(receiverargs), receiver, (Stringname.getValue(), args);
             case 2:
                 if (iter != nullreturn new CallTwoArgBlockNode(position(receiverargs), receiver, (Stringname.getValue(), args, (IterNodeiter);
                 
                 return new CallTwoArgNode(position(receiverargs), receiver, (Stringname.getValue(), args);
             case 3:
                 if (iter != nullreturn new CallThreeArgBlockNode(position(receiverargs), receiver, (Stringname.getValue(), args, (IterNodeiter);
                 
                 return new CallThreeArgNode(position(receiverargs), receiver, (Stringname.getValue(), args);
             default:
                 if (iter != nullreturn new CallManyArgsBlockNode(position(receiverargs), receiver, (Stringname.getValue(), args, (IterNodeiter);
 
                 return new CallManyArgsNode(position(receiverargs), receiver, (Stringname.getValue(), args);
         }
     }
 
     public Node new_aref(Node receiverToken nameNode argsNode) {
         if (argsNode instanceof ArrayNode) {
             ArrayNode args = (ArrayNodeargsNode;
 
             if (args.size() == 1 && args.get(0) instanceof FixnumNode) {
                 return new CallOneArgFixnumNode(position(receiverargs), receiver"[]"args);
             }
         }
         return new_call(receivernameargsNodenull);
     }