rubinius-ast 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/rubinius/ast/constants.rb +324 -0
- data/lib/rubinius/ast/control_flow.rb +698 -0
- data/lib/rubinius/ast/data.rb +30 -0
- data/lib/rubinius/ast/definitions.rb +1134 -0
- data/lib/rubinius/ast/encoding.rb +26 -0
- data/lib/rubinius/ast/exceptions.rb +545 -0
- data/lib/rubinius/ast/file.rb +18 -0
- data/lib/rubinius/ast/grapher.rb +89 -0
- data/lib/rubinius/ast/literals.rb +555 -0
- data/lib/rubinius/ast/node.rb +389 -0
- data/lib/rubinius/ast/operators.rb +394 -0
- data/lib/rubinius/ast/self.rb +25 -0
- data/lib/rubinius/ast/sends.rb +1028 -0
- data/lib/rubinius/ast/transforms.rb +371 -0
- data/lib/rubinius/ast/values.rb +182 -0
- data/lib/rubinius/ast/variables.rb +842 -0
- data/lib/rubinius/ast/version.rb +5 -0
- data/lib/rubinius/ast.rb +18 -0
- data/rubinius-ast.gemspec +22 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 813fe60589de3d0cb89d69641cbc57f5141d8a59
|
4
|
+
data.tar.gz: 3115c03413ae9350818dffbccd915bb37230d0f9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 19aacbcff956617afb4c139d2b8e9cbe232a1b4f0d2ff9e9a3a6a55b2ffbe83bd920a6ee99ba7dfeaa987fc6160a3a243bd6addcac6c8913fb0fafc9a2c49b6a
|
7
|
+
data.tar.gz: 829c797ed156b13791c5e0746b451172d5c356ea163d3a97085b3f8018028a5dd689d9591546392ae135004c86cfe1232c8c7087cc33f0935f7953c873d49878
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2013, Brian Shirai
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
3. Neither the name of the library nor the names of its contributors may be
|
13
|
+
used to endorse or promote products derived from this software without
|
14
|
+
specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
|
20
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
21
|
+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
22
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
23
|
+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
24
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
25
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Rubinius::Ast
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rubinius-ast'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install rubinius-ast
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,324 @@
|
|
1
|
+
# -*- encoding: us-ascii -*-
|
2
|
+
|
3
|
+
module Rubinius::ToolSet.current::TS
|
4
|
+
module AST
|
5
|
+
|
6
|
+
class TypeConstant < Node
|
7
|
+
def initialize(line)
|
8
|
+
@line = line
|
9
|
+
end
|
10
|
+
|
11
|
+
def bytecode(g)
|
12
|
+
pos(g)
|
13
|
+
g.push_type
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class MirrorConstant < Node
|
18
|
+
def initialize(line)
|
19
|
+
@line = line
|
20
|
+
end
|
21
|
+
|
22
|
+
def bytecode(g)
|
23
|
+
pos(g)
|
24
|
+
g.push_mirror
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ScopedConstant < Node
|
29
|
+
attr_accessor :parent, :name
|
30
|
+
|
31
|
+
def initialize(line, parent, name)
|
32
|
+
@line = line
|
33
|
+
@parent = parent
|
34
|
+
@name = name
|
35
|
+
end
|
36
|
+
|
37
|
+
def bytecode(g)
|
38
|
+
pos(g)
|
39
|
+
|
40
|
+
@parent.bytecode(g)
|
41
|
+
g.find_const @name
|
42
|
+
end
|
43
|
+
|
44
|
+
def assign_bytecode(g, value)
|
45
|
+
pos(g)
|
46
|
+
|
47
|
+
value.bytecode(g)
|
48
|
+
g.push_literal @name
|
49
|
+
@parent.bytecode(g)
|
50
|
+
g.rotate 3
|
51
|
+
end
|
52
|
+
|
53
|
+
def masgn_bytecode(g)
|
54
|
+
pos(g)
|
55
|
+
|
56
|
+
@parent.bytecode(g)
|
57
|
+
g.swap
|
58
|
+
g.push_literal @name
|
59
|
+
end
|
60
|
+
|
61
|
+
def defined(g)
|
62
|
+
f = g.new_label
|
63
|
+
done = g.new_label
|
64
|
+
|
65
|
+
value_defined(g, f, false)
|
66
|
+
|
67
|
+
g.pop
|
68
|
+
g.push_literal "constant"
|
69
|
+
g.goto done
|
70
|
+
|
71
|
+
f.set!
|
72
|
+
g.push :nil
|
73
|
+
|
74
|
+
done.set!
|
75
|
+
end
|
76
|
+
|
77
|
+
def value_defined(g, f, const_missing=true)
|
78
|
+
# Save the current exception into a stack local
|
79
|
+
g.push_exception_state
|
80
|
+
outer_exc_state = g.new_stack_local
|
81
|
+
g.set_stack_local outer_exc_state
|
82
|
+
g.pop
|
83
|
+
|
84
|
+
ex = g.new_label
|
85
|
+
ok = g.new_label
|
86
|
+
g.setup_unwind ex, RescueType
|
87
|
+
|
88
|
+
@parent.bytecode(g)
|
89
|
+
g.push_literal @name
|
90
|
+
g.push(const_missing ? :true : :false)
|
91
|
+
g.invoke_primitive :vm_const_defined_under, 3
|
92
|
+
|
93
|
+
g.pop_unwind
|
94
|
+
g.goto ok
|
95
|
+
|
96
|
+
ex.set!
|
97
|
+
g.clear_exception
|
98
|
+
g.push_stack_local outer_exc_state
|
99
|
+
g.restore_exception_state
|
100
|
+
g.goto f
|
101
|
+
|
102
|
+
ok.set!
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_sexp
|
106
|
+
[:colon2, @parent.to_sexp, @name]
|
107
|
+
end
|
108
|
+
|
109
|
+
alias_method :assign_sexp, :to_sexp
|
110
|
+
end
|
111
|
+
|
112
|
+
class ToplevelConstant < Node
|
113
|
+
attr_accessor :name
|
114
|
+
|
115
|
+
def initialize(line, name)
|
116
|
+
@line = line
|
117
|
+
@name = name
|
118
|
+
end
|
119
|
+
|
120
|
+
def bytecode(g)
|
121
|
+
pos(g)
|
122
|
+
|
123
|
+
g.push_cpath_top
|
124
|
+
g.find_const @name
|
125
|
+
end
|
126
|
+
|
127
|
+
def assign_bytecode(g, value)
|
128
|
+
pos(g)
|
129
|
+
|
130
|
+
g.push_cpath_top
|
131
|
+
g.push_literal @name
|
132
|
+
value.bytecode(g)
|
133
|
+
end
|
134
|
+
|
135
|
+
def masgn_bytecode(g)
|
136
|
+
pos(g)
|
137
|
+
|
138
|
+
g.push_cpath_top
|
139
|
+
g.swap
|
140
|
+
g.push_literal @name
|
141
|
+
end
|
142
|
+
|
143
|
+
def defined(g)
|
144
|
+
f = g.new_label
|
145
|
+
done = g.new_label
|
146
|
+
|
147
|
+
value_defined(g, f)
|
148
|
+
|
149
|
+
g.pop
|
150
|
+
g.push_literal "constant"
|
151
|
+
g.goto done
|
152
|
+
|
153
|
+
f.set!
|
154
|
+
g.push :nil
|
155
|
+
|
156
|
+
done.set!
|
157
|
+
end
|
158
|
+
|
159
|
+
def value_defined(g, f)
|
160
|
+
# Save the current exception into a stack local
|
161
|
+
g.push_exception_state
|
162
|
+
outer_exc_state = g.new_stack_local
|
163
|
+
g.set_stack_local outer_exc_state
|
164
|
+
g.pop
|
165
|
+
|
166
|
+
ex = g.new_label
|
167
|
+
ok = g.new_label
|
168
|
+
g.setup_unwind ex, RescueType
|
169
|
+
|
170
|
+
g.push_cpath_top
|
171
|
+
g.push_literal @name
|
172
|
+
g.push :false
|
173
|
+
g.invoke_primitive :vm_const_defined_under, 3
|
174
|
+
|
175
|
+
g.pop_unwind
|
176
|
+
g.goto ok
|
177
|
+
|
178
|
+
ex.set!
|
179
|
+
g.clear_exception
|
180
|
+
g.push_stack_local outer_exc_state
|
181
|
+
g.restore_exception_state
|
182
|
+
g.goto f
|
183
|
+
|
184
|
+
ok.set!
|
185
|
+
end
|
186
|
+
|
187
|
+
def to_sexp
|
188
|
+
[:colon3, @name]
|
189
|
+
end
|
190
|
+
|
191
|
+
alias_method :assign_sexp, :to_sexp
|
192
|
+
end
|
193
|
+
|
194
|
+
class ConstantAccess < Node
|
195
|
+
attr_accessor :name
|
196
|
+
|
197
|
+
def initialize(line, name, top_level = false)
|
198
|
+
@line = line
|
199
|
+
@name = name
|
200
|
+
@top_level = top_level
|
201
|
+
end
|
202
|
+
|
203
|
+
def bytecode(g)
|
204
|
+
pos(g)
|
205
|
+
|
206
|
+
if g.state.op_asgn?
|
207
|
+
g.push_literal Compiler::Runtime
|
208
|
+
g.push_literal @name
|
209
|
+
g.push_scope
|
210
|
+
g.send :find_constant_for_op_asign_or, 2
|
211
|
+
else
|
212
|
+
if @top_level
|
213
|
+
g.push_cpath_top
|
214
|
+
g.find_const @name
|
215
|
+
else
|
216
|
+
g.push_const @name
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def assign_bytecode(g, value)
|
222
|
+
pos(g)
|
223
|
+
|
224
|
+
g.push_scope
|
225
|
+
g.push_literal @name
|
226
|
+
value.bytecode(g)
|
227
|
+
end
|
228
|
+
|
229
|
+
def masgn_bytecode(g)
|
230
|
+
pos(g)
|
231
|
+
|
232
|
+
g.push_scope
|
233
|
+
g.swap
|
234
|
+
g.push_literal @name
|
235
|
+
end
|
236
|
+
|
237
|
+
def defined(g)
|
238
|
+
f = g.new_label
|
239
|
+
done = g.new_label
|
240
|
+
|
241
|
+
value_defined(g, f)
|
242
|
+
|
243
|
+
g.pop
|
244
|
+
g.push_literal "constant"
|
245
|
+
g.goto done
|
246
|
+
|
247
|
+
f.set!
|
248
|
+
g.push :nil
|
249
|
+
|
250
|
+
done.set!
|
251
|
+
end
|
252
|
+
|
253
|
+
def value_defined(g, f)
|
254
|
+
# Save the current exception into a stack local
|
255
|
+
g.push_exception_state
|
256
|
+
outer_exc_state = g.new_stack_local
|
257
|
+
g.set_stack_local outer_exc_state
|
258
|
+
g.pop
|
259
|
+
|
260
|
+
ex = g.new_label
|
261
|
+
ok = g.new_label
|
262
|
+
g.setup_unwind ex, RescueType
|
263
|
+
|
264
|
+
g.push_literal @name
|
265
|
+
g.invoke_primitive :vm_const_defined, 1
|
266
|
+
|
267
|
+
g.pop_unwind
|
268
|
+
g.goto ok
|
269
|
+
|
270
|
+
ex.set!
|
271
|
+
g.clear_exception
|
272
|
+
g.push_stack_local outer_exc_state
|
273
|
+
g.restore_exception_state
|
274
|
+
g.goto f
|
275
|
+
|
276
|
+
ok.set!
|
277
|
+
end
|
278
|
+
|
279
|
+
def assign_sexp
|
280
|
+
@name
|
281
|
+
end
|
282
|
+
|
283
|
+
def to_sexp
|
284
|
+
[:const, @name]
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
class ConstantAssignment < Node
|
289
|
+
attr_accessor :constant, :value
|
290
|
+
|
291
|
+
def initialize(line, expr, value)
|
292
|
+
@line = line
|
293
|
+
@value = value
|
294
|
+
|
295
|
+
if expr.kind_of? Symbol
|
296
|
+
@constant = ConstantAccess.new line, expr
|
297
|
+
else
|
298
|
+
@constant = expr
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def masgn_bytecode(g)
|
303
|
+
@constant.masgn_bytecode(g)
|
304
|
+
g.swap
|
305
|
+
g.send :const_set, 2
|
306
|
+
end
|
307
|
+
|
308
|
+
def bytecode(g)
|
309
|
+
pos(g)
|
310
|
+
|
311
|
+
return masgn_bytecode(g) if g.state.masgn?
|
312
|
+
|
313
|
+
@constant.assign_bytecode(g, @value)
|
314
|
+
g.send :const_set, 2
|
315
|
+
end
|
316
|
+
|
317
|
+
def to_sexp
|
318
|
+
sexp = [:cdecl, @constant.assign_sexp]
|
319
|
+
sexp << @value.to_sexp if @value
|
320
|
+
sexp
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
@@ -0,0 +1,698 @@
|
|
1
|
+
# -*- encoding: us-ascii -*-
|
2
|
+
|
3
|
+
module Rubinius::ToolSet.current::TS
|
4
|
+
module AST
|
5
|
+
class Case < Node
|
6
|
+
attr_accessor :whens, :else
|
7
|
+
|
8
|
+
def initialize(line, whens, else_body)
|
9
|
+
@line = line
|
10
|
+
@whens = whens
|
11
|
+
@else = else_body || NilLiteral.new(line)
|
12
|
+
end
|
13
|
+
|
14
|
+
def bytecode(g)
|
15
|
+
pos(g)
|
16
|
+
|
17
|
+
done = g.new_label
|
18
|
+
|
19
|
+
@whens.each do |w|
|
20
|
+
w.bytecode(g, done)
|
21
|
+
end
|
22
|
+
|
23
|
+
@else.bytecode(g)
|
24
|
+
|
25
|
+
# See command in if about why using line 0
|
26
|
+
g.set_line 0
|
27
|
+
|
28
|
+
done.set!
|
29
|
+
end
|
30
|
+
|
31
|
+
def receiver_sexp
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_sexp
|
36
|
+
else_sexp = @else.kind_of?(NilLiteral) ? nil : @else.to_sexp
|
37
|
+
sexp = [:case, receiver_sexp]
|
38
|
+
sexp << [:whens] + @whens.map { |x| x.to_sexp }
|
39
|
+
sexp << else_sexp
|
40
|
+
sexp
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class ReceiverCase < Case
|
45
|
+
attr_accessor :receiver
|
46
|
+
|
47
|
+
def initialize(line, receiver, whens, else_body)
|
48
|
+
@line = line
|
49
|
+
@receiver = receiver
|
50
|
+
@whens = whens
|
51
|
+
@else = else_body || NilLiteral.new(line)
|
52
|
+
end
|
53
|
+
|
54
|
+
def bytecode(g)
|
55
|
+
pos(g)
|
56
|
+
|
57
|
+
done = g.new_label
|
58
|
+
|
59
|
+
@receiver.bytecode(g)
|
60
|
+
|
61
|
+
@whens.each do |w|
|
62
|
+
w.receiver_bytecode(g, done)
|
63
|
+
end
|
64
|
+
|
65
|
+
g.pop
|
66
|
+
@else.bytecode(g)
|
67
|
+
|
68
|
+
# See command in if about why using line 0
|
69
|
+
g.set_line 0
|
70
|
+
|
71
|
+
done.set!
|
72
|
+
end
|
73
|
+
|
74
|
+
def receiver_sexp
|
75
|
+
@receiver.to_sexp
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class When < Node
|
80
|
+
attr_accessor :conditions, :body, :single, :splat
|
81
|
+
|
82
|
+
def initialize(line, conditions, body)
|
83
|
+
@line = line
|
84
|
+
@body = body || NilLiteral.new(line)
|
85
|
+
@splat = nil
|
86
|
+
@single = nil
|
87
|
+
|
88
|
+
if conditions.kind_of? ConcatArgs
|
89
|
+
@splat = SplatWhen.new line, conditions.rest
|
90
|
+
conditions = conditions.array
|
91
|
+
end
|
92
|
+
|
93
|
+
if conditions.kind_of? ArrayLiteral
|
94
|
+
if conditions.body.last.kind_of? When
|
95
|
+
last = conditions.body.pop
|
96
|
+
if last.conditions.kind_of? ArrayLiteral
|
97
|
+
conditions.body.concat last.conditions.body
|
98
|
+
elsif last.single
|
99
|
+
@splat = SplatWhen.new line, last.single
|
100
|
+
else
|
101
|
+
@splat = SplatWhen.new line, last.conditions
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if conditions.body.size == 1 and !@splat
|
106
|
+
@single = conditions.body.first
|
107
|
+
else
|
108
|
+
@conditions = conditions
|
109
|
+
end
|
110
|
+
elsif conditions.kind_of? SplatValue
|
111
|
+
@splat = SplatWhen.new line, conditions.value
|
112
|
+
@conditions = nil
|
113
|
+
else
|
114
|
+
@conditions = conditions
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def condition_bytecode(g, condition)
|
119
|
+
condition.pos(g)
|
120
|
+
g.dup
|
121
|
+
condition.bytecode(g)
|
122
|
+
g.swap
|
123
|
+
g.send :===, 1
|
124
|
+
end
|
125
|
+
|
126
|
+
def receiver_bytecode(g, done)
|
127
|
+
body = g.new_label
|
128
|
+
nxt = g.new_label
|
129
|
+
|
130
|
+
if @single
|
131
|
+
condition_bytecode(g, @single)
|
132
|
+
g.gif nxt
|
133
|
+
else
|
134
|
+
if @conditions
|
135
|
+
@conditions.body.each do |c|
|
136
|
+
condition_bytecode(g, c)
|
137
|
+
g.git body
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
@splat.receiver_bytecode(g, body, nxt) if @splat
|
142
|
+
g.goto nxt
|
143
|
+
|
144
|
+
body.set!
|
145
|
+
end
|
146
|
+
|
147
|
+
g.pop
|
148
|
+
@body.bytecode(g)
|
149
|
+
g.goto done
|
150
|
+
|
151
|
+
nxt.set!
|
152
|
+
end
|
153
|
+
|
154
|
+
def bytecode(g, done)
|
155
|
+
pos(g)
|
156
|
+
|
157
|
+
nxt = g.new_label
|
158
|
+
body = g.new_label
|
159
|
+
|
160
|
+
if @single
|
161
|
+
@single.bytecode(g)
|
162
|
+
g.gif nxt
|
163
|
+
else
|
164
|
+
if @conditions
|
165
|
+
@conditions.body.each do |condition|
|
166
|
+
condition.bytecode(g)
|
167
|
+
g.git body
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
@splat.bytecode(g, body, nxt) if @splat
|
172
|
+
g.goto nxt
|
173
|
+
|
174
|
+
body.set!
|
175
|
+
end
|
176
|
+
|
177
|
+
@body.bytecode(g)
|
178
|
+
g.goto done
|
179
|
+
|
180
|
+
nxt.set!
|
181
|
+
end
|
182
|
+
|
183
|
+
def to_sexp
|
184
|
+
if @single
|
185
|
+
conditions_sexp = [:array, @single.to_sexp]
|
186
|
+
else
|
187
|
+
conditions_sexp = @conditions ? @conditions.to_sexp : []
|
188
|
+
conditions_sexp << @splat.to_sexp if @splat
|
189
|
+
end
|
190
|
+
[:when, conditions_sexp, @body.to_sexp]
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
class SplatWhen < Node
|
195
|
+
attr_accessor :condition
|
196
|
+
|
197
|
+
def initialize(line, condition)
|
198
|
+
@line = line
|
199
|
+
@condition = condition
|
200
|
+
end
|
201
|
+
|
202
|
+
def receiver_bytecode(g, body, nxt)
|
203
|
+
pos(g)
|
204
|
+
|
205
|
+
g.dup
|
206
|
+
@condition.bytecode(g)
|
207
|
+
g.cast_array
|
208
|
+
g.push_literal Compiler::Runtime
|
209
|
+
g.rotate(3)
|
210
|
+
g.send :matches_when, 2
|
211
|
+
g.git body
|
212
|
+
end
|
213
|
+
|
214
|
+
def bytecode(g, body, nxt)
|
215
|
+
# TODO: why is this empty?
|
216
|
+
end
|
217
|
+
|
218
|
+
def to_sexp
|
219
|
+
[:when, @condition.to_sexp, nil]
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
class Flip2 < Node
|
224
|
+
def initialize(line, start, finish)
|
225
|
+
@line = line
|
226
|
+
@start = start
|
227
|
+
@finish = finish
|
228
|
+
end
|
229
|
+
|
230
|
+
def sexp_name
|
231
|
+
:flip2
|
232
|
+
end
|
233
|
+
|
234
|
+
def exclusive?
|
235
|
+
false
|
236
|
+
end
|
237
|
+
|
238
|
+
def bytecode(g)
|
239
|
+
done = g.new_label
|
240
|
+
on_label = g.new_label
|
241
|
+
index = g.state.flip_flops
|
242
|
+
g.state.push_flip_flop
|
243
|
+
|
244
|
+
get_flip_flop(g, index)
|
245
|
+
g.git on_label
|
246
|
+
|
247
|
+
@start.bytecode(g)
|
248
|
+
g.dup
|
249
|
+
g.gif done
|
250
|
+
g.pop
|
251
|
+
set_flip_flop(g, index, true)
|
252
|
+
|
253
|
+
if exclusive?
|
254
|
+
g.goto done
|
255
|
+
else
|
256
|
+
g.pop
|
257
|
+
end
|
258
|
+
|
259
|
+
on_label.set!
|
260
|
+
g.push_literal true
|
261
|
+
@finish.bytecode(g)
|
262
|
+
g.gif done
|
263
|
+
set_flip_flop(g, index, false)
|
264
|
+
g.pop
|
265
|
+
|
266
|
+
done.set!
|
267
|
+
end
|
268
|
+
|
269
|
+
def get_flip_flop(g, index)
|
270
|
+
g.push_literal Compiler::Runtime
|
271
|
+
g.push_scope
|
272
|
+
g.push_literal index
|
273
|
+
g.send(:get_flip_flop, 2)
|
274
|
+
end
|
275
|
+
|
276
|
+
def set_flip_flop(g, index, value)
|
277
|
+
g.push_literal Compiler::Runtime
|
278
|
+
g.push_scope
|
279
|
+
g.push_literal index
|
280
|
+
g.push_literal value
|
281
|
+
g.send(:set_flip_flop, 3)
|
282
|
+
end
|
283
|
+
|
284
|
+
def to_sexp
|
285
|
+
[sexp_name, @start.to_sexp, @finish.to_sexp]
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
class Flip3 < Flip2
|
290
|
+
def sexp_name
|
291
|
+
:flip3
|
292
|
+
end
|
293
|
+
|
294
|
+
def exclusive?
|
295
|
+
true
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
class If < Node
|
300
|
+
attr_accessor :condition, :body, :else
|
301
|
+
|
302
|
+
def initialize(line, condition, body, else_body)
|
303
|
+
@line = line
|
304
|
+
@condition = condition
|
305
|
+
@body = body || NilLiteral.new(line)
|
306
|
+
@else = else_body || NilLiteral.new(line)
|
307
|
+
end
|
308
|
+
|
309
|
+
def bytecode(g)
|
310
|
+
pos(g)
|
311
|
+
|
312
|
+
done = g.new_label
|
313
|
+
else_label = g.new_label
|
314
|
+
|
315
|
+
@condition.bytecode(g)
|
316
|
+
g.gif else_label
|
317
|
+
|
318
|
+
@body.bytecode(g)
|
319
|
+
g.goto done
|
320
|
+
|
321
|
+
else_label.set!
|
322
|
+
@else.bytecode(g)
|
323
|
+
|
324
|
+
# Use line 0 to indicate "compiler generated code"
|
325
|
+
# so that debuggers and such don't get confused by
|
326
|
+
# thinking the then branch jumps into the else branch.
|
327
|
+
g.set_line 0
|
328
|
+
done.set!
|
329
|
+
end
|
330
|
+
|
331
|
+
def to_sexp
|
332
|
+
else_sexp = @else.kind_of?(NilLiteral) ? nil : @else.to_sexp
|
333
|
+
[:if, @condition.to_sexp, @body.to_sexp, else_sexp]
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
class While < Node
|
338
|
+
attr_accessor :condition, :body, :check_first
|
339
|
+
|
340
|
+
def initialize(line, condition, body, check_first)
|
341
|
+
@line = line
|
342
|
+
@condition = condition
|
343
|
+
@body = body || NilLiteral.new(line)
|
344
|
+
@check_first = check_first
|
345
|
+
end
|
346
|
+
|
347
|
+
def condition_bytecode(g, bottom, use_gif)
|
348
|
+
@condition.bytecode(g)
|
349
|
+
if use_gif
|
350
|
+
g.gif bottom
|
351
|
+
else
|
352
|
+
g.git bottom
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def body_bytecode(g, lbl)
|
357
|
+
g.state.push_loop
|
358
|
+
@body.bytecode(g)
|
359
|
+
g.state.pop_loop
|
360
|
+
|
361
|
+
# This is a loop epilogue. Nothing that changes
|
362
|
+
# computation should be put here.
|
363
|
+
lbl.set!
|
364
|
+
g.pop
|
365
|
+
g.check_interrupts
|
366
|
+
end
|
367
|
+
|
368
|
+
def bytecode(g, use_gif=true)
|
369
|
+
pos(g)
|
370
|
+
|
371
|
+
g.push_modifiers
|
372
|
+
|
373
|
+
top = g.new_label
|
374
|
+
post = g.next = g.new_label
|
375
|
+
bottom = g.new_label
|
376
|
+
|
377
|
+
g.break = g.new_label
|
378
|
+
|
379
|
+
if @check_first
|
380
|
+
g.redo = g.new_label
|
381
|
+
|
382
|
+
top.set!
|
383
|
+
condition_bytecode(g, bottom, use_gif)
|
384
|
+
|
385
|
+
g.redo.set!
|
386
|
+
body_bytecode(g, post)
|
387
|
+
else
|
388
|
+
g.redo = top
|
389
|
+
|
390
|
+
top.set!
|
391
|
+
body_bytecode(g, post)
|
392
|
+
|
393
|
+
condition_bytecode(g, bottom, use_gif)
|
394
|
+
end
|
395
|
+
|
396
|
+
g.goto top
|
397
|
+
|
398
|
+
# See other set_line(0) comments
|
399
|
+
g.set_line 0
|
400
|
+
|
401
|
+
bottom.set!
|
402
|
+
g.push :nil
|
403
|
+
g.break.set!
|
404
|
+
|
405
|
+
g.pop_modifiers
|
406
|
+
end
|
407
|
+
|
408
|
+
def sexp_name
|
409
|
+
:while
|
410
|
+
end
|
411
|
+
|
412
|
+
def to_sexp
|
413
|
+
[sexp_name, @condition.to_sexp, @body.to_sexp, @check_first]
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
class Until < While
|
418
|
+
def bytecode(g)
|
419
|
+
super(g, false)
|
420
|
+
end
|
421
|
+
|
422
|
+
def sexp_name
|
423
|
+
:until
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
class Match < Node
|
428
|
+
attr_accessor :pattern
|
429
|
+
|
430
|
+
def initialize(line, pattern, flags)
|
431
|
+
@line = line
|
432
|
+
@pattern = RegexLiteral.new line, pattern, flags
|
433
|
+
end
|
434
|
+
|
435
|
+
def bytecode(g)
|
436
|
+
pos(g)
|
437
|
+
|
438
|
+
g.push_rubinius
|
439
|
+
g.find_const :Globals
|
440
|
+
g.push_literal :$_
|
441
|
+
g.send :[], 1
|
442
|
+
|
443
|
+
@pattern.bytecode(g)
|
444
|
+
|
445
|
+
g.send :=~, 1
|
446
|
+
end
|
447
|
+
|
448
|
+
def to_sexp
|
449
|
+
[:match, @pattern.to_sexp]
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
class Match2 < Node
|
454
|
+
attr_accessor :pattern, :value
|
455
|
+
|
456
|
+
def initialize(line, pattern, value)
|
457
|
+
@line = line
|
458
|
+
@pattern = pattern
|
459
|
+
@value = value
|
460
|
+
end
|
461
|
+
|
462
|
+
def bytecode(g)
|
463
|
+
pos(g)
|
464
|
+
|
465
|
+
@pattern.bytecode(g)
|
466
|
+
@value.bytecode(g)
|
467
|
+
g.send :=~, 1
|
468
|
+
if @pattern.kind_of? RegexLiteral
|
469
|
+
regexp = Regexp.new(@pattern.source)
|
470
|
+
# TODO: this code cannot just use Rubinius-specific methods.
|
471
|
+
# Fix without using respond_to?.
|
472
|
+
if regexp.respond_to? :name_table
|
473
|
+
if table = regexp.name_table
|
474
|
+
table.sort_by { |name, idx| idx }.each do |name, idx|
|
475
|
+
local = g.state.scope.new_local name
|
476
|
+
g.last_match 5, idx.last - 1
|
477
|
+
|
478
|
+
case local
|
479
|
+
when Compiler::LocalVariable
|
480
|
+
g.set_local local.slot
|
481
|
+
when Compiler::EvalLocalVariable
|
482
|
+
g.push_variables
|
483
|
+
g.swap
|
484
|
+
g.push_literal name
|
485
|
+
g.swap
|
486
|
+
g.send :set_eval_local, 2, false
|
487
|
+
else
|
488
|
+
raise CompileError, "unknown type of local #{local.inspect}"
|
489
|
+
end
|
490
|
+
|
491
|
+
g.pop
|
492
|
+
end
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
def to_sexp
|
499
|
+
[:match2, @pattern.to_sexp, @value.to_sexp]
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
class Match3 < Node
|
504
|
+
attr_accessor :pattern, :value
|
505
|
+
|
506
|
+
def initialize(line, pattern, value)
|
507
|
+
@line = line
|
508
|
+
@pattern = pattern
|
509
|
+
@value = value
|
510
|
+
end
|
511
|
+
|
512
|
+
def bytecode(g)
|
513
|
+
pos(g)
|
514
|
+
|
515
|
+
@value.bytecode(g)
|
516
|
+
@pattern.bytecode(g)
|
517
|
+
g.send :=~, 1
|
518
|
+
end
|
519
|
+
|
520
|
+
def to_sexp
|
521
|
+
[:match3, @pattern.to_sexp, @value.to_sexp]
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
class Break < Node
|
526
|
+
attr_accessor :value
|
527
|
+
|
528
|
+
def initialize(line, expr)
|
529
|
+
@line = line
|
530
|
+
@value = expr || NilLiteral.new(line)
|
531
|
+
end
|
532
|
+
|
533
|
+
def jump_error(g, name)
|
534
|
+
g.push_rubinius
|
535
|
+
g.push_literal name
|
536
|
+
g.send :jump_error, 1
|
537
|
+
end
|
538
|
+
|
539
|
+
def bytecode(g)
|
540
|
+
pos(g)
|
541
|
+
|
542
|
+
@value.bytecode(g)
|
543
|
+
|
544
|
+
if g.break
|
545
|
+
g.goto g.break
|
546
|
+
elsif g.state.block?
|
547
|
+
g.raise_break
|
548
|
+
else
|
549
|
+
g.pop
|
550
|
+
jump_error g, :break
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
def sexp_name
|
555
|
+
:break
|
556
|
+
end
|
557
|
+
|
558
|
+
def to_sexp
|
559
|
+
sexp = [sexp_name]
|
560
|
+
sexp << @value.to_sexp if @value
|
561
|
+
sexp
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
class Next < Break
|
566
|
+
def initialize(line, value)
|
567
|
+
@line = line
|
568
|
+
@value = value
|
569
|
+
end
|
570
|
+
|
571
|
+
def bytecode(g)
|
572
|
+
pos(g)
|
573
|
+
|
574
|
+
# From "The Ruby Programming Lanuage"
|
575
|
+
# "When next is used in a loop, any values following the next
|
576
|
+
# are ignored"
|
577
|
+
#
|
578
|
+
# By ignored, it must mean evaluated and the value of the expression
|
579
|
+
# is thrown away, because 1.8 evaluates them even though it doesn't
|
580
|
+
# use them.
|
581
|
+
if @value
|
582
|
+
@value.bytecode(g)
|
583
|
+
else
|
584
|
+
g.push :nil
|
585
|
+
end
|
586
|
+
|
587
|
+
if g.state.loop?
|
588
|
+
g.goto g.next
|
589
|
+
elsif g.state.block?
|
590
|
+
if g.next
|
591
|
+
g.goto g.next
|
592
|
+
else
|
593
|
+
g.ret
|
594
|
+
end
|
595
|
+
else
|
596
|
+
g.pop
|
597
|
+
|
598
|
+
jump_error g, :next
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
def sexp_name
|
603
|
+
:next
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
class Redo < Break
|
608
|
+
def initialize(line)
|
609
|
+
@line = line
|
610
|
+
end
|
611
|
+
|
612
|
+
def bytecode(g)
|
613
|
+
pos(g)
|
614
|
+
|
615
|
+
if g.redo
|
616
|
+
g.check_interrupts
|
617
|
+
g.goto g.redo
|
618
|
+
else
|
619
|
+
jump_error g, :redo
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
def to_sexp
|
624
|
+
[:redo]
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
class Retry < Break
|
629
|
+
def initialize(line)
|
630
|
+
@line = line
|
631
|
+
end
|
632
|
+
|
633
|
+
def bytecode(g)
|
634
|
+
pos(g)
|
635
|
+
|
636
|
+
if g.retry
|
637
|
+
g.goto g.retry
|
638
|
+
else
|
639
|
+
jump_error g, :retry
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
def to_sexp
|
644
|
+
[:retry]
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
class Return < Node
|
649
|
+
attr_accessor :value
|
650
|
+
|
651
|
+
def initialize(line, expr)
|
652
|
+
@line = line
|
653
|
+
@value = expr
|
654
|
+
@splat = nil
|
655
|
+
end
|
656
|
+
|
657
|
+
def block=(node)
|
658
|
+
@value.block = node if @value
|
659
|
+
end
|
660
|
+
|
661
|
+
def bytecode(g, force=false)
|
662
|
+
pos(g)
|
663
|
+
|
664
|
+
# Literal ArrayList and a splat
|
665
|
+
if @splat
|
666
|
+
splat_node = @value.body.pop
|
667
|
+
@value.bytecode(g)
|
668
|
+
splat_node.call_bytecode(g)
|
669
|
+
g.send :+, 1
|
670
|
+
elsif @value
|
671
|
+
@value.bytecode(g)
|
672
|
+
else
|
673
|
+
g.push :nil
|
674
|
+
end
|
675
|
+
|
676
|
+
if lcl = g.state.rescue?
|
677
|
+
g.push_stack_local lcl
|
678
|
+
g.restore_exception_state
|
679
|
+
end
|
680
|
+
|
681
|
+
if g.state.block?
|
682
|
+
g.raise_return
|
683
|
+
elsif !force and g.state.ensure?
|
684
|
+
g.ensure_return
|
685
|
+
else
|
686
|
+
g.ret
|
687
|
+
end
|
688
|
+
end
|
689
|
+
|
690
|
+
def to_sexp
|
691
|
+
sexp = [:return]
|
692
|
+
sexp << @value.to_sexp if @value
|
693
|
+
sexp << @splat.to_sexp if @splat
|
694
|
+
sexp
|
695
|
+
end
|
696
|
+
end
|
697
|
+
end
|
698
|
+
end
|