private RubyNode composeBody(RubyNode prelude, RubyNode body) { final SourceSection sourceSection = SequenceNode.enclosing(prelude.getSourceSection(), body.getSourceSection()); body = SequenceNode.sequence(context, sourceSection, prelude, body); if (environment.getFlipFlopStates().size() > 0) { body = SequenceNode.sequence(context, sourceSection, initFlipFlopStates(sourceSection), body); } return body; }
public RubyNode doCompileMethodBody( SourceSection sourceSection, String methodName, org.jruby.ast.Node bodyNode, SharedMethodInfo sharedMethodInfo) { declareArguments(sourceSection, methodName, sharedMethodInfo); final Arity arity = getArity(argsNode); final LoadArgumentsTranslator loadArgumentsTranslator = new LoadArgumentsTranslator(currentNode, context, source, false, this); final RubyNode loadArguments = argsNode.accept(loadArgumentsTranslator); RubyNode body; parentSourceSection.push(sourceSection); try { body = translateNodeOrNil(sourceSection, bodyNode); } finally { parentSourceSection.pop(); } final RubyNode prelude; if (usesRubiniusPrimitive) { // Use Rubinius.primitive seems to turn off arity checking. See Time.from_array for example. prelude = loadArguments; } else { prelude = SequenceNode.sequence( context, sourceSection, CheckArityNode.create(context, sourceSection, arity), loadArguments); } body = SequenceNode.sequence(context, body.getSourceSection(), prelude, body); if (environment.getFlipFlopStates().size() > 0) { body = SequenceNode.sequence( context, body.getSourceSection(), initFlipFlopStates(sourceSection), body); } body = new CatchForMethodNode(context, body.getSourceSection(), body, environment.getReturnID()); // TODO(CS, 10-Jan-15) why do we only translate exceptions in methods and not blocks? body = new ExceptionTranslatingNode(context, body.getSourceSection(), body); return body; }
@Override public RubyNode visitZSuperNode(org.jruby.ast.ZSuperNode node) { final SourceSection sourceSection = translate(node.getPosition()); if (environment.isBlock()) { // We need the declaration frame to get the arguments to use environment.setNeedsDeclarationFrame(); } currentCallMethodName = environment.getNamedMethodName(); final RubyNode blockNode; if (node.getIterNode() != null) { blockNode = node.getIterNode().accept(this); } else { blockNode = null; } boolean insideDefineMethod = false; MethodTranslator methodArgumentsTranslator = this; while (methodArgumentsTranslator.isBlock) { if (!(methodArgumentsTranslator.parent instanceof MethodTranslator)) { return new ZSuperOutsideMethodNode(context, sourceSection, insideDefineMethod); } else if (methodArgumentsTranslator.currentCallMethodName.equals("define_method")) { insideDefineMethod = true; } methodArgumentsTranslator = (MethodTranslator) methodArgumentsTranslator.parent; } final ReloadArgumentsTranslator reloadTranslator = new ReloadArgumentsTranslator(currentNode, context, source, this); final ArgsNode argsNode = methodArgumentsTranslator.argsNode; final SequenceNode reloadSequence = (SequenceNode) reloadTranslator.visitArgsNode(argsNode); final RubyNode arguments = new ReadZSuperArgumentsNode( context, sourceSection, reloadTranslator.isSplatted(), reloadSequence.getSequence()); final RubyNode block = executeOrInheritBlock(sourceSection, blockNode); return new SuperCallNode(context, sourceSection, arguments, block); }
public MethodDefinitionNode compileClassNode( SourceSection sourceSection, String name, org.jruby.ast.Node bodyNode) { environment.addMethodDeclarationSlots(); RubyNode body; if (bodyNode != null) { parentSourceSection = sourceSection; try { body = bodyNode.accept(this); } finally { parentSourceSection = null; } } else { body = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getNilObject()); } if (environment.getFlipFlopStates().size() > 0) { body = SequenceNode.sequence(context, sourceSection, initFlipFlopStates(sourceSection), body); } body = new CatchReturnPlaceholderNode(context, sourceSection, body, environment.getReturnID()); final RubyRootNode rootNode = new RubyRootNode( context, sourceSection, environment.getFrameDescriptor(), environment.getSharedMethodInfo(), body); return new MethodDefinitionNode( context, sourceSection, environment.getSharedMethodInfo().getName(), environment.getSharedMethodInfo(), environment.needsDeclarationFrame(), rootNode, false); }
public BlockDefinitionNode compileBlockNode( SourceSection sourceSection, String methodName, org.jruby.ast.Node bodyNode, SharedMethodInfo sharedMethodInfo, Type type) { declareArguments(sourceSection, methodName, sharedMethodInfo); final Arity arity = getArity(argsNode); final Arity arityForCheck; /* * If you have a block with parameters |a,| Ruby checks the arity as if was minimum 1, maximum 1. That's * counter-intuitive - as you'd expect the anonymous rest argument to cause it to have no maximum. Indeed, * that's how JRuby reports it, and by the look of their failing spec they consider this to be correct. We'll * follow the specs for now until we see a reason to do something else. */ if (argsNode.getRestArgNode() instanceof org.jruby.ast.UnnamedRestArgNode && !((UnnamedRestArgNode) argsNode.getRestArgNode()).isStar()) { arityForCheck = arity.withRest(false); } else { arityForCheck = arity; } final boolean isProc = type == Type.PROC; final LoadArgumentsTranslator loadArgumentsTranslator = new LoadArgumentsTranslator(currentNode, context, source, isProc, this); final RubyNode loadArguments = argsNode.accept(loadArgumentsTranslator); final RubyNode preludeProc; if (shouldConsiderDestructuringArrayArg(arity)) { final RubyNode readArrayNode = new ReadPreArgumentNode( context, sourceSection, 0, MissingArgumentBehaviour.RUNTIME_ERROR); final RubyNode castArrayNode = ArrayCastNodeGen.create(context, sourceSection, readArrayNode); final FrameSlot arraySlot = environment.declareVar(environment.allocateLocalTemp("destructure")); final RubyNode writeArrayNode = new WriteLocalVariableNode(context, sourceSection, castArrayNode, arraySlot); final LoadArgumentsTranslator destructureArgumentsTranslator = new LoadArgumentsTranslator(currentNode, context, source, isProc, this); destructureArgumentsTranslator.pushArraySlot(arraySlot); final RubyNode newDestructureArguments = argsNode.accept(destructureArgumentsTranslator); final RubyNode shouldDestructure = new ShouldDestructureNode( context, sourceSection, new RespondToNode(context, sourceSection, readArrayNode, "to_ary")); final RubyNode arrayWasNotNil = SequenceNode.sequence( context, sourceSection, writeArrayNode, new NotNode( context, sourceSection, new IsNilNode( context, sourceSection, new ReadLocalVariableNode(context, sourceSection, arraySlot)))); final RubyNode shouldDestructureAndArrayWasNotNil = new AndNode(context, sourceSection, shouldDestructure, arrayWasNotNil); preludeProc = new IfNode( context, sourceSection, shouldDestructureAndArrayWasNotNil, newDestructureArguments, loadArguments); } else { preludeProc = loadArguments; } final RubyNode preludeLambda = SequenceNode.sequence( context, sourceSection, CheckArityNode.create(context, sourceSection, arityForCheck), NodeUtil.cloneNode(loadArguments)); RubyNode body; parentSourceSection.push(sourceSection); try { if (argsNode.getBlockLocalVariables() != null && !argsNode.getBlockLocalVariables().isEmpty()) { for (org.jruby.ast.Node var : argsNode.getBlockLocalVariables().children()) { environment.declareVar(((INameNode) var).getName()); } } body = translateNodeOrNil(sourceSection, bodyNode); } finally { parentSourceSection.pop(); } // Procs final RubyNode bodyProc = new CatchForProcNode( context, SequenceNode.enclosing(sourceSection, body.getEncapsulatingSourceSection()), composeBody(preludeProc, NodeUtil.cloneNode(body))); final RubyRootNode newRootNodeForProcs = new RubyRootNode( context, considerExtendingMethodToCoverEnd(bodyProc.getEncapsulatingSourceSection()), environment.getFrameDescriptor(), environment.getSharedMethodInfo(), bodyProc, environment.needsDeclarationFrame()); // Lambdas final RubyNode composed = composeBody(preludeLambda, body /* no copy, last usage */); final RubyNode bodyLambda = new CatchForLambdaNode( context, composed.getEncapsulatingSourceSection(), composed, environment.getReturnID()); final RubyRootNode newRootNodeForLambdas = new RubyRootNode( context, considerExtendingMethodToCoverEnd(bodyLambda.getEncapsulatingSourceSection()), environment.getFrameDescriptor(), environment.getSharedMethodInfo(), bodyLambda, environment.needsDeclarationFrame()); // TODO CS 23-Nov-15 only the second one will get instrumented properly! final CallTarget callTargetAsLambda = Truffle.getRuntime().createCallTarget(newRootNodeForLambdas); final CallTarget callTargetAsProc = Truffle.getRuntime().createCallTarget(newRootNodeForProcs); FrameSlot frameOnStackMarkerSlot; if (frameOnStackMarkerSlotStack.isEmpty()) { frameOnStackMarkerSlot = null; } else { frameOnStackMarkerSlot = frameOnStackMarkerSlotStack.peek(); if (frameOnStackMarkerSlot == BAD_FRAME_SLOT) { frameOnStackMarkerSlot = null; } } return new BlockDefinitionNode( context, newRootNodeForProcs.getEncapsulatingSourceSection(), type, environment.getSharedMethodInfo(), callTargetAsProc, callTargetAsLambda, environment.getBreakID(), frameOnStackMarkerSlot); }