0001: /*******************************************************************************
0002: * BEGIN LICENSE BLOCK *** Version: CPL 1.0/GPL 2.0/LGPL 2.1
0003: *
0004: * The contents of this file are subject to the Common Public License Version
0005: * 1.0 (the "License"); you may not use this file except in compliance with the
0006: * License. You may obtain a copy of the License at
0007: * http://www.eclipse.org/legal/cpl-v10.html
0008: *
0009: * Software distributed under the License is distributed on an "AS IS" basis,
0010: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
0011: * the specific language governing rights and limitations under the License.
0012: *
0013: * Copyright (C) 2006 Charles Oliver Nutter <headius@headius.com>
0014: * Copytight (C) 2006-2007 Thomas E Enebo <enebo@acm.org>
0015: * Copyright (C) 2007 Miguel Covarrubias <mlcovarrubias@gmail.com>
0016: * Copyright (C) 2007 Ola Bini <ola@ologix.com>
0017: *
0018: * Alternatively, the contents of this file may be used under the terms of
0019: * either of the GNU General Public License Version 2 or later (the "GPL"), or
0020: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in
0021: * which case the provisions of the GPL or the LGPL are applicable instead of
0022: * those above. If you wish to allow use of your version of this file only under
0023: * the terms of either the GPL or the LGPL, and not to allow others to use your
0024: * version of this file under the terms of the CPL, indicate your decision by
0025: * deleting the provisions above and replace them with the notice and other
0026: * provisions required by the GPL or the LGPL. If you do not delete the
0027: * provisions above, a recipient may use your version of this file under the
0028: * terms of any one of the CPL, the GPL or the LGPL. END LICENSE BLOCK ****
0029: ******************************************************************************/package org.jruby.evaluator;
0030:
0031: import org.jruby.Ruby;
0032: import org.jruby.MetaClass;
0033: import org.jruby.RubyArray;
0034: import org.jruby.RubyBignum;
0035: import org.jruby.RubyClass;
0036: import org.jruby.RubyException;
0037: import org.jruby.RubyFloat;
0038: import org.jruby.RubyHash;
0039: import org.jruby.RubyKernel;
0040: import org.jruby.RubyLocalJumpError;
0041: import org.jruby.RubyModule;
0042: import org.jruby.RubyObject;
0043: import org.jruby.RubyProc;
0044: import org.jruby.RubyRange;
0045: import org.jruby.RubyRegexp;
0046: import org.jruby.RubyString;
0047: import org.jruby.ast.AliasNode;
0048: import org.jruby.ast.ArgsCatNode;
0049: import org.jruby.ast.ArgsNode;
0050: import org.jruby.ast.ArgsPushNode;
0051: import org.jruby.ast.ArrayNode;
0052: import org.jruby.ast.AttrAssignNode;
0053: import org.jruby.ast.BackRefNode;
0054: import org.jruby.ast.BeginNode;
0055: import org.jruby.ast.BignumNode;
0056: import org.jruby.ast.BinaryOperatorNode;
0057: import org.jruby.ast.BlockNode;
0058: import org.jruby.ast.BlockPassNode;
0059: import org.jruby.ast.BreakNode;
0060: import org.jruby.ast.CallNode;
0061: import org.jruby.ast.CaseNode;
0062: import org.jruby.ast.ClassNode;
0063: import org.jruby.ast.ClassVarAsgnNode;
0064: import org.jruby.ast.ClassVarDeclNode;
0065: import org.jruby.ast.ClassVarNode;
0066: import org.jruby.ast.Colon2Node;
0067: import org.jruby.ast.Colon3Node;
0068: import org.jruby.ast.ConstDeclNode;
0069: import org.jruby.ast.ConstNode;
0070: import org.jruby.ast.DAsgnNode;
0071: import org.jruby.ast.DRegexpNode;
0072: import org.jruby.ast.DStrNode;
0073: import org.jruby.ast.DSymbolNode;
0074: import org.jruby.ast.DVarNode;
0075: import org.jruby.ast.DXStrNode;
0076: import org.jruby.ast.DefinedNode;
0077: import org.jruby.ast.DefnNode;
0078: import org.jruby.ast.DefsNode;
0079: import org.jruby.ast.DotNode;
0080: import org.jruby.ast.EnsureNode;
0081: import org.jruby.ast.EvStrNode;
0082: import org.jruby.ast.FCallNode;
0083: import org.jruby.ast.FixnumNode;
0084: import org.jruby.ast.FlipNode;
0085: import org.jruby.ast.FloatNode;
0086: import org.jruby.ast.ForNode;
0087: import org.jruby.ast.GlobalAsgnNode;
0088: import org.jruby.ast.GlobalVarNode;
0089: import org.jruby.ast.HashNode;
0090: import org.jruby.ast.IfNode;
0091: import org.jruby.ast.InstAsgnNode;
0092: import org.jruby.ast.InstVarNode;
0093: import org.jruby.ast.IterNode;
0094: import org.jruby.ast.ListNode;
0095: import org.jruby.ast.LocalAsgnNode;
0096: import org.jruby.ast.LocalVarNode;
0097: import org.jruby.ast.Match2Node;
0098: import org.jruby.ast.Match3Node;
0099: import org.jruby.ast.MatchNode;
0100: import org.jruby.ast.ModuleNode;
0101: import org.jruby.ast.MultipleAsgnNode;
0102: import org.jruby.ast.NewlineNode;
0103: import org.jruby.ast.NextNode;
0104: import org.jruby.ast.Node;
0105: import org.jruby.ast.NodeTypes;
0106: import org.jruby.ast.NotNode;
0107: import org.jruby.ast.NthRefNode;
0108: import org.jruby.ast.OpAsgnNode;
0109: import org.jruby.ast.OpAsgnOrNode;
0110: import org.jruby.ast.OpElementAsgnNode;
0111: import org.jruby.ast.OptNNode;
0112: import org.jruby.ast.OrNode;
0113: import org.jruby.ast.PostExeNode;
0114: import org.jruby.ast.RegexpNode;
0115: import org.jruby.ast.RescueBodyNode;
0116: import org.jruby.ast.RescueNode;
0117: import org.jruby.ast.ReturnNode;
0118: import org.jruby.ast.RootNode;
0119: import org.jruby.ast.SClassNode;
0120: import org.jruby.ast.SValueNode;
0121: import org.jruby.ast.SplatNode;
0122: import org.jruby.ast.StrNode;
0123: import org.jruby.ast.SuperNode;
0124: import org.jruby.ast.SymbolNode;
0125: import org.jruby.ast.ToAryNode;
0126: import org.jruby.ast.UndefNode;
0127: import org.jruby.ast.UntilNode;
0128: import org.jruby.ast.VAliasNode;
0129: import org.jruby.ast.VCallNode;
0130: import org.jruby.ast.WhenNode;
0131: import org.jruby.ast.WhileNode;
0132: import org.jruby.ast.XStrNode;
0133: import org.jruby.ast.YieldNode;
0134: import org.jruby.ast.ZSuperNode;
0135: import org.jruby.ast.types.INameNode;
0136: import org.jruby.ast.util.ArgsUtil;
0137: import org.jruby.exceptions.JumpException;
0138: import org.jruby.exceptions.RaiseException;
0139: import org.jruby.exceptions.JumpException.JumpType;
0140: import org.jruby.internal.runtime.methods.DefaultMethod;
0141: import org.jruby.internal.runtime.methods.DynamicMethod;
0142: import org.jruby.internal.runtime.methods.WrapperMethod;
0143: import org.jruby.lexer.yacc.ISourcePosition;
0144: import org.jruby.parser.ReOptions;
0145: import org.jruby.parser.StaticScope;
0146: import org.jruby.runtime.Block;
0147: import org.jruby.runtime.CallType;
0148: import org.jruby.runtime.DynamicScope;
0149: import org.jruby.runtime.EventHook;
0150: import org.jruby.runtime.SharedScopeBlock;
0151: import org.jruby.runtime.MethodIndex;
0152: import org.jruby.runtime.ThreadContext;
0153: import org.jruby.runtime.Visibility;
0154: import org.jruby.runtime.builtin.IRubyObject;
0155: import org.jruby.util.ByteList;
0156: import org.jruby.util.KCode;
0157: import org.jruby.util.collections.SinglyLinkedList;
0158:
0159: public class EvaluationState {
0160: public static IRubyObject eval(Ruby runtime, ThreadContext context,
0161: Node node, IRubyObject self, Block block) {
0162: try {
0163: return evalInternal(runtime, context, node, self, block);
0164: } catch (StackOverflowError sfe) {
0165: throw runtime.newSystemStackError("stack level too deep");
0166: }
0167: }
0168:
0169: private static IRubyObject evalInternal(Ruby runtime,
0170: ThreadContext context, Node node, IRubyObject self,
0171: Block aBlock) {
0172: do {
0173: if (node == null)
0174: return nilNode(runtime, context);
0175:
0176: switch (node.nodeId) {
0177: case NodeTypes.ALIASNODE:
0178: return aliasNode(runtime, context, node);
0179: case NodeTypes.ANDNODE: {
0180: BinaryOperatorNode iVisited = (BinaryOperatorNode) node;
0181:
0182: IRubyObject result = evalInternal(runtime, context,
0183: iVisited.getFirstNode(), self, aBlock);
0184: if (!result.isTrue())
0185: return result;
0186: node = iVisited.getSecondNode();
0187: continue;
0188: }
0189: case NodeTypes.ARGSCATNODE:
0190: return argsCatNode(runtime, context, node, self, aBlock);
0191: case NodeTypes.ARGSPUSHNODE:
0192: return argsPushNode(runtime, context, node, self,
0193: aBlock);
0194: case NodeTypes.ARRAYNODE:
0195: return arrayNode(runtime, context, node, self, aBlock);
0196: case NodeTypes.ATTRASSIGNNODE:
0197: return attrAssignNode(runtime, context, node, self,
0198: aBlock);
0199: case NodeTypes.BACKREFNODE:
0200: return backRefNode(context, node);
0201: case NodeTypes.BEGINNODE:
0202: node = ((BeginNode) node).getBodyNode();
0203: continue;
0204: case NodeTypes.BIGNUMNODE:
0205: return bignumNode(runtime, node);
0206: case NodeTypes.BLOCKNODE:
0207: return blockNode(runtime, context, node, self, aBlock);
0208: case NodeTypes.BLOCKPASSNODE:
0209: assert false : "Call nodes and friends deal with this";
0210: case NodeTypes.BREAKNODE:
0211: return breakNode(runtime, context, node, self, aBlock);
0212: case NodeTypes.CALLNODE:
0213: return callNode(runtime, context, node, self, aBlock);
0214: case NodeTypes.CASENODE:
0215: return caseNode(runtime, context, node, self, aBlock);
0216: case NodeTypes.CLASSNODE:
0217: return classNode(runtime, context, node, self, aBlock);
0218: case NodeTypes.CLASSVARASGNNODE:
0219: return classVarAsgnNode(runtime, context, node, self,
0220: aBlock);
0221: case NodeTypes.CLASSVARDECLNODE:
0222: return classVarDeclNode(runtime, context, node, self,
0223: aBlock);
0224: case NodeTypes.CLASSVARNODE:
0225: return classVarNode(runtime, context, node, self);
0226: case NodeTypes.COLON2NODE:
0227: return colon2Node(runtime, context, node, self, aBlock);
0228: case NodeTypes.COLON3NODE:
0229: return colon3Node(runtime, node);
0230: case NodeTypes.CONSTDECLNODE:
0231: return constDeclNode(runtime, context, node, self,
0232: aBlock);
0233: case NodeTypes.CONSTNODE:
0234: return constNode(context, node);
0235: case NodeTypes.DASGNNODE:
0236: return dAsgnNode(runtime, context, node, self, aBlock);
0237: case NodeTypes.DEFINEDNODE:
0238: return definedNode(runtime, context, node, self, aBlock);
0239: case NodeTypes.DEFNNODE:
0240: return defnNode(runtime, context, node);
0241: case NodeTypes.DEFSNODE:
0242: return defsNode(runtime, context, node, self, aBlock);
0243: case NodeTypes.DOTNODE:
0244: return dotNode(runtime, context, node, self, aBlock);
0245: case NodeTypes.DREGEXPNODE:
0246: return dregexpNode(runtime, context, node, self, aBlock);
0247: case NodeTypes.DSTRNODE:
0248: return dStrNode(runtime, context, node, self, aBlock);
0249: case NodeTypes.DSYMBOLNODE:
0250: return dSymbolNode(runtime, context, node, self, aBlock);
0251: case NodeTypes.DVARNODE:
0252: return dVarNode(runtime, context, node);
0253: case NodeTypes.DXSTRNODE:
0254: return dXStrNode(runtime, context, node, self, aBlock);
0255: case NodeTypes.ENSURENODE:
0256: return ensureNode(runtime, context, node, self, aBlock);
0257: case NodeTypes.EVSTRNODE:
0258: return evStrNode(runtime, context, node, self, aBlock);
0259: case NodeTypes.FALSENODE:
0260: return falseNode(runtime, context);
0261: case NodeTypes.FCALLNODE:
0262: return fCallNode(runtime, context, node, self, aBlock);
0263: case NodeTypes.FIXNUMNODE:
0264: return fixnumNode(runtime, node);
0265: case NodeTypes.FLIPNODE:
0266: return flipNode(runtime, context, node, self, aBlock);
0267: case NodeTypes.FLOATNODE:
0268: return floatNode(runtime, node);
0269: case NodeTypes.FORNODE:
0270: return forNode(runtime, context, node, self, aBlock);
0271: case NodeTypes.GLOBALASGNNODE:
0272: return globalAsgnNode(runtime, context, node, self,
0273: aBlock);
0274: case NodeTypes.GLOBALVARNODE:
0275: return globalVarNode(runtime, context, node);
0276: case NodeTypes.HASHNODE:
0277: return hashNode(runtime, context, node, self, aBlock);
0278: case NodeTypes.IFNODE: {
0279: IfNode iVisited = (IfNode) node;
0280: IRubyObject result = evalInternal(runtime, context,
0281: iVisited.getCondition(), self, aBlock);
0282:
0283: if (result.isTrue()) {
0284: node = iVisited.getThenBody();
0285: } else {
0286: node = iVisited.getElseBody();
0287: }
0288: continue;
0289: }
0290: case NodeTypes.INSTASGNNODE:
0291: return instAsgnNode(runtime, context, node, self,
0292: aBlock);
0293: case NodeTypes.INSTVARNODE:
0294: return instVarNode(runtime, node, self);
0295: case NodeTypes.ITERNODE:
0296: assert false : "Call nodes deal with these directly";
0297: case NodeTypes.LOCALASGNNODE:
0298: return localAsgnNode(runtime, context, node, self,
0299: aBlock);
0300: case NodeTypes.LOCALVARNODE:
0301: return localVarNode(runtime, context, node);
0302: case NodeTypes.MATCH2NODE:
0303: return match2Node(runtime, context, node, self, aBlock);
0304: case NodeTypes.MATCH3NODE:
0305: return match3Node(runtime, context, node, self, aBlock);
0306: case NodeTypes.MATCHNODE:
0307: return matchNode(runtime, context, node, self, aBlock);
0308: case NodeTypes.MODULENODE:
0309: return moduleNode(runtime, context, node, self, aBlock);
0310: case NodeTypes.MULTIPLEASGNNODE:
0311: return multipleAsgnNode(runtime, context, node, self,
0312: aBlock);
0313: case NodeTypes.NEWLINENODE: {
0314: NewlineNode iVisited = (NewlineNode) node;
0315:
0316: // something in here is used to build up ruby stack trace...
0317: context.setPosition(iVisited.getPosition());
0318:
0319: if (isTrace(runtime)) {
0320: callTraceFunction(runtime, context,
0321: EventHook.RUBY_EVENT_LINE);
0322: }
0323:
0324: // TODO: do above but not below for additional newline nodes
0325: node = iVisited.getNextNode();
0326: continue;
0327: }
0328: case NodeTypes.NEXTNODE:
0329: return nextNode(runtime, context, node, self, aBlock);
0330: case NodeTypes.NILNODE:
0331: return nilNode(runtime, context);
0332: case NodeTypes.NOTNODE:
0333: return notNode(runtime, context, node, self, aBlock);
0334: case NodeTypes.NTHREFNODE:
0335: return nthRefNode(context, node);
0336: case NodeTypes.OPASGNANDNODE: {
0337: BinaryOperatorNode iVisited = (BinaryOperatorNode) node;
0338:
0339: // add in reverse order
0340: IRubyObject result = evalInternal(runtime, context,
0341: iVisited.getFirstNode(), self, aBlock);
0342: if (!result.isTrue())
0343: return pollAndReturn(context, result);
0344: node = iVisited.getSecondNode();
0345: continue;
0346: }
0347: case NodeTypes.OPASGNNODE:
0348: return opAsgnNode(runtime, context, node, self, aBlock);
0349: case NodeTypes.OPASGNORNODE:
0350: return opAsgnOrNode(runtime, context, node, self,
0351: aBlock);
0352: case NodeTypes.OPELEMENTASGNNODE:
0353: return opElementAsgnNode(runtime, context, node, self,
0354: aBlock);
0355: case NodeTypes.OPTNNODE:
0356: return optNNode(runtime, context, node, self, aBlock);
0357: case NodeTypes.ORNODE:
0358: return orNode(runtime, context, node, self, aBlock);
0359: case NodeTypes.POSTEXENODE:
0360: return postExeNode(runtime, context, node, self, aBlock);
0361: case NodeTypes.REDONODE:
0362: return redoNode(context, node);
0363: case NodeTypes.REGEXPNODE:
0364: return regexpNode(runtime, node);
0365: case NodeTypes.RESCUEBODYNODE:
0366: node = ((RescueBodyNode) node).getBodyNode();
0367: continue;
0368: case NodeTypes.RESCUENODE:
0369: return rescueNode(runtime, context, node, self, aBlock);
0370: case NodeTypes.RETRYNODE:
0371: return retryNode(context);
0372: case NodeTypes.RETURNNODE:
0373: return returnNode(runtime, context, node, self, aBlock);
0374: case NodeTypes.ROOTNODE:
0375: return rootNode(runtime, context, node, self, aBlock);
0376: case NodeTypes.SCLASSNODE:
0377: return sClassNode(runtime, context, node, self, aBlock);
0378: case NodeTypes.SELFNODE:
0379: return pollAndReturn(context, self);
0380: case NodeTypes.SPLATNODE:
0381: return splatNode(runtime, context, node, self, aBlock);
0382: case NodeTypes.STRNODE:
0383: return strNode(runtime, node);
0384: case NodeTypes.SUPERNODE:
0385: return super Node(runtime, context, node, self, aBlock);
0386: case NodeTypes.SVALUENODE:
0387: return sValueNode(runtime, context, node, self, aBlock);
0388: case NodeTypes.SYMBOLNODE:
0389: return symbolNode(runtime, node);
0390: case NodeTypes.TOARYNODE:
0391: return toAryNode(runtime, context, node, self, aBlock);
0392: case NodeTypes.TRUENODE:
0393: return trueNode(runtime, context);
0394: case NodeTypes.UNDEFNODE:
0395: return undefNode(runtime, context, node);
0396: case NodeTypes.UNTILNODE:
0397: return untilNode(runtime, context, node, self, aBlock);
0398: case NodeTypes.VALIASNODE:
0399: return valiasNode(runtime, node);
0400: case NodeTypes.VCALLNODE:
0401: return vcallNode(runtime, context, node, self);
0402: case NodeTypes.WHENNODE:
0403: assert false;
0404: return null;
0405: case NodeTypes.WHILENODE:
0406: return whileNode(runtime, context, node, self, aBlock);
0407: case NodeTypes.XSTRNODE:
0408: return xStrNode(runtime, context, node, self);
0409: case NodeTypes.YIELDNODE:
0410: return yieldNode(runtime, context, node, self, aBlock);
0411: case NodeTypes.ZARRAYNODE:
0412: return zArrayNode(runtime);
0413: case NodeTypes.ZSUPERNODE:
0414: return zsuper Node(runtime, context, node, self, aBlock);
0415: default:
0416: throw new RuntimeException(
0417: "Invalid node encountered in interpreter: \""
0418: + node.getClass().getName()
0419: + "\", please report this at www.jruby.org");
0420: }
0421: } while (true);
0422: }
0423:
0424: private static IRubyObject aliasNode(Ruby runtime,
0425: ThreadContext context, Node node) {
0426: AliasNode iVisited = (AliasNode) node;
0427:
0428: if (context.getRubyClass() == null) {
0429: throw runtime.newTypeError("no class to make alias");
0430: }
0431:
0432: context.getRubyClass().defineAlias(iVisited.getNewName(),
0433: iVisited.getOldName());
0434: context.getRubyClass().callMethod(context, "method_added",
0435: runtime.newSymbol(iVisited.getNewName()));
0436:
0437: return runtime.getNil();
0438: }
0439:
0440: private static IRubyObject argsCatNode(Ruby runtime,
0441: ThreadContext context, Node node, IRubyObject self,
0442: Block aBlock) {
0443: ArgsCatNode iVisited = (ArgsCatNode) node;
0444:
0445: IRubyObject args = evalInternal(runtime, context, iVisited
0446: .getFirstNode(), self, aBlock);
0447: IRubyObject secondArgs = splatValue(runtime, evalInternal(
0448: runtime, context, iVisited.getSecondNode(), self,
0449: aBlock));
0450: RubyArray list = args instanceof RubyArray ? (RubyArray) args
0451: : runtime.newArray(args);
0452:
0453: return list.concat(secondArgs);
0454: }
0455:
0456: private static IRubyObject argsPushNode(Ruby runtime,
0457: ThreadContext context, Node node, IRubyObject self,
0458: Block aBlock) {
0459: ArgsPushNode iVisited = (ArgsPushNode) node;
0460:
0461: RubyArray args = (RubyArray) evalInternal(runtime, context,
0462: iVisited.getFirstNode(), self, aBlock).dup();
0463: return args.append(evalInternal(runtime, context, iVisited
0464: .getSecondNode(), self, aBlock));
0465: }
0466:
0467: private static IRubyObject arrayNode(Ruby runtime,
0468: ThreadContext context, Node node, IRubyObject self,
0469: Block aBlock) {
0470: ArrayNode iVisited = (ArrayNode) node;
0471: IRubyObject[] array = new IRubyObject[iVisited.size()];
0472:
0473: for (int i = 0; i < iVisited.size(); i++) {
0474: Node next = iVisited.get(i);
0475:
0476: array[i] = evalInternal(runtime, context, next, self,
0477: aBlock);
0478: }
0479:
0480: if (iVisited.isLightweight()) {
0481: return runtime.newArrayNoCopyLight(array);
0482: }
0483:
0484: return runtime.newArrayNoCopy(array);
0485: }
0486:
0487: public static RubyArray arrayValue(Ruby runtime, IRubyObject value) {
0488: IRubyObject newValue = value.convertToType(runtime.getArray(),
0489: MethodIndex.TO_ARY, "to_ary", false);
0490: if (newValue.isNil()) {
0491: // Object#to_a is obsolete. We match Ruby's hack until to_a goes away. Then we can
0492: // remove this hack too.
0493: if (value.getMetaClass().searchMethod("to_a")
0494: .getImplementationClass() != runtime.getKernel()) {
0495: newValue = value.convertToType(runtime.getArray(),
0496: MethodIndex.TO_A, "to_a", false);
0497: if (newValue.getType() != runtime.getClass("Array")) {
0498: throw runtime
0499: .newTypeError("`to_a' did not return Array");
0500: }
0501: } else {
0502: newValue = runtime.newArray(value);
0503: }
0504: }
0505:
0506: return (RubyArray) newValue;
0507: }
0508:
0509: private static IRubyObject aryToAry(Ruby runtime, IRubyObject value) {
0510: if (value instanceof RubyArray)
0511: return value;
0512:
0513: if (value.respondsTo("to_ary")) {
0514: return value.convertToType(runtime.getArray(),
0515: MethodIndex.TO_A, "to_ary", false);
0516: }
0517:
0518: return runtime.newArray(value);
0519: }
0520:
0521: private static IRubyObject attrAssignNode(Ruby runtime,
0522: ThreadContext context, Node node, IRubyObject self,
0523: Block aBlock) {
0524: AttrAssignNode iVisited = (AttrAssignNode) node;
0525:
0526: IRubyObject receiver = evalInternal(runtime, context, iVisited
0527: .getReceiverNode(), self, aBlock);
0528: IRubyObject[] args = setupArgs(runtime, context, iVisited
0529: .getArgsNode(), self);
0530:
0531: assert receiver.getMetaClass() != null : receiver.getClass()
0532: .getName();
0533:
0534: // If reciever is self then we do the call the same way as vcall
0535: CallType callType = (receiver == self ? CallType.VARIABLE
0536: : CallType.NORMAL);
0537:
0538: RubyModule module = receiver.getMetaClass();
0539:
0540: String name = iVisited.getName();
0541:
0542: DynamicMethod method = module.searchMethod(name);
0543:
0544: if (method.isUndefined()
0545: || (!method.isCallableFrom(self, callType))) {
0546: return RubyObject.callMethodMissing(context, receiver,
0547: method, name, args, self, callType,
0548: Block.NULL_BLOCK);
0549: }
0550:
0551: method.call(context, receiver, module, name, args, false,
0552: Block.NULL_BLOCK);
0553:
0554: return args[args.length - 1];
0555: }
0556:
0557: private static IRubyObject backRefNode(ThreadContext context,
0558: Node node) {
0559: BackRefNode iVisited = (BackRefNode) node;
0560: IRubyObject backref = context.getBackref();
0561: switch (iVisited.getType()) {
0562: case '~':
0563: return backref;
0564: case '&':
0565: return RubyRegexp.last_match(backref);
0566: case '`':
0567: return RubyRegexp.match_pre(backref);
0568: case '\'':
0569: return RubyRegexp.match_post(backref);
0570: case '+':
0571: return RubyRegexp.match_last(backref);
0572: default:
0573: assert false : "backref with invalid type";
0574: return null;
0575: }
0576: }
0577:
0578: private static IRubyObject bignumNode(Ruby runtime, Node node) {
0579: return RubyBignum.newBignum(runtime, ((BignumNode) node)
0580: .getValue());
0581: }
0582:
0583: private static IRubyObject blockNode(Ruby runtime,
0584: ThreadContext context, Node node, IRubyObject self,
0585: Block aBlock) {
0586: BlockNode iVisited = (BlockNode) node;
0587:
0588: IRubyObject result = runtime.getNil();
0589: for (int i = 0; i < iVisited.size(); i++) {
0590: result = evalInternal(runtime, context, (Node) iVisited
0591: .get(i), self, aBlock);
0592: }
0593:
0594: return result;
0595: }
0596:
0597: private static IRubyObject breakNode(Ruby runtime,
0598: ThreadContext context, Node node, IRubyObject self,
0599: Block aBlock) {
0600: BreakNode iVisited = (BreakNode) node;
0601:
0602: IRubyObject result = evalInternal(runtime, context, iVisited
0603: .getValueNode(), self, aBlock);
0604:
0605: throw context.prepareJumpException(
0606: JumpException.JumpType.BreakJump, null, result);
0607: }
0608:
0609: private static IRubyObject callNode(Ruby runtime,
0610: ThreadContext context, Node node, IRubyObject self,
0611: Block aBlock) {
0612: CallNode iVisited = (CallNode) node;
0613:
0614: IRubyObject receiver = evalInternal(runtime, context, iVisited
0615: .getReceiverNode(), self, aBlock);
0616: IRubyObject[] args = setupArgs(runtime, context, iVisited
0617: .getArgsNode(), self);
0618:
0619: assert receiver.getMetaClass() != null : receiver.getClass()
0620: .getName();
0621:
0622: Block block = getBlock(runtime, context, self, aBlock, iVisited
0623: .getIterNode());
0624: RubyModule module = receiver.getMetaClass();
0625: String name = iVisited.getName();
0626: int index = iVisited.index;
0627:
0628: // No block provided lets look at fast path for STI dispatch.
0629: if (!block.isGiven()) {
0630: if (index != 0) {
0631: return receiver.callMethod(context, module, index,
0632: name, args, CallType.NORMAL, Block.NULL_BLOCK);
0633: } else {
0634: DynamicMethod method = module.searchMethod(name);
0635:
0636: if (method.isUndefined()
0637: || (!method.isCallableFrom(self,
0638: CallType.NORMAL))) {
0639: return RubyObject.callMethodMissing(context,
0640: receiver, method, name, args, self,
0641: CallType.NORMAL, Block.NULL_BLOCK);
0642: }
0643:
0644: return method.call(context, receiver, module, name,
0645: args, false, Block.NULL_BLOCK);
0646: }
0647: }
0648:
0649: while (true) {
0650: try {
0651: DynamicMethod method = module.searchMethod(name);
0652:
0653: if (method.isUndefined()
0654: || (index != MethodIndex.METHOD_MISSING && !method
0655: .isCallableFrom(self, CallType.NORMAL))) {
0656: return RubyObject.callMethodMissing(context,
0657: receiver, method, name, index, args, self,
0658: CallType.NORMAL, block);
0659: }
0660:
0661: return method.call(context, receiver, module, name,
0662: args, false, block);
0663: } catch (JumpException je) {
0664: switch (je.getJumpType().getTypeId()) {
0665: case JumpType.RETRY:
0666: // allow loop to retry
0667: case JumpType.BREAK:
0668: return (IRubyObject) je.getValue();
0669: default:
0670: throw je;
0671: }
0672: }
0673: }
0674: }
0675:
0676: private static IRubyObject caseNode(Ruby runtime,
0677: ThreadContext context, Node node, IRubyObject self,
0678: Block aBlock) {
0679: CaseNode iVisited = (CaseNode) node;
0680: IRubyObject expression = null;
0681: if (iVisited.getCaseNode() != null) {
0682: expression = evalInternal(runtime, context, iVisited
0683: .getCaseNode(), self, aBlock);
0684: }
0685:
0686: context.pollThreadEvents();
0687:
0688: IRubyObject result = runtime.getNil();
0689:
0690: Node firstWhenNode = iVisited.getFirstWhenNode();
0691: while (firstWhenNode != null) {
0692: if (!(firstWhenNode instanceof WhenNode)) {
0693: node = firstWhenNode;
0694: return evalInternal(runtime, context, node, self,
0695: aBlock);
0696: }
0697:
0698: WhenNode whenNode = (WhenNode) firstWhenNode;
0699:
0700: if (whenNode.getExpressionNodes() instanceof ArrayNode) {
0701: ArrayNode arrayNode = (ArrayNode) whenNode
0702: .getExpressionNodes();
0703: for (int i = 0; i < arrayNode.size(); i++) {
0704: Node tag = arrayNode.get(i);
0705:
0706: context.setPosition(tag.getPosition());
0707: if (isTrace(runtime)) {
0708: callTraceFunction(runtime, context,
0709: EventHook.RUBY_EVENT_LINE);
0710: }
0711:
0712: // Ruby grammar has nested whens in a case body because of
0713: // productions case_body and when_args.
0714: if (tag instanceof WhenNode) {
0715: RubyArray expressions = (RubyArray) evalInternal(
0716: runtime, context, ((WhenNode) tag)
0717: .getExpressionNodes(), self,
0718: aBlock);
0719:
0720: for (int j = 0, k = expressions.getLength(); j < k; j++) {
0721: IRubyObject condition = expressions
0722: .eltInternal(j);
0723:
0724: if ((expression != null && condition
0725: .callMethod(context,
0726: MethodIndex.OP_EQQ, "===",
0727: expression).isTrue())
0728: || (expression == null && condition
0729: .isTrue())) {
0730: node = ((WhenNode) firstWhenNode)
0731: .getBodyNode();
0732: return evalInternal(runtime, context,
0733: node, self, aBlock);
0734: }
0735: }
0736: continue;
0737: }
0738:
0739: result = evalInternal(runtime, context, tag, self,
0740: aBlock);
0741:
0742: if ((expression != null && result.callMethod(
0743: context, MethodIndex.OP_EQQ, "===",
0744: expression).isTrue())
0745: || (expression == null && result.isTrue())) {
0746: node = whenNode.getBodyNode();
0747: return evalInternal(runtime, context, node,
0748: self, aBlock);
0749: }
0750: }
0751: } else {
0752: result = evalInternal(runtime, context, whenNode
0753: .getExpressionNodes(), self, aBlock);
0754:
0755: if ((expression != null && result.callMethod(context,
0756: MethodIndex.OP_EQQ, "===", expression).isTrue())
0757: || (expression == null && result.isTrue())) {
0758: node = ((WhenNode) firstWhenNode).getBodyNode();
0759: return evalInternal(runtime, context, node, self,
0760: aBlock);
0761: }
0762: }
0763:
0764: context.pollThreadEvents();
0765:
0766: firstWhenNode = whenNode.getNextCase();
0767: }
0768:
0769: return runtime.getNil();
0770: }
0771:
0772: private static IRubyObject classNode(Ruby runtime,
0773: ThreadContext context, Node node, IRubyObject self,
0774: Block aBlock) {
0775: ClassNode iVisited = (ClassNode) node;
0776: Node super Node = iVisited.getSuperNode();
0777: RubyClass super Class = null;
0778: if (super Node != null) {
0779: IRubyObject _super = evalInternal(runtime, context,
0780: super Node, self, aBlock);
0781: if (!(_super instanceof RubyClass)) {
0782: throw runtime
0783: .newTypeError("superclass must be a Class ("
0784: + RubyObject.trueFalseNil(_super )
0785: + ") given");
0786: }
0787: super Class = super Node == null ? null : (RubyClass) _super ;
0788: }
0789: Node classNameNode = iVisited.getCPath();
0790: String name = ((INameNode) classNameNode).getName();
0791: RubyModule enclosingClass = getEnclosingModule(runtime,
0792: context, classNameNode, self, aBlock);
0793: RubyClass rubyClass = enclosingClass.defineOrGetClassUnder(
0794: name, super Class);
0795:
0796: return evalClassDefinitionBody(runtime, context, iVisited
0797: .getScope(), iVisited.getBodyNode(), rubyClass, self,
0798: aBlock);
0799: }
0800:
0801: private static IRubyObject classVarAsgnNode(Ruby runtime,
0802: ThreadContext context, Node node, IRubyObject self,
0803: Block aBlock) {
0804: ClassVarAsgnNode iVisited = (ClassVarAsgnNode) node;
0805: IRubyObject result = evalInternal(runtime, context, iVisited
0806: .getValueNode(), self, aBlock);
0807: RubyModule rubyClass = getClassVariableBase(context, runtime);
0808:
0809: if (rubyClass == null) {
0810: rubyClass = self.getMetaClass();
0811: }
0812: rubyClass.setClassVar(iVisited.getName(), result);
0813:
0814: return result;
0815: }
0816:
0817: private static IRubyObject classVarDeclNode(Ruby runtime,
0818: ThreadContext context, Node node, IRubyObject self,
0819: Block aBlock) {
0820: ClassVarDeclNode iVisited = (ClassVarDeclNode) node;
0821:
0822: RubyModule rubyClass = getClassVariableBase(context, runtime);
0823: if (rubyClass == null) {
0824: throw runtime
0825: .newTypeError("no class/module to define class variable");
0826: }
0827: IRubyObject result = evalInternal(runtime, context, iVisited
0828: .getValueNode(), self, aBlock);
0829: rubyClass.setClassVar(iVisited.getName(), result);
0830:
0831: return result;
0832: }
0833:
0834: private static IRubyObject classVarNode(Ruby runtime,
0835: ThreadContext context, Node node, IRubyObject self) {
0836: ClassVarNode iVisited = (ClassVarNode) node;
0837: RubyModule rubyClass = getClassVariableBase(context, runtime);
0838:
0839: if (rubyClass == null) {
0840: rubyClass = self.getMetaClass();
0841: }
0842:
0843: return rubyClass.getClassVar(iVisited.getName());
0844: }
0845:
0846: private static IRubyObject colon2Node(Ruby runtime,
0847: ThreadContext context, Node node, IRubyObject self,
0848: Block aBlock) {
0849: Colon2Node iVisited = (Colon2Node) node;
0850: Node leftNode = iVisited.getLeftNode();
0851: // TODO: Made this more colon3 friendly because of cpath production
0852: // rule in grammar (it is convenient to think of them as the same thing
0853: // at a grammar level even though evaluation is).
0854: if (leftNode == null) {
0855: return runtime.getObject().getConstantFrom(
0856: iVisited.getName());
0857: } else {
0858: IRubyObject result = evalInternal(runtime, context,
0859: iVisited.getLeftNode(), self, aBlock);
0860: if (result instanceof RubyModule) {
0861: return ((RubyModule) result).getConstantFrom(iVisited
0862: .getName());
0863: } else {
0864: return result.callMethod(context, iVisited.getName(),
0865: aBlock);
0866: }
0867: }
0868: }
0869:
0870: private static IRubyObject colon3Node(Ruby runtime, Node node) {
0871: return runtime.getObject().getConstantFrom(
0872: ((Colon3Node) node).getName());
0873: }
0874:
0875: private static IRubyObject constDeclNode(Ruby runtime,
0876: ThreadContext context, Node node, IRubyObject self,
0877: Block aBlock) {
0878: ConstDeclNode iVisited = (ConstDeclNode) node;
0879: Node constNode = iVisited.getConstNode();
0880:
0881: IRubyObject result = evalInternal(runtime, context, iVisited
0882: .getValueNode(), self, aBlock);
0883:
0884: if (constNode == null) {
0885: return context.setConstantInCurrent(iVisited.getName(),
0886: result);
0887: } else if (constNode.nodeId == NodeTypes.COLON2NODE) {
0888: RubyModule module = (RubyModule) evalInternal(runtime,
0889: context, ((Colon2Node) iVisited.getConstNode())
0890: .getLeftNode(), self, aBlock);
0891: return context.setConstantInModule(iVisited.getName(),
0892: module, result);
0893: } else { // colon3
0894: return context.setConstantInObject(iVisited.getName(),
0895: result);
0896: }
0897: }
0898:
0899: private static IRubyObject constNode(ThreadContext context,
0900: Node node) {
0901: return context.getConstant(((ConstNode) node).getName());
0902: }
0903:
0904: private static IRubyObject dAsgnNode(Ruby runtime,
0905: ThreadContext context, Node node, IRubyObject self,
0906: Block aBlock) {
0907: DAsgnNode iVisited = (DAsgnNode) node;
0908:
0909: IRubyObject result = evalInternal(runtime, context, iVisited
0910: .getValueNode(), self, aBlock);
0911:
0912: // System.out.println("DSetting: " + iVisited.getName() + " at index " + iVisited.getIndex() + " and at depth " + iVisited.getDepth() + " and set " + result);
0913: context.getCurrentScope().setValue(iVisited.getIndex(), result,
0914: iVisited.getDepth());
0915:
0916: return result;
0917: }
0918:
0919: private static IRubyObject definedNode(Ruby runtime,
0920: ThreadContext context, Node node, IRubyObject self,
0921: Block aBlock) {
0922: DefinedNode iVisited = (DefinedNode) node;
0923: String definition = getDefinition(runtime, context, iVisited
0924: .getExpressionNode(), self, aBlock);
0925: if (definition != null) {
0926: return runtime.newString(definition);
0927: } else {
0928: return runtime.getNil();
0929: }
0930: }
0931:
0932: private static IRubyObject defnNode(Ruby runtime,
0933: ThreadContext context, Node node) {
0934: DefnNode iVisited = (DefnNode) node;
0935:
0936: RubyModule containingClass = context.getRubyClass();
0937:
0938: if (containingClass == null) {
0939: throw runtime.newTypeError("No class to add method.");
0940: }
0941:
0942: String name = iVisited.getName();
0943:
0944: if (containingClass == runtime.getObject()
0945: && name == "initialize") {
0946: runtime
0947: .getWarnings()
0948: .warn(
0949: "redefining Object#initialize may cause infinite loop");
0950: }
0951:
0952: Visibility visibility = context.getCurrentVisibility();
0953: if (name == "initialize" || visibility.isModuleFunction()
0954: || context.isTopLevel()) {
0955: visibility = Visibility.PRIVATE;
0956: }
0957:
0958: DefaultMethod newMethod = new DefaultMethod(containingClass,
0959: iVisited.getScope(), iVisited.getBodyNode(),
0960: (ArgsNode) iVisited.getArgsNode(), visibility, context
0961: .peekCRef());
0962:
0963: containingClass.addMethod(name, newMethod);
0964:
0965: if (context.getCurrentVisibility().isModuleFunction()) {
0966: containingClass.getSingletonClass().addMethod(
0967: name,
0968: new WrapperMethod(containingClass
0969: .getSingletonClass(), newMethod,
0970: Visibility.PUBLIC));
0971: containingClass.callMethod(context,
0972: "singleton_method_added", runtime.newSymbol(name));
0973: }
0974:
0975: // 'class << state.self' and 'class << obj' uses defn as opposed to defs
0976: if (containingClass.isSingleton()) {
0977: ((MetaClass) containingClass).getAttachedObject()
0978: .callMethod(context, "singleton_method_added",
0979: runtime.newSymbol(iVisited.getName()));
0980: } else {
0981: containingClass.callMethod(context, "method_added", runtime
0982: .newSymbol(name));
0983: }
0984:
0985: return runtime.getNil();
0986: }
0987:
0988: private static IRubyObject defsNode(Ruby runtime,
0989: ThreadContext context, Node node, IRubyObject self,
0990: Block aBlock) {
0991: DefsNode iVisited = (DefsNode) node;
0992: IRubyObject receiver = evalInternal(runtime, context, iVisited
0993: .getReceiverNode(), self, aBlock);
0994:
0995: RubyClass rubyClass;
0996:
0997: if (receiver.isNil()) {
0998: rubyClass = runtime.getNilClass();
0999: } else if (receiver == runtime.getTrue()) {
1000: rubyClass = runtime.getClass("TrueClass");
1001: } else if (receiver == runtime.getFalse()) {
1002: rubyClass = runtime.getClass("FalseClass");
1003: } else {
1004: if (runtime.getSafeLevel() >= 4 && !receiver.isTaint()) {
1005: throw runtime
1006: .newSecurityError("Insecure; can't define singleton method.");
1007: }
1008: if (receiver.isFrozen()) {
1009: throw runtime.newFrozenError("object");
1010: }
1011: if (receiver.getMetaClass() == runtime.getFixnum()
1012: || receiver.getMetaClass() == runtime
1013: .getClass("Symbol")) {
1014: throw runtime
1015: .newTypeError("can't define singleton method \""
1016: + iVisited.getName()
1017: + "\" for "
1018: + receiver.getType());
1019: }
1020:
1021: rubyClass = receiver.getSingletonClass();
1022: }
1023:
1024: if (runtime.getSafeLevel() >= 4) {
1025: Object method = rubyClass.getMethods().get(
1026: iVisited.getName());
1027: if (method != null) {
1028: throw runtime
1029: .newSecurityError("Redefining method prohibited.");
1030: }
1031: }
1032:
1033: DefaultMethod newMethod = new DefaultMethod(rubyClass, iVisited
1034: .getScope(), iVisited.getBodyNode(),
1035: (ArgsNode) iVisited.getArgsNode(), Visibility.PUBLIC,
1036: context.peekCRef());
1037:
1038: rubyClass.addMethod(iVisited.getName(), newMethod);
1039: receiver.callMethod(context, "singleton_method_added", runtime
1040: .newSymbol(iVisited.getName()));
1041:
1042: return runtime.getNil();
1043: }
1044:
1045: private static IRubyObject dotNode(Ruby runtime,
1046: ThreadContext context, Node node, IRubyObject self,
1047: Block aBlock) {
1048: DotNode iVisited = (DotNode) node;
1049: return RubyRange.newRange(runtime, evalInternal(runtime,
1050: context, iVisited.getBeginNode(), self, aBlock),
1051: evalInternal(runtime, context, iVisited.getEndNode(),
1052: self, aBlock), iVisited.isExclusive());
1053: }
1054:
1055: private static IRubyObject dregexpNode(Ruby runtime,
1056: ThreadContext context, Node node, IRubyObject self,
1057: Block aBlock) {
1058: DRegexpNode iVisited = (DRegexpNode) node;
1059:
1060: RubyString string = runtime.newString(new ByteList());
1061: for (int i = 0; i < iVisited.size(); i++) {
1062: Node iterNode = iVisited.get(i);
1063: if (iterNode instanceof StrNode) {
1064: string.getByteList().append(
1065: ((StrNode) iterNode).getValue());
1066: } else {
1067: string.append(evalInternal(runtime, context, iterNode,
1068: self, aBlock));
1069: }
1070: }
1071:
1072: String lang = null;
1073: int opts = iVisited.getOptions();
1074: if ((opts & 16) != 0) { // param n
1075: lang = "n";
1076: } else if ((opts & 48) != 0) { // param s
1077: lang = "s";
1078: } else if ((opts & 64) != 0) { // param s
1079: lang = "u";
1080: }
1081:
1082: try {
1083: return RubyRegexp.newRegexp(runtime, string.toString(),
1084: iVisited.getOptions(), lang);
1085: } catch (jregex.PatternSyntaxException e) {
1086: // System.err.println(iVisited.getValue().toString());
1087: // e.printStackTrace();
1088: throw runtime.newRegexpError(e.getMessage());
1089: }
1090: }
1091:
1092: private static IRubyObject dStrNode(Ruby runtime,
1093: ThreadContext context, Node node, IRubyObject self,
1094: Block aBlock) {
1095: DStrNode iVisited = (DStrNode) node;
1096:
1097: RubyString string = runtime.newString(new ByteList());
1098: for (int i = 0; i < iVisited.size(); i++) {
1099: Node iterNode = iVisited.get(i);
1100: if (iterNode instanceof StrNode) {
1101: string.getByteList().append(
1102: ((StrNode) iterNode).getValue());
1103: } else {
1104: string.append(evalInternal(runtime, context, iterNode,
1105: self, aBlock));
1106: }
1107: }
1108:
1109: return string;
1110: }
1111:
1112: private static IRubyObject dSymbolNode(Ruby runtime,
1113: ThreadContext context, Node node, IRubyObject self,
1114: Block aBlock) {
1115: DSymbolNode iVisited = (DSymbolNode) node;
1116:
1117: RubyString string = runtime.newString(new ByteList());
1118: for (int i = 0; i < iVisited.size(); i++) {
1119: Node iterNode = iVisited.get(i);
1120: if (iterNode instanceof StrNode) {
1121: string.getByteList().append(
1122: ((StrNode) iterNode).getValue());
1123: } else {
1124: string.append(evalInternal(runtime, context, iterNode,
1125: self, aBlock));
1126: }
1127: }
1128:
1129: return runtime.newSymbol(string.toString());
1130: }
1131:
1132: private static IRubyObject dVarNode(Ruby runtime,
1133: ThreadContext context, Node node) {
1134: DVarNode iVisited = (DVarNode) node;
1135:
1136: // System.out.println("DGetting: " + iVisited.getName() + " at index " + iVisited.getIndex() + " and at depth " + iVisited.getDepth());
1137: IRubyObject obj = context.getCurrentScope().getValue(
1138: iVisited.getIndex(), iVisited.getDepth());
1139:
1140: // FIXME: null check is removable once we figure out how to assign to unset named block args
1141: return obj == null ? runtime.getNil() : obj;
1142: }
1143:
1144: private static IRubyObject dXStrNode(Ruby runtime,
1145: ThreadContext context, Node node, IRubyObject self,
1146: Block aBlock) {
1147: DXStrNode iVisited = (DXStrNode) node;
1148:
1149: RubyString string = runtime.newString(new ByteList());
1150: for (int i = 0; i < iVisited.size(); i++) {
1151: Node iterNode = iVisited.get(i);
1152: if (iterNode instanceof StrNode) {
1153: string.getByteList().append(
1154: ((StrNode) iterNode).getValue());
1155: } else {
1156: string.append(evalInternal(runtime, context, iterNode,
1157: self, aBlock));
1158: }
1159: }
1160:
1161: return self.callMethod(context, "`", string);
1162: }
1163:
1164: private static IRubyObject ensureNode(Ruby runtime,
1165: ThreadContext context, Node node, IRubyObject self,
1166: Block aBlock) {
1167: EnsureNode iVisited = (EnsureNode) node;
1168:
1169: // save entering the try if there's nothing to ensure
1170: if (iVisited.getEnsureNode() != null) {
1171: IRubyObject result = runtime.getNil();
1172:
1173: try {
1174: result = evalInternal(runtime, context, iVisited
1175: .getBodyNode(), self, aBlock);
1176: } finally {
1177: evalInternal(runtime, context,
1178: iVisited.getEnsureNode(), self, aBlock);
1179: }
1180:
1181: return result;
1182: }
1183:
1184: node = iVisited.getBodyNode();
1185: return evalInternal(runtime, context, node, self, aBlock);
1186: }
1187:
1188: private static IRubyObject evStrNode(Ruby runtime,
1189: ThreadContext context, Node node, IRubyObject self,
1190: Block aBlock) {
1191: return evalInternal(runtime, context,
1192: ((EvStrNode) node).getBody(), self, aBlock).asString();
1193: }
1194:
1195: private static IRubyObject falseNode(Ruby runtime,
1196: ThreadContext context) {
1197: return pollAndReturn(context, runtime.getFalse());
1198: }
1199:
1200: private static IRubyObject fCallNode(Ruby runtime,
1201: ThreadContext context, Node node, IRubyObject self,
1202: Block aBlock) {
1203: FCallNode iVisited = (FCallNode) node;
1204:
1205: IRubyObject[] args = setupArgs(runtime, context, iVisited
1206: .getArgsNode(), self);
1207: Block block = getBlock(runtime, context, self, aBlock, iVisited
1208: .getIterNode());
1209:
1210: String name = iVisited.getName();
1211: int index = iVisited.index;
1212:
1213: // No block provided lets look at fast path for STI dispatch.
1214: if (!block.isGiven()) {
1215: RubyModule module = self.getMetaClass();
1216: if (module.index != 0 && index != 0) {
1217: return self.callMethod(context, module, iVisited.index,
1218: name, args, CallType.FUNCTIONAL,
1219: Block.NULL_BLOCK);
1220: } else {
1221: DynamicMethod method = module.searchMethod(name);
1222: if (method.isUndefined()
1223: || (!method.isCallableFrom(self,
1224: CallType.FUNCTIONAL))) {
1225: return RubyObject.callMethodMissing(context, self,
1226: method, name, args, self,
1227: CallType.FUNCTIONAL, Block.NULL_BLOCK);
1228: }
1229:
1230: return method.call(context, self, module, name, args,
1231: false, Block.NULL_BLOCK);
1232: }
1233: }
1234:
1235: while (true) {
1236: try {
1237: RubyModule module = self.getMetaClass();
1238: IRubyObject result = self.callMethod(context, module,
1239: name, args, CallType.FUNCTIONAL, block);
1240: if (result == null) {
1241: result = runtime.getNil();
1242: }
1243:
1244: return result;
1245: } catch (JumpException je) {
1246: switch (je.getJumpType().getTypeId()) {
1247: case JumpType.RETRY:
1248: // allow loop to retry
1249: break;
1250: case JumpType.BREAK:
1251: // JRUBY-530, Kernel#loop case:
1252: if (je.isBreakInKernelLoop()) {
1253: // consume and rethrow or just keep rethrowing?
1254: if (block == je.getTarget())
1255: je.setBreakInKernelLoop(false);
1256:
1257: throw je;
1258: }
1259:
1260: return (IRubyObject) je.getValue();
1261: default:
1262: throw je;
1263: }
1264: }
1265: }
1266: }
1267:
1268: private static IRubyObject fixnumNode(Ruby runtime, Node node) {
1269: return ((FixnumNode) node).getFixnum(runtime);
1270: }
1271:
1272: private static IRubyObject flipNode(Ruby runtime,
1273: ThreadContext context, Node node, IRubyObject self,
1274: Block aBlock) {
1275: FlipNode iVisited = (FlipNode) node;
1276: IRubyObject result = runtime.getNil();
1277:
1278: if (iVisited.isExclusive()) {
1279: if (!context.getCurrentScope().getValue(
1280: iVisited.getIndex(), iVisited.getDepth()).isTrue()) {
1281: result = evalInternal(runtime, context,
1282: iVisited.getBeginNode(), self, aBlock).isTrue() ? runtime
1283: .getFalse()
1284: : runtime.getTrue();
1285: context.getCurrentScope().setValue(iVisited.getIndex(),
1286: result, iVisited.getDepth());
1287: return result;
1288: } else {
1289: if (evalInternal(runtime, context,
1290: iVisited.getEndNode(), self, aBlock).isTrue()) {
1291: context.getCurrentScope().setValue(
1292: iVisited.getIndex(), runtime.getFalse(),
1293: iVisited.getDepth());
1294: }
1295: return runtime.getTrue();
1296: }
1297: } else {
1298: if (!context.getCurrentScope().getValue(
1299: iVisited.getIndex(), iVisited.getDepth()).isTrue()) {
1300: if (evalInternal(runtime, context,
1301: iVisited.getBeginNode(), self, aBlock).isTrue()) {
1302: context
1303: .getCurrentScope()
1304: .setValue(
1305: iVisited.getIndex(),
1306: evalInternal(runtime, context,
1307: iVisited.getEndNode(),
1308: self, aBlock).isTrue() ? runtime
1309: .getFalse()
1310: : runtime.getTrue(),
1311: iVisited.getDepth());
1312: return runtime.getTrue();
1313: } else {
1314: return runtime.getFalse();
1315: }
1316: } else {
1317: if (evalInternal(runtime, context,
1318: iVisited.getEndNode(), self, aBlock).isTrue()) {
1319: context.getCurrentScope().setValue(
1320: iVisited.getIndex(), runtime.getFalse(),
1321: iVisited.getDepth());
1322: }
1323: return runtime.getTrue();
1324: }
1325: }
1326: }
1327:
1328: private static IRubyObject floatNode(Ruby runtime, Node node) {
1329: return RubyFloat.newFloat(runtime, ((FloatNode) node)
1330: .getValue());
1331: }
1332:
1333: private static IRubyObject forNode(Ruby runtime,
1334: ThreadContext context, Node node, IRubyObject self,
1335: Block aBlock) {
1336: ForNode iVisited = (ForNode) node;
1337:
1338: Block block = SharedScopeBlock.createSharedScopeBlock(context,
1339: iVisited, context.getCurrentScope(), self);
1340:
1341: try {
1342: while (true) {
1343: try {
1344: ISourcePosition position = context.getPosition();
1345:
1346: IRubyObject recv = null;
1347: try {
1348: recv = evalInternal(runtime, context, iVisited
1349: .getIterNode(), self, aBlock);
1350: } finally {
1351: context.setPosition(position);
1352: }
1353:
1354: return recv.callMethod(context, "each",
1355: IRubyObject.NULL_ARRAY, CallType.NORMAL,
1356: block);
1357: } catch (JumpException je) {
1358: switch (je.getJumpType().getTypeId()) {
1359: case JumpType.RETRY:
1360: // do nothing, allow loop to retry
1361: break;
1362: default:
1363: throw je;
1364: }
1365: }
1366: }
1367: } catch (JumpException je) {
1368: switch (je.getJumpType().getTypeId()) {
1369: case JumpType.BREAK:
1370: return (IRubyObject) je.getValue();
1371: default:
1372: throw je;
1373: }
1374: }
1375: }
1376:
1377: private static IRubyObject globalAsgnNode(Ruby runtime,
1378: ThreadContext context, Node node, IRubyObject self,
1379: Block aBlock) {
1380: GlobalAsgnNode iVisited = (GlobalAsgnNode) node;
1381:
1382: IRubyObject result = evalInternal(runtime, context, iVisited
1383: .getValueNode(), self, aBlock);
1384:
1385: if (iVisited.getName().length() == 2) {
1386: switch (iVisited.getName().charAt(1)) {
1387: case '_':
1388: context.getCurrentScope().setLastLine(result);
1389: return result;
1390: case '~':
1391: context.setBackref(result);
1392: return result;
1393: }
1394: }
1395:
1396: runtime.getGlobalVariables().set(iVisited.getName(), result);
1397:
1398: // FIXME: this should be encapsulated along with the set above
1399: if (iVisited.getName() == "$KCODE") {
1400: runtime.setKCode(KCode.create(runtime, result.toString()));
1401: }
1402:
1403: return result;
1404: }
1405:
1406: private static IRubyObject globalVarNode(Ruby runtime,
1407: ThreadContext context, Node node) {
1408: GlobalVarNode iVisited = (GlobalVarNode) node;
1409:
1410: if (iVisited.getName().length() == 2) {
1411: IRubyObject value = null;
1412: switch (iVisited.getName().charAt(1)) {
1413: case '_':
1414: value = context.getCurrentScope().getLastLine();
1415: if (value == null) {
1416: return runtime.getNil();
1417: }
1418: return value;
1419: case '~':
1420: value = context.getCurrentScope().getBackRef();
1421: if (value == null) {
1422: return runtime.getNil();
1423: }
1424: return value;
1425: }
1426: }
1427:
1428: return runtime.getGlobalVariables().get(iVisited.getName());
1429: }
1430:
1431: private static IRubyObject hashNode(Ruby runtime,
1432: ThreadContext context, Node node, IRubyObject self,
1433: Block aBlock) {
1434: HashNode iVisited = (HashNode) node;
1435:
1436: RubyHash hash = null;
1437: if (iVisited.getListNode() != null) {
1438: hash = RubyHash.newHash(runtime);
1439:
1440: for (int i = 0; i < iVisited.getListNode().size();) {
1441: // insert all nodes in sequence, hash them in the final instruction
1442: // KEY
1443: IRubyObject key = evalInternal(runtime, context,
1444: iVisited.getListNode().get(i++), self, aBlock);
1445: IRubyObject value = evalInternal(runtime, context,
1446: iVisited.getListNode().get(i++), self, aBlock);
1447:
1448: hash.fastASet(key, value);
1449: }
1450: }
1451:
1452: if (hash == null) {
1453: return RubyHash.newHash(runtime);
1454: }
1455:
1456: return hash;
1457: }
1458:
1459: private static IRubyObject instAsgnNode(Ruby runtime,
1460: ThreadContext context, Node node, IRubyObject self,
1461: Block aBlock) {
1462: InstAsgnNode iVisited = (InstAsgnNode) node;
1463:
1464: IRubyObject result = evalInternal(runtime, context, iVisited
1465: .getValueNode(), self, aBlock);
1466: self.setInstanceVariable(iVisited.getName(), result);
1467:
1468: return result;
1469: }
1470:
1471: private static IRubyObject instVarNode(Ruby runtime, Node node,
1472: IRubyObject self) {
1473: InstVarNode iVisited = (InstVarNode) node;
1474: IRubyObject variable = self.getInstanceVariable(iVisited
1475: .getName());
1476:
1477: return variable == null ? runtime.getNil() : variable;
1478: }
1479:
1480: private static IRubyObject localAsgnNode(Ruby runtime,
1481: ThreadContext context, Node node, IRubyObject self,
1482: Block aBlock) {
1483: LocalAsgnNode iVisited = (LocalAsgnNode) node;
1484: IRubyObject result = evalInternal(runtime, context, iVisited
1485: .getValueNode(), self, aBlock);
1486:
1487: //System.out.println("LSetting: " + iVisited.getName() + " at index " + iVisited.getIndex() + " and at depth " + iVisited.getDepth() + " and set " + result);
1488: context.getCurrentScope().setValue(iVisited.getIndex(), result,
1489: iVisited.getDepth());
1490:
1491: return result;
1492: }
1493:
1494: private static IRubyObject localVarNode(Ruby runtime,
1495: ThreadContext context, Node node) {
1496: LocalVarNode iVisited = (LocalVarNode) node;
1497:
1498: // System.out.println("DGetting: " + iVisited.getName() + " at index " + iVisited.getIndex() + " and at depth " + iVisited.getDepth());
1499: IRubyObject result = context.getCurrentScope().getValue(
1500: iVisited.getIndex(), iVisited.getDepth());
1501:
1502: return result == null ? runtime.getNil() : result;
1503: }
1504:
1505: private static IRubyObject match2Node(Ruby runtime,
1506: ThreadContext context, Node node, IRubyObject self,
1507: Block aBlock) {
1508: Match2Node iVisited = (Match2Node) node;
1509: IRubyObject recv = evalInternal(runtime, context, iVisited
1510: .getReceiverNode(), self, aBlock);
1511: IRubyObject value = evalInternal(runtime, context, iVisited
1512: .getValueNode(), self, aBlock);
1513:
1514: return ((RubyRegexp) recv).match(value);
1515: }
1516:
1517: private static IRubyObject match3Node(Ruby runtime,
1518: ThreadContext context, Node node, IRubyObject self,
1519: Block aBlock) {
1520: Match3Node iVisited = (Match3Node) node;
1521: IRubyObject recv = evalInternal(runtime, context, iVisited
1522: .getReceiverNode(), self, aBlock);
1523: IRubyObject value = evalInternal(runtime, context, iVisited
1524: .getValueNode(), self, aBlock);
1525:
1526: if (value instanceof RubyString) {
1527: return ((RubyRegexp) recv).match(value);
1528: } else {
1529: return value.callMethod(context, "=~", recv);
1530: }
1531: }
1532:
1533: private static IRubyObject matchNode(Ruby runtime,
1534: ThreadContext context, Node node, IRubyObject self,
1535: Block aBlock) {
1536: return ((RubyRegexp) evalInternal(runtime, context,
1537: ((MatchNode) node).getRegexpNode(), self, aBlock))
1538: .match2();
1539: }
1540:
1541: private static IRubyObject moduleNode(Ruby runtime,
1542: ThreadContext context, Node node, IRubyObject self,
1543: Block aBlock) {
1544: ModuleNode iVisited = (ModuleNode) node;
1545: Node classNameNode = iVisited.getCPath();
1546: String name = ((INameNode) classNameNode).getName();
1547: RubyModule enclosingModule = getEnclosingModule(runtime,
1548: context, classNameNode, self, aBlock);
1549:
1550: if (enclosingModule == null) {
1551: throw runtime.newTypeError("no outer class/module");
1552: }
1553:
1554: RubyModule module;
1555: if (enclosingModule == runtime.getObject()) {
1556: module = runtime.getOrCreateModule(name);
1557: } else {
1558: module = enclosingModule.defineModuleUnder(name);
1559: }
1560: return evalClassDefinitionBody(runtime, context, iVisited
1561: .getScope(), iVisited.getBodyNode(), module, self,
1562: aBlock);
1563: }
1564:
1565: private static IRubyObject multipleAsgnNode(Ruby runtime,
1566: ThreadContext context, Node node, IRubyObject self,
1567: Block aBlock) {
1568: MultipleAsgnNode iVisited = (MultipleAsgnNode) node;
1569:
1570: switch (iVisited.getValueNode().nodeId) {
1571: case NodeTypes.ARRAYNODE: {
1572: ArrayNode iVisited2 = (ArrayNode) iVisited.getValueNode();
1573: IRubyObject[] array = new IRubyObject[iVisited2.size()];
1574:
1575: for (int i = 0; i < iVisited2.size(); i++) {
1576: Node next = iVisited2.get(i);
1577:
1578: array[i] = evalInternal(runtime, context, next, self,
1579: aBlock);
1580: }
1581: return AssignmentVisitor.multiAssign(runtime, context,
1582: self, iVisited, RubyArray.newArrayNoCopyLight(
1583: runtime, array), false);
1584: }
1585: case NodeTypes.SPLATNODE: {
1586: SplatNode splatNode = (SplatNode) iVisited.getValueNode();
1587: RubyArray rubyArray = splatValue(runtime, evalInternal(
1588: runtime, context, ((SplatNode) splatNode)
1589: .getValue(), self, aBlock));
1590: return AssignmentVisitor.multiAssign(runtime, context,
1591: self, iVisited, rubyArray, false);
1592: }
1593: default:
1594: IRubyObject value = evalInternal(runtime, context, iVisited
1595: .getValueNode(), self, aBlock);
1596:
1597: if (!(value instanceof RubyArray)) {
1598: value = RubyArray.newArray(runtime, value);
1599: }
1600:
1601: return AssignmentVisitor.multiAssign(runtime, context,
1602: self, iVisited, (RubyArray) value, false);
1603: }
1604: }
1605:
1606: private static IRubyObject nextNode(Ruby runtime,
1607: ThreadContext context, Node node, IRubyObject self,
1608: Block aBlock) {
1609: NextNode iVisited = (NextNode) node;
1610:
1611: context.pollThreadEvents();
1612:
1613: IRubyObject result = evalInternal(runtime, context, iVisited
1614: .getValueNode(), self, aBlock);
1615:
1616: // now used as an interpreter event
1617: throw context.prepareJumpException(
1618: JumpException.JumpType.NextJump, iVisited, result);
1619: }
1620:
1621: private static IRubyObject nilNode(Ruby runtime,
1622: ThreadContext context) {
1623: return pollAndReturn(context, runtime.getNil());
1624: }
1625:
1626: private static IRubyObject notNode(Ruby runtime,
1627: ThreadContext context, Node node, IRubyObject self,
1628: Block aBlock) {
1629: NotNode iVisited = (NotNode) node;
1630:
1631: IRubyObject result = evalInternal(runtime, context, iVisited
1632: .getConditionNode(), self, aBlock);
1633: return result.isTrue() ? runtime.getFalse() : runtime.getTrue();
1634: }
1635:
1636: private static IRubyObject nthRefNode(ThreadContext context,
1637: Node node) {
1638: return RubyRegexp.nth_match(((NthRefNode) node)
1639: .getMatchNumber(), context.getBackref());
1640: }
1641:
1642: private static IRubyObject pollAndReturn(ThreadContext context,
1643: IRubyObject result) {
1644: context.pollThreadEvents();
1645: return result;
1646: }
1647:
1648: private static IRubyObject opAsgnNode(Ruby runtime,
1649: ThreadContext context, Node node, IRubyObject self,
1650: Block aBlock) {
1651: OpAsgnNode iVisited = (OpAsgnNode) node;
1652: IRubyObject receiver = evalInternal(runtime, context, iVisited
1653: .getReceiverNode(), self, aBlock);
1654: IRubyObject value = receiver.callMethod(context, iVisited
1655: .getVariableName());
1656:
1657: if (iVisited.getOperatorName() == "||") {
1658: if (value.isTrue()) {
1659: return pollAndReturn(context, value);
1660: }
1661: value = evalInternal(runtime, context, iVisited
1662: .getValueNode(), self, aBlock);
1663: } else if (iVisited.getOperatorName() == "&&") {
1664: if (!value.isTrue()) {
1665: return pollAndReturn(context, value);
1666: }
1667: value = evalInternal(runtime, context, iVisited
1668: .getValueNode(), self, aBlock);
1669: } else {
1670: value = value.callMethod(context, iVisited.index, iVisited
1671: .getOperatorName(), evalInternal(runtime, context,
1672: iVisited.getValueNode(), self, aBlock));
1673: }
1674:
1675: receiver.callMethod(context, iVisited.getVariableNameAsgn(),
1676: value);
1677:
1678: return pollAndReturn(context, value);
1679: }
1680:
1681: private static IRubyObject opAsgnOrNode(Ruby runtime,
1682: ThreadContext context, Node node, IRubyObject self,
1683: Block aBlock) {
1684: OpAsgnOrNode iVisited = (OpAsgnOrNode) node;
1685: String def = getDefinition(runtime, context, iVisited
1686: .getFirstNode(), self, aBlock);
1687:
1688: IRubyObject result = runtime.getNil();
1689: if (def != null) {
1690: result = evalInternal(runtime, context, iVisited
1691: .getFirstNode(), self, aBlock);
1692: }
1693: if (!result.isTrue()) {
1694: result = evalInternal(runtime, context, iVisited
1695: .getSecondNode(), self, aBlock);
1696: }
1697:
1698: return pollAndReturn(context, result);
1699: }
1700:
1701: private static IRubyObject opElementAsgnNode(Ruby runtime,
1702: ThreadContext context, Node node, IRubyObject self,
1703: Block aBlock) {
1704: OpElementAsgnNode iVisited = (OpElementAsgnNode) node;
1705: IRubyObject receiver = evalInternal(runtime, context, iVisited
1706: .getReceiverNode(), self, aBlock);
1707:
1708: IRubyObject[] args = setupArgs(runtime, context, iVisited
1709: .getArgsNode(), self);
1710:
1711: IRubyObject firstValue = receiver.callMethod(context,
1712: MethodIndex.AREF, "[]", args);
1713:
1714: if (iVisited.getOperatorName() == "||") {
1715: if (firstValue.isTrue()) {
1716: return firstValue;
1717: }
1718: firstValue = evalInternal(runtime, context, iVisited
1719: .getValueNode(), self, aBlock);
1720: } else if (iVisited.getOperatorName() == "&&") {
1721: if (!firstValue.isTrue()) {
1722: return firstValue;
1723: }
1724: firstValue = evalInternal(runtime, context, iVisited
1725: .getValueNode(), self, aBlock);
1726: } else {
1727: firstValue = firstValue.callMethod(context, iVisited.index,
1728: iVisited.getOperatorName(), evalInternal(runtime,
1729: context, iVisited.getValueNode(), self,
1730: aBlock));
1731: }
1732:
1733: IRubyObject[] expandedArgs = new IRubyObject[args.length + 1];
1734: System.arraycopy(args, 0, expandedArgs, 0, args.length);
1735: expandedArgs[expandedArgs.length - 1] = firstValue;
1736: return receiver.callMethod(context, MethodIndex.ASET, "[]=",
1737: expandedArgs);
1738: }
1739:
1740: private static IRubyObject optNNode(Ruby runtime,
1741: ThreadContext context, Node node, IRubyObject self,
1742: Block aBlock) {
1743: OptNNode iVisited = (OptNNode) node;
1744:
1745: IRubyObject result = runtime.getNil();
1746: outerLoop: while (RubyKernel.gets(runtime.getTopSelf(),
1747: IRubyObject.NULL_ARRAY).isTrue()) {
1748: loop: while (true) { // Used for the 'redo' command
1749: try {
1750: result = evalInternal(runtime, context, iVisited
1751: .getBodyNode(), self, aBlock);
1752: break;
1753: } catch (JumpException je) {
1754: switch (je.getJumpType().getTypeId()) {
1755: case JumpType.REDO:
1756: // do nothing, this iteration restarts
1757: break;
1758: case JumpType.NEXT:
1759: // recheck condition
1760: break loop;
1761: case JumpType.BREAK:
1762: // end loop
1763: result = (IRubyObject) je.getValue();
1764: break outerLoop;
1765: default:
1766: throw je;
1767: }
1768: }
1769: }
1770: }
1771:
1772: return pollAndReturn(context, result);
1773: }
1774:
1775: private static IRubyObject orNode(Ruby runtime,
1776: ThreadContext context, Node node, IRubyObject self,
1777: Block aBlock) {
1778: OrNode iVisited = (OrNode) node;
1779:
1780: IRubyObject result = evalInternal(runtime, context, iVisited
1781: .getFirstNode(), self, aBlock);
1782:
1783: if (!result.isTrue()) {
1784: result = evalInternal(runtime, context, iVisited
1785: .getSecondNode(), self, aBlock);
1786: }
1787:
1788: return result;
1789: }
1790:
1791: private static IRubyObject postExeNode(Ruby runtime,
1792: ThreadContext context, Node node, IRubyObject self,
1793: Block aBlock) {
1794: PostExeNode iVisited = (PostExeNode) node;
1795:
1796: // FIXME: I use a for block to implement END node because we need a proc which captures
1797: // its enclosing scope. ForBlock now represents these node and should be renamed.
1798: Block block = SharedScopeBlock.createSharedScopeBlock(context,
1799: iVisited, context.getCurrentScope(), self);
1800:
1801: runtime.pushExitBlock(runtime.newProc(true, block));
1802:
1803: return runtime.getNil();
1804: }
1805:
1806: private static IRubyObject redoNode(ThreadContext context, Node node) {
1807: context.pollThreadEvents();
1808:
1809: // now used as an interpreter event
1810: throw context.prepareJumpException(
1811: JumpException.JumpType.RedoJump, null, node);
1812: }
1813:
1814: private static IRubyObject regexpNode(Ruby runtime, Node node) {
1815: RegexpNode iVisited = (RegexpNode) node;
1816: String lang = null;
1817: int opts = iVisited.getOptions();
1818: if ((opts & 16) != 0) { // param n
1819: lang = "n";
1820: } else if ((opts & 48) != 0) { // param s
1821: lang = "s";
1822: } else if ((opts & 64) != 0) { // param s
1823: lang = "u";
1824: }
1825:
1826: IRubyObject noCaseGlobal = runtime.getGlobalVariables().get(
1827: "$=");
1828:
1829: int extraOptions = noCaseGlobal.isTrue() ? ReOptions.RE_OPTION_IGNORECASE
1830: : 0;
1831:
1832: try {
1833: return RubyRegexp.newRegexp(runtime, iVisited.getValue(),
1834: iVisited.getPattern(extraOptions), iVisited
1835: .getFlags(extraOptions), lang);
1836: } catch (jregex.PatternSyntaxException e) {
1837: throw runtime.newRegexpError(e.getMessage());
1838: }
1839: }
1840:
1841: private static IRubyObject rescueNode(Ruby runtime,
1842: ThreadContext context, Node node, IRubyObject self,
1843: Block aBlock) {
1844: RescueNode iVisited = (RescueNode) node;
1845: RescuedBlock: while (true) {
1846: IRubyObject globalExceptionState = runtime
1847: .getGlobalVariables().get("$!");
1848: boolean anotherExceptionRaised = false;
1849: try {
1850: // Execute rescue block
1851: IRubyObject result = evalInternal(runtime, context,
1852: iVisited.getBodyNode(), self, aBlock);
1853:
1854: // If no exception is thrown execute else block
1855: if (iVisited.getElseNode() != null) {
1856: if (iVisited.getRescueNode() == null) {
1857: runtime.getWarnings().warn(
1858: iVisited.getElseNode().getPosition(),
1859: "else without rescue is useless");
1860: }
1861: result = evalInternal(runtime, context, iVisited
1862: .getElseNode(), self, aBlock);
1863: }
1864:
1865: return result;
1866: } catch (RaiseException raiseJump) {
1867: RubyException raisedException = raiseJump
1868: .getException();
1869: // TODO: Rubicon TestKernel dies without this line. A cursory glance implies we
1870: // falsely set $! to nil and this sets it back to something valid. This should
1871: // get fixed at the same time we address bug #1296484.
1872: runtime.getGlobalVariables().set("$!", raisedException);
1873:
1874: RescueBodyNode rescueNode = iVisited.getRescueNode();
1875:
1876: while (rescueNode != null) {
1877: Node exceptionNodes = rescueNode
1878: .getExceptionNodes();
1879: ListNode exceptionNodesList;
1880:
1881: if (exceptionNodes instanceof SplatNode) {
1882: exceptionNodesList = (ListNode) evalInternal(
1883: runtime, context, exceptionNodes, self,
1884: aBlock);
1885: } else {
1886: exceptionNodesList = (ListNode) exceptionNodes;
1887: }
1888:
1889: if (isRescueHandled(runtime, context,
1890: raisedException, exceptionNodesList, self)) {
1891: try {
1892: return evalInternal(runtime, context,
1893: rescueNode, self, aBlock);
1894: } catch (JumpException je) {
1895: if (je.getJumpType() == JumpException.JumpType.RetryJump) {
1896: // should be handled in the finally block below
1897: //state.runtime.getGlobalVariables().set("$!", state.runtime.getNil());
1898: //state.threadContext.setRaisedException(null);
1899: continue RescuedBlock;
1900:
1901: } else {
1902: anotherExceptionRaised = true;
1903: throw je;
1904: }
1905: }
1906: }
1907:
1908: rescueNode = rescueNode.getOptRescueNode();
1909: }
1910:
1911: // no takers; bubble up
1912: throw raiseJump;
1913: } finally {
1914: // clear exception when handled or retried
1915: if (!anotherExceptionRaised)
1916: runtime.getGlobalVariables().set("$!",
1917: globalExceptionState);
1918: }
1919: }
1920: }
1921:
1922: private static IRubyObject retryNode(ThreadContext context) {
1923: context.pollThreadEvents();
1924:
1925: throw context.prepareJumpException(
1926: JumpException.JumpType.RetryJump, null, null);
1927: }
1928:
1929: private static IRubyObject returnNode(Ruby runtime,
1930: ThreadContext context, Node node, IRubyObject self,
1931: Block aBlock) {
1932: ReturnNode iVisited = (ReturnNode) node;
1933:
1934: IRubyObject result = evalInternal(runtime, context, iVisited
1935: .getValueNode(), self, aBlock);
1936:
1937: throw context.prepareJumpException(
1938: JumpException.JumpType.ReturnJump, context
1939: .getFrameJumpTarget(), result);
1940: }
1941:
1942: private static IRubyObject rootNode(Ruby runtime,
1943: ThreadContext context, Node node, IRubyObject self,
1944: Block aBlock) {
1945: RootNode iVisited = (RootNode) node;
1946: DynamicScope scope = iVisited.getScope();
1947:
1948: // Serialization killed our dynamic scope. We can just create an empty one
1949: // since serialization cannot serialize an eval (which is the only thing
1950: // which is capable of having a non-empty dynamic scope).
1951: if (scope == null) {
1952: scope = new DynamicScope(iVisited.getStaticScope());
1953: }
1954:
1955: // Each root node has a top-level scope that we need to push
1956: context.preRootNode(scope);
1957:
1958: // FIXME: Wire up BEGIN and END nodes
1959:
1960: try {
1961: return evalInternal(runtime, context, iVisited
1962: .getBodyNode(), self, aBlock);
1963: } finally {
1964: context.postRootNode();
1965: }
1966: }
1967:
1968: private static IRubyObject sClassNode(Ruby runtime,
1969: ThreadContext context, Node node, IRubyObject self,
1970: Block aBlock) {
1971: SClassNode iVisited = (SClassNode) node;
1972: IRubyObject receiver = evalInternal(runtime, context, iVisited
1973: .getReceiverNode(), self, aBlock);
1974:
1975: RubyClass singletonClass;
1976:
1977: if (receiver.isNil()) {
1978: singletonClass = runtime.getNilClass();
1979: } else if (receiver == runtime.getTrue()) {
1980: singletonClass = runtime.getClass("TrueClass");
1981: } else if (receiver == runtime.getFalse()) {
1982: singletonClass = runtime.getClass("FalseClass");
1983: } else if (receiver.getMetaClass() == runtime.getFixnum()
1984: || receiver.getMetaClass() == runtime
1985: .getClass("Symbol")) {
1986: throw runtime.newTypeError("no virtual class for "
1987: + receiver.getMetaClass().getBaseName());
1988: } else {
1989: if (runtime.getSafeLevel() >= 4 && !receiver.isTaint()) {
1990: throw runtime
1991: .newSecurityError("Insecure: can't extend object.");
1992: }
1993:
1994: singletonClass = receiver.getSingletonClass();
1995: }
1996:
1997: return evalClassDefinitionBody(runtime, context, iVisited
1998: .getScope(), iVisited.getBodyNode(), singletonClass,
1999: self, aBlock);
2000: }
2001:
2002: private static IRubyObject splatNode(Ruby runtime,
2003: ThreadContext context, Node node, IRubyObject self,
2004: Block aBlock) {
2005: return splatValue(runtime, evalInternal(runtime, context,
2006: ((SplatNode) node).getValue(), self, aBlock));
2007: }
2008:
2009: private static IRubyObject strNode(Ruby runtime, Node node) {
2010: return runtime.newStringShared((ByteList) ((StrNode) node)
2011: .getValue());
2012: }
2013:
2014: private static IRubyObject super Node(Ruby runtime,
2015: ThreadContext context, Node node, IRubyObject self,
2016: Block aBlock) {
2017: SuperNode iVisited = (SuperNode) node;
2018:
2019: RubyModule klazz = context.getFrameKlazz();
2020:
2021: if (klazz == null) {
2022: String name = context.getFrameName();
2023: throw runtime.newNameError("Superclass method '" + name
2024: + "' disabled.", name);
2025: }
2026: IRubyObject[] args = setupArgs(runtime, context, iVisited
2027: .getArgsNode(), self);
2028: Block block = getBlock(runtime, context, self, aBlock, iVisited
2029: .getIterNode());
2030:
2031: // If no explicit block passed to super, then use the one passed in.
2032: if (!block.isGiven())
2033: block = aBlock;
2034:
2035: return self.callSuper(context, args, block);
2036: }
2037:
2038: private static IRubyObject sValueNode(Ruby runtime,
2039: ThreadContext context, Node node, IRubyObject self,
2040: Block aBlock) {
2041: return aValueSplat(runtime, evalInternal(runtime, context,
2042: ((SValueNode) node).getValue(), self, aBlock));
2043: }
2044:
2045: private static IRubyObject symbolNode(Ruby runtime, Node node) {
2046: return runtime.newSymbol(((SymbolNode) node).getName());
2047: }
2048:
2049: private static IRubyObject toAryNode(Ruby runtime,
2050: ThreadContext context, Node node, IRubyObject self,
2051: Block aBlock) {
2052: return aryToAry(runtime, evalInternal(runtime, context,
2053: ((ToAryNode) node).getValue(), self, aBlock));
2054: }
2055:
2056: private static IRubyObject trueNode(Ruby runtime,
2057: ThreadContext context) {
2058: return pollAndReturn(context, runtime.getTrue());
2059: }
2060:
2061: private static IRubyObject undefNode(Ruby runtime,
2062: ThreadContext context, Node node) {
2063: UndefNode iVisited = (UndefNode) node;
2064:
2065: if (context.getRubyClass() == null) {
2066: throw runtime.newTypeError("No class to undef method '"
2067: + iVisited.getName() + "'.");
2068: }
2069: context.getRubyClass().undef(iVisited.getName());
2070:
2071: return runtime.getNil();
2072: }
2073:
2074: private static IRubyObject untilNode(Ruby runtime,
2075: ThreadContext context, Node node, IRubyObject self,
2076: Block aBlock) {
2077: UntilNode iVisited = (UntilNode) node;
2078:
2079: IRubyObject result = runtime.getNil();
2080: boolean firstTest = iVisited.evaluateAtStart();
2081:
2082: outerLoop: while (!firstTest
2083: || !(result = evalInternal(runtime, context, iVisited
2084: .getConditionNode(), self, aBlock)).isTrue()) {
2085: firstTest = true;
2086: loop: while (true) { // Used for the 'redo' command
2087: try {
2088: result = evalInternal(runtime, context, iVisited
2089: .getBodyNode(), self, aBlock);
2090: break loop;
2091: } catch (JumpException je) {
2092: switch (je.getJumpType().getTypeId()) {
2093: case JumpType.REDO:
2094: continue;
2095: case JumpType.NEXT:
2096: break loop;
2097: case JumpType.BREAK:
2098: // JRUBY-530 until case
2099: if (je.getTarget() == aBlock) {
2100: je.setTarget(null);
2101:
2102: throw je;
2103: }
2104:
2105: result = (IRubyObject) je.getValue();
2106:
2107: break outerLoop;
2108: default:
2109: throw je;
2110: }
2111: }
2112: }
2113: }
2114:
2115: return pollAndReturn(context, result);
2116: }
2117:
2118: private static IRubyObject valiasNode(Ruby runtime, Node node) {
2119: VAliasNode iVisited = (VAliasNode) node;
2120: runtime.getGlobalVariables().alias(iVisited.getNewName(),
2121: iVisited.getOldName());
2122:
2123: return runtime.getNil();
2124: }
2125:
2126: private static IRubyObject vcallNode(Ruby runtime,
2127: ThreadContext context, Node node, IRubyObject self) {
2128: VCallNode iVisited = (VCallNode) node;
2129: RubyModule module = self.getMetaClass();
2130: String name = iVisited.getName();
2131: int index = iVisited.index;
2132:
2133: if (module.index != 0 && index != 0) {
2134: return self.callMethod(context, module, index, name,
2135: IRubyObject.NULL_ARRAY, CallType.VARIABLE,
2136: Block.NULL_BLOCK);
2137: } else {
2138: DynamicMethod method = module.searchMethod(name);
2139:
2140: if (method.isUndefined()
2141: || (index != MethodIndex.METHOD_MISSING && !method
2142: .isCallableFrom(self, CallType.VARIABLE))) {
2143: return RubyObject.callMethodMissing(context, self,
2144: method, name, index, IRubyObject.NULL_ARRAY,
2145: self, CallType.VARIABLE, Block.NULL_BLOCK);
2146: }
2147:
2148: return method.call(context, self, module, name,
2149: IRubyObject.NULL_ARRAY, false, Block.NULL_BLOCK);
2150: }
2151: }
2152:
2153: private static IRubyObject whileNode(Ruby runtime,
2154: ThreadContext context, Node node, IRubyObject self,
2155: Block aBlock) {
2156: WhileNode iVisited = (WhileNode) node;
2157:
2158: IRubyObject result = runtime.getNil();
2159: boolean firstTest = iVisited.evaluateAtStart();
2160:
2161: outerLoop: while (!firstTest
2162: || (result = evalInternal(runtime, context, iVisited
2163: .getConditionNode(), self, aBlock)).isTrue()) {
2164: firstTest = true;
2165: loop: while (true) { // Used for the 'redo' command
2166: try {
2167: evalInternal(runtime, context, iVisited
2168: .getBodyNode(), self, aBlock);
2169: break loop;
2170: } catch (RaiseException re) {
2171: if (re.getException().isKindOf(
2172: runtime.getClass("LocalJumpError"))) {
2173: RubyLocalJumpError jumpError = (RubyLocalJumpError) re
2174: .getException();
2175:
2176: IRubyObject reason = jumpError.reason();
2177:
2178: // admittedly inefficient
2179: if (reason.asSymbol().equals("break")) {
2180: return jumpError.exitValue();
2181: } else if (reason.asSymbol().equals("next")) {
2182: break loop;
2183: } else if (reason.asSymbol().equals("redo")) {
2184: continue;
2185: }
2186: }
2187:
2188: throw re;
2189: } catch (JumpException je) {
2190: switch (je.getJumpType().getTypeId()) {
2191: case JumpType.REDO:
2192: continue;
2193: case JumpType.NEXT:
2194: break loop;
2195: case JumpType.BREAK:
2196: // JRUBY-530, while case
2197: if (je.getTarget() == aBlock) {
2198: je.setTarget(null);
2199:
2200: throw je;
2201: }
2202:
2203: break outerLoop;
2204: default:
2205: throw je;
2206: }
2207: }
2208: }
2209: }
2210:
2211: return pollAndReturn(context, result);
2212: }
2213:
2214: private static IRubyObject xStrNode(Ruby runtime,
2215: ThreadContext context, Node node, IRubyObject self) {
2216: return self.callMethod(context, "`", runtime
2217: .newStringShared((ByteList) ((XStrNode) node)
2218: .getValue()));
2219: }
2220:
2221: private static IRubyObject yieldNode(Ruby runtime,
2222: ThreadContext context, Node node, IRubyObject self,
2223: Block aBlock) {
2224: YieldNode iVisited = (YieldNode) node;
2225:
2226: IRubyObject result = null;
2227: if (iVisited.getArgsNode() != null) {
2228: result = evalInternal(runtime, context, iVisited
2229: .getArgsNode(), self, aBlock);
2230: }
2231:
2232: Block block = context.getCurrentFrame().getBlock();
2233:
2234: return block.yield(context, result, null, null, iVisited
2235: .getCheckState());
2236: }
2237:
2238: private static IRubyObject zArrayNode(Ruby runtime) {
2239: return runtime.newArray();
2240: }
2241:
2242: private static IRubyObject zsuper Node(Ruby runtime,
2243: ThreadContext context, Node node, IRubyObject self,
2244: Block aBlock) {
2245: if (context.getFrameKlazz() == null) {
2246: String name = context.getFrameName();
2247: throw runtime.newNameError("superclass method '" + name
2248: + "' disabled", name);
2249: }
2250:
2251: Block block = getBlock(runtime, context, self, aBlock,
2252: ((ZSuperNode) node).getIterNode());
2253:
2254: // Has the method that is calling super received a block argument
2255: if (!block.isGiven())
2256: block = context.getCurrentFrame().getBlock();
2257:
2258: context.getCurrentScope().getArgValues(context.getFrameArgs(),
2259: context.getCurrentFrame().getRequiredArgCount());
2260: return self.callSuper(context, context.getFrameArgs(), block);
2261: }
2262:
2263: public static IRubyObject aValueSplat(Ruby runtime,
2264: IRubyObject value) {
2265: if (!(value instanceof RubyArray)
2266: || ((RubyArray) value).length().getLongValue() == 0) {
2267: return runtime.getNil();
2268: }
2269:
2270: RubyArray array = (RubyArray) value;
2271:
2272: return array.getLength() == 1 ? array
2273: .first(IRubyObject.NULL_ARRAY) : array;
2274: }
2275:
2276: private static void callTraceFunction(Ruby runtime,
2277: ThreadContext context, int event) {
2278: String name = context.getFrameName();
2279: RubyModule type = context.getFrameKlazz();
2280: runtime.callEventHooks(context, event, context.getPosition()
2281: .getFile(), context.getPosition().getStartLine(), name,
2282: type);
2283: }
2284:
2285: /** Evaluates the body in a class or module definition statement.
2286: *
2287: */
2288: private static IRubyObject evalClassDefinitionBody(Ruby runtime,
2289: ThreadContext context, StaticScope scope, Node bodyNode,
2290: RubyModule type, IRubyObject self, Block block) {
2291: context.preClassEval(scope, type);
2292:
2293: try {
2294: if (isTrace(runtime)) {
2295: callTraceFunction(runtime, context,
2296: EventHook.RUBY_EVENT_CLASS);
2297: }
2298:
2299: return evalInternal(runtime, context, bodyNode, type, block);
2300: } finally {
2301: if (isTrace(runtime)) {
2302: callTraceFunction(runtime, context,
2303: EventHook.RUBY_EVENT_END);
2304: }
2305:
2306: context.postClassEval();
2307: }
2308: }
2309:
2310: private static String getArgumentDefinition(Ruby runtime,
2311: ThreadContext context, Node node, String type,
2312: IRubyObject self, Block block) {
2313: if (node == null)
2314: return type;
2315:
2316: if (node instanceof ArrayNode) {
2317: for (int i = 0; i < ((ArrayNode) node).size(); i++) {
2318: Node iterNode = ((ArrayNode) node).get(i);
2319: if (getDefinitionInner(runtime, context, iterNode,
2320: self, block) == null)
2321: return null;
2322: }
2323: } else if (getDefinitionInner(runtime, context, node, self,
2324: block) == null) {
2325: return null;
2326: }
2327:
2328: return type;
2329: }
2330:
2331: public static Block getBlock(Ruby runtime, ThreadContext context,
2332: IRubyObject self, Block currentBlock, Node blockNode) {
2333: if (blockNode == null)
2334: return Block.NULL_BLOCK;
2335:
2336: if (blockNode instanceof IterNode) {
2337: IterNode iterNode = (IterNode) blockNode;
2338: // Create block for this iter node
2339: // FIXME: We shouldn't use the current scope if it's not actually from the same hierarchy of static scopes
2340: return Block.createBlock(context, iterNode,
2341: new DynamicScope(iterNode.getScope(), context
2342: .getCurrentScope()), self);
2343: } else if (blockNode instanceof BlockPassNode) {
2344: BlockPassNode blockPassNode = (BlockPassNode) blockNode;
2345: IRubyObject proc = evalInternal(runtime, context,
2346: blockPassNode.getBodyNode(), self, currentBlock);
2347:
2348: // No block from a nil proc
2349: if (proc.isNil())
2350: return Block.NULL_BLOCK;
2351:
2352: // If not already a proc then we should try and make it one.
2353: if (!(proc instanceof RubyProc)) {
2354: proc = proc.convertToType(runtime.getClass("Proc"), 0,
2355: "to_proc", false);
2356:
2357: if (!(proc instanceof RubyProc)) {
2358: throw runtime.newTypeError("wrong argument type "
2359: + proc.getMetaClass().getName()
2360: + " (expected Proc)");
2361: }
2362: }
2363:
2364: // TODO: Add safety check for taintedness
2365:
2366: if (currentBlock.isGiven()) {
2367: RubyProc procObject = currentBlock.getProcObject();
2368: // The current block is already associated with proc. No need to create a new one
2369: if (procObject != null && procObject == proc)
2370: return currentBlock;
2371: }
2372:
2373: return ((RubyProc) proc).getBlock();
2374: }
2375:
2376: assert false : "Trying to get block from something which cannot deliver";
2377: return null;
2378: }
2379:
2380: /* Something like cvar_cbase() from eval.c, factored out for the benefit
2381: * of all the classvar-related node evaluations */
2382: public static RubyModule getClassVariableBase(
2383: ThreadContext context, Ruby runtime) {
2384: SinglyLinkedList cref = context.peekCRef();
2385: RubyModule rubyClass = (RubyModule) cref.getValue();
2386: if (rubyClass.isSingleton()) {
2387: cref = cref.getNext();
2388: rubyClass = (RubyModule) cref.getValue();
2389: if (cref.getNext() == null) {
2390: runtime
2391: .getWarnings()
2392: .warn(
2393: "class variable access from toplevel singleton method");
2394: }
2395: }
2396: return rubyClass;
2397: }
2398:
2399: private static String getDefinition(Ruby runtime,
2400: ThreadContext context, Node node, IRubyObject self,
2401: Block aBlock) {
2402: try {
2403: context.setWithinDefined(true);
2404: return getDefinitionInner(runtime, context, node, self,
2405: aBlock);
2406: } finally {
2407: context.setWithinDefined(false);
2408: }
2409: }
2410:
2411: private static String getDefinitionInner(Ruby runtime,
2412: ThreadContext context, Node node, IRubyObject self,
2413: Block aBlock) {
2414: if (node == null)
2415: return "expression";
2416:
2417: switch (node.nodeId) {
2418: case NodeTypes.ATTRASSIGNNODE: {
2419: AttrAssignNode iVisited = (AttrAssignNode) node;
2420:
2421: if (getDefinitionInner(runtime, context, iVisited
2422: .getReceiverNode(), self, aBlock) != null) {
2423: try {
2424: IRubyObject receiver = eval(runtime, context,
2425: iVisited.getReceiverNode(), self, aBlock);
2426: RubyClass metaClass = receiver.getMetaClass();
2427: DynamicMethod method = metaClass
2428: .searchMethod(iVisited.getName());
2429: Visibility visibility = method.getVisibility();
2430:
2431: if (!visibility.isPrivate()
2432: && (!visibility.isProtected() || self
2433: .isKindOf(metaClass.getRealClass()))) {
2434: if (metaClass.isMethodBound(iVisited.getName(),
2435: false)) {
2436: return getArgumentDefinition(runtime,
2437: context, iVisited.getArgsNode(),
2438: "assignment", self, aBlock);
2439: }
2440: }
2441: } catch (JumpException excptn) {
2442: }
2443: }
2444:
2445: return null;
2446: }
2447: case NodeTypes.BACKREFNODE:
2448: return "$" + ((BackRefNode) node).getType();
2449: case NodeTypes.CALLNODE: {
2450: CallNode iVisited = (CallNode) node;
2451:
2452: if (getDefinitionInner(runtime, context, iVisited
2453: .getReceiverNode(), self, aBlock) != null) {
2454: try {
2455: IRubyObject receiver = eval(runtime, context,
2456: iVisited.getReceiverNode(), self, aBlock);
2457: RubyClass metaClass = receiver.getMetaClass();
2458: DynamicMethod method = metaClass
2459: .searchMethod(iVisited.getName());
2460: Visibility visibility = method.getVisibility();
2461:
2462: if (!visibility.isPrivate()
2463: && (!visibility.isProtected() || self
2464: .isKindOf(metaClass.getRealClass()))) {
2465: if (metaClass.isMethodBound(iVisited.getName(),
2466: false)) {
2467: return getArgumentDefinition(runtime,
2468: context, iVisited.getArgsNode(),
2469: "method", self, aBlock);
2470: }
2471: }
2472: } catch (JumpException excptn) {
2473: }
2474: }
2475:
2476: return null;
2477: }
2478: case NodeTypes.CLASSVARASGNNODE:
2479: case NodeTypes.CLASSVARDECLNODE:
2480: case NodeTypes.CONSTDECLNODE:
2481: case NodeTypes.DASGNNODE:
2482: case NodeTypes.GLOBALASGNNODE:
2483: case NodeTypes.LOCALASGNNODE:
2484: case NodeTypes.MULTIPLEASGNNODE:
2485: case NodeTypes.OPASGNNODE:
2486: case NodeTypes.OPELEMENTASGNNODE:
2487: return "assignment";
2488:
2489: case NodeTypes.CLASSVARNODE: {
2490: ClassVarNode iVisited = (ClassVarNode) node;
2491:
2492: if (context.getRubyClass() == null
2493: && self.getMetaClass().isClassVarDefined(
2494: iVisited.getName())) {
2495: return "class_variable";
2496: } else if (!context.getRubyClass().isSingleton()
2497: && context.getRubyClass().isClassVarDefined(
2498: iVisited.getName())) {
2499: return "class_variable";
2500: }
2501:
2502: IRubyObject attached = context.getRubyClass()
2503: .getInstanceVariable("__attached__");
2504: if (attached instanceof RubyModule) {
2505: RubyModule module = (RubyModule) attached;
2506: if (module.isClassVarDefined(iVisited.getName()))
2507: return "class_variable";
2508: }
2509:
2510: return null;
2511: }
2512: case NodeTypes.COLON3NODE:
2513: case NodeTypes.COLON2NODE: {
2514: Colon3Node iVisited = (Colon3Node) node;
2515:
2516: try {
2517: IRubyObject left = runtime.getObject();
2518: if (iVisited instanceof Colon2Node) {
2519: left = EvaluationState.eval(runtime, context,
2520: ((Colon2Node) iVisited).getLeftNode(),
2521: self, aBlock);
2522: }
2523:
2524: if (left instanceof RubyModule
2525: && ((RubyModule) left).getConstantAt(iVisited
2526: .getName()) != null) {
2527: return "constant";
2528: } else if (left.getMetaClass().isMethodBound(
2529: iVisited.getName(), true)) {
2530: return "method";
2531: }
2532: } catch (JumpException excptn) {
2533: }
2534:
2535: return null;
2536: }
2537: case NodeTypes.CONSTNODE:
2538: if (context
2539: .getConstantDefined(((ConstNode) node).getName())) {
2540: return "constant";
2541: }
2542: return null;
2543: case NodeTypes.DVARNODE:
2544: return "local-variable(in-block)";
2545: case NodeTypes.FALSENODE:
2546: return "false";
2547: case NodeTypes.FCALLNODE: {
2548: FCallNode iVisited = (FCallNode) node;
2549: if (self.getMetaClass().isMethodBound(iVisited.getName(),
2550: false)) {
2551: return getArgumentDefinition(runtime, context, iVisited
2552: .getArgsNode(), "method", self, aBlock);
2553: }
2554:
2555: return null;
2556: }
2557: case NodeTypes.GLOBALVARNODE:
2558: if (runtime.getGlobalVariables().isDefined(
2559: ((GlobalVarNode) node).getName())) {
2560: return "global-variable";
2561: }
2562: return null;
2563: case NodeTypes.INSTVARNODE:
2564: if (self
2565: .getInstanceVariable(((InstVarNode) node).getName()) != null) {
2566: return "instance-variable";
2567: }
2568: return null;
2569: case NodeTypes.LOCALVARNODE:
2570: return "local-variable";
2571: case NodeTypes.MATCH2NODE:
2572: case NodeTypes.MATCH3NODE:
2573: return "method";
2574: case NodeTypes.NILNODE:
2575: return "nil";
2576: case NodeTypes.NTHREFNODE:
2577: return "$" + ((NthRefNode) node).getMatchNumber();
2578: case NodeTypes.SELFNODE:
2579: return "state.getSelf()";
2580: case NodeTypes.SUPERNODE: {
2581: SuperNode iVisited = (SuperNode) node;
2582: String name = context.getFrameName();
2583: RubyModule klazz = context.getFrameKlazz();
2584: if (name != null && klazz != null
2585: && klazz.getSuperClass().isMethodBound(name, false)) {
2586: return getArgumentDefinition(runtime, context, iVisited
2587: .getArgsNode(), "super", self, aBlock);
2588: }
2589:
2590: return null;
2591: }
2592: case NodeTypes.TRUENODE:
2593: return "true";
2594: case NodeTypes.VCALLNODE: {
2595: VCallNode iVisited = (VCallNode) node;
2596: if (self.getMetaClass().isMethodBound(iVisited.getName(),
2597: false)) {
2598: return "method";
2599: }
2600:
2601: return null;
2602: }
2603: case NodeTypes.YIELDNODE:
2604: return aBlock.isGiven() ? "yield" : null;
2605: case NodeTypes.ZSUPERNODE: {
2606: String name = context.getFrameName();
2607: RubyModule klazz = context.getFrameKlazz();
2608: if (name != null && klazz != null
2609: && klazz.getSuperClass().isMethodBound(name, false)) {
2610: return "super";
2611: }
2612: return null;
2613: }
2614: default:
2615: try {
2616: EvaluationState.eval(runtime, context, node, self,
2617: aBlock);
2618: return "expression";
2619: } catch (JumpException jumpExcptn) {
2620: }
2621: }
2622:
2623: return null;
2624: }
2625:
2626: private static RubyModule getEnclosingModule(Ruby runtime,
2627: ThreadContext context, Node node, IRubyObject self,
2628: Block block) {
2629: RubyModule enclosingModule = null;
2630:
2631: if (node instanceof Colon2Node) {
2632: IRubyObject result = evalInternal(runtime, context,
2633: ((Colon2Node) node).getLeftNode(), self, block);
2634:
2635: if (result != null && !result.isNil()) {
2636: enclosingModule = (RubyModule) result;
2637: }
2638: } else if (node instanceof Colon3Node) {
2639: enclosingModule = runtime.getObject();
2640: }
2641:
2642: if (enclosingModule == null) {
2643: enclosingModule = (RubyModule) context.peekCRef()
2644: .getValue();
2645: }
2646:
2647: return enclosingModule;
2648: }
2649:
2650: private static boolean isRescueHandled(Ruby runtime,
2651: ThreadContext context, RubyException currentException,
2652: ListNode exceptionNodes, IRubyObject self) {
2653: if (exceptionNodes == null) {
2654: return currentException.isKindOf(runtime
2655: .getClass("StandardError"));
2656: }
2657:
2658: IRubyObject[] args = setupArgs(runtime, context,
2659: exceptionNodes, self);
2660:
2661: for (int i = 0; i < args.length; i++) {
2662: if (!args[i].isKindOf(runtime.getClass("Module"))) {
2663: throw runtime
2664: .newTypeError("class or module required for rescue clause");
2665: }
2666: if (args[i].callMethod(context, "===", currentException)
2667: .isTrue())
2668: return true;
2669: }
2670: return false;
2671: }
2672:
2673: /**
2674: * Helper method.
2675: *
2676: * test if a trace function is avaiable.
2677: *
2678: */
2679: private static boolean isTrace(Ruby runtime) {
2680: return runtime.hasEventHooks();
2681: }
2682:
2683: private static IRubyObject[] setupArgs(Ruby runtime,
2684: ThreadContext context, Node node, IRubyObject self) {
2685: if (node == null)
2686: return IRubyObject.NULL_ARRAY;
2687:
2688: if (node instanceof ArrayNode) {
2689: ArrayNode argsArrayNode = (ArrayNode) node;
2690: ISourcePosition position = context.getPosition();
2691: int size = argsArrayNode.size();
2692: IRubyObject[] argsArray = new IRubyObject[size];
2693:
2694: for (int i = 0; i < size; i++) {
2695: argsArray[i] = evalInternal(runtime, context,
2696: argsArrayNode.get(i), self, Block.NULL_BLOCK);
2697: }
2698:
2699: context.setPosition(position);
2700:
2701: return argsArray;
2702: }
2703:
2704: return ArgsUtil.convertToJavaArray(evalInternal(runtime,
2705: context, node, self, Block.NULL_BLOCK));
2706: }
2707:
2708: public static RubyArray splatValue(Ruby runtime, IRubyObject value) {
2709: if (value.isNil()) {
2710: return runtime.newArray(value);
2711: }
2712:
2713: return arrayValue(runtime, value);
2714: }
2715: }
|