Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
diff --git a/kernel/compiler/bytecode.rb b/kernel/compiler/bytecode.rb index 6f321d3..95a02a9 100644 --- a/kernel/compiler/bytecode.rb +++ b/kernel/compiler/bytecode.rb @@ -1420,22 +1420,39 @@ class Compiler class Loop def bytecode(g) - g.push_modifiers + pos(g) - g.break = g.new_label - g.next = g.redo = top = g.new_label - top.set! + desc = MethodDescription.new @compiler.generator_class, @locals + desc.name = :__block__ + desc.for_block = true + sub = desc.generator - if @body then - @body.bytecode(g) - g.pop - end + # Push line info down. + sub.set_line g.line, g.file - g.check_interrupts - g.goto top + show_errors(sub) do + sub.push_modifiers + sub.break = sub.new_label + top = sub.next = sub.redo = sub.new_label + top.set! - g.break.set! - g.pop_modifiers + if @body then + @body.bytecode(sub) + sub.pop + end + + sub.check_interrupts + sub.goto top + + sub.break.set! + sub.pop_modifiers + + sub.ret + sub.close + end + + g.create_block desc + g.send :call, 0 end end diff --git a/kernel/compiler/local.rb b/kernel/compiler/local.rb index 5fb6394..87d29d0 100644 --- a/kernel/compiler/local.rb +++ b/kernel/compiler/local.rb @@ -11,6 +11,7 @@ class Compiler @names = [] @locals = Hash.new { |h,k| h[k] = Local.new(@scope, k) } @from_eval = false + @skip = false end attr_accessor :from_eval @@ -45,6 +46,14 @@ class Compiler @names.size end + def skip? + @skip + end + + def skip! + @skip = true + end + def encoded_order # figure out the size size = 0 diff --git a/kernel/compiler/nodes.rb b/kernel/compiler/nodes.rb index 05a72bc..cecbef9 100644 --- a/kernel/compiler/nodes.rb +++ b/kernel/compiler/nodes.rb @@ -593,6 +593,10 @@ raise "no" end end + def skip! + @block_scope.last.skip! + end + def depth @block_scope.size end @@ -634,7 +638,7 @@ raise "no" dep = 0 @block_scope.reverse_each do |scope| - if scope.key?(name) + if !scope.skip? && scope.key?(name) if scope.from_eval depth = dep + 1 else @@ -655,14 +659,20 @@ raise "no" return nil else # This not found. create it. - in_scope = @block_scope.last + depth = 0 + in_scope = @top_scope + @block_scope.reverse_each do |scope| + if !scope.skip? + in_scope = scope + break + end + depth += 1 + end idx = in_scope.size lcl = in_scope[name] lcl.created_in_block!(idx) if in_scope.from_eval - depth = 1 - else - depth = 0 + depth += 1 end end end @@ -1170,6 +1180,8 @@ raise "no" set(:iter) do @locals = get(:scope).new_block_scope do + get(:scope).skip! + set(:iter_args) do sexp[1] = convert(s(:iter_args, sexp[1])) # local var assignment end @@ -1307,9 +1319,13 @@ raise "no" end if c.is? Call and c.method == :loop - sexp[1] = convert(sexp[1]) - set(:pop_unwind, false) do - sexp[2] = convert(sexp[2]) + set(:iter) do + @locals = get(:scope).new_block_scope do + sexp[1] = convert(sexp[1]) + set(:pop_unwind, false) do + sexp[2] = convert(sexp[2]) + end + end end return sexp end @@ -1334,7 +1350,7 @@ raise "no" if c.is? Call and c.method == :loop n = Loop.new(@compiler) - n.args(b) + n.args(b, @locals) return n end @@ -1575,7 +1591,8 @@ raise "no" end class Loop < Node - def args(body) + def args(body, locals) + @locals = locals @body = body end end diff --git a/spec/tags/frozen/language/for_tags.txt b/spec/tags/frozen/language/for_tags.txt index 060b4f9..c033480 100644 --- a/spec/tags/frozen/language/for_tags.txt +++ b/spec/tags/frozen/language/for_tags.txt @@ -1,3 +1 @@ -fails:The for expression executes code in containing variable scope -fails:The for expression executes code in containing variable scope with 'do' fails:The for expression repeats the loop from the beginning with 'retry' diff --git a/spec/tags/frozen/language/loop_tags.txt b/spec/tags/frozen/language/loop_tags.txt deleted file mode 100644 index 4131550..0000000 --- a/spec/tags/frozen/language/loop_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:The loop expression executes code in its own scope
This paste will be private.
From the Design Piracy series on my blog: