Report abuse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
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