KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > parser > ParserSupport


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
15  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
16  * Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
17  * Copyright (C) 2004 Charles O Nutter <headius@headius.com>
18  * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
19  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
20  * Copyright (C) 2006 Mirko Stocker <me@misto.ch>
21  * Copyright (C) 2006 Thomas Corbat <tcorbat@hsr.ch>
22  *
23  * Alternatively, the contents of this file may be used under the terms of
24  * either of the GNU General Public License Version 2 or later (the "GPL"),
25  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26  * in which case the provisions of the GPL or the LGPL are applicable instead
27  * of those above. If you wish to allow use of your version of this file only
28  * under the terms of either the GPL or the LGPL, and not to allow others to
29  * use your version of this file under the terms of the CPL, indicate your
30  * decision by deleting the provisions above and replace them with the notice
31  * and other provisions required by the GPL or the LGPL. If you do not delete
32  * the provisions above, a recipient may use your version of this file under
33  * the terms of any one of the CPL, the GPL or the LGPL.
34  ***** END LICENSE BLOCK *****/

35 package org.jruby.parser;
36
37 import java.util.Iterator JavaDoc;
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 /**
107  *
108  */

109 public class ParserSupport {
110     // Parser states:
111
private StaticScope currentScope;
112     
113     // Is the parser current within a singleton (value is number of nested singletons)
114
private int inSingleton;
115     
116     // Is the parser currently within a method definition
117
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     /**
176      * We know for callers of this that it cannot be any of the specials checked in gettable.
177      *
178      * @param id to check its variable type
179      * @param position location of this position
180      * @return an AST node representing this new variable
181      */

182     public Node gettable2(String JavaDoc 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     /**
200      * Create AST node representing variable type it represents.
201      *
202      * @param id to check its variable type
203      * @param position location of this position
204      * @return an AST node representing this new variable
205      */

206     public Node gettable(String JavaDoc 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 JavaDoc id = (String JavaDoc) 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     /**
266      * Wraps node with NEWLINE node.
267      *
268      *@param node
269      *@return a NewlineNode or null if node is null.
270      */

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         // I am not sure we need to get AST to set AST and the appendToBlock could maybe get removed.
307
// For sure once we do two pass parsing we should since this is mostly just optimzation.
308
RootNode root = new RootNode(topOfAST != null ? topOfAST.getPosition() : null, result.getScope(),
309                 appendToBlock(result.getAST(), topOfAST));
310
311         // FIXME: Should add begin and end nodes
312

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         //Mirko asks: This was added, and it breaks a lof of my code, is it really needed?
322
//while (head instanceof NewlineNode) {
323
// head = ((NewlineNode) head).getNextNode();
324
//}
325

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         // Assumption: tail is never a list node
335
((ListNode) head).addAll(tail);
336         head.setPosition(union(head, tail));
337         return head;
338     }
339
340     public Node getOperatorCallNode(Node firstNode, String JavaDoc operator) {
341         checkExpression(firstNode);
342
343         return new CallNode(firstNode.getPosition(), firstNode, operator, null);
344     }
345
346     public Node getOperatorCallNode(Node firstNode, String JavaDoc 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     /**
364      * Define an array set condition so we can return lhs
365      *
366      * @param receiver array being set
367      * @param index node which should evalute to index of array set
368      * @return an AttrAssignNode
369      */

370     public Node aryset(Node receiver, Node index) {
371         checkExpression(receiver);
372
373         return new AttrAssignNode(receiver.getPosition(), receiver, "[]=", index);
374     }
375
376     /**
377      * Define an attribute set condition so we can return lhs
378      *
379      * @param receiver object which contains attribute
380      * @param name of the attribute being set
381      * @return an AttrAssignNode
382      */

383     public Node attrset(Node receiver, String JavaDoc 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     /**
405      * @fixme position
406      **/

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     /**
441      * Is the supplied node a break/control statement?
442      *
443      * @param node to be checked
444      * @return true if a control node, false otherwise
445      */

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     /**
464      * Does this node represent an expression?
465      * @param node to be checked
466      * @return true if an expression, false otherwise
467      */

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: // Node
500
return true;
501             }
502         } while (true);
503     }
504
505     private void handleUselessWarn(Node node, String JavaDoc useless) {
506         warnings.warn(node.getPosition(), "Useless use of " + useless + " in void context.");
507     }
508
509     /**
510      * Check to see if current node is an useless statement. If useless a warning if printed.
511      *
512      * @param node to be checked.
513      */

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 JavaDoc 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             // FIXME: Temporarily disabling because this fires way too much running Rails tests. JRUBY-518
540
/*case NodeTypes.CONSTNODE:
541                 handleUselessWarn(node, "a constant"); return;*/

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             // FIXME: Temporarily disabling because this fires way too much running Rails tests. JRUBY-518
547
/*case NodeTypes.CLASSNODE: case NodeTypes.COLON2NODE:
548                 handleUselessWarn(node, "::"); return;*/

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             // FIXME: Temporarily disabling because this fires way too much running Rails tests. JRUBY-518
558
/*case NodeTypes.SELFNODE:
559                 handleUselessWarn(node, "self"); return;*/

560             case NodeTypes.TRUENODE:
561                 handleUselessWarn(node, "true"); return;
562             default: return;
563             }
564         } while (true);
565     }
566
567     /**
568      * Check all nodes but the last one in a BlockNode for useless (void context) statements.
569      *
570      * @param blockNode to be checked.
571      */

572     public void checkUselessStatements(BlockNode blockNode) {
573         if (warnings.isVerbose()) {
574             Node lastNode = blockNode.getLast();
575
576             for (Iterator JavaDoc 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     /**
587      * @fixme error handling
588      **/

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 JavaDoc) name.getValue(), null, iter);
673         }
674
675         if (args instanceof BlockPassNode) {
676             // Block and block pass passed in at same time....uh oh
677
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 JavaDoc) name.getValue(),
682                     ((BlockPassNode) args).getArgsNode(), args);
683         }
684             
685         return new CallNode(union(receiver, args), receiver,(String JavaDoc) name.getValue(), args, iter);
686     }
687
688     public Node new_fcall(Token operation, Node args, Node iter) {
689         String JavaDoc name = (String JavaDoc) 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     /**
711     * Description of the RubyMethod
712     */

713     public void initTopLocalVariables() {
714         DynamicScope scope = configuration.getScope();
715         currentScope = scope.getStaticScope();
716         
717         result.setScope(scope);
718     }
719
720     /** Getter for property inSingle.
721      * @return Value of property inSingle.
722      */

723     public boolean isInSingle() {
724         return inSingleton != 0;
725     }
726
727     /** Setter for property inSingle.
728      * @param inSingle New value of property inSingle.
729      */

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     /** Getter for property inSingle.
743      * @return Value of property inSingle.
744      */

745     public int getInSingle() {
746         return inSingleton;
747     }
748
749     /**
750      * Gets the result.
751      * @return Returns a RubyParserResult
752      */

753     public RubyParserResult getResult() {
754         return result;
755     }
756
757     /**
758      * Sets the result.
759      * @param result The result to set
760      */

761     public void setResult(RubyParserResult result) {
762         this.result = result;
763     }
764
765     /**
766      * Sets the configuration.
767      * @param configuration The configuration to set
768      */

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         // tail must be EvStrNode at this point
802
if (head instanceof StrNode) {
803             
804             //Do not add an empty string node
805
if(((StrNode) head).getValue().length() == 0) {
806                 head = new DStrNode(head.getPosition());
807             } else {
808                 // All first element StrNode's do not include syntacical sugar.
809
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