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