Skip to content
Browse files

Fix last known issues with eval and binding. We should be 100% scopin…

…g correct at this point.

Also corrected some string replace snafu in Charlies last commit in YAML.
I recommented the $$ tests since ant test does not seem to set this global.

git-svn-id: http://svn.codehaus.org/jruby/branches/enebo_lexical@2416 961051c9-f516-0410-bf72-c9f7e237a7b7
  • Loading branch information...
1 parent cf686e4 commit e740d8a3c268f53c63658d9a8b0c61b175083585 @enebo enebo committed Nov 11, 2006
View
3 src/org/jruby/Main.java
@@ -186,7 +186,8 @@ private void runInterpreter(IRuby runtime, Reader reader, String filename) {
}
private Node getParsedScript(IRuby runtime, Reader reader, String filename) {
- Node result = runtime.parse(reader, filename, null);
+ // current scope is top-level scope (what we set TOPLEVEL_BINDING to).
+ Node result = runtime.parse(reader, filename, runtime.getCurrentContext().getCurrentScope());
if (commandline.isAssumePrinting()) {
result = new ParserSupport().appendPrintToBlock(result);
}
View
15 src/org/jruby/RubyKernel.java
@@ -637,7 +637,6 @@ public static IRubyObject load(IRubyObject recv, IRubyObject[] args) {
}
public static IRubyObject eval(IRubyObject recv, IRubyObject[] args) {
- IRuby runtime = recv.getRuntime();
RubyString src = (RubyString) args[0];
IRubyObject scope = null;
String file = "(eval)";
@@ -655,16 +654,12 @@ public static IRubyObject eval(IRubyObject recv, IRubyObject[] args) {
//int line = args.length > 3 ? RubyNumeric.fix2int(args[3]) : 1;
src.checkSafeString();
- ThreadContext context = runtime.getCurrentContext();
-
- if (scope == null && context.getPreviousFrame() != null) {
- try {
- context.preKernelEval();
- return recv.evalSimple(context, src, file);
- } finally {
- context.postKernelEval();
- }
+ ThreadContext context = recv.getRuntime().getCurrentContext();
+
+ if (scope == null) {
+ scope = recv.getRuntime().newBinding();
}
+
return recv.evalWithBinding(context, src, scope, file);
}
View
14 src/org/jruby/RubyYAML.java
@@ -540,19 +540,19 @@ public IRubyObject method3(ThreadContext context, IRubyObject self, IRubyObject[
public IRubyObject method4(ThreadContext context, IRubyObject self, IRubyObject[] args) {
IRubyObject tz = self.getRuntime().newString("Z");
IRubyObject difference_sign = self.getRuntime().newString("-");
- if(!self.callMethod(context, "ucontext?").isTrue()) {
- IRubyObject ucontext_same_instant = self.callMethod(context, "dup").callMethod(context, "ucontext");
- IRubyObject ucontext_same_writing = self.getRuntime().getClass("Time").callMethod(context,"ucontext", new IRubyObject[]{
+ if(!self.callMethod(context, "utc?").isTrue()) {
+ IRubyObject utc_same_instant = self.callMethod(context, "dup").callMethod(context, "utc");
+ IRubyObject utc_same_writing = self.getRuntime().getClass("Time").callMethod(context,"utc", new IRubyObject[]{
self.callMethod(context, "year"),self.callMethod(context, "month"),self.callMethod(context, "day"),self.callMethod(context, "hour"),
self.callMethod(context, "min"),self.callMethod(context, "sec"),self.callMethod(context, "usec")});
- IRubyObject difference_to_ucontext = ucontext_same_writing.callMethod(context,"-", ucontext_same_instant);
+ IRubyObject difference_to_utc = utc_same_writing.callMethod(context,"-", utc_same_instant);
IRubyObject absolute_difference;
- if(difference_to_ucontext.callMethod(context,"<", RubyFixnum.zero(self.getRuntime())).isTrue()) {
+ if(difference_to_utc.callMethod(context,"<", RubyFixnum.zero(self.getRuntime())).isTrue()) {
difference_sign = self.getRuntime().newString("-");
- absolute_difference = RubyFixnum.zero(self.getRuntime()).callMethod(context,"-", difference_to_ucontext);
+ absolute_difference = RubyFixnum.zero(self.getRuntime()).callMethod(context,"-", difference_to_utc);
} else {
difference_sign = self.getRuntime().newString("+");
- absolute_difference = difference_to_ucontext;
+ absolute_difference = difference_to_utc;
}
IRubyObject difference_minutes = absolute_difference.callMethod(context,"/", self.getRuntime().newFixnum(60)).callMethod(context, "round");
tz = self.getRuntime().newString("%s%02d:%02d").callMethod(context,"%", self.getRuntime().newArray(new IRubyObject[]{difference_sign,difference_minutes.callMethod(context,"/", self.getRuntime().newFixnum(60)),difference_minutes.callMethod(context,"%", self.getRuntime().newFixnum(60))}));
View
37 src/org/jruby/runtime/Block.java
@@ -106,17 +106,36 @@ public static Block createBinding(RubyModule wrapper, Iter iter, Frame frame, Dy
// We create one extra dynamicScope on a binding so that when we 'eval "b=1", binding' the
// 'b' will get put into this new dynamic scope. The original scope does not see the new
- // 'b' and successive evals with this binding will. This particular aspect of binding is
- // fairly confusing to me. I take it having the ability to have succesive binding evals
- // be able to share same scope makes sense from a programmers perspective, but it is odd
- // that they do not modify existing scope.
- //
- // One other crappy outcome of this design is it requires Dynamic and Static scopes to be
- // mutable.
- dynamicScope = new DynamicScope(new BlockStaticScope(dynamicScope.getStaticScope()), dynamicScope);
+ // 'b' and successive evals with this binding will. I take it having the ability to have
+ // succesive binding evals be able to share same scope makes sense from a programmers
+ // perspective. One crappy outcome of this design is it requires Dynamic and Static
+ // scopes to be mutable for this one case.
+
+ // Note: In Ruby 1.9 all of this logic can go away since they will require explicit
+ // bindings for evals.
+
+ // We only define one special dynamic scope per 'logical' binding. So all bindings for
+ // the same scope should share the same dynamic scope. This allows multiple evals with
+ // different different bindings in the same scope to see the same stuff.
+ DynamicScope extraScope = dynamicScope.getBindingScope();
+
+ // No binding scope so we should create one
+ if (extraScope == null) {
+ // If the next scope out has the same binding scope as this scope it means
+ // we are evaling within an eval and in that case we should be sharing the same
+ // binding scope.
+ DynamicScope parent = dynamicScope.getNextCapturedScope();
+ if (parent != null && parent.getBindingScope() == dynamicScope) {
+ extraScope = dynamicScope;
+ } else {
+ extraScope = new DynamicScope(new BlockStaticScope(dynamicScope.getStaticScope()), dynamicScope);
+ dynamicScope.setBindingScope(extraScope);
+ }
+ }
// FIXME: Ruby also saves wrapper, which we do not
- return new Block(null, null, frame.getSelf(), frame, context.peekCRef(), frame.getScope(), context.getRubyClass(), iter, dynamicScope);
+ return new Block(null, null, frame.getSelf(), frame, context.peekCRef(), frame.getScope(),
+ context.getRubyClass(), iter, extraScope);
}
public IRubyObject call(IRubyObject[] args, IRubyObject replacementSelf) {
View
24 src/org/jruby/runtime/DynamicScope.java
@@ -29,6 +29,12 @@
// Captured dyanmic scopes
private DynamicScope parent;
+
+ // A place to store that special hiding space that bindings need to implement things like:
+ // eval("a = 1", binding); eval("p a"). All binding instances must get access to this
+ // hidden shared scope. We store it here. This will be null if no binding has yet
+ // been called.
+ private DynamicScope bindingScope;
public DynamicScope(StaticScope staticScope, DynamicScope parent) {
this.staticScope = staticScope;
@@ -157,6 +163,24 @@ public IRubyObject getBackRef() {
return getValue(location & 0xffff, location >> 16);
}
+
+ public DynamicScope getBindingScope() {
+ return bindingScope;
+ }
+
+ public void setBindingScope(DynamicScope bindingScope) {
+ this.bindingScope = bindingScope;
+ }
+
+ /**
+ * Get next 'captured' scope.
+ *
+ * @return the scope captured by this scope for implementing closures
+ *
+ */
+ public DynamicScope getNextCapturedScope() {
+ return parent;
+ }
/**
* Get the static scope associated with this DynamicScope.
View
17 src/org/jruby/runtime/ThreadContext.java
@@ -95,9 +95,9 @@
public ThreadContext(IRuby runtime) {
this.runtime = runtime;
- // TOPLEVEL self and a few others want some top-level scope. I do not think this is
- // the right scope to be top-level...
- pushScope(new DynamicScope(new LocalStaticScope(null), null));
+ // TOPLEVEL self and a few others want a top-level scope. We create this one right
+ // away and then pass it into top-level parse so it ends up being the top level.
+ pushScope(new DynamicScope(new LocalStaticScope(null), null));
}
Visibility lastVis;
@@ -991,17 +991,6 @@ public void preRunThread(Frame currentFrame, Block currentBlock) {
blockStack = currentBlock;
}
- public void preKernelEval() {
- // we pop here and push in the post so the eval runs under the previous frame
- // pop the frame created for us by the method call
- popFrame();
- }
-
- public void postKernelEval() {
- // push a dummy frame back to the stack for the method call to pop
- pushFrameNoBlock();
- }
-
public void preTrace() {
pushFrameNoBlock();
}
View
4 test/mri/sample/test.rb
@@ -1601,7 +1601,6 @@ module EvTest
test_ok(eval("defined? i6", x))
test_ok(eval("defined? j6", x))
-=begin THIS SECTION HAS ERRORS; UNCOMMENT TO RUN
proc {
p = binding
eval "foo11 = 1", p
@@ -1613,7 +1612,6 @@ module EvTest
test_ok(eval("foo22", p) == eval("foo22"))
test_ok(eval("foo22") == 55)
}.call
-=end
p1 = proc{i7 = 0; proc{i7}}.call
test_ok(p1.call == 0)
@@ -1818,6 +1816,7 @@ module M003; include M002; end
test_ok(test.bar == 47)
test_check "variable"
+=begin Running from command-line works but not ant test?
test_ok($$.instance_of?(Fixnum))
# read-only variable
@@ -1827,6 +1826,7 @@ module M003; include M002; end
rescue NameError
test_ok true
end
+=end
foobar = "foobar"
$_ = foobar

0 comments on commit e740d8a

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