Permalink
Browse files

[1.9] Implement Proc#parameter for compile blocks.

  • Loading branch information...
headius authored and yokolet committed Jan 8, 2011
1 parent 9c4779e commit eefbc74814881344e159a8b2c7f80b27ad81d8c4
@@ -47,6 +47,7 @@
import org.jruby.ast.Node;
import org.jruby.ast.OptArgNode;
import org.jruby.exceptions.JumpException;
import org.jruby.javasupport.util.RuntimeHelpers;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.parser.BlockStaticScope;
import org.jruby.parser.StaticScope;
@@ -357,78 +358,14 @@ public IRubyObject source_location(ThreadContext context) {
@JRubyMethod(name = "parameters", compat = RUBY1_9)
public IRubyObject parameters(ThreadContext context) {
Ruby runtime = context.getRuntime();
RubyArray parms = RubyArray.newEmptyArray(runtime);
ArgsNode args;
BlockBody body = this.getBlock().getBody();
if (!(body instanceof Interpreted19Block)) {
if (body instanceof MethodBlock) {
MethodBlock methodBlock = (MethodBlock)body;
return methodBlock.getMethod().parameters(context);
}
return parms;
}
// argument names are easily accessible from interpreter
RubyArray elem = RubyArray.newEmptyArray(runtime);
args = ((Interpreted19Block) this.getBlock().getBody()).getArgs();
// required parameters
List<Node> children = new ArrayList();
if (args.getPreCount() > 0) children.addAll(args.getPre().childNodes());
if (args.getPostCount() > 0) children.addAll(args.getPost().childNodes());
Iterator iter = children.iterator();
while (iter.hasNext()) {
Node node = (Node) iter.next();
elem = RubyArray.newEmptyArray(runtime);
elem.add(RubySymbol.newSymbol(runtime, this.isLambda() ? "req" : "opt"));
if (node instanceof ArgumentNode) {
elem.add(RubySymbol.newSymbol(runtime, ((ArgumentNode) node).getName()));
}
parms.add(elem);
}
// optional parameters
if (args.getOptArgs() != null) {
children = args.getOptArgs().childNodes();
if (! children.isEmpty()) {
iter = children.iterator();
while (iter.hasNext()) {
Node node = (Node) iter.next();
elem = RubyArray.newEmptyArray(runtime);
elem.add(RubySymbol.newSymbol(runtime, "opt"));
if (node instanceof OptArgNode) {
elem.add(RubySymbol.newSymbol(runtime, ((OptArgNode) node).getName()));
}
parms.add(elem);
}
}
if (body instanceof MethodBlock) {
MethodBlock methodBlock = (MethodBlock)body;
return methodBlock.getMethod().parameters(context);
}
if (args instanceof ArgsNoArgNode) {
elem = RubyArray.newEmptyArray(runtime);
elem.add(RubySymbol.newSymbol(runtime, "rest"));
parms.add(elem);
} else {
ArgumentNode rest = args.getRestArgNode();
if (rest != null) {
elem = RubyArray.newEmptyArray(runtime);
elem.add(RubySymbol.newSymbol(runtime, "rest"));
elem.add(RubySymbol.newSymbol(runtime, rest.getName()));
parms.add(elem);
}
}
BlockArgNode blockArg = args.getBlock();
if (blockArg != null) {
elem = RubyArray.newEmptyArray(runtime);
elem.add(RubySymbol.newSymbol(runtime, "block"));
elem.add(RubySymbol.newSymbol(runtime, blockArg.getName()));
parms.add(elem);
}
return parms;
return RuntimeHelpers.parameterListToParameters(runtime, body.getParameterList(), isLambda());
}
@JRubyMethod(name = "lambda?", compat = RUBY1_9)
@@ -439,10 +376,7 @@ public IRubyObject lambda_p(ThreadContext context) {
private boolean isLambda() {
return type.equals(Block.Type.LAMBDA);
}
private boolean isNormal() {
return type.equals(Block.Type.NORMAL);
}
private boolean isProc() {
return type.equals(Block.Type.PROC);
}
@@ -23,7 +23,6 @@
import org.jruby.runtime.MethodIndex;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.encoding.EncodingService;
import org.jruby.util.ByteList;
/**
@@ -48,6 +48,7 @@
import org.jruby.ast.OptArgNode;
import org.jruby.ast.SValue19Node;
import org.jruby.ast.StarNode;
import org.jruby.javasupport.util.RuntimeHelpers;
import org.jruby.runtime.Arity;
import org.jruby.runtime.BlockBody;
@@ -258,10 +259,10 @@ public void call(BodyCompiler context) {
if (argsNodeId == null) {
// no args, do not pass args processor
context.createNewClosure19(iterNode.getPosition().getFile(), iterNode.getPosition().getStartLine(), iterNode.getScope(), Arity.procArityOf(iterNode.getVarNode()).getValue(),
closureBody, null, hasMultipleArgsHead, argsNodeId, inspector);
closureBody, null, hasMultipleArgsHead, argsNodeId, RuntimeHelpers.encodeParameterList(argsNode), inspector);
} else {
context.createNewClosure19(iterNode.getPosition().getFile(), iterNode.getPosition().getStartLine(), iterNode.getScope(), Arity.procArityOf(iterNode.getVarNode()).getValue(),
closureBody, closureArgs, hasMultipleArgsHead, argsNodeId, inspector);
closureBody, closureArgs, hasMultipleArgsHead, argsNodeId, RuntimeHelpers.encodeParameterList(argsNode), inspector);
}
}
@@ -313,42 +313,25 @@
/**
* Create a new closure (block) using the given lexical scope information, call arity, and
* body generated by the body callback. The closure will capture containing scopes and related information.
*
* @param scope The static scoping information
* @param arity The arity of the block's argument list
* @param body The callback which will generate the closure's body
*/
public void createNewClosure(String file, int line, StaticScope scope, int arity, CompilerCallback body, CompilerCallback args, boolean hasMultipleArgsHead, NodeType argsNodeId, ASTInspector inspector);
/**
* Create a new closure (block) using the given lexical scope information, call arity, and
* body generated by the body callback. The closure will capture containing scopes and related information.
*
* @param scope The static scoping information
* @param arity The arity of the block's argument list
* @param body The callback which will generate the closure's body
*/
public void createNewClosure19(String file, int line, StaticScope scope, int arity, CompilerCallback body, CompilerCallback args, boolean hasMultipleArgsHead, NodeType argsNodeId, ASTInspector inspector);
public void createNewClosure19(String file, int line, StaticScope scope, int arity, CompilerCallback body, CompilerCallback args, boolean hasMultipleArgsHead, NodeType argsNodeId, String parameterList, ASTInspector inspector);
/**
* Create a new closure (block) for a for loop with the given call arity and
* body generated by the body callback.
*
* @param scope The static scoping information
* @param arity The arity of the block's argument list
* @param body The callback which will generate the closure's body
*/
public void createNewForLoop(int arity, CompilerCallback body, CompilerCallback args, boolean hasMultipleArgsHead, NodeType argsNodeId, ASTInspector inspector);
/**
* Define a new method with the given name, arity, local variable count, and body callback.
* This will create a new compiled method and bind it to the given name at this point in
* the program's execution.
*
* @param name The name to which to bind the resulting method.
* @param arity The arity of the method's argument list
* @param localVarCount The number of local variables within the method
* @param body The callback which will generate the method's body.
*/
public void defineNewMethod(String name, int methodArity, StaticScope scope,
CompilerCallback body, CompilerCallback args,
@@ -40,7 +40,7 @@
public void cacheClosure(BaseBodyCompiler method, String closureMethod, int arity, StaticScope scope, String file, int line, boolean hasMultipleArgsHead, NodeType argsNodeId, ASTInspector inspector);
public void cacheClosure19(BaseBodyCompiler method, String closureMethod, int arity, StaticScope scope, String file, int line, boolean hasMultipleArgsHead, NodeType argsNodeId, ASTInspector inspector);
public void cacheClosure19(BaseBodyCompiler method, String closureMethod, int arity, StaticScope scope, String file, int line, boolean hasMultipleArgsHead, NodeType argsNodeId, String parameterList, ASTInspector inspector);
public void cacheSpecialClosure(BaseBodyCompiler method, String closureMethod);
@@ -1017,6 +1017,7 @@ public void createNewClosure19(
CompilerCallback args,
boolean hasMultipleArgsHead,
NodeType argsNodeId,
String parameterList,
ASTInspector inspector) {
String blockInMethod = JavaNameMangler.mangleMethodName(rubyName);
if (rubyName == null || rubyName.length() == 0) {
@@ -1036,7 +1037,7 @@ public void createNewClosure19(
loadThreadContext();
loadSelf();
script.getCacheCompiler().cacheClosure19(this, closureMethodName, arity, scope, file, line, hasMultipleArgsHead, argsNodeId, inspector);
script.getCacheCompiler().cacheClosure19(this, closureMethodName, arity, scope, file, line, hasMultipleArgsHead, argsNodeId, parameterList, inspector);
script.addBlockCallback19Descriptor(closureMethodName, file, line);
@@ -401,15 +401,16 @@ public void cacheClosure(BaseBodyCompiler method, String closureMethod, int arit
inheritedBlockBodyCount++;
}
public void cacheClosure19(BaseBodyCompiler method, String closureMethod, int arity, StaticScope scope, String file, int line, boolean hasMultipleArgsHead, NodeType argsNodeId, ASTInspector inspector) {
String descriptor = RuntimeHelpers.buildBlockDescriptor(
public void cacheClosure19(BaseBodyCompiler method, String closureMethod, int arity, StaticScope scope, String file, int line, boolean hasMultipleArgsHead, NodeType argsNodeId, String parameterList, ASTInspector inspector) {
String descriptor = RuntimeHelpers.buildBlockDescriptor19(
closureMethod,
arity,
scope,
file,
line,
hasMultipleArgsHead,
argsNodeId,
parameterList,
inspector);
method.loadThis();
@@ -20,11 +20,15 @@
import org.jruby.RubyRegexp;
import org.jruby.RubyString;
import org.jruby.RubySymbol;
import org.jruby.ast.ArgsNode;
import org.jruby.ast.ArgumentNode;
import org.jruby.ast.DSymbolNode;
import org.jruby.ast.IterNode;
import org.jruby.ast.LiteralNode;
import org.jruby.ast.MultipleAsgn19Node;
import org.jruby.ast.Node;
import org.jruby.ast.NodeType;
import org.jruby.ast.OptArgNode;
import org.jruby.ast.util.ArgsUtil;
import org.jruby.common.IRubyWarnings.ID;
import org.jruby.compiler.ASTInspector;
@@ -178,6 +182,20 @@ public static CompiledBlockCallback19 createBlockCallback19(Ruby runtime, Object
return factory.getBlockCallback19Offline(closureMethod, file, line, classPath);
}
public static String buildBlockDescriptor19(
String closureMethod,
int arity,
StaticScope scope,
String file,
int line,
boolean hasMultipleArgsHead,
NodeType argsNodeId,
String parameterList,
ASTInspector inspector) {
return buildBlockDescriptor(closureMethod, arity, scope, file, line, hasMultipleArgsHead, argsNodeId, inspector) +
"," + parameterList;
}
public static String buildBlockDescriptor(
String closureMethod,
int arity,
@@ -254,11 +272,11 @@ public static BlockBody createCompiledBlockBody19(ThreadContext context, Object
String[][] splitDesc = parseBlockDescriptor(descriptor);
String[] firstSplit = splitDesc[0];
String[] secondSplit = splitDesc[1];
return createCompiledBlockBody19(context, scriptObject, firstSplit[0], Integer.parseInt(firstSplit[1]), secondSplit, Boolean.valueOf(firstSplit[3]), Integer.parseInt(firstSplit[4]), firstSplit[5], Integer.parseInt(firstSplit[6]), Boolean.valueOf(firstSplit[7]));
return createCompiledBlockBody19(context, scriptObject, firstSplit[0], Integer.parseInt(firstSplit[1]), secondSplit, Boolean.valueOf(firstSplit[3]), Integer.parseInt(firstSplit[4]), firstSplit[5], Integer.parseInt(firstSplit[6]), Boolean.valueOf(firstSplit[7]), firstSplit[8]);
}
public static BlockBody createCompiledBlockBody19(ThreadContext context, Object scriptObject, String closureMethod, int arity,
String[] staticScopeNames, boolean hasMultipleArgsHead, int argsNodeType, String file, int line, boolean light) {
String[] staticScopeNames, boolean hasMultipleArgsHead, int argsNodeType, String file, int line, boolean light, String parameterList) {
StaticScope staticScope =
new BlockStaticScope(context.getCurrentScope().getStaticScope(), staticScopeNames);
staticScope.determineModule();
@@ -267,12 +285,12 @@ public static BlockBody createCompiledBlockBody19(ThreadContext context, Object
return CompiledBlockLight19.newCompiledBlockLight(
Arity.createArity(arity), staticScope,
createBlockCallback19(context.getRuntime(), scriptObject, closureMethod, file, line),
hasMultipleArgsHead, argsNodeType);
hasMultipleArgsHead, argsNodeType, parameterList.split(";"));
} else {
return CompiledBlock19.newCompiledBlock(
Arity.createArity(arity), staticScope,
createBlockCallback19(context.getRuntime(), scriptObject, closureMethod, file, line),
hasMultipleArgsHead, argsNodeType);
hasMultipleArgsHead, argsNodeType, parameterList.split(";"));
}
}
@@ -2141,4 +2159,90 @@ public static void updateScopeWithCaptures(ThreadContext context, DynamicScope s
public static RubyArray argsPush(RubyArray first, IRubyObject second) {
return ((RubyArray)first.dup()).append(second);
}
public static String encodeParameterList(ArgsNode argsNode) {
StringBuilder builder = new StringBuilder();
boolean added = false;
if (argsNode.getPre() != null) {
for (Node preNode : argsNode.getPre().childNodes()) {
if (added) builder.append(';');
added = true;
if (preNode instanceof MultipleAsgn19Node) {
builder.append("nil");
} else {
builder.append("q").append(((ArgumentNode)preNode).getName());
}
}
}
if (argsNode.getOptArgs() != null) {
for (Node optNode : argsNode.getOptArgs().childNodes()) {
if (added) builder.append(';');
added = true;
builder.append("o").append(((OptArgNode)optNode).getName());
}
}
if (argsNode.getRestArg() >= 0) {
if (added) builder.append(';');
added = true;
builder.append("r").append(argsNode.getRestArgNode().getName());
}
if (argsNode.getPost() != null) {
for (Node postNode : argsNode.getPost().childNodes()) {
if (added) builder.append(';');
added = true;
if (postNode instanceof MultipleAsgn19Node) {
builder.append("nil");
} else {
builder.append("q").append(((ArgumentNode)postNode).getName());
}
}
}
if (argsNode.getBlock() != null) {
if (added) builder.append(';');
added = true;
builder.append("b").append(argsNode.getBlock().getName());
}
if (!added) builder.append("NONE");
return builder.toString();
}
public static RubyArray parameterListToParameters(Ruby runtime, String[] parameterList, boolean isLambda) {
RubyArray parms = RubyArray.newEmptyArray(runtime);
for (String param : parameterList) {
if (param.equals("NONE")) break;
RubyArray elem = RubyArray.newEmptyArray(runtime);
if (param.equals("nil")) {
elem.add(RubySymbol.newSymbol(runtime, isLambda ? "req" : "opt"));
parms.add(elem);
continue;
}
if (param.charAt(0) == 'q') {
elem.add(RubySymbol.newSymbol(runtime, isLambda ? "req" : "opt"));
} else if (param.charAt(0) == 'r') {
elem.add(RubySymbol.newSymbol(runtime, "rest"));
} else if (param.charAt(0) == 'R') {
elem.add(RubySymbol.newSymbol(runtime, "rest"));
parms.add(elem);
continue;
} else if (param.charAt(0) == 'o') {
elem.add(RubySymbol.newSymbol(runtime, "opt"));
} else if (param.charAt(0) == 'b') {
elem.add(RubySymbol.newSymbol(runtime, "block"));
}
elem.add(RubySymbol.newSymbol(runtime, param.substring(1)));
parms.add(elem);
}
return parms;
}
}
@@ -51,6 +51,9 @@
public static final int MULTIPLE_ASSIGNMENT = 1;
public static final int ARRAY = 2;
public static final int SINGLE_RESTARG = 3;
public static final String[] EMPTY_PARAMETER_LIST = new String[0];
protected final int argumentType;
public BlockBody(int argumentType) {
@@ -235,6 +238,10 @@ public static int asArgumentType(NodeType nodeId) {
return args;
}
public String[] getParameterList() {
return EMPTY_PARAMETER_LIST;
}
public static NodeType getArgumentTypeWackyHack(IterNode iterNode) {
NodeType argsNodeId = null;
if (iterNode.getVarNode() != null && iterNode.getVarNode().getNodeType() != NodeType.ZEROARGNODE) {
Oops, something went wrong.

0 comments on commit eefbc74

Please sign in to comment.