Permalink
Browse files

Fix two more issues:

  $~ is null when not used (protect against it)
  eval with binding is odd

git-svn-id: http://svn.codehaus.org/jruby/branches/enebo_lexical@2411 961051c9-f516-0410-bf72-c9f7e237a7b7
  • Loading branch information...
enebo committed Nov 8, 2006
1 parent 23f7acb commit 849b019d6a1e9a84ab54e53d8e7637ae91b12200
View
@@ -19,6 +19,7 @@
import org.jruby.runtime.Block;
import org.jruby.runtime.CacheMap;
import org.jruby.runtime.CallbackFactory;
+import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.GlobalVariable;
import org.jruby.runtime.ObjectSpace;
import org.jruby.runtime.ThreadContext;
@@ -165,20 +166,20 @@
*
* @param content to be parsed
* @param file the name of the file to be used in warnings/errors
- * @param asBlock if we want to parse this in a block scope rather than a local scope
+ * @param scope that this content is being parsed under
* @return the top of the AST
*/
- public Node parse(Reader content, String file, boolean asBlock);
+ public Node parse(Reader content, String file, DynamicScope scope);
/**
* Parse the source specified by the string and return an AST
*
* @param content to be parsed
* @param file the name of the file to be used in warnings/errors
- * @param asBlock if we want to parse this in a block scope rather than a local scope
+ * @param scope that this content is being parsed under
* @return the top of the AST
*/
- public Node parse(String content, String file, boolean asBlock);
+ public Node parse(String content, String file, DynamicScope scope);
public ThreadService getThreadService();
View
@@ -182,7 +182,7 @@ private void runInterpreter(IRuby runtime, Reader reader, String filename) {
}
private Node getParsedScript(IRuby runtime, Reader reader, String filename) {
- Node result = runtime.parse(reader, filename, false);
+ Node result = runtime.parse(reader, filename, null);
if (commandline.isAssumePrinting()) {
result = new ParserSupport().appendPrintToBlock(result);
}
View
@@ -70,6 +70,7 @@
import org.jruby.runtime.Block;
import org.jruby.runtime.CacheMap;
import org.jruby.runtime.CallbackFactory;
+import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.GlobalVariable;
import org.jruby.runtime.IAccessor;
import org.jruby.runtime.ObjectSpace;
@@ -226,7 +227,7 @@ public static IRuby newInstance(InputStream in, PrintStream out, PrintStream err
* Evaluates a script and returns a RubyObject.
*/
public IRubyObject evalScript(String script) {
- return eval(parse(script, "<script>", true));
+ return eval(parse(script, "<script>", getCurrentContext().getCurrentScope()));
}
public IRubyObject eval(Node node) {
@@ -689,12 +690,12 @@ public void defineReadonlyVariable(String name, IRubyObject value) {
globalVariables.defineReadonly(name, new ValueAccessor(value));
}
- public Node parse(Reader content, String file, boolean asBlock) {
- return parser.parse(file, content, asBlock);
+ public Node parse(Reader content, String file, DynamicScope scope) {
+ return parser.parse(file, content, scope);
}
- public Node parse(String content, String file, boolean asBlock) {
- return parser.parse(file, content, asBlock);
+ public Node parse(String content, String file, DynamicScope scope) {
+ return parser.parse(file, content, scope);
}
public ThreadService getThreadService() {
@@ -854,7 +855,7 @@ public void loadScript(String scriptName, Reader source, boolean wrap) {
self.extendObject(context.getRubyClass());
}
- Node node = parse(source, scriptName, false);
+ Node node = parse(source, scriptName, null);
self.eval(node);
} catch (JumpException je) {
if (je.getJumpType() == JumpException.JumpType.ReturnJump) {
@@ -56,6 +56,6 @@ public static IRubyObject parse(IRubyObject recv, IRubyObject arg1, IRubyObject
RubyString content = arg1.convertToString();
RubyString filename = arg2.convertToString();
return Java.java_to_ruby(recv, JavaObject.wrap(recv.getRuntime(),
- recv.getRuntime().parse(content.toString(), filename.toString(), false)));
+ recv.getRuntime().parse(content.toString(), filename.toString(), null)));
}
}
@@ -693,9 +693,9 @@ public IRubyObject evalWithBinding(IRubyObject src, IRubyObject scope, String fi
threadContext.preEvalWithBinding(blockOfBinding);
newSelf = threadContext.getFrameSelf();
- result = EvaluationState.eval(threadContext, getRuntime().parse(src.toString(), file, true), newSelf);
+ result = EvaluationState.eval(threadContext, getRuntime().parse(src.toString(), file, blockOfBinding.getDynamicScope()), newSelf);
} finally {
- threadContext.postBoundEvalOrYield(blockOfBinding);
+ threadContext.postEvalWithBinding(blockOfBinding);
// restore position
threadContext.setPosition(savedPosition);
@@ -723,7 +723,7 @@ public IRubyObject evalSimple(IRubyObject src, String file) {
threadContext.setFrameIter(threadContext.getPreviousFrameIter());
}
- result = EvaluationState.eval(threadContext, getRuntime().parse(src.toString(), file, true), this);
+ result = EvaluationState.eval(threadContext, getRuntime().parse(src.toString(), file, threadContext.getCurrentScope()), this);
} finally {
// FIXME: this is broken for Proc, see above
threadContext.setFrameIter(iter);
@@ -33,6 +33,7 @@
import org.jruby.evaluator.Instruction;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.parser.StaticScope;
+import org.jruby.runtime.DynamicScope;
/**
* Represents the top of the AST. This is a node not present in MRI. It was created to
@@ -46,26 +47,42 @@
public class RootNode extends Node {
private static final long serialVersionUID = 1754281364026417051L;
- private StaticScope scope;
+ private transient DynamicScope scope;
+ private StaticScope staticScope;
private Node bodyNode;
- public RootNode(ISourcePosition position, StaticScope scope, Node bodyNode) {
+ public RootNode(ISourcePosition position, DynamicScope scope, Node bodyNode) {
super(position, NodeTypes.ROOTNODE);
this.scope = scope;
+ this.staticScope = scope.getStaticScope();
this.bodyNode = bodyNode;
}
/**
- * The static scoping relationships that should get set first thing before interpretation
- * of the code represented by this AST
+ * Return the dynamic scope for this AST. The variable backed by this is transient so
+ * for serialization this is null. In that case we use staticScope to rebuild the dynamic
+ * scope. The real reason for this method is supporting bindings+eval. We need to pass
+ * our live dynamic scope in so when we eval we can use that dynamic scope.
*
- * @return the top scope for the AST
+ * @return dynamic scope of this AST
*/
- public StaticScope getScope() {
+ public DynamicScope getScope() {
return scope;
}
+ /**
+ * The static scoping relationships that should get set first thing before interpretation
+ * of the code represented by this AST. Actually, we use getScope first since that also
+ * can contain a live dynamic scope. We rely on this method only for interpreting a root
+ * node from a serialized format.
+ *
+ * @return the top static scope for the AST
+ */
+ public StaticScope getStaticScope() {
+ return staticScope;
+ }
+
/**
* First real AST node to be interpreted
*
@@ -75,7 +92,6 @@ public Node getBodyNode() {
return bodyNode;
}
- // TODO: Visitors will need something here I think
public Instruction accept(NodeVisitor iVisitor) {
return iVisitor.visitRootNode(this);
}
@@ -889,7 +889,7 @@ public static IRubyObject eval(ThreadContext context, Node node, IRubyObject sel
case NodeTypes.LOCALVARNODE: {
LocalVarNode iVisited = (LocalVarNode) node;
- // System.out.println("DGetting: " + iVisited.getName() + " at index " + iVisited.getIndex() + " and at depth " + iVisited.getDepth());
+ //System.out.println("DGetting: " + iVisited.getName() + " at index " + iVisited.getIndex() + " and at depth " + iVisited.getDepth());
IRubyObject result = context.getCurrentScope().getValue(iVisited.getIndex(), iVisited.getDepth());
return result == null ? runtime.getNil() : result;
@@ -1202,9 +1202,17 @@ public static IRubyObject eval(ThreadContext context, Node node, IRubyObject sel
}
case NodeTypes.ROOTNODE: {
RootNode iVisited = (RootNode) node;
+ DynamicScope scope = iVisited.getScope();
+
+ // Serialization killed our dynamic scope. We can just create an empty one
+ // since serialization cannot serialize an eval (which is the only thing
+ // which is capable of having a non-empty dynamic scope).
+ if (scope == null) {
+ scope = new DynamicScope(iVisited.getStaticScope(), null);
+ }
// Each root node has a top-level scope that we need to push
- context.preRootNode(iVisited.getScope());
+ context.preRootNode(scope);
// FIXME: Wire up BEGIN and END nodes
@@ -84,7 +84,7 @@ public Object apply(String file, int line, int col, Object funcBody, Vector para
// See eval todo about why this is commented out
//runtime.setPosition(file, line);
- Node node = runtime.parse(file, funcBody.toString(), false);
+ Node node = runtime.parse(file, funcBody.toString(), null);
return JavaEmbedUtils.rubyToJava(runtime, runtime.getTopSelf().eval(node), Object.class);
} finally {
threadContext.postBsfApply();
@@ -38,6 +38,7 @@
import org.jruby.ast.Node;
import org.jruby.lexer.yacc.LexerSource;
import org.jruby.lexer.yacc.SyntaxException;
+import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.util.collections.SinglyLinkedList;
@@ -51,20 +52,20 @@ public Parser(IRuby runtime) {
this.runtime = runtime;
}
- public Node parse(String file, String content, boolean asBlock) {
- return parse(file, new StringReader(content), asBlock);
+ public Node parse(String file, String content, DynamicScope blockScope) {
+ return parse(file, new StringReader(content), blockScope);
}
- public Node parse(String file, Reader content, boolean asBlock) {
+ public Node parse(String file, Reader content, DynamicScope blockScope) {
RubyParserConfiguration configuration = new RubyParserConfiguration();
SinglyLinkedList cref = runtime.getObject().getCRef();
ThreadContext tc = runtime.getCurrentContext();
- // We only need to pass in current static scope if we are evaluating as a block (which
+ // We only need to pass in current scope if we are evaluating as a block (which
// is only done for evals). We need to pass this in so that we can appropriately scope
// down to captured scopes when we are parsing.
- if (asBlock) {
- configuration.parseAsBlock(tc.getCurrentScope().getStaticScope());
+ if (blockScope != null) {
+ configuration.parseAsBlock(blockScope);
}
DefaultRubyParser parser = null;
@@ -89,6 +90,15 @@ public Node parse(String file, Reader content, boolean asBlock) {
RubyParserPool.getInstance().returnParser(parser);
tc.unsetCRef();
}
+
+ // If variables were added then we may need to grow the dynamic scope to match the static
+ // one.
+ // FIXME: Make this so we only need to check this for blockScope != null. We cannot
+ // currently since we create the DynamicScope for a LocalStaticScope before parse begins.
+ // Refactoring should make this fixable.
+ if (result.getScope() != null) {
+ result.getScope().growIfNeeded();
+ }
// FIXME: We should move this into ParserSupport.addRootNode since actual parser should do this.
result.addAppendBeginAndEndNodes();
@@ -92,6 +92,7 @@
import org.jruby.lexer.yacc.ISourcePositionHolder;
import org.jruby.lexer.yacc.SyntaxException;
import org.jruby.lexer.yacc.Token;
+import org.jruby.runtime.DynamicScope;
import org.jruby.util.IdUtil;
/**
@@ -283,7 +284,7 @@ public ISourcePosition union(ISourcePositionHolder first, ISourcePositionHolder
public Node addRootNode(Node topOfAST) {
// I am not sure we need to get AST to set AST and the appendToBlock could maybe get removed.
// For sure once we do two pass parsing we should since this is mostly just optimzation.
- RootNode root = new RootNode(null, currentScope,
+ RootNode root = new RootNode(null, result.getScope(),
appendToBlock(result.getAST(), topOfAST));
// FIXME: Should add begin and end nodes
@@ -556,9 +557,10 @@ public Node new_super(Node args, Token operation) {
* Description of the RubyMethod
*/
public void initTopLocalVariables() {
- currentScope = configuration.getExistingScope();
+ DynamicScope scope = configuration.getScope();
+ currentScope = scope.getStaticScope();
- result.setStaticScope(currentScope);
+ result.setScope(scope);
}
/** Getter for property inSingle.
@@ -29,17 +29,19 @@
***** END LICENSE BLOCK *****/
package org.jruby.parser;
+import org.jruby.runtime.DynamicScope;
+
public class RubyParserConfiguration {
- private StaticScope existingScope = null;
+ private DynamicScope existingScope = null;
private boolean asBlock = false;
/**
- * If we are performing an eval the static scope we should create first as part of
- * parsing should be a block scope. Calling this lets the parser no we need to do this.
+ * If we are performing an eval we should pass existing scope in.
+ * Calling this lets the parser know we need to do this.
*
- * @param existingScope that the new BlockLocalScope will as its captured scopes
+ * @param existingScope is the scope that captures new vars, etc...
*/
- public void parseAsBlock(StaticScope existingScope) {
+ public void parseAsBlock(DynamicScope existingScope) {
this.asBlock = true;
this.existingScope = existingScope;
}
@@ -49,10 +51,15 @@ public void parseAsBlock(StaticScope existingScope) {
*
* @return correct top scope for source to be parsed
*/
- public StaticScope getExistingScope() {
+ public DynamicScope getScope() {
if (asBlock) {
- return new BlockStaticScope(existingScope);
+ return existingScope;
}
- return new LocalStaticScope(existingScope);
+
+ // FIXME: We should really not be creating the dynamic scope for the root
+ // of the AST before parsing. This makes us end up needing to readjust
+ // this dynamic scope coming out of parse (and for local static scopes it
+ // will always happen because of $~ and $_).
+ return new DynamicScope(new LocalStaticScope(null), existingScope);
}
}
@@ -37,6 +37,7 @@
import org.jruby.ast.CommentNode;
import org.jruby.ast.Node;
import org.jruby.lexer.yacc.ISourcePosition;
+import org.jruby.runtime.DynamicScope;
/**
*/
@@ -46,7 +47,7 @@
private Node ast;
private boolean endSeen;
private List commentNodes = new ArrayList();
- private StaticScope staticScope;
+ private DynamicScope scope;
public List getCommentNodes() {
return commentNodes;
@@ -56,12 +57,12 @@ public Node getAST() {
return ast;
}
- public StaticScope getStaticScope() {
- return staticScope;
+ public DynamicScope getScope() {
+ return scope;
}
- public void setStaticScope(StaticScope staticScope) {
- this.staticScope = staticScope;
+ public void setScope(DynamicScope scope) {
+ this.scope = scope;
}
/**
Oops, something went wrong.

0 comments on commit 849b019

Please sign in to comment.