Skip to content

Commit

Permalink
JRUBY-4180: [1.8.7] Blocks should be able to receive block arguments …
Browse files Browse the repository at this point in the history
…(interpreted-mode only + some internals)
  • Loading branch information
enebo committed Dec 31, 2009
1 parent eadc874 commit 6ba2522
Show file tree
Hide file tree
Showing 29 changed files with 2,317 additions and 665 deletions.
4 changes: 4 additions & 0 deletions src/org/jruby/RubyProc.java
Expand Up @@ -200,6 +200,10 @@ public IRubyObject binding() {
}

@JRubyMethod(name = {"call", "[]"}, rest = true, frame = true, compat = CompatVersion.RUBY1_8)
public IRubyObject call(ThreadContext context, IRubyObject[] args, Block block) {
return call(context, args, null, block);
}

public IRubyObject call(ThreadContext context, IRubyObject[] args) {
return call(context, args, null, Block.NULL_BLOCK);
}
Expand Down
53 changes: 53 additions & 0 deletions src/org/jruby/ast/BlockArg18Node.java
@@ -0,0 +1,53 @@
package org.jruby.ast;

import java.util.List;
import org.jruby.ast.visitor.NodeVisitor;
import org.jruby.lexer.yacc.ISourcePosition;

/**
* Similiar to BlockArg, but with idiosyncracies that 1.8.7 allows:
*
* proc { |a,&b| }
* proc { |a,&FOO| }
* proc { |a,b.c| }
* proc { |a,b[0]| }
*
*/
public class BlockArg18Node extends Node {
private Node normalBlockArgs;
private Node blockArgAssignee;

public BlockArg18Node(ISourcePosition position, Node blockArgAssignee,
Node normalBlockArgs) {
super(position);

assert blockArgAssignee != null : "Must be a value to assign too";

this.blockArgAssignee = blockArgAssignee;
this.normalBlockArgs = normalBlockArgs;
}

public Node getArgs() {
return normalBlockArgs;
}

public Node getBlockArg() {
return blockArgAssignee;
}

@Override
public Object accept(NodeVisitor visitor) {
return visitor.visitBlockArg18Node(this);
}

@Override
public List<Node> childNodes() {
return createList(normalBlockArgs, blockArgAssignee);
}

@Override
public NodeType getNodeType() {
return NodeType.BLOCKARG18NODE;
}

}
2 changes: 1 addition & 1 deletion src/org/jruby/ast/BlockArgNode.java
Expand Up @@ -38,7 +38,7 @@
import org.jruby.lexer.yacc.ISourcePosition;

/**
* An explicit block argument (&amp;my_block).
* An explicit block argument (&amp;my_block) in parameter list.
*/
public class BlockArgNode extends Node implements INameNode {
private final int count;
Expand Down
11 changes: 8 additions & 3 deletions src/org/jruby/ast/BlockPassNode.java
Expand Up @@ -41,14 +41,19 @@
import org.jruby.runtime.builtin.IRubyObject;

/**
* Block passed explicitly as an argument in a method call.
* A block passing argument in a method call (last argument prefixed by an ampersand).
* Explicit block argument (on caller side):
* foobar(1, 2, &foo)
* foobar(1, 2, &lhs_which_returns_something_block/proc_like)
*
* bodyNode is any expression which can return something which is ultimately
* coercible to a proc.
*/
public class BlockPassNode extends Node {
private final Node bodyNode;

/** Used by the arg_blk_pass and new_call, new_fcall and new_super
* methods in ParserSupport to temporary save the args node.
* methods in ParserSupport to temporary save the args node. This should
* not be used directly by compiler or interpreter.
*/
private Node argsNode;

Expand Down
2 changes: 1 addition & 1 deletion src/org/jruby/ast/ForNode.java
Expand Up @@ -60,7 +60,7 @@ public ForNode(ISourcePosition position, Node varNode, Node bodyNode, Node iterN
// 'For's are implemented as blocks in evaluation, but they have no scope so we
// just deal with this lack of scope throughout its lifespan. We should probably
// change the way this works to get rid of multiple null checks.
super(position, varNode, null, bodyNode);
super(position, varNode, null, null, bodyNode);

assert iterNode != null : "iterNode is not null";

Expand Down
21 changes: 17 additions & 4 deletions src/org/jruby/ast/IterNode.java
Expand Up @@ -51,16 +51,24 @@
public class IterNode extends Node {
private final Node varNode;
private final Node bodyNode;
private final Node blockVarNode; // This is only for 1.8 blocks

// What static scoping relationship exists when it comes into being.
private StaticScope scope;
private BlockBody blockBody;

public IterNode(ISourcePosition position, Node varNode, StaticScope scope, Node bodyNode) {
public IterNode(ISourcePosition position, Node args, BlockPassNode iter, StaticScope scope, Node body) {
super(position);
this.varNode = varNode;

if (args instanceof BlockArg18Node) {
this.varNode = ((BlockArg18Node) args).getArgs();
this.blockVarNode = ((BlockArg18Node) args).getBlockArg();
} else {
this.varNode = args;
this.blockVarNode = null;
}
this.scope = scope;
this.bodyNode = bodyNode;
this.bodyNode = body;
NodeType argsNodeId = BlockBody.getArgumentTypeWackyHack(this);
this.blockBody = InterpretedBlock.newBlockBody(this, Arity.procArityOf(varNode), BlockBody.asArgumentType(argsNodeId));
}
Expand All @@ -69,6 +77,7 @@ public IterNode(ISourcePosition position, ArgsNode args, Node body, StaticScope
super(position);

this.varNode = args;
this.blockVarNode = null; // This is only for 1.8 blocks
this.bodyNode = body;
this.scope = scope;
this.blockBody = new Interpreted19Block(this);
Expand All @@ -85,6 +94,10 @@ public NodeType getNodeType() {
public Object accept(NodeVisitor iVisitor) {
return iVisitor.visitIterNode(this);
}

public Node getBlockVarNode() {
return blockVarNode;
}

public StaticScope getScope() {
return scope;
Expand All @@ -111,7 +124,7 @@ public BlockBody getBlockBody() {
}

public List<Node> childNodes() {
return Node.createList(varNode, bodyNode);
return Node.createList(varNode, blockVarNode, bodyNode);
}

@Override
Expand Down
1 change: 0 additions & 1 deletion src/org/jruby/ast/MultipleAsgnNode.java
Expand Up @@ -39,7 +39,6 @@
import org.jruby.ast.visitor.NodeVisitor;
import org.jruby.evaluator.ASTInterpreter;
import org.jruby.evaluator.AssignmentVisitor;
import org.jruby.javasupport.util.RuntimeHelpers;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.runtime.Arity;
import org.jruby.runtime.Block;
Expand Down
2 changes: 1 addition & 1 deletion src/org/jruby/ast/NodeType.java
Expand Up @@ -45,7 +45,7 @@ public enum NodeType {
TRUENODE, UNDEFNODE, UNTILNODE, VALIASNODE, VCALLNODE, WHENNODE, WHILENODE, XSTRNODE, YIELDNODE,
ZARRAYNODE, ZEROARGNODE, ZSUPERNODE, COMMENTNODE, ROOTNODE, ATTRASSIGNNODE, ARGSPUSHNODE,
OPTARGNODE, ARGAUXILIARYNODE, LAMBDANODE, MULTIPLEASGN19NODE, RESTARG, ENCODINGNODE,
LITERALNODE;
LITERALNODE, BLOCKARG18NODE;


/**
Expand Down
2 changes: 1 addition & 1 deletion src/org/jruby/ast/PostExeNode.java
Expand Up @@ -44,7 +44,7 @@
*/
public class PostExeNode extends IterNode {
public PostExeNode(ISourcePosition position, Node body) {
super(position, null, null, body);
super(position, null, null, null, body);
}

public NodeType getNodeType() {
Expand Down
3 changes: 2 additions & 1 deletion src/org/jruby/ast/PreExeNode.java
Expand Up @@ -43,9 +43,10 @@
*/
public class PreExeNode extends IterNode {
public PreExeNode(ISourcePosition position, StaticScope scope, Node body) {
super(position, null, scope, body);
super(position, null, null, scope, body);
}

@Override
public NodeType getNodeType() {
return NodeType.PREEXENODE;
}
Expand Down
2 changes: 2 additions & 0 deletions src/org/jruby/ast/visitor/NodeVisitor.java
Expand Up @@ -42,6 +42,7 @@
import org.jruby.ast.BeginNode;
import org.jruby.ast.BignumNode;
import org.jruby.ast.BlockArgNode;
import org.jruby.ast.BlockArg18Node;
import org.jruby.ast.BlockNode;
import org.jruby.ast.BlockPassNode;
import org.jruby.ast.BreakNode;
Expand Down Expand Up @@ -150,6 +151,7 @@ public interface NodeVisitor {
public Object visitBeginNode(BeginNode iVisited);
public Object visitBignumNode(BignumNode iVisited);
public Object visitBlockArgNode(BlockArgNode iVisited);
public Object visitBlockArg18Node(BlockArg18Node iVisited);
public Object visitBlockNode(BlockNode iVisited);
public Object visitBlockPassNode(BlockPassNode iVisited);
public Object visitBreakNode(BreakNode iVisited);
Expand Down

0 comments on commit 6ba2522

Please sign in to comment.