Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit e740d8a3c268f53c63658d9a8b0c61b175083585 1 parent cf686e4
@enebo enebo authored
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
Please sign in to comment.
Something went wrong with that request. Please try again.