예제 #1
0
  /**
   * Evaluate the given string under the specified binding object. If the binding is not a Proc or
   * Binding object (RubyProc or RubyBinding) throw an appropriate type error.
   *
   * @param context the thread context for the current thread
   * @param self the self against which eval was called; used as self in the eval in 1.9 mode
   * @param src The string containing the text to be evaluated
   * @param binding The binding object under which to perform the evaluation
   * @return An IRubyObject result from the evaluation
   */
  public static IRubyObject evalWithBinding(
      ThreadContext context, IRubyObject self, IRubyObject src, Binding binding) {
    Ruby runtime = src.getRuntime();
    DynamicScope evalScope;

    if (runtime.is1_9()) {
      // in 1.9, eval scopes are local to the binding
      evalScope = binding.getEvalScope(runtime);
    } else {
      // in 1.8, eval scopes are local to the parent scope
      evalScope = binding.getDynamicScope().getEvalScope(runtime);
    }

    // FIXME:  This determine module is in a strange location and should somehow be in block
    evalScope.getStaticScope().determineModule();

    Frame lastFrame = context.preEvalWithBinding(binding);
    try {
      // Binding provided for scope, use it
      RubyString source = src.convertToString();
      Node node =
          runtime.parseEval(source.getByteList(), binding.getFile(), evalScope, binding.getLine());
      Block block = binding.getFrame().getBlock();

      if (runtime.getInstanceConfig().getCompileMode() == CompileMode.OFFIR) {
        // SSS FIXME: AST interpreter passed both a runtime (which comes from the source string)
        // and the thread-context rather than fetch one from the other.  Why is that?
        return Interpreter.interpretBindingEval(
            runtime, binding.getFile(), binding.getLine(), binding.getMethod(), node, self, block);
      } else {
        return INTERPRET_EVAL(
            runtime,
            context,
            binding.getFile(),
            binding.getLine(),
            node,
            binding.getMethod(),
            self,
            block);
      }
    } catch (JumpException.BreakJump bj) {
      throw runtime.newLocalJumpError(
          RubyLocalJumpError.Reason.BREAK, (IRubyObject) bj.getValue(), "unexpected break");
    } catch (JumpException.RedoJump rj) {
      throw runtime.newLocalJumpError(
          RubyLocalJumpError.Reason.REDO, (IRubyObject) rj.getValue(), "unexpected redo");
    } catch (StackOverflowError soe) {
      throw runtime.newSystemStackError("stack level too deep", soe);
    } finally {
      context.postEvalWithBinding(binding, lastFrame);
    }
  }
예제 #2
0
 public RuntimeException getException(Ruby runtime) {
   switch (getType()) {
     case NEXT:
       return runtime.newLocalJumpError(getType(), null, "unexpected next");
     case BREAK:
       return runtime.newLocalJumpError(getType(), null, "unexpected break");
     case RETURN:
       return runtime.newLocalJumpError(getType(), null, "unexpected return");
     case REDO:
       return runtime.newLocalJumpError(getType(), null, "unexpected redo");
     case RETRY:
       return runtime.newLocalJumpError(getType(), null, "retry outside of rescue not supported");
   }
   throw new RuntimeException("Unhandled case in operands/IRException.java");
 }
예제 #3
0
  /**
   * Evaluate the given string.
   *
   * @param context the current thread's context
   * @param self the self to evaluate under
   * @param src The string containing the text to be evaluated
   * @param file The filename to use when reporting errors during the evaluation
   * @param lineNumber that the eval supposedly starts from
   * @return An IRubyObject result from the evaluation
   */
  public static IRubyObject evalSimple(
      ThreadContext context, IRubyObject self, RubyString src, String file, int lineNumber) {
    // this is ensured by the callers
    assert file != null;

    Ruby runtime = src.getRuntime();

    // no binding, just eval in "current" frame (caller's frame)
    RubyString source = src.convertToString();

    DynamicScope evalScope = context.getCurrentScope().getEvalScope(runtime);
    evalScope.getStaticScope().determineModule();

    try {
      Node node = runtime.parseEval(source.getByteList(), file, evalScope, lineNumber);

      if (runtime.getInstanceConfig().getCompileMode() == CompileMode.OFFIR) {
        // SSS FIXME: AST interpreter passed both a runtime (which comes from the source string)
        // and the thread-context rather than fetch one from the other.  Why is that?
        return Interpreter.interpretSimpleEval(runtime, file, lineNumber, "(eval)", node, self);
      } else {
        return INTERPRET_EVAL(
            runtime, context, file, lineNumber, node, "(eval)", self, Block.NULL_BLOCK);
      }
    } catch (JumpException.BreakJump bj) {
      throw runtime.newLocalJumpError(
          RubyLocalJumpError.Reason.BREAK, (IRubyObject) bj.getValue(), "unexpected break");
    } catch (StackOverflowError soe) {
      throw runtime.newSystemStackError("stack level too deep", soe);
    }
  }
예제 #4
0
 protected IRubyObject handleRedo(Ruby runtime) throws RaiseException {
   throw runtime.newLocalJumpError(
       RubyLocalJumpError.Reason.REDO, runtime.getNil(), "unexpected redo");
 }
예제 #5
0
  public static IRubyObject interpret(ThreadContext context, CFG cfg, InterpreterContext interp) {
    Ruby runtime = context.getRuntime();
    boolean inClosure = (cfg.getScope() instanceof IRClosure);
    boolean passThroughBreak = false;

    try {
      interp.setMethodExitLabel(
          cfg.getExitBB().getLabel()); // used by return and break instructions!

      Instr[] instrs = cfg.prepareForInterpretation();
      int n = instrs.length;
      int ipc = 0;
      Instr lastInstr = null;
      while (ipc < n) {
        interpInstrsCount++;
        lastInstr = instrs[ipc];

        if (isDebug()) LOG.debug("I: {}", lastInstr);

        try {
          Label jumpTarget = lastInstr.interpret(interp);
          ipc = (jumpTarget == null) ? ipc + 1 : jumpTarget.getTargetPC();
        }
        // SSS FIXME: This only catches Ruby exceptions
        // What about Java exceptions?
        catch (org.jruby.exceptions.RaiseException re) {
          ipc = cfg.getRescuerPC(lastInstr);

          if (ipc == -1) throw re; // No one rescued exception, pass it on!

          interp.setException(re.getException());
        }
      }

      // If a closure, and lastInstr was a return, have to return from the nearest method!
      IRubyObject rv = (IRubyObject) interp.getReturnValue();

      if (lastInstr instanceof ReturnInstr && inClosure && !interp.inLambda()) {
        throw new IRReturnJump(((ReturnInstr) lastInstr).methodToReturnFrom, rv);
      }
      // If a closure, and lastInstr was a break, have to return from the nearest closure!
      else if (lastInstr instanceof BREAK_Instr) {
        if (!inClosure) throw runtime.newLocalJumpError(Reason.BREAK, rv, "unexpected break");

        passThroughBreak = true;
        RuntimeHelpers.breakJump(context, rv);
      }

      return rv;
    } catch (JumpException.BreakJump bj) {
      if (passThroughBreak) throw bj;
      return (IRubyObject) bj.getValue();
    } catch (IRReturnJump rj) {
      // - If we are in a lambda, stop propagating
      // - If not in a lambda
      //   - if in a closure, pass it along
      //   - if not in a closure, we got this return jump from a closure further up the call stack.
      //     So, continue popping the call stack till we get to the right method
      if (!interp.inLambda() && (inClosure || (rj.methodToReturnFrom != cfg.getScope())))
        throw rj; // pass it along

      return (IRubyObject) rj.returnValue;
    } finally {
      if (interp.getFrame() != null) {
        context.popFrame();
        interp.setFrame(null);
      }

      if (interp.hasAllocatedDynamicScope()) context.postMethodScopeOnly();
    }
  }