private static IRubyObject handleBreakJump(ThreadContext context, JumpException.BreakJump bj) throws JumpException.BreakJump { if (context.getFrameJumpTarget() == bj.getTarget()) { return (IRubyObject) bj.getValue(); } throw bj; }
@Override public IRubyObject interpret( Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) { Block block = SharedScopeBlock.newInterpretedSharedScopeClosure( context, this, context.getCurrentScope(), self); try { while (true) { try { String savedFile = context.getFile(); int savedLine = context.getLine(); IRubyObject recv = null; try { recv = iterNode.interpret(runtime, context, self, aBlock); } finally { context.setFileAndLine(savedFile, savedLine); } return callAdapter.call(context, self, recv, block); } catch (JumpException.RetryJump rj) { // do nothing, allow loop to retry } } } catch (JumpException.BreakJump bj) { return (IRubyObject) bj.getValue(); } }
/** * 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); } }
/** * 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); } }
private IRubyObject handleBreakJump( Ruby runtime, Block newBlock, JumpException.BreakJump bj, int jumpTarget) { switch (newBlock.type) { case LAMBDA: if (bj.getTarget() == jumpTarget) { return (IRubyObject) bj.getValue(); } else { throw runtime.newLocalJumpError( RubyLocalJumpError.Reason.BREAK, (IRubyObject) bj.getValue(), "unexpected break"); } case PROC: if (newBlock.isEscaped()) { throw runtime.newLocalJumpError( RubyLocalJumpError.Reason.BREAK, (IRubyObject) bj.getValue(), "break from proc-closure"); } else { throw bj; } default: throw bj; } }
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(); } }