Skip to content
Browse files

[1.9] Implement Proc#parameter for compile blocks.

  • Loading branch information...
1 parent 9c4779e commit eefbc74814881344e159a8b2c7f80b27ad81d8c4 @headius headius committed with yokolet Jan 8, 2011
View
78 src/org/jruby/RubyProc.java
@@ -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);
}
View
1 src/org/jruby/ast/executable/AbstractScript.java
@@ -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;
/**
View
5 src/org/jruby/compiler/ASTCompiler19.java
@@ -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);
}
}
View
19 src/org/jruby/compiler/BodyCompiler.java
@@ -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,
View
2 src/org/jruby/compiler/CacheCompiler.java
@@ -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);
View
3 src/org/jruby/compiler/impl/BaseBodyCompiler.java
@@ -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);
View
5 src/org/jruby/compiler/impl/InheritedCacheCompiler.java
@@ -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();
View
112 src/org/jruby/javasupport/util/RuntimeHelpers.java
@@ -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;
+ }
}
View
7 src/org/jruby/runtime/BlockBody.java
@@ -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) {
View
14 src/org/jruby/runtime/CompiledBlock19.java
@@ -44,11 +44,12 @@
public class CompiledBlock19 extends ContextAwareBlockBody {
protected final CompiledBlockCallback19 callback;
protected final boolean hasMultipleArgsHead;
+ protected final String[] parameterList;
public static Block newCompiledClosure(ThreadContext context, IRubyObject self, Arity arity,
StaticScope scope, CompiledBlockCallback19 callback, boolean hasMultipleArgsHead, int argumentType) {
Binding binding = context.currentBinding(self, Visibility.PUBLIC);
- BlockBody body = new CompiledBlock19(arity, scope, callback, hasMultipleArgsHead, argumentType);
+ BlockBody body = new CompiledBlock19(arity, scope, callback, hasMultipleArgsHead, argumentType, EMPTY_PARAMETER_LIST);
return new Block(body, binding);
}
@@ -59,15 +60,16 @@ public static Block newCompiledClosure(ThreadContext context, IRubyObject self,
}
public static BlockBody newCompiledBlock(Arity arity,
- StaticScope scope, CompiledBlockCallback19 callback, boolean hasMultipleArgsHead, int argumentType) {
- return new CompiledBlock19(arity, scope, callback, hasMultipleArgsHead, argumentType);
+ StaticScope scope, CompiledBlockCallback19 callback, boolean hasMultipleArgsHead, int argumentType, String[] parameterList) {
+ return new CompiledBlock19(arity, scope, callback, hasMultipleArgsHead, argumentType, parameterList);
}
- protected CompiledBlock19(Arity arity, StaticScope scope, CompiledBlockCallback19 callback, boolean hasMultipleArgsHead, int argumentType) {
+ protected CompiledBlock19(Arity arity, StaticScope scope, CompiledBlockCallback19 callback, boolean hasMultipleArgsHead, int argumentType, String[] parameterList) {
super(scope, arity, argumentType);
this.callback = callback;
this.hasMultipleArgsHead = hasMultipleArgsHead;
+ this.parameterList = parameterList;
}
@Override
@@ -211,4 +213,8 @@ public String getFile() {
public int getLine() {
return callback.getLine();
}
+
+ public String[] getParameterList() {
+ return parameterList;
+ }
}
View
10 src/org/jruby/runtime/CompiledBlockLight19.java
@@ -40,18 +40,18 @@
public static Block newCompiledClosureLight(ThreadContext context, IRubyObject self, Arity arity,
StaticScope scope, CompiledBlockCallback19 callback, boolean hasMultipleArgsHead, int argumentType) {
Binding binding = context.currentBinding(self, Visibility.PUBLIC);
- BlockBody body = new CompiledBlockLight19(arity, scope, callback, hasMultipleArgsHead, argumentType);
+ BlockBody body = new CompiledBlockLight19(arity, scope, callback, hasMultipleArgsHead, argumentType, EMPTY_PARAMETER_LIST);
return new Block(body, binding);
}
public static BlockBody newCompiledBlockLight(Arity arity,
- StaticScope scope, CompiledBlockCallback19 callback, boolean hasMultipleArgsHead, int argumentType) {
- return new CompiledBlockLight19(arity, scope, callback, hasMultipleArgsHead, argumentType);
+ StaticScope scope, CompiledBlockCallback19 callback, boolean hasMultipleArgsHead, int argumentType, String[] parameterList) {
+ return new CompiledBlockLight19(arity, scope, callback, hasMultipleArgsHead, argumentType, parameterList);
}
- protected CompiledBlockLight19(Arity arity, StaticScope scope, CompiledBlockCallback19 callback, boolean hasMultipleArgsHead, int argumentType) {
- super(arity, scope, callback, hasMultipleArgsHead, argumentType);
+ protected CompiledBlockLight19(Arity arity, StaticScope scope, CompiledBlockCallback19 callback, boolean hasMultipleArgsHead, int argumentType, String[] parameterList) {
+ super(arity, scope, callback, hasMultipleArgsHead, argumentType, parameterList);
}
@Override
View
11 src/org/jruby/runtime/Interpreted19Block.java
@@ -40,6 +40,7 @@
import org.jruby.common.IRubyWarnings.ID;
import org.jruby.evaluator.ASTInterpreter;
import org.jruby.exceptions.JumpException;
+import org.jruby.javasupport.util.RuntimeHelpers;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.runtime.builtin.IRubyObject;
/**
@@ -55,6 +56,9 @@
/** The argument list, pulled out of iterNode */
private final ArgsNode args;
+ /** The parameter names, for Proc#parameters */
+ private final String[] parameterList;
+
/** The body of the block, pulled out of bodyNode */
private final Node body;
@@ -78,6 +82,7 @@ public Interpreted19Block(IterNode iterNode) {
super(iterNode.getScope(), ((ArgsNode)iterNode.getVarNode()).getArity(), -1); // We override that the logic which uses this
this.args = (ArgsNode)iterNode.getVarNode();
+ this.parameterList = RuntimeHelpers.encodeParameterList(args).split(";");
this.body = iterNode.getBodyNode() == null ? NilImplicitNode.NIL : iterNode.getBodyNode();
this.position = iterNode.getPosition();
}
@@ -86,6 +91,7 @@ public Interpreted19Block(LambdaNode lambdaNode) {
super(lambdaNode.getScope(), lambdaNode.getArgs().getArity(), -1); // We override that the logic which uses this
this.args = lambdaNode.getArgs();
+ this.parameterList = RuntimeHelpers.encodeParameterList(args).split(";");
this.body = lambdaNode.getBody() == null ? NilImplicitNode.NIL : lambdaNode.getBody();
this.position = lambdaNode.getPosition();
}
@@ -283,4 +289,9 @@ public String getFile() {
public int getLine() {
return position.getLine();
}
+
+ @Override
+ public String[] getParameterList() {
+ return parameterList;
+ }
}

0 comments on commit eefbc74

Please sign in to comment.
Something went wrong with that request. Please try again.