KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > evaluator > EvaluationState


1 /*******************************************************************************
2  * BEGIN LICENSE BLOCK *** Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public License Version
5  * 1.0 (the "License"); you may not use this file except in compliance with the
6  * License. You may obtain a copy of the License at
7  * http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
11  * the specific language governing rights and limitations under the License.
12  *
13  * Copyright (C) 2006 Charles Oliver Nutter <headius@headius.com>
14  * Copytight (C) 2006-2007 Thomas E Enebo <enebo@acm.org>
15  * Copyright (C) 2007 Miguel Covarrubias <mlcovarrubias@gmail.com>
16  * Copyright (C) 2007 Ola Bini <ola@ologix.com>
17  *
18  * Alternatively, the contents of this file may be used under the terms of
19  * either of the GNU General Public License Version 2 or later (the "GPL"), or
20  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in
21  * which case the provisions of the GPL or the LGPL are applicable instead of
22  * those above. If you wish to allow use of your version of this file only under
23  * the terms of either the GPL or the LGPL, and not to allow others to use your
24  * version of this file under the terms of the CPL, indicate your decision by
25  * deleting the provisions above and replace them with the notice and other
26  * provisions required by the GPL or the LGPL. If you do not delete the
27  * provisions above, a recipient may use your version of this file under the
28  * terms of any one of the CPL, the GPL or the LGPL. END LICENSE BLOCK ****
29  ******************************************************************************/

30
31 package org.jruby.evaluator;
32
33 import java.util.HashMap JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.Map JavaDoc;
36
37 import org.jruby.Ruby;
38 import org.jruby.MetaClass;
39 import org.jruby.RubyArray;
40 import org.jruby.RubyBignum;
41 import org.jruby.RubyClass;
42 import org.jruby.RubyException;
43 import org.jruby.RubyFloat;
44 import org.jruby.RubyHash;
45 import org.jruby.RubyKernel;
46 import org.jruby.RubyModule;
47 import org.jruby.RubyObject;
48 import org.jruby.RubyProc;
49 import org.jruby.RubyRange;
50 import org.jruby.RubyRegexp;
51 import org.jruby.RubyString;
52 import org.jruby.ast.AliasNode;
53 import org.jruby.ast.ArgsCatNode;
54 import org.jruby.ast.ArgsNode;
55 import org.jruby.ast.ArgsPushNode;
56 import org.jruby.ast.ArrayNode;
57 import org.jruby.ast.AttrAssignNode;
58 import org.jruby.ast.BackRefNode;
59 import org.jruby.ast.BeginNode;
60 import org.jruby.ast.BignumNode;
61 import org.jruby.ast.BinaryOperatorNode;
62 import org.jruby.ast.BlockNode;
63 import org.jruby.ast.BlockPassNode;
64 import org.jruby.ast.BreakNode;
65 import org.jruby.ast.CallNode;
66 import org.jruby.ast.CaseNode;
67 import org.jruby.ast.ClassNode;
68 import org.jruby.ast.ClassVarAsgnNode;
69 import org.jruby.ast.ClassVarDeclNode;
70 import org.jruby.ast.ClassVarNode;
71 import org.jruby.ast.Colon2Node;
72 import org.jruby.ast.Colon3Node;
73 import org.jruby.ast.ConstDeclNode;
74 import org.jruby.ast.ConstNode;
75 import org.jruby.ast.DAsgnNode;
76 import org.jruby.ast.DRegexpNode;
77 import org.jruby.ast.DStrNode;
78 import org.jruby.ast.DSymbolNode;
79 import org.jruby.ast.DVarNode;
80 import org.jruby.ast.DXStrNode;
81 import org.jruby.ast.DefinedNode;
82 import org.jruby.ast.DefnNode;
83 import org.jruby.ast.DefsNode;
84 import org.jruby.ast.DotNode;
85 import org.jruby.ast.EnsureNode;
86 import org.jruby.ast.EvStrNode;
87 import org.jruby.ast.FCallNode;
88 import org.jruby.ast.FixnumNode;
89 import org.jruby.ast.FlipNode;
90 import org.jruby.ast.FloatNode;
91 import org.jruby.ast.ForNode;
92 import org.jruby.ast.GlobalAsgnNode;
93 import org.jruby.ast.GlobalVarNode;
94 import org.jruby.ast.HashNode;
95 import org.jruby.ast.IfNode;
96 import org.jruby.ast.InstAsgnNode;
97 import org.jruby.ast.InstVarNode;
98 import org.jruby.ast.IterNode;
99 import org.jruby.ast.ListNode;
100 import org.jruby.ast.LocalAsgnNode;
101 import org.jruby.ast.LocalVarNode;
102 import org.jruby.ast.Match2Node;
103 import org.jruby.ast.Match3Node;
104 import org.jruby.ast.MatchNode;
105 import org.jruby.ast.ModuleNode;
106 import org.jruby.ast.MultipleAsgnNode;
107 import org.jruby.ast.NewlineNode;
108 import org.jruby.ast.NextNode;
109 import org.jruby.ast.Node;
110 import org.jruby.ast.NodeTypes;
111 import org.jruby.ast.NotNode;
112 import org.jruby.ast.NthRefNode;
113 import org.jruby.ast.OpAsgnNode;
114 import org.jruby.ast.OpAsgnOrNode;
115 import org.jruby.ast.OpElementAsgnNode;
116 import org.jruby.ast.OptNNode;
117 import org.jruby.ast.OrNode;
118 import org.jruby.ast.RegexpNode;
119 import org.jruby.ast.RescueBodyNode;
120 import org.jruby.ast.RescueNode;
121 import org.jruby.ast.ReturnNode;
122 import org.jruby.ast.RootNode;
123 import org.jruby.ast.SClassNode;
124 import org.jruby.ast.SValueNode;
125 import org.jruby.ast.SplatNode;
126 import org.jruby.ast.StrNode;
127 import org.jruby.ast.SuperNode;
128 import org.jruby.ast.SymbolNode;
129 import org.jruby.ast.ToAryNode;
130 import org.jruby.ast.UndefNode;
131 import org.jruby.ast.UntilNode;
132 import org.jruby.ast.VAliasNode;
133 import org.jruby.ast.VCallNode;
134 import org.jruby.ast.WhenNode;
135 import org.jruby.ast.WhileNode;
136 import org.jruby.ast.XStrNode;
137 import org.jruby.ast.YieldNode;
138 import org.jruby.ast.ZSuperNode;
139 import org.jruby.ast.types.INameNode;
140 import org.jruby.ast.util.ArgsUtil;
141 import org.jruby.exceptions.JumpException;
142 import org.jruby.exceptions.RaiseException;
143 import org.jruby.exceptions.JumpException.JumpType;
144 import org.jruby.internal.runtime.methods.DefaultMethod;
145 import org.jruby.internal.runtime.methods.DynamicMethod;
146 import org.jruby.internal.runtime.methods.WrapperMethod;
147 import org.jruby.lexer.yacc.ISourcePosition;
148 import org.jruby.parser.StaticScope;
149 import org.jruby.runtime.Block;
150 import org.jruby.runtime.CallType;
151 import org.jruby.runtime.DynamicScope;
152 import org.jruby.runtime.ForBlock;
153 import org.jruby.runtime.ThreadContext;
154 import org.jruby.runtime.Visibility;
155 import org.jruby.runtime.builtin.IRubyObject;
156 import org.jruby.util.ByteList;
157 import org.jruby.util.KCode;
158 import org.jruby.util.collections.SinglyLinkedList;
159
160 public class EvaluationState {
161     public static IRubyObject eval(Ruby runtime, ThreadContext context, Node node, IRubyObject self, Block block) {
162         try {
163             return evalInternal(runtime, context, node, self, block);
164         } catch (StackOverflowError JavaDoc sfe) {
165             throw runtime.newSystemStackError("stack level too deep");
166         }
167     }
168     
169     /* Something like cvar_cbase() from eval.c, factored out for the benefit
170      * of all the classvar-related node evaluations */

171     private static RubyModule getClassVariableBase(ThreadContext context, Ruby runtime) {
172         SinglyLinkedList cref = context.peekCRef();
173         RubyModule rubyClass = (RubyModule) cref.getValue();
174         if (rubyClass.isSingleton()) {
175             cref = cref.getNext();
176             rubyClass = (RubyModule) cref.getValue();
177             if (cref.getNext() == null) {
178                 runtime.getWarnings().warn("class variable access from toplevel singleton method");
179             }
180         }
181         return rubyClass;
182     }
183
184     private static IRubyObject evalInternal(Ruby runtime, ThreadContext context, Node node, IRubyObject self, Block aBlock) {
185         bigloop: do {
186             if (node == null) return runtime.getNil();
187
188             switch (node.nodeId) {
189             case NodeTypes.ALIASNODE: {
190                 AliasNode iVisited = (AliasNode) node;
191     
192                 if (context.getRubyClass() == null) {
193                     throw runtime.newTypeError("no class to make alias");
194                 }
195     
196                 context.getRubyClass().defineAlias(iVisited.getNewName(), iVisited.getOldName());
197                 context.getRubyClass().callMethod(context, "method_added", runtime.newSymbol(iVisited.getNewName()));
198     
199                 return runtime.getNil();
200             }
201             case NodeTypes.ANDNODE: {
202                 BinaryOperatorNode iVisited = (BinaryOperatorNode) node;
203     
204                 IRubyObject result = evalInternal(runtime,context, iVisited.getFirstNode(), self, aBlock);
205                 if (!result.isTrue()) return result;
206                 node = iVisited.getSecondNode();
207                 continue bigloop;
208             }
209             case NodeTypes.ARGSCATNODE: {
210                 ArgsCatNode iVisited = (ArgsCatNode) node;
211     
212                 IRubyObject args = evalInternal(runtime,context, iVisited.getFirstNode(), self, aBlock);
213                 IRubyObject secondArgs = splatValue(runtime, evalInternal(runtime,context, iVisited.getSecondNode(), self, aBlock));
214                 RubyArray list = args instanceof RubyArray ? (RubyArray) args : runtime.newArray(args);
215     
216                 return list.concat(secondArgs);
217             }
218             case NodeTypes.ARGSPUSHNODE: {
219                 ArgsPushNode iVisited = (ArgsPushNode) node;
220                 
221                 RubyArray args = (RubyArray) evalInternal(runtime,context, iVisited.getFirstNode(), self, aBlock).dup();
222                 return args.append(evalInternal(runtime,context, iVisited.getSecondNode(), self, aBlock));
223             }
224                 // case NodeTypes.ARGSNODE:
225
// EvaluateVisitor.argsNodeVisitor.execute(this, node);
226
// break;
227
// case NodeTypes.ARGUMENTNODE:
228
// EvaluateVisitor.argumentNodeVisitor.execute(this, node);
229
// break;
230
case NodeTypes.ARRAYNODE: {
231                 ArrayNode iVisited = (ArrayNode) node;
232                 IRubyObject[] array = new IRubyObject[iVisited.size()];
233                 int i = 0;
234                 for (Iterator JavaDoc iterator = iVisited.iterator(); iterator.hasNext();) {
235                     Node next = (Node) iterator.next();
236     
237                     array[i++] = evalInternal(runtime,context, next, self, aBlock);
238                 }
239     
240                 return runtime.newArrayNoCopy(array);
241             }
242                 // case NodeTypes.ASSIGNABLENODE:
243
// EvaluateVisitor.assignableNodeVisitor.execute(this, node);
244
// break;
245
case NodeTypes.ATTRASSIGNNODE: {
246                 AttrAssignNode iVisited = (AttrAssignNode) node;
247     
248                 IRubyObject receiver = evalInternal(runtime,context, iVisited.getReceiverNode(), self, aBlock);
249                 IRubyObject[] args = setupArgs(runtime, context, iVisited.getArgsNode(), self);
250                 
251                 assert receiver.getMetaClass() != null : receiver.getClass().getName();
252                 
253                 // If reciever is self then we do the call the same way as vcall
254
CallType callType = (receiver == self ? CallType.VARIABLE : CallType.NORMAL);
255     
256                 receiver.callMethod(context, iVisited.getName(), args, callType);
257                 
258                 return args[args.length - 1];
259             }
260             case NodeTypes.BACKREFNODE: {
261                 BackRefNode iVisited = (BackRefNode) node;
262                 IRubyObject backref = context.getBackref();
263                 switch (iVisited.getType()) {
264                 case '~':
265                     return backref;
266                 case '&':
267                     return RubyRegexp.last_match(backref);
268                 case '`':
269                     return RubyRegexp.match_pre(backref);
270                 case '\'':
271                     return RubyRegexp.match_post(backref);
272                 case '+':
273                     return RubyRegexp.match_last(backref);
274                 }
275                 break;
276             }
277             case NodeTypes.BEGINNODE: {
278                 BeginNode iVisited = (BeginNode) node;
279     
280                 node = iVisited.getBodyNode();
281                 continue bigloop;
282             }
283             case NodeTypes.BIGNUMNODE: {
284                 BignumNode iVisited = (BignumNode) node;
285                 return RubyBignum.newBignum(runtime, iVisited.getValue());
286             }
287                 // case NodeTypes.BINARYOPERATORNODE:
288
// EvaluateVisitor.binaryOperatorNodeVisitor.execute(this, node);
289
// break;
290
// case NodeTypes.BLOCKARGNODE:
291
// EvaluateVisitor.blockArgNodeVisitor.execute(this, node);
292
// break;
293
case NodeTypes.BLOCKNODE: {
294                 BlockNode iVisited = (BlockNode) node;
295     
296                 IRubyObject result = runtime.getNil();
297                 for (Iterator JavaDoc iter = iVisited.iterator(); iter.hasNext();) {
298                     result = evalInternal(runtime,context, (Node) iter.next(), self, aBlock);
299                 }
300     
301                 return result;
302             }
303             case NodeTypes.BLOCKPASSNODE:
304                 assert false: "Call nodes and friends deal with this";
305             case NodeTypes.BREAKNODE: {
306                 BreakNode iVisited = (BreakNode) node;
307     
308                 IRubyObject result = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
309     
310                 JumpException je = new JumpException(JumpException.JumpType.BreakJump);
311     
312                 je.setValue(result);
313     
314                 throw je;
315             }
316             case NodeTypes.CALLNODE: {
317                 CallNode iVisited = (CallNode) node;
318     
319                 IRubyObject receiver = evalInternal(runtime,context, iVisited.getReceiverNode(), self, aBlock);
320                 IRubyObject[] args = setupArgs(runtime, context, iVisited.getArgsNode(), self);
321                 
322                 assert receiver.getMetaClass() != null : receiver.getClass().getName();
323
324                 Block block = getBlock(runtime, context, self, aBlock, iVisited.getIterNode());
325                 
326                 // No block provided lets look at fast path for STI dispatch.
327
if (!block.isGiven()) {
328                     RubyModule module = receiver.getMetaClass();
329                     if (module.index != 0) {
330                          return receiver.callMethod(context, module,
331                                 runtime.getSelectorTable().table[module.index][iVisited.index],
332                                 iVisited.getName(), args, CallType.NORMAL);
333                     }
334                 }
335                     
336                 try {
337                     while (true) {
338                         try {
339                             return receiver.callMethod(context, iVisited.getName(), args,
340                                     CallType.NORMAL, block);
341                         } catch (JumpException je) {
342                             switch (je.getJumpType().getTypeId()) {
343                             case JumpType.RETRY:
344                                 // allow loop to retry
345
break;
346                             default:
347                                 throw je;
348                             }
349                         }
350                     }
351                 } catch (JumpException je) {
352                     switch (je.getJumpType().getTypeId()) {
353                     case JumpType.BREAK:
354                         return (IRubyObject) je.getValue();
355                     default:
356                         throw je;
357                     }
358                 }
359             }
360             case NodeTypes.CASENODE: {
361                 CaseNode iVisited = (CaseNode) node;
362                 IRubyObject expression = null;
363                 if (iVisited.getCaseNode() != null) {
364                     expression = evalInternal(runtime,context, iVisited.getCaseNode(), self, aBlock);
365                 }
366     
367                 context.pollThreadEvents();
368     
369                 IRubyObject result = runtime.getNil();
370     
371                 Node firstWhenNode = iVisited.getFirstWhenNode();
372                 while (firstWhenNode != null) {
373                     if (!(firstWhenNode instanceof WhenNode)) {
374                         node = firstWhenNode;
375                         continue bigloop;
376                     }
377     
378                     WhenNode whenNode = (WhenNode) firstWhenNode;
379     
380                     if (whenNode.getExpressionNodes() instanceof ArrayNode) {
381                         for (Iterator JavaDoc iter = ((ArrayNode) whenNode.getExpressionNodes()).iterator(); iter
382                                 .hasNext();) {
383                             Node tag = (Node) iter.next();
384     
385                             context.setPosition(tag.getPosition());
386                             if (isTrace(runtime)) {
387                                 callTraceFunction(runtime, context, "line", self);
388                             }
389     
390                             // Ruby grammar has nested whens in a case body because of
391
// productions case_body and when_args.
392
if (tag instanceof WhenNode) {
393                                 RubyArray expressions = (RubyArray) evalInternal(runtime,context, ((WhenNode) tag)
394                                                 .getExpressionNodes(), self, aBlock);
395     
396                                 for (int j = 0,k = expressions.getLength(); j < k; j++) {
397                                     IRubyObject condition = expressions.eltInternal(j);
398     
399                                     if ((expression != null && condition.callMethod(context, "===", expression)
400                                             .isTrue())
401                                             || (expression == null && condition.isTrue())) {
402                                         node = ((WhenNode) firstWhenNode).getBodyNode();
403                                         continue bigloop;
404                                     }
405                                 }
406                                 continue;
407                             }
408     
409                             result = evalInternal(runtime,context, tag, self, aBlock);
410     
411                             if ((expression != null && result.callMethod(context, "===", expression).isTrue())
412                                     || (expression == null && result.isTrue())) {
413                                 node = whenNode.getBodyNode();
414                                 continue bigloop;
415                             }
416                         }
417                     } else {
418                         result = evalInternal(runtime,context, whenNode.getExpressionNodes(), self, aBlock);
419     
420                         if ((expression != null && result.callMethod(context, "===", expression).isTrue())
421                                 || (expression == null && result.isTrue())) {
422                             node = ((WhenNode) firstWhenNode).getBodyNode();
423                             continue bigloop;
424                         }
425                     }
426     
427                     context.pollThreadEvents();
428     
429                     firstWhenNode = whenNode.getNextCase();
430                 }
431     
432                 return runtime.getNil();
433             }
434             case NodeTypes.CLASSNODE: {
435                 ClassNode iVisited = (ClassNode) node;
436                 Node superNode = iVisited.getSuperNode();
437                 RubyClass superClass = null;
438                 if(superNode != null) {
439                     IRubyObject _super = evalInternal(runtime,context, superNode, self, aBlock);
440                     if(!(_super instanceof RubyClass)) {
441                         throw runtime.newTypeError("superclass must be a Class (" + RubyObject.trueFalseNil(_super) + ") given");
442                     }
443                     superClass = superNode == null ? null : (RubyClass)_super;
444                 }
445                 Node classNameNode = iVisited.getCPath();
446                 String JavaDoc name = ((INameNode) classNameNode).getName();
447                 RubyModule enclosingClass = getEnclosingModule(runtime, context, classNameNode, self, aBlock);
448                 RubyClass rubyClass = enclosingClass.defineOrGetClassUnder(name, superClass);
449     
450                 if (context.getWrapper() != null) {
451                     rubyClass.extendObject(context.getWrapper());
452                     rubyClass.includeModule(context.getWrapper());
453                 }
454                 return evalClassDefinitionBody(runtime, context, iVisited.getScope(), iVisited.getBodyNode(), rubyClass, self, aBlock);
455             }
456             case NodeTypes.CLASSVARASGNNODE: {
457                 ClassVarAsgnNode iVisited = (ClassVarAsgnNode) node;
458                 IRubyObject result = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
459                 RubyModule rubyClass = getClassVariableBase(context, runtime);
460     
461                 if (rubyClass == null) {
462                     rubyClass = self.getMetaClass();
463                 }
464                 rubyClass.setClassVar(iVisited.getName(), result);
465     
466                 return result;
467             }
468             case NodeTypes.CLASSVARDECLNODE: {
469     
470                 ClassVarDeclNode iVisited = (ClassVarDeclNode) node;
471     
472                 RubyModule rubyClass = getClassVariableBase(context, runtime);
473                 if (rubyClass == null) {
474                     throw runtime.newTypeError("no class/module to define class variable");
475                 }
476                 IRubyObject result = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
477                 rubyClass.setClassVar(iVisited.getName(), result);
478     
479                 return result;
480             }
481             case NodeTypes.CLASSVARNODE: {
482                 ClassVarNode iVisited = (ClassVarNode) node;
483                 RubyModule rubyClass = getClassVariableBase(context, runtime);
484     
485                 if (rubyClass == null) {
486                     rubyClass = self.getMetaClass();
487                 }
488
489                 return rubyClass.getClassVar(iVisited.getName());
490             }
491             case NodeTypes.COLON2NODE: {
492                 Colon2Node iVisited = (Colon2Node) node;
493                 Node leftNode = iVisited.getLeftNode();
494     
495                 // TODO: Made this more colon3 friendly because of cpath production
496
// rule in grammar (it is convenient to think of them as the same thing
497
// at a grammar level even though evaluation is).
498
if (leftNode == null) {
499                     return runtime.getObject().getConstantFrom(iVisited.getName());
500                 } else {
501                     IRubyObject result = evalInternal(runtime,context, iVisited.getLeftNode(), self, aBlock);
502                     if (result instanceof RubyModule) {
503                         return ((RubyModule) result).getConstantFrom(iVisited.getName());
504                     } else {
505                         return result.callMethod(context, iVisited.getName(), aBlock);
506                     }
507                 }
508             }
509             case NodeTypes.COLON3NODE: {
510                 Colon3Node iVisited = (Colon3Node) node;
511                 return runtime.getObject().getConstantFrom(iVisited.getName());
512             }
513             case NodeTypes.CONSTDECLNODE: {
514                 ConstDeclNode iVisited = (ConstDeclNode) node;
515                 Node constNode = iVisited.getConstNode();
516     
517                 IRubyObject result = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
518                 IRubyObject module;
519
520                 if (constNode == null) {
521                     // FIXME: why do we check RubyClass and then use CRef?
522
if (context.getRubyClass() == null) {
523                         // TODO: wire into new exception handling mechanism
524
throw runtime.newTypeError("no class/module to define constant");
525                     }
526                     module = (RubyModule) context.peekCRef().getValue();
527                 } else if (constNode instanceof Colon2Node) {
528                     module = evalInternal(runtime,context, ((Colon2Node) iVisited.getConstNode()).getLeftNode(), self, aBlock);
529                 } else { // Colon3
530
module = runtime.getObject();
531                 }
532     
533                 // FIXME: shouldn't we use the result of this set in setResult?
534
((RubyModule) module).setConstant(iVisited.getName(), result);
535     
536                 return result;
537             }
538             case NodeTypes.CONSTNODE: {
539                 ConstNode iVisited = (ConstNode) node;
540                 return context.getConstant(iVisited.getName());
541             }
542             case NodeTypes.DASGNNODE: {
543                 DAsgnNode iVisited = (DAsgnNode) node;
544     
545                 IRubyObject result = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
546
547                 // System.out.println("DSetting: " + iVisited.getName() + " at index " + iVisited.getIndex() + " and at depth " + iVisited.getDepth() + " and set " + result);
548
context.getCurrentScope().setValue(iVisited.getIndex(), result, iVisited.getDepth());
549     
550                 return result;
551             }
552             case NodeTypes.DEFINEDNODE: {
553                 DefinedNode iVisited = (DefinedNode) node;
554                 String JavaDoc definition = getDefinition(runtime, context, iVisited.getExpressionNode(), self, aBlock);
555                 if (definition != null) {
556                     return runtime.newString(definition);
557                 } else {
558                     return runtime.getNil();
559                 }
560             }
561             case NodeTypes.DEFNNODE: {
562                 DefnNode iVisited = (DefnNode) node;
563                 
564                 RubyModule containingClass = context.getRubyClass();
565     
566                 if (containingClass == null) {
567                     throw runtime.newTypeError("No class to add method.");
568                 }
569     
570                 String JavaDoc name = iVisited.getName();
571
572                 if (containingClass == runtime.getObject() && name == "initialize") {
573                     runtime.getWarnings().warn("redefining Object#initialize may cause infinite loop");
574                 }
575     
576                 Visibility visibility = context.getCurrentVisibility();
577                 if (name == "initialize" || visibility.isModuleFunction() || context.isTopLevel()) {
578                     visibility = Visibility.PRIVATE;
579                 }
580                 
581                 DefaultMethod newMethod = new DefaultMethod(containingClass, iVisited.getScope(),
582                         iVisited.getBodyNode(), (ArgsNode) iVisited.getArgsNode(), visibility, context.peekCRef());
583     
584                 containingClass.addMethod(name, newMethod);
585     
586                 if (context.getCurrentVisibility().isModuleFunction()) {
587                     containingClass.getSingletonClass().addMethod(
588                             name,
589                             new WrapperMethod(containingClass.getSingletonClass(), newMethod,
590                                     Visibility.PUBLIC));
591                     containingClass.callMethod(context, "singleton_method_added", runtime.newSymbol(name));
592                 }
593     
594                 // 'class << state.self' and 'class << obj' uses defn as opposed to defs
595
if (containingClass.isSingleton()) {
596                     ((MetaClass) containingClass).getAttachedObject().callMethod(
597                             context, "singleton_method_added", runtime.newSymbol(iVisited.getName()));
598                 } else {
599                     containingClass.callMethod(context, "method_added", runtime.newSymbol(name));
600                 }
601     
602                 return runtime.getNil();
603             }
604             case NodeTypes.DEFSNODE: {
605                 DefsNode iVisited = (DefsNode) node;
606                 IRubyObject receiver = evalInternal(runtime,context, iVisited.getReceiverNode(), self, aBlock);
607     
608                 RubyClass rubyClass;
609     
610                 if (receiver.isNil()) {
611                     rubyClass = runtime.getNilClass();
612                 } else if (receiver == runtime.getTrue()) {
613                     rubyClass = runtime.getClass("TrueClass");
614                 } else if (receiver == runtime.getFalse()) {
615                     rubyClass = runtime.getClass("FalseClass");
616                 } else {
617                     if (runtime.getSafeLevel() >= 4 && !receiver.isTaint()) {
618                         throw runtime.newSecurityError("Insecure; can't define singleton method.");
619                     }
620                     if (receiver.isFrozen()) {
621                         throw runtime.newFrozenError("object");
622                     }
623                     if (receiver.getMetaClass() == runtime.getFixnum() || receiver.getMetaClass() == runtime.getClass("Symbol")) {
624                         throw runtime.newTypeError("can't define singleton method \"" + iVisited.getName()
625                                                    + "\" for " + receiver.getType());
626                     }
627     
628                     rubyClass = receiver.getSingletonClass();
629                 }
630     
631                 if (runtime.getSafeLevel() >= 4) {
632                     Object JavaDoc method = rubyClass.getMethods().get(iVisited.getName());
633                     if (method != null) {
634                         throw runtime.newSecurityError("Redefining method prohibited.");
635                     }
636                 }
637     
638                 DefaultMethod newMethod = new DefaultMethod(rubyClass, iVisited.getScope(),
639                         iVisited.getBodyNode(), (ArgsNode) iVisited.getArgsNode(),
640                         Visibility.PUBLIC, context.peekCRef());
641     
642                 rubyClass.addMethod(iVisited.getName(), newMethod);
643                 receiver.callMethod(context, "singleton_method_added", runtime.newSymbol(iVisited.getName()));
644     
645                 return runtime.getNil();
646             }
647             case NodeTypes.DOTNODE: {
648                 DotNode iVisited = (DotNode) node;
649                 return RubyRange.newRange(runtime,
650                         evalInternal(runtime,context, iVisited.getBeginNode(), self, aBlock),
651                         evalInternal(runtime,context, iVisited.getEndNode(), self, aBlock),
652                         iVisited.isExclusive());
653             }
654             case NodeTypes.DREGEXPNODE: {
655                 DRegexpNode iVisited = (DRegexpNode) node;
656     
657                 RubyString string = runtime.newString(new ByteList());
658                 for (Iterator JavaDoc iterator = iVisited.iterator(); iterator.hasNext();) {
659                     Node iterNode = (Node) iterator.next();
660                     if (iterNode instanceof StrNode) {
661                         string.getByteList().append(((StrNode) iterNode).getValue());
662                     } else {
663                         string.append(evalInternal(runtime,context, iterNode, self, aBlock));
664                     }
665                 }
666     
667                 String JavaDoc lang = null;
668                 int opts = iVisited.getOptions();
669                 if((opts & 16) != 0) { // param n
670
lang = "n";
671                 } else if((opts & 48) != 0) { // param s
672
lang = "s";
673                 } else if((opts & 64) != 0) { // param s
674
lang = "u";
675                 }
676
677                 return RubyRegexp.newRegexp(runtime, string.toString(), iVisited.getOptions(), lang);
678             }
679             case NodeTypes.DSTRNODE: {
680                 DStrNode iVisited = (DStrNode) node;
681     
682                 RubyString string = runtime.newString(new ByteList());
683                 for (Iterator JavaDoc iterator = iVisited.iterator(); iterator.hasNext();) {
684                     Node iterNode = (Node) iterator.next();
685                     if (iterNode instanceof StrNode) {
686                         string.getByteList().append(((StrNode) iterNode).getValue());
687                     } else {
688                         string.append(evalInternal(runtime,context, iterNode, self, aBlock));
689                     }
690                 }
691     
692                 return string;
693             }
694             case NodeTypes.DSYMBOLNODE: {
695                 DSymbolNode iVisited = (DSymbolNode) node;
696     
697                 RubyString string = runtime.newString(new ByteList());
698                 for (Iterator JavaDoc iterator = iVisited.iterator(); iterator.hasNext();) {
699                     Node iterNode = (Node) iterator.next();
700                     if (iterNode instanceof StrNode) {
701                         string.getByteList().append(((StrNode) iterNode).getValue());
702                     } else {
703                         string.append(evalInternal(runtime,context, iterNode, self, aBlock));
704                     }
705                 }
706     
707                 return runtime.newSymbol(string.toString());
708             }
709             case NodeTypes.DVARNODE: {
710                 DVarNode iVisited = (DVarNode) node;
711
712                 // System.out.println("DGetting: " + iVisited.getName() + " at index " + iVisited.getIndex() + " and at depth " + iVisited.getDepth());
713
IRubyObject obj = context.getCurrentScope().getValue(iVisited.getIndex(), iVisited.getDepth());
714
715                 // FIXME: null check is removable once we figure out how to assign to unset named block args
716
return obj == null ? runtime.getNil() : obj;
717             }
718             case NodeTypes.DXSTRNODE: {
719                 DXStrNode iVisited = (DXStrNode) node;
720     
721                 RubyString string = runtime.newString(new ByteList());
722                 for (Iterator JavaDoc iterator = iVisited.iterator(); iterator.hasNext();) {
723                     Node iterNode = (Node) iterator.next();
724                     if (iterNode instanceof StrNode) {
725                         string.getByteList().append(((StrNode) iterNode).getValue());
726                     } else {
727                         string.append(evalInternal(runtime,context, iterNode, self, aBlock));
728                     }
729                 }
730     
731                 return self.callMethod(context, "`", string);
732             }
733             case NodeTypes.ENSURENODE: {
734                 EnsureNode iVisited = (EnsureNode) node;
735     
736                 // save entering the try if there's nothing to ensure
737
if (iVisited.getEnsureNode() != null) {
738                     IRubyObject result = runtime.getNil();
739     
740                     try {
741                         result = evalInternal(runtime,context, iVisited.getBodyNode(), self, aBlock);
742                     } finally {
743                         evalInternal(runtime,context, iVisited.getEnsureNode(), self, aBlock);
744                     }
745     
746                     return result;
747                 }
748     
749                 node = iVisited.getBodyNode();
750                 continue bigloop;
751             }
752             case NodeTypes.EVSTRNODE: {
753                 EvStrNode iVisited = (EvStrNode) node;
754     
755                 return evalInternal(runtime,context, iVisited.getBody(), self, aBlock).objAsString();
756             }
757             case NodeTypes.FALSENODE: {
758                 context.pollThreadEvents();
759                 return runtime.getFalse();
760             }
761             case NodeTypes.FCALLNODE: {
762                 FCallNode iVisited = (FCallNode) node;
763                 
764                 IRubyObject[] args = setupArgs(runtime, context, iVisited.getArgsNode(), self);
765                 Block block = getBlock(runtime, context, self, aBlock, iVisited.getIterNode());
766
767                 try {
768                     while (true) {
769                         try {
770                             IRubyObject result = self.callMethod(context, iVisited.getName(), args,
771                                     CallType.FUNCTIONAL, block);
772                             if (result == null) {
773                                 result = runtime.getNil();
774                             }
775                             
776                             return result;
777                         } catch (JumpException je) {
778                             switch (je.getJumpType().getTypeId()) {
779                             case JumpType.RETRY:
780                                 // allow loop to retry
781
break;
782                             default:
783                                 throw je;
784                             }
785                         }
786                     }
787                 } catch (JumpException je) {
788                     switch (je.getJumpType().getTypeId()) {
789                     case JumpType.BREAK:
790                         // JRUBY-530, Kernel#loop case:
791
if (je.isBreakInKernelLoop()) {
792                             // consume and rethrow or just keep rethrowing?
793
if (block == je.getTarget()) je.setBreakInKernelLoop(false);
794
795                             throw je;
796                         }
797                         
798                         return (IRubyObject) je.getValue();
799                     default:
800                         throw je;
801                     }
802                 }
803             }
804             case NodeTypes.FIXNUMNODE: {
805                 FixnumNode iVisited = (FixnumNode) node;
806                 return iVisited.getFixnum(runtime);
807             }
808             case NodeTypes.FLIPNODE: {
809                 FlipNode iVisited = (FlipNode) node;
810                 IRubyObject result = runtime.getNil();
811     
812                 if (iVisited.isExclusive()) {
813                     if (!context.getCurrentScope().getValue(iVisited.getIndex(), iVisited.getDepth()).isTrue()) {
814                         result = evalInternal(runtime,context, iVisited.getBeginNode(), self, aBlock).isTrue() ? runtime.getFalse()
815                                 : runtime.getTrue();
816                         context.getCurrentScope().setValue(iVisited.getIndex(), result, iVisited.getDepth());
817                         return result;
818                     } else {
819                         if (evalInternal(runtime,context, iVisited.getEndNode(), self, aBlock).isTrue()) {
820                             context.getCurrentScope().setValue(iVisited.getIndex(), runtime.getFalse(), iVisited.getDepth());
821                         }
822                         return runtime.getTrue();
823                     }
824                 } else {
825                     if (!context.getCurrentScope().getValue(iVisited.getIndex(), iVisited.getDepth()).isTrue()) {
826                         if (evalInternal(runtime,context, iVisited.getBeginNode(), self, aBlock).isTrue()) {
827                             context.getCurrentScope().setValue(
828                                     iVisited.getIndex(),
829                                     evalInternal(runtime,context, iVisited.getEndNode(), self, aBlock).isTrue() ? runtime.getFalse()
830                                             : runtime.getTrue(), iVisited.getDepth());
831                             return runtime.getTrue();
832                         } else {
833                             return runtime.getFalse();
834                         }
835                     } else {
836                         if (evalInternal(runtime,context, iVisited.getEndNode(), self, aBlock).isTrue()) {
837                             context.getCurrentScope().setValue(iVisited.getIndex(), runtime.getFalse(), iVisited.getDepth());
838                         }
839                         return runtime.getTrue();
840                     }
841                 }
842             }
843             case NodeTypes.FLOATNODE: {
844                 FloatNode iVisited = (FloatNode) node;
845                 return RubyFloat.newFloat(runtime, iVisited.getValue());
846             }
847             case NodeTypes.FORNODE: {
848                 ForNode iVisited = (ForNode) node;
849                 
850                 Block block = ForBlock.createBlock(context, iVisited.getVarNode(),
851                         context.getCurrentScope(), iVisited.getCallable(), self);
852     
853                 try {
854                     while (true) {
855                         try {
856                             ISourcePosition position = context.getPosition();
857     
858                             IRubyObject recv = null;
859                             try {
860                                 recv = evalInternal(runtime,context, iVisited.getIterNode(), self, aBlock);
861                             } finally {
862                                 context.setPosition(position);
863                             }
864     
865                             return recv.callMethod(context, "each", IRubyObject.NULL_ARRAY, CallType.NORMAL, block);
866                         } catch (JumpException je) {
867                             switch (je.getJumpType().getTypeId()) {
868                             case JumpType.RETRY:
869                                 // do nothing, allow loop to retry
870
break;
871                             default:
872                                 throw je;
873                             }
874                         }
875                     }
876                 } catch (JumpException je) {
877                     switch (je.getJumpType().getTypeId()) {
878                     case JumpType.BREAK:
879                         return (IRubyObject) je.getValue();
880                     default:
881                         throw je;
882                     }
883                 }
884             }
885             case NodeTypes.GLOBALASGNNODE: {
886                 GlobalAsgnNode iVisited = (GlobalAsgnNode) node;
887     
888                 IRubyObject result = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
889     
890                 runtime.getGlobalVariables().set(iVisited.getName(), result);
891     
892                 // FIXME: this should be encapsulated along with the set above
893
if (iVisited.getName() == "$KCODE") {
894                     runtime.setKCode(KCode.create(runtime, result.toString()));
895                 }
896     
897                 return result;
898             }
899             case NodeTypes.GLOBALVARNODE: {
900                 GlobalVarNode iVisited = (GlobalVarNode) node;
901                 return runtime.getGlobalVariables().get(iVisited.getName());
902             }
903             case NodeTypes.HASHNODE: {
904                 HashNode iVisited = (HashNode) node;
905     
906                 Map JavaDoc hash = null;
907                 if (iVisited.getListNode() != null) {
908                     hash = new HashMap JavaDoc(iVisited.getListNode().size() / 2);
909     
910                     for (Iterator JavaDoc iterator = iVisited.getListNode().iterator(); iterator.hasNext();) {
911                         // insert all nodes in sequence, hash them in the final instruction
912
// KEY
913
IRubyObject key = evalInternal(runtime,context, (Node) iterator.next(), self, aBlock);
914                         IRubyObject value = evalInternal(runtime,context, (Node) iterator.next(), self, aBlock);
915     
916                         hash.put(key, value);
917                     }
918                 }
919     
920                 if (hash == null) {
921                     return RubyHash.newHash(runtime);
922                 }
923     
924                 return RubyHash.newHash(runtime, hash, runtime.getNil());
925             }
926             case NodeTypes.IFNODE: {
927                 IfNode iVisited = (IfNode) node;
928                 IRubyObject result = evalInternal(runtime,context, iVisited.getCondition(), self, aBlock);
929     
930                 if (result.isTrue()) {
931                     node = iVisited.getThenBody();
932                     continue bigloop;
933                 } else {
934                     node = iVisited.getElseBody();
935                     continue bigloop;
936                 }
937             }
938             case NodeTypes.INSTASGNNODE: {
939                 InstAsgnNode iVisited = (InstAsgnNode) node;
940     
941                 IRubyObject result = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
942                 self.setInstanceVariable(iVisited.getName(), result);
943     
944                 return result;
945             }
946             case NodeTypes.INSTVARNODE: {
947                 InstVarNode iVisited = (InstVarNode) node;
948                 IRubyObject variable = self.getInstanceVariable(iVisited.getName());
949     
950                 return variable == null ? runtime.getNil() : variable;
951             }
952                 // case NodeTypes.ISCOPINGNODE:
953
// EvaluateVisitor.iScopingNodeVisitor.execute(this, node);
954
// break;
955
case NodeTypes.ITERNODE:
956                 assert false: "Call nodes deal with these directly";
957             case NodeTypes.LOCALASGNNODE: {
958                 LocalAsgnNode iVisited = (LocalAsgnNode) node;
959                 IRubyObject result = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
960                 
961                 // System.out.println("LSetting: " + iVisited.getName() + " at index " + iVisited.getIndex() + " and at depth " + iVisited.getDepth() + " and set " + result);
962
context.getCurrentScope().setValue(iVisited.getIndex(), result, iVisited.getDepth());
963
964                 return result;
965             }
966             case NodeTypes.LOCALVARNODE: {
967                 LocalVarNode iVisited = (LocalVarNode) node;
968
969                 //System.out.println("DGetting: " + iVisited.getName() + " at index " + iVisited.getIndex() + " and at depth " + iVisited.getDepth());
970
IRubyObject result = context.getCurrentScope().getValue(iVisited.getIndex(), iVisited.getDepth());
971
972                 return result == null ? runtime.getNil() : result;
973             }
974             case NodeTypes.MATCH2NODE: {
975                 Match2Node iVisited = (Match2Node) node;
976                 IRubyObject recv = evalInternal(runtime,context, iVisited.getReceiverNode(), self, aBlock);
977                 IRubyObject value = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
978     
979                 return ((RubyRegexp) recv).match(value);
980             }
981             case NodeTypes.MATCH3NODE: {
982                 Match3Node iVisited = (Match3Node) node;
983                 IRubyObject recv = evalInternal(runtime,context, iVisited.getReceiverNode(), self, aBlock);
984                 IRubyObject value = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
985     
986                 if (value instanceof RubyString) {
987                     return ((RubyRegexp) recv).match(value);
988                 } else {
989                     return value.callMethod(context, "=~", recv);
990                 }
991             }
992             case NodeTypes.MATCHNODE: {
993                 MatchNode iVisited = (MatchNode) node;
994                 return ((RubyRegexp) evalInternal(runtime,context, iVisited.getRegexpNode(), self, aBlock)).match2();
995             }
996             case NodeTypes.MODULENODE: {
997                 ModuleNode iVisited = (ModuleNode) node;
998                 Node classNameNode = iVisited.getCPath();
999                 String JavaDoc name = ((INameNode) classNameNode).getName();
1000                RubyModule enclosingModule = getEnclosingModule(runtime, context, classNameNode, self, aBlock);
1001    
1002                if (enclosingModule == null) {
1003                    throw runtime.newTypeError("no outer class/module");
1004                }
1005    
1006                RubyModule module;
1007                if (enclosingModule == runtime.getObject()) {
1008                    module = runtime.getOrCreateModule(name);
1009                } else {
1010                    module = enclosingModule.defineModuleUnder(name);
1011                }
1012                return evalClassDefinitionBody(runtime, context, iVisited.getScope(), iVisited.getBodyNode(), module, self, aBlock);
1013            }
1014            case NodeTypes.MULTIPLEASGNNODE: {
1015                MultipleAsgnNode iVisited = (MultipleAsgnNode) node;
1016                IRubyObject value = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
1017
1018                if (!(value instanceof RubyArray)) {
1019                    value = RubyArray.newArray(runtime, value);
1020                }
1021                return AssignmentVisitor.multiAssign(runtime, context, self, iVisited, (RubyArray) value, false);
1022            }
1023            case NodeTypes.NEWLINENODE: {
1024                NewlineNode iVisited = (NewlineNode) node;
1025    
1026                // something in here is used to build up ruby stack trace...
1027
context.setPosition(iVisited.getPosition());
1028    
1029                if (isTrace(runtime)) {
1030                    callTraceFunction(runtime, context, "line", self);
1031                }
1032    
1033                // TODO: do above but not below for additional newline nodes
1034
node = iVisited.getNextNode();
1035                continue bigloop;
1036            }
1037            case NodeTypes.NEXTNODE: {
1038                NextNode iVisited = (NextNode) node;
1039    
1040                context.pollThreadEvents();
1041    
1042                IRubyObject result = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
1043    
1044                // now used as an interpreter event
1045
JumpException je = new JumpException(JumpException.JumpType.NextJump);
1046    
1047                je.setTarget(iVisited);
1048                je.setValue(result);
1049    
1050                throw je;
1051            }
1052            case NodeTypes.NILNODE:
1053                return runtime.getNil();
1054            case NodeTypes.NOTNODE: {
1055                NotNode iVisited = (NotNode) node;
1056    
1057                IRubyObject result = evalInternal(runtime,context, iVisited.getConditionNode(), self, aBlock);
1058                return result.isTrue() ? runtime.getFalse() : runtime.getTrue();
1059            }
1060            case NodeTypes.NTHREFNODE: {
1061                NthRefNode iVisited = (NthRefNode) node;
1062                return RubyRegexp.nth_match(iVisited.getMatchNumber(), context.getBackref());
1063            }
1064            case NodeTypes.OPASGNANDNODE: {
1065                BinaryOperatorNode iVisited = (BinaryOperatorNode) node;
1066    
1067                // add in reverse order
1068
IRubyObject result = evalInternal(runtime,context, iVisited.getFirstNode(), self, aBlock);
1069                if (!result.isTrue()) return result;
1070                node = iVisited.getSecondNode();
1071                continue bigloop;
1072            }
1073            case NodeTypes.OPASGNNODE: {
1074                OpAsgnNode iVisited = (OpAsgnNode) node;
1075                IRubyObject receiver = evalInternal(runtime,context, iVisited.getReceiverNode(), self, aBlock);
1076                IRubyObject value = receiver.callMethod(context, iVisited.getVariableName());
1077    
1078                if (iVisited.getOperatorName() == "||") {
1079                    if (value.isTrue()) {
1080                        return value;
1081                    }
1082                    value = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
1083                } else if (iVisited.getOperatorName() == "&&") {
1084                    if (!value.isTrue()) {
1085                        return value;
1086                    }
1087                    value = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
1088                } else {
1089                    value = value.callMethod(context, iVisited.getOperatorName(), evalInternal(runtime,context,
1090                            iVisited.getValueNode(), self, aBlock));
1091                }
1092    
1093                receiver.callMethod(context, iVisited.getVariableNameAsgn(), value);
1094    
1095                context.pollThreadEvents();
1096    
1097                return value;
1098            }
1099            case NodeTypes.OPASGNORNODE: {
1100                OpAsgnOrNode iVisited = (OpAsgnOrNode) node;
1101                String JavaDoc def = getDefinition(runtime, context, iVisited.getFirstNode(), self, aBlock);
1102    
1103                IRubyObject result = runtime.getNil();
1104                if (def != null) {
1105                    result = evalInternal(runtime,context, iVisited.getFirstNode(), self, aBlock);
1106                }
1107                if (!result.isTrue()) {
1108                    result = evalInternal(runtime,context, iVisited.getSecondNode(), self, aBlock);
1109                }
1110    
1111                return result;
1112            }
1113            case NodeTypes.OPELEMENTASGNNODE: {
1114                OpElementAsgnNode iVisited = (OpElementAsgnNode) node;
1115                IRubyObject receiver = evalInternal(runtime,context, iVisited.getReceiverNode(), self, aBlock);
1116    
1117                IRubyObject[] args = setupArgs(runtime, context, iVisited.getArgsNode(), self);
1118    
1119                IRubyObject firstValue = receiver.callMethod(context, "[]", args);
1120    
1121                if (iVisited.getOperatorName() == "||") {
1122                    if (firstValue.isTrue()) {
1123                        return firstValue;
1124                    }
1125                    firstValue = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
1126                } else if (iVisited.getOperatorName() == "&&") {
1127                    if (!firstValue.isTrue()) {
1128                        return firstValue;
1129                    }
1130                    firstValue = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
1131                } else {
1132                    firstValue = firstValue.callMethod(context, iVisited.getOperatorName(), evalInternal(runtime,context, iVisited
1133                                    .getValueNode(), self, aBlock));
1134                }
1135    
1136                IRubyObject[] expandedArgs = new IRubyObject[args.length + 1];
1137                System.arraycopy(args, 0, expandedArgs, 0, args.length);
1138                expandedArgs[expandedArgs.length - 1] = firstValue;
1139                return receiver.callMethod(context, "[]=", expandedArgs);
1140            }
1141            case NodeTypes.OPTNNODE: {
1142                OptNNode iVisited = (OptNNode) node;
1143    
1144                IRubyObject result = runtime.getNil();
1145                while (RubyKernel.gets(runtime.getTopSelf(), IRubyObject.NULL_ARRAY).isTrue()) {
1146                    loop: while (true) { // Used for the 'redo' command
1147
try {
1148                            result = evalInternal(runtime,context, iVisited.getBodyNode(), self, aBlock);
1149                            break;
1150                        } catch (JumpException je) {
1151                            switch (je.getJumpType().getTypeId()) {
1152                            case JumpType.REDO:
1153                                // do nothing, this iteration restarts
1154
break;
1155                            case JumpType.NEXT:
1156                                // recheck condition
1157
break loop;
1158                            case JumpType.BREAK:
1159                                // end loop
1160
return (IRubyObject) je.getValue();
1161                            default:
1162                                throw je;
1163                            }
1164                        }
1165                    }
1166                }
1167                return result;
1168            }
1169            case NodeTypes.ORNODE: {
1170                OrNode iVisited = (OrNode) node;
1171    
1172                IRubyObject result = evalInternal(runtime,context, iVisited.getFirstNode(), self, aBlock);
1173    
1174                if (!result.isTrue()) {
1175                    result = evalInternal(runtime,context, iVisited.getSecondNode(), self, aBlock);
1176                }
1177    
1178                return result;
1179            }
1180                // case NodeTypes.POSTEXENODE:
1181
// EvaluateVisitor.postExeNodeVisitor.execute(this, node);
1182
// break;
1183
case NodeTypes.REDONODE: {
1184                context.pollThreadEvents();
1185    
1186                // now used as an interpreter event
1187
JumpException je = new JumpException(JumpException.JumpType.RedoJump);
1188    
1189                je.setValue(node);
1190    
1191                throw je;
1192            }
1193            case NodeTypes.REGEXPNODE: {
1194                RegexpNode iVisited = (RegexpNode) node;
1195                String JavaDoc lang = null;
1196                int opts = iVisited.getOptions();
1197                if((opts & 16) != 0) { // param n
1198
lang = "n";
1199                } else if((opts & 48) != 0) { // param s
1200
lang = "s";
1201                } else if((opts & 64) != 0) { // param s
1202
lang = "u";
1203                }
1204                try {
1205                    return RubyRegexp.newRegexp(runtime, iVisited.getPattern(), lang);
1206                } catch(java.util.regex.PatternSyntaxException JavaDoc e) {
1207                    throw runtime.newSyntaxError(e.getMessage());
1208                }
1209            }
1210            case NodeTypes.RESCUEBODYNODE: {
1211                RescueBodyNode iVisited = (RescueBodyNode) node;
1212                node = iVisited.getBodyNode();
1213                continue bigloop;
1214            }
1215            case NodeTypes.RESCUENODE: {
1216                RescueNode iVisited = (RescueNode)node;
1217                RescuedBlock : while (true) {
1218                    IRubyObject globalExceptionState = runtime.getGlobalVariables().get("$!");
1219                    boolean anotherExceptionRaised = false;
1220                    try {
1221                        // Execute rescue block
1222
IRubyObject result = evalInternal(runtime,context, iVisited.getBodyNode(), self, aBlock);
1223
1224                        // If no exception is thrown execute else block
1225
if (iVisited.getElseNode() != null) {
1226                            if (iVisited.getRescueNode() == null) {
1227                                runtime.getWarnings().warn(iVisited.getElseNode().getPosition(), "else without rescue is useless");
1228                            }
1229                            result = evalInternal(runtime,context, iVisited.getElseNode(), self, aBlock);
1230                        }
1231
1232                        return result;
1233                    } catch (RaiseException raiseJump) {
1234                        RubyException raisedException = raiseJump.getException();
1235                        // TODO: Rubicon TestKernel dies without this line. A cursory glance implies we
1236
// falsely set $! to nil and this sets it back to something valid. This should
1237
// get fixed at the same time we address bug #1296484.
1238
runtime.getGlobalVariables().set("$!", raisedException);
1239
1240                        RescueBodyNode rescueNode = iVisited.getRescueNode();
1241
1242                        while (rescueNode != null) {
1243                            Node exceptionNodes = rescueNode.getExceptionNodes();
1244                            ListNode exceptionNodesList;
1245                            
1246                            if (exceptionNodes instanceof SplatNode) {
1247                                exceptionNodesList = (ListNode) evalInternal(runtime,context, exceptionNodes, self, aBlock);
1248                            } else {
1249                                exceptionNodesList = (ListNode) exceptionNodes;
1250                            }
1251                            
1252                            if (isRescueHandled(runtime, context, raisedException, exceptionNodesList, self)) {
1253                                try {
1254                                    return evalInternal(runtime,context, rescueNode, self, aBlock);
1255                                } catch (JumpException je) {
1256                                    if (je.getJumpType() == JumpException.JumpType.RetryJump) {
1257                                        // should be handled in the finally block below
1258
//state.runtime.getGlobalVariables().set("$!", state.runtime.getNil());
1259
//state.threadContext.setRaisedException(null);
1260
continue RescuedBlock;
1261                                        
1262                                    } else {
1263                                        anotherExceptionRaised = true;
1264                                        throw je;
1265                                    }
1266                                }
1267                            }
1268                            
1269                            rescueNode = rescueNode.getOptRescueNode();
1270                        }
1271
1272                        // no takers; bubble up
1273
throw raiseJump;
1274                    } finally {
1275                        // clear exception when handled or retried
1276
if (!anotherExceptionRaised)
1277                            runtime.getGlobalVariables().set("$!", globalExceptionState);
1278                    }
1279                }
1280            }
1281            case NodeTypes.RETRYNODE: {
1282                context.pollThreadEvents();
1283    
1284                JumpException je = new JumpException(JumpException.JumpType.RetryJump);
1285    
1286                throw je;
1287            }
1288            case NodeTypes.RETURNNODE: {
1289                ReturnNode iVisited = (ReturnNode) node;
1290    
1291                IRubyObject result = evalInternal(runtime,context, iVisited.getValueNode(), self, aBlock);
1292    
1293                JumpException je = new JumpException(JumpException.JumpType.ReturnJump);
1294    
1295                je.setTarget(iVisited.getTarget());
1296                je.setValue(result);
1297    
1298                throw je;
1299            }
1300            case NodeTypes.ROOTNODE: {
1301                RootNode iVisited = (RootNode) node;
1302                DynamicScope scope = iVisited.getScope();
1303                
1304                // Serialization killed our dynamic scope. We can just create an empty one
1305
// since serialization cannot serialize an eval (which is the only thing
1306
// which is capable of having a non-empty dynamic scope).
1307
if (scope == null) {
1308                    scope = new DynamicScope(iVisited.getStaticScope(), null);
1309                }
1310                
1311                // Each root node has a top-level scope that we need to push
1312
context.preRootNode(scope);
1313                
1314                // FIXME: Wire up BEGIN and END nodes
1315

1316                try {
1317                    return eval(runtime, context, iVisited.getBodyNode(), self, aBlock);
1318                } finally {
1319                    context.postRootNode();
1320                }
1321            }
1322            case NodeTypes.SCLASSNODE: {
1323                SClassNode iVisited = (SClassNode) node;
1324                IRubyObject receiver = evalInternal(runtime,context, iVisited.getReceiverNode(), self, aBlock);
1325    
1326                RubyClass singletonClass;
1327    
1328                if (receiver.isNil()) {
1329                    singletonClass = runtime.getNilClass();
1330                } else if (receiver == runtime.getTrue()) {
1331                    singletonClass = runtime.getClass("TrueClass");
1332                } else if (receiver == runtime.getFalse()) {
1333                    singletonClass = runtime.getClass("FalseClass");
1334                } else if (receiver.getMetaClass() == runtime.getFixnum() || receiver.getMetaClass() == runtime.getClass("Symbol")) {
1335                    throw runtime.newTypeError("no virtual class for " + receiver.getMetaClass().getBaseName());
1336                } else {
1337                    if (runtime.getSafeLevel() >= 4 && !receiver.isTaint()) {
1338                        throw runtime.newSecurityError("Insecure: can't extend object.");
1339                    }
1340    
1341                    singletonClass = receiver.getSingletonClass();
1342                }
1343    
1344                
1345    
1346                if (context.getWrapper() != null) {
1347                    singletonClass.extendObject(context.getWrapper());
1348                    singletonClass.includeModule(context.getWrapper());
1349                }
1350    
1351                return evalClassDefinitionBody(runtime, context, iVisited.getScope(), iVisited.getBodyNode(), singletonClass, self, aBlock);
1352            }
1353            case NodeTypes.SELFNODE:
1354                return self;
1355            case NodeTypes.SPLATNODE: {
1356                SplatNode iVisited = (SplatNode) node;
1357                return splatValue(runtime, evalInternal(runtime,context, iVisited.getValue(), self, aBlock));
1358            }
1359                //// case NodeTypes.STARNODE:
1360
//// EvaluateVisitor.starNodeVisitor.execute(this, node);
1361
//// break;
1362
case NodeTypes.STRNODE: {
1363                StrNode iVisited = (StrNode) node;
1364                return runtime.newString((ByteList) iVisited.getValue().clone());
1365            }
1366            case NodeTypes.SUPERNODE: {
1367                SuperNode iVisited = (SuperNode) node;
1368                
1369    
1370                if (context.getFrameKlazz() == null) {
1371                    String JavaDoc name = context.getFrameName();
1372                    throw runtime.newNameError("Superclass method '" + name
1373                            + "' disabled.", name);
1374                }
1375                IRubyObject[] args = setupArgs(runtime, context, iVisited.getArgsNode(), self);
1376                Block block = getBlock(runtime, context, self, aBlock, iVisited.getIterNode());
1377                
1378                // If no explicit block passed to super, then use the one passed in.
1379
if (!block.isGiven()) block = aBlock;
1380                
1381                return context.callSuper(args, block);
1382            }
1383            case NodeTypes.SVALUENODE: {
1384                SValueNode iVisited = (SValueNode) node;
1385                return aValueSplat(runtime, evalInternal(runtime,context, iVisited.getValue(), self, aBlock));
1386            }
1387            case NodeTypes.SYMBOLNODE: {
1388                SymbolNode iVisited = (SymbolNode) node;
1389                return runtime.newSymbol(iVisited.getName());
1390            }
1391            case NodeTypes.TOARYNODE: {
1392                ToAryNode iVisited = (ToAryNode) node;
1393                return aryToAry(runtime, evalInternal(runtime,context, iVisited.getValue(), self, aBlock));
1394            }
1395            case NodeTypes.TRUENODE: {
1396                context.pollThreadEvents();
1397                return runtime.getTrue();
1398            }
1399            case NodeTypes.UNDEFNODE: {
1400                UndefNode iVisited = (UndefNode) node;
1401                
1402    
1403                if (context.getRubyClass() == null) {
1404                    throw runtime
1405                            .newTypeError("No class to undef method '" + iVisited.getName() + "'.");
1406                }
1407                context.getRubyClass().undef(iVisited.getName());
1408    
1409                return runtime.getNil();
1410            }
1411            case NodeTypes.UNTILNODE: {
1412                UntilNode iVisited = (UntilNode) node;
1413    
1414                IRubyObject result = runtime.getNil();
1415                
1416                while (!(result = evalInternal(runtime,context, iVisited.getConditionNode(), self, aBlock)).isTrue()) {
1417                    loop: while (true) { // Used for the 'redo' command
1418
try {
1419                            result = evalInternal(runtime,context, iVisited.getBodyNode(), self, aBlock);
1420                            break loop;
1421                        } catch (JumpException je) {
1422                            switch (je.getJumpType().getTypeId()) {
1423                            case JumpType.REDO:
1424                                continue;
1425                            case JumpType.NEXT:
1426                                break loop;
1427                            case JumpType.BREAK:
1428                                // JRUBY-530 until case
1429
if (je.getTarget() == aBlock) {
1430                                     je.setTarget(null);
1431                                     
1432                                     throw je;
1433                                }
1434                                
1435                                return (IRubyObject) je.getValue();
1436                            default:
1437                                throw je;
1438                            }
1439                        }
1440                    }
1441                }
1442                
1443                return result;
1444            }
1445            case NodeTypes.VALIASNODE: {
1446                VAliasNode iVisited = (VAliasNode) node;
1447                runtime.getGlobalVariables().alias(iVisited.getNewName(), iVisited.getOldName());
1448    
1449                return runtime.getNil();
1450            }
1451            case NodeTypes.VCALLNODE: {
1452                VCallNode iVisited = (VCallNode) node;
1453                return self.callMethod(context, iVisited.getName(),
1454                        IRubyObject.NULL_ARRAY, CallType.VARIABLE);
1455            }
1456            case NodeTypes.WHENNODE:
1457                assert false;
1458                return null;
1459            case NodeTypes.WHILENODE: {
1460                WhileNode iVisited = (WhileNode) node;
1461    
1462                IRubyObject result = runtime.getNil();
1463                boolean firstTest = iVisited.evaluateAtStart();
1464                
1465                while (!firstTest || (result = evalInternal(runtime,context, iVisited.getConditionNode(), self, aBlock)).isTrue()) {
1466                    firstTest = true;
1467                    loop: while (true) { // Used for the 'redo' command
1468
try {
1469                            evalInternal(runtime,context, iVisited.getBodyNode(), self, aBlock);
1470                            break loop;
1471                        } catch (JumpException je) {
1472                            switch (je.getJumpType().getTypeId()) {
1473                            case JumpType.REDO:
1474                                continue;
1475                            case JumpType.NEXT:
1476                                break loop;
1477                            case JumpType.BREAK:
1478                                // JRUBY-530, while case
1479
if (je.getTarget() == aBlock) {
1480                                    je.setTarget(null);
1481                                    
1482                                    throw je;
1483                                }
1484                                
1485                                return result;
1486                            default:
1487                                throw je;
1488                            }
1489                        }
1490                    }
1491                }
1492                
1493                return result;
1494            }
1495            case NodeTypes.XSTRNODE: {
1496                XStrNode iVisited = (XStrNode) node;
1497                return self.callMethod(context, "`", runtime.newString((ByteList) iVisited.getValue().clone()));
1498            }
1499            case NodeTypes.YIELDNODE: {
1500                YieldNode iVisited = (YieldNode) node;
1501    
1502                IRubyObject result = evalInternal(runtime,context, iVisited.getArgsNode(), self, aBlock);
1503                if (iVisited.getArgsNode() == null) {
1504                    result = null;
1505                }
1506
1507                Block block = context.getCurrentFrame().getBlock();
1508
1509                return block.yield(context, result, null, null, iVisited.getCheckState());
1510                                
1511            }
1512            case NodeTypes.ZARRAYNODE: {
1513                return runtime.newArray();
1514            }
1515            case NodeTypes.ZSUPERNODE: {
1516                
1517    
1518                if (context.getFrameKlazz() == null) {
1519                    String JavaDoc name = context.getFrameName();
1520                    throw runtime.newNameError("superclass method '" + name
1521                            + "' disabled", name);
1522                }
1523
1524                Block block = getBlock(runtime, context, self, aBlock, ((ZSuperNode) node).getIterNode());
1525
1526                // Has the method that is calling super received a block argument
1527
if (!block.isGiven()) block = context.getCurrentFrame().getBlock();
1528
1529                return context.callSuper(context.getFrameArgs(), block);
1530            }
1531            default:
1532                throw new RuntimeException JavaDoc("Invalid node encountered in interpreter: \"" + node.getClass().getName() + "\", please report this at www.jruby.org");
1533            }
1534        } while (true);
1535    }
1536    
1537    private static String JavaDoc getArgumentDefinition(Ruby runtime, ThreadContext context, Node node, String JavaDoc type, IRubyObject self, Block block) {
1538        if (node == null) return type;
1539            
1540        if (node instanceof ArrayNode) {
1541            for (Iterator JavaDoc iter = ((ArrayNode)node).iterator(); iter.hasNext(); ) {
1542                if (getDefinitionInner(runtime, context, (Node)iter.next(), self, block) == null) return null;
1543            }
1544        } else if (getDefinitionInner(runtime, context, node, self, block) == null) {
1545            return null;
1546        }
1547
1548        return type;
1549    }
1550    
1551    private static String JavaDoc getDefinition(Ruby runtime, ThreadContext context, Node node, IRubyObject self, Block aBlock) {
1552        try {
1553            context.setWithinDefined(true);
1554            return getDefinitionInner(runtime, context, node, self, aBlock);
1555        } finally {
1556            context.setWithinDefined(false);
1557        }
1558    }
1559    
1560    private static String JavaDoc getDefinitionInner(Ruby runtime, ThreadContext context, Node node, IRubyObject self, Block aBlock) {
1561        if (node == null) return "expression";
1562        
1563        switch(node.nodeId) {
1564        case NodeTypes.ATTRASSIGNNODE: {
1565            AttrAssignNode iVisited = (AttrAssignNode) node;
1566            
1567            if (getDefinitionInner(runtime, context, iVisited.getReceiverNode(), self, aBlock) != null) {
1568                try {
1569                    IRubyObject receiver = eval(runtime, context, iVisited.getReceiverNode(), self, aBlock);
1570                    RubyClass metaClass = receiver.getMetaClass();
1571                    DynamicMethod method = metaClass.searchMethod(iVisited.getName());
1572                    Visibility visibility = method.getVisibility();
1573
1574                    if (!visibility.isPrivate() &&
1575                            (!visibility.isProtected() || self.isKindOf(metaClass.getRealClass()))) {
1576                        if (metaClass.isMethodBound(iVisited.getName(), false)) {
1577                            return getArgumentDefinition(runtime,context, iVisited.getArgsNode(), "assignment", self, aBlock);
1578                        }
1579                    }
1580                } catch (JumpException excptn) {
1581                }
1582            }
1583
1584            return null;
1585        }
1586        case NodeTypes.BACKREFNODE:
1587            return "$" + ((BackRefNode) node).getType();
1588        case NodeTypes.CALLNODE: {
1589            CallNode iVisited = (CallNode) node;
1590            
1591            if (getDefinitionInner(runtime, context, iVisited.getReceiverNode(), self, aBlock) != null) {
1592                try {
1593                    IRubyObject receiver = eval(runtime, context, iVisited.getReceiverNode(), self, aBlock);
1594                    RubyClass metaClass = receiver.getMetaClass();
1595                    DynamicMethod method = metaClass.searchMethod(iVisited.getName());
1596                    Visibility visibility = method.getVisibility();
1597
1598                    if (!visibility.isPrivate() &&
1599                            (!visibility.isProtected() || self.isKindOf(metaClass.getRealClass()))) {
1600                        if (metaClass.isMethodBound(iVisited.getName(), false)) {
1601                            return getArgumentDefinition(runtime, context, iVisited.getArgsNode(), "method", self, aBlock);
1602                        }
1603                    }
1604                } catch (JumpException excptn) {
1605                }
1606            }
1607
1608            return null;
1609        }
1610        case NodeTypes.CLASSVARASGNNODE: case NodeTypes.CLASSVARDECLNODE: case NodeTypes.CONSTDECLNODE:
1611        case NodeTypes.DASGNNODE: case NodeTypes.GLOBALASGNNODE: case NodeTypes.LOCALASGNNODE:
1612        case NodeTypes.MULTIPLEASGNNODE: case NodeTypes.OPASGNNODE: case NodeTypes.OPELEMENTASGNNODE:
1613            return "assignment";
1614            
1615        case NodeTypes.CLASSVARNODE: {
1616            ClassVarNode iVisited = (ClassVarNode) node;
1617            
1618            if (context.getRubyClass() == null && self.getMetaClass().isClassVarDefined(iVisited.getName())) {
1619                return "class_variable";
1620            } else if (!context.getRubyClass().isSingleton() && context.getRubyClass().isClassVarDefined(iVisited.getName())) {
1621                return "class_variable";
1622            }
1623              
1624            RubyModule module = (RubyModule) context.getRubyClass().getInstanceVariable("__attached__");
1625            if (module != null && module.isClassVarDefined(iVisited.getName())) return "class_variable";
1626
1627            return null;
1628        }
1629        case NodeTypes.COLON2NODE: {
1630            Colon2Node iVisited = (Colon2Node) node;
1631            
1632            try {
1633                IRubyObject left = EvaluationState.eval(runtime, context, iVisited.getLeftNode(), self, aBlock);
1634                if (left instanceof RubyModule &&
1635                        ((RubyModule) left).getConstantAt(iVisited.getName()) != null) {
1636                    return "constant";
1637                } else if (left.getMetaClass().isMethodBound(iVisited.getName(), true)) {
1638                    return "method";
1639                }
1640            } catch (JumpException excptn) {}
1641            
1642            return null;
1643        }
1644        case NodeTypes.CONSTNODE:
1645            if (context.getConstantDefined(((ConstNode) node).getName())) {
1646                return "constant";
1647            }
1648            return null;
1649        case NodeTypes.DVARNODE:
1650            return "local-variable(in-block)";
1651        case NodeTypes.FALSENODE:
1652            return "false";
1653        case NodeTypes.FCALLNODE: {
1654            FCallNode iVisited = (FCallNode) node;
1655            if (self.getMetaClass().isMethodBound(iVisited.getName(), false)) {
1656                return getArgumentDefinition(runtime, context, iVisited.getArgsNode(), "method", self, aBlock);
1657            }
1658            
1659            return null;
1660        }
1661        case NodeTypes.GLOBALVARNODE:
1662            if (runtime.getGlobalVariables().isDefined(((GlobalVarNode) node).getName())) {
1663                return "global-variable";
1664            }
1665            return null;
1666        case NodeTypes.INSTVARNODE:
1667            if (self.getInstanceVariable(((InstVarNode) node).getName()) != null) {
1668                return "instance-variable";
1669            }
1670            return null;
1671        case NodeTypes.LOCALVARNODE:
1672            return "local-variable";
1673        case NodeTypes.MATCH2NODE: case NodeTypes.MATCH3NODE:
1674            return "method";
1675        case NodeTypes.NILNODE:
1676            return "nil";
1677        case NodeTypes.NTHREFNODE:
1678            return "$" + ((NthRefNode) node).getMatchNumber();
1679        case NodeTypes.SELFNODE:
1680            return "state.getSelf()";
1681        case NodeTypes.SUPERNODE: {
1682            SuperNode iVisited = (SuperNode) node;
1683            String JavaDoc name = context.getFrameName();
1684            RubyModule klazz = context.getFrameKlazz();
1685            if (name != null && klazz != null && klazz.getSuperClass().isMethodBound(name, false)) {
1686                return getArgumentDefinition(runtime, context, iVisited.getArgsNode(), "super", self, aBlock);
1687            }
1688            
1689            return null;
1690        }
1691        case NodeTypes.TRUENODE:
1692            return "true";
1693        case NodeTypes.VCALLNODE: {
1694            VCallNode iVisited = (VCallNode) node;
1695            if (self.getMetaClass().isMethodBound(iVisited.getName(), false)) {
1696                return "method";
1697            }
1698            
1699            return null;
1700        }
1701        case NodeTypes.YIELDNODE:
1702            return aBlock.isGiven() ? "yield" : null;
1703        case NodeTypes.ZSUPERNODE: {
1704            String JavaDoc name = context.getFrameName();
1705            RubyModule klazz = context.getFrameKlazz();
1706            if (name != null && klazz != null && klazz.getSuperClass().isMethodBound(name, false)) {
1707                return "super";
1708            }
1709            return null;
1710        }
1711        default:
1712            try {
1713                EvaluationState.eval(runtime, context, node, self, aBlock);
1714                return "expression";
1715            } catch (JumpException jumpExcptn) {}
1716        }
1717        
1718        return null;
1719    }
1720    
1721    private static IRubyObject aryToAry(Ruby runtime, IRubyObject value) {
1722        if (value instanceof RubyArray) return value;
1723
1724        if (value.respondsTo("to_ary")) {
1725            return value.convertToType("Array", "to_ary", false);
1726        }
1727
1728        return runtime.newArray(value);
1729    }
1730
1731    /** Evaluates the body in a class or module definition statement.
1732     *
1733     */

1734    private static IRubyObject evalClassDefinitionBody(Ruby runtime, ThreadContext context, StaticScope scope,
1735            Node bodyNode, RubyModule type, IRubyObject self, Block block) {
1736        context.preClassEval(scope, type);
1737
1738        try {
1739            if (isTrace(runtime)) {
1740                callTraceFunction(runtime, context, "class", type);
1741            }
1742
1743            return evalInternal(runtime,context, bodyNode, type, block);
1744        } finally {
1745            context.postClassEval();
1746
1747            if (isTrace(runtime)) {
1748                callTraceFunction(runtime, context, "end", null);
1749            }
1750        }
1751    }
1752    
1753    /**
1754     * Helper method.
1755     *
1756     * test if a trace function is avaiable.
1757     *
1758     */

1759    private static boolean isTrace(Ruby runtime) {
1760        return runtime.getTraceFunction() != null;
1761    }
1762
1763    private static void callTraceFunction(Ruby runtime, ThreadContext context, String JavaDoc event, IRubyObject zelf) {
1764        String JavaDoc name = context.getFrameName();
1765        RubyModule type = context.getFrameKlazz();
1766        runtime.callTraceFunction(context, event, context.getPosition(), zelf, name, type);
1767    }
1768
1769    public static IRubyObject splatValue(Ruby runtime, IRubyObject value) {
1770        if (value.isNil()) {
1771            return runtime.newArray(value);
1772        }
1773
1774        return arrayValue(runtime, value);
1775    }
1776
1777    public static IRubyObject aValueSplat(Ruby runtime, IRubyObject value) {
1778        if (!(value instanceof RubyArray) || ((RubyArray) value).length().getLongValue() == 0) {
1779            return runtime.getNil();
1780        }
1781
1782        RubyArray array = (RubyArray) value;
1783
1784        return array.getLength() == 1 ? array.first(IRubyObject.NULL_ARRAY) : array;
1785    }
1786
1787    public static RubyArray arrayValue(Ruby runtime, IRubyObject value) {
1788        IRubyObject newValue = value.convertToType("Array", "to_ary", false);
1789        if (newValue.isNil()) {
1790            // Object#to_a is obsolete. We match Ruby's hack until to_a goes away. Then we can
1791
// remove this hack too.
1792
if (value.getMetaClass().searchMethod("to_a").getImplementationClass() != runtime
1793                    .getKernel()) {
1794                newValue = value.convertToType("Array", "to_a", false);
1795                if (newValue.getType() != runtime.getClass("Array")) {
1796                    throw runtime.newTypeError("`to_a' did not return Array");
1797                }
1798            } else {
1799                newValue = runtime.newArray(value);
1800            }
1801        }
1802
1803        return (RubyArray) newValue;
1804    }
1805
1806    private static IRubyObject[] setupArgs(Ruby runtime, ThreadContext context, Node node, IRubyObject self) {
1807        if (node == null) return IRubyObject.NULL_ARRAY;
1808
1809        if (node instanceof ArrayNode) {
1810            ArrayNode argsArrayNode = (ArrayNode) node;
1811            ISourcePosition position = context.getPosition();
1812            int size = argsArrayNode.size();
1813            IRubyObject[] argsArray = new IRubyObject[size];
1814
1815            for (int i = 0; i < size; i++) {
1816                argsArray[i] = evalInternal(runtime,context, argsArrayNode.get(i), self, Block.NULL_BLOCK);
1817            }
1818
1819            context.setPosition(position);
1820
1821            return argsArray;
1822        }
1823
1824        return ArgsUtil.convertToJavaArray(evalInternal(runtime,context, node, self, Block.NULL_BLOCK));
1825    }
1826
1827    private static RubyModule getEnclosingModule(Ruby runtime, ThreadContext context, Node node, IRubyObject self, Block block) {
1828        RubyModule enclosingModule = null;
1829
1830        if (node instanceof Colon2Node) {
1831            IRubyObject result = evalInternal(runtime,context, ((Colon2Node) node).getLeftNode(), self, block);
1832
1833            if (result != null && !result.isNil()) {
1834                enclosingModule = (RubyModule) result;
1835            }
1836        } else if (node instanceof Colon3Node) {
1837            enclosingModule = runtime.getObject();
1838        }
1839
1840        if (enclosingModule == null) {
1841            enclosingModule = (RubyModule) context.peekCRef().getValue();
1842        }
1843
1844        return enclosingModule;
1845    }
1846
1847    private static boolean isRescueHandled(Ruby runtime, ThreadContext context, RubyException currentException, ListNode exceptionNodes,
1848            IRubyObject self) {
1849        if (exceptionNodes == null) {
1850            return currentException.isKindOf(runtime.getClass("StandardError"));
1851        }
1852
1853        IRubyObject[] args = setupArgs(runtime, context, exceptionNodes, self);
1854
1855        for (int i = 0; i < args.length; i++) {
1856            if (!args[i].isKindOf(runtime.getClass("Module"))) {
1857                throw runtime.newTypeError("class or module required for rescue clause");
1858            }
1859            if (args[i].callMethod(context, "===", currentException).isTrue()) return true;
1860        }
1861        return false;
1862    }
1863    
1864    public static Block getBlock(Ruby runtime, ThreadContext context, IRubyObject self, Block currentBlock, Node blockNode) {
1865        if (blockNode == null) return Block.NULL_BLOCK;
1866        
1867        if (blockNode instanceof IterNode) {
1868            IterNode iterNode = (IterNode) blockNode;
1869            // Create block for this iter node
1870
return Block.createBlock(context, iterNode.getVarNode(),
1871                    new DynamicScope(iterNode.getScope(), context.getCurrentScope()),
1872                    iterNode.getCallable(), self);
1873        } else if (blockNode instanceof BlockPassNode) {
1874            BlockPassNode blockPassNode = (BlockPassNode) blockNode;
1875            IRubyObject proc = evalInternal(runtime,context, blockPassNode.getBodyNode(), self, currentBlock);
1876
1877            // No block from a nil proc
1878
if (proc.isNil()) return Block.NULL_BLOCK;
1879
1880            // If not already a proc then we should try and make it one.
1881
if (!(proc instanceof RubyProc)) {
1882                proc = proc.convertToType("Proc", "to_proc", false);
1883
1884                if (!(proc instanceof RubyProc)) {
1885                    throw runtime.newTypeError("wrong argument type "
1886                            + proc.getMetaClass().getName() + " (expected Proc)");
1887                }
1888            }
1889
1890            // TODO: Add safety check for taintedness
1891

1892            if (currentBlock.isGiven()) {
1893                RubyProc procObject = currentBlock.getProcObject();
1894                // The current block is already associated with proc. No need to create a new one
1895
if (procObject != null && procObject == proc) return currentBlock;
1896            }
1897            
1898            return ((RubyProc) proc).getBlock();
1899        }
1900         
1901        assert false: "Trying to get block from something which cannot deliver";
1902        return null;
1903    }
1904}
1905
Popular Tags