twostroke 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/twostroke/ast/array.rb +8 -0
- data/lib/twostroke/ast/assignment.rb +7 -0
- data/lib/twostroke/ast/binary_operators.rb +7 -0
- data/lib/twostroke/ast/body.rb +6 -0
- data/lib/twostroke/ast/break.rb +4 -0
- data/lib/twostroke/ast/call.rb +7 -0
- data/lib/twostroke/ast/case.rb +9 -1
- data/lib/twostroke/ast/continue.rb +11 -0
- data/lib/twostroke/ast/declaration.rb +4 -0
- data/lib/twostroke/ast/delete.rb +6 -0
- data/lib/twostroke/ast/do_while.rb +7 -0
- data/lib/twostroke/ast/false.rb +11 -0
- data/lib/twostroke/ast/for_in.rb +8 -0
- data/lib/twostroke/ast/for_loop.rb +10 -1
- data/lib/twostroke/ast/function.rb +6 -0
- data/lib/twostroke/ast/if.rb +8 -0
- data/lib/twostroke/ast/index.rb +7 -0
- data/lib/twostroke/ast/member_access.rb +6 -0
- data/lib/twostroke/ast/multi_expression.rb +7 -0
- data/lib/twostroke/ast/new.rb +7 -0
- data/lib/twostroke/ast/null.rb +4 -0
- data/lib/twostroke/ast/number.rb +4 -0
- data/lib/twostroke/ast/object_literal.rb +6 -0
- data/lib/twostroke/ast/regexp.rb +4 -0
- data/lib/twostroke/ast/return.rb +6 -0
- data/lib/twostroke/ast/string.rb +4 -0
- data/lib/twostroke/ast/switch.rb +7 -0
- data/lib/twostroke/ast/ternary.rb +8 -0
- data/lib/twostroke/ast/this.rb +4 -0
- data/lib/twostroke/ast/throw.rb +6 -0
- data/lib/twostroke/ast/true.rb +11 -0
- data/lib/twostroke/ast/try.rb +8 -0
- data/lib/twostroke/ast/unary_operators.rb +7 -1
- data/lib/twostroke/ast/variable.rb +4 -0
- data/lib/twostroke/ast/while.rb +8 -1
- data/lib/twostroke/ast/with.rb +16 -0
- data/lib/twostroke/compiler/javascript.rb +396 -0
- data/lib/twostroke/compiler/tsasm.rb +595 -0
- data/lib/twostroke/compiler.rb +8 -0
- data/lib/twostroke/parser.rb +47 -9
- data/lib/twostroke/runtime/lib/array.js +144 -0
- data/lib/twostroke/runtime/lib/array.rb +71 -0
- data/lib/twostroke/runtime/lib/boolean.rb +23 -0
- data/lib/twostroke/runtime/lib/console.rb +13 -0
- data/lib/twostroke/runtime/lib/date.rb +65 -0
- data/lib/twostroke/runtime/lib/error.rb +36 -0
- data/lib/twostroke/runtime/lib/function.js +0 -0
- data/lib/twostroke/runtime/lib/function.rb +45 -0
- data/lib/twostroke/runtime/lib/math.rb +36 -0
- data/lib/twostroke/runtime/lib/number.rb +65 -0
- data/lib/twostroke/runtime/lib/object.js +0 -0
- data/lib/twostroke/runtime/lib/object.rb +55 -0
- data/lib/twostroke/runtime/lib/regexp.rb +28 -0
- data/lib/twostroke/runtime/lib/string.rb +86 -0
- data/lib/twostroke/runtime/lib/undefined.rb +7 -0
- data/lib/twostroke/runtime/lib.rb +42 -0
- data/lib/twostroke/runtime/scope.rb +120 -0
- data/lib/twostroke/runtime/types/array.rb +79 -0
- data/lib/twostroke/runtime/types/boolean.rb +23 -0
- data/lib/twostroke/runtime/types/boolean_object.rb +25 -0
- data/lib/twostroke/runtime/types/function.rb +83 -0
- data/lib/twostroke/runtime/types/null.rb +11 -3
- data/lib/twostroke/runtime/types/number.rb +31 -0
- data/lib/twostroke/runtime/types/number_object.rb +25 -0
- data/lib/twostroke/runtime/types/object.rb +169 -20
- data/lib/twostroke/runtime/types/regexp.rb +31 -0
- data/lib/twostroke/runtime/types/string.rb +16 -0
- data/lib/twostroke/runtime/types/string_object.rb +52 -0
- data/lib/twostroke/runtime/types/undefined.rb +11 -3
- data/lib/twostroke/runtime/types/value.rb +14 -0
- data/lib/twostroke/runtime/types.rb +133 -4
- data/lib/twostroke/runtime/vm.rb +25 -0
- data/lib/twostroke/runtime/vm_frame.rb +459 -0
- data/lib/twostroke/runtime.rb +6 -5
- data/lib/twostroke/tokens.rb +20 -8
- data/lib/twostroke.rb +3 -1
- metadata +41 -7
- data/lib/twostroke/runtime/context.rb +0 -33
- data/lib/twostroke/runtime/environment.rb +0 -13
- data/lib/twostroke/runtime/types/basic_type.rb +0 -5
@@ -0,0 +1,595 @@
|
|
1
|
+
class Twostroke::Compiler::TSASM
|
2
|
+
attr_accessor :bytecode, :ast, :prefix
|
3
|
+
|
4
|
+
def initialize(ast, prefix = nil)
|
5
|
+
@methods = Hash[self.class.private_instance_methods(false).map { |name| [name, true] }]
|
6
|
+
@ast = ast
|
7
|
+
@prefix = prefix
|
8
|
+
end
|
9
|
+
|
10
|
+
def compile(node = nil)
|
11
|
+
if node
|
12
|
+
if node.respond_to? :each
|
13
|
+
# hoist named functions to top
|
14
|
+
node.select { |n| n.is_a?(Twostroke::AST::Function) && n.name }.each { |n| compile n }
|
15
|
+
node.reject { |n| n.is_a?(Twostroke::AST::Function) && n.name }.each { |n| compile n }
|
16
|
+
elsif node.is_a? Symbol
|
17
|
+
send node
|
18
|
+
else
|
19
|
+
if @methods[type(node)]
|
20
|
+
send type(node), node if node
|
21
|
+
else
|
22
|
+
error! "#{type node} not implemented"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
else
|
26
|
+
@indent = 0
|
27
|
+
@bytecode = Hash.new { |h,k| h[k] = [] }
|
28
|
+
@current_section = :"#{prefix}main"
|
29
|
+
@auto_inc = 0
|
30
|
+
@sections = [:"#{prefix}main"]
|
31
|
+
@break_stack = []
|
32
|
+
@continue_stack = []
|
33
|
+
|
34
|
+
ast.each { |node| hoist node }
|
35
|
+
ast.each { |node| compile node }
|
36
|
+
output :undefined
|
37
|
+
output :ret
|
38
|
+
|
39
|
+
fix_labels
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
# utility methods
|
45
|
+
|
46
|
+
def fix_labels
|
47
|
+
bytecode.each do |k,v|
|
48
|
+
labels_at = {}
|
49
|
+
offset = 0
|
50
|
+
v.each_with_index do |ins,i|
|
51
|
+
if ins[0] == :".label"
|
52
|
+
labels_at[ins[1]] = i + offset
|
53
|
+
offset -= 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
bytecode[k] = v.select do |ins|
|
57
|
+
if [:jmp, :jit, :jif, :pushcatch, :pushfinally, :jiee].include?(ins[0])
|
58
|
+
ins[1] = labels_at[ins[1]]
|
59
|
+
end
|
60
|
+
ins[0] != :".label"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def hoist(node)
|
66
|
+
node.walk do |node|
|
67
|
+
if node.is_a? Twostroke::AST::Declaration
|
68
|
+
output :".local", node.name.intern
|
69
|
+
elsif node.is_a? Twostroke::AST::Function
|
70
|
+
output :".local", node.name.intern if node.name
|
71
|
+
false
|
72
|
+
else
|
73
|
+
true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def error!(msg)
|
79
|
+
raise Twostroke::Compiler::CompileError, msg
|
80
|
+
end
|
81
|
+
|
82
|
+
def type(node)
|
83
|
+
node.class.name.split("::").last.intern
|
84
|
+
end
|
85
|
+
|
86
|
+
def output(*args)
|
87
|
+
@bytecode[@current_section] << args
|
88
|
+
end
|
89
|
+
|
90
|
+
def section(sect)
|
91
|
+
@sections.push @current_section
|
92
|
+
@current_section = sect
|
93
|
+
end
|
94
|
+
|
95
|
+
def pop_section
|
96
|
+
@current_section = @sections.pop
|
97
|
+
end
|
98
|
+
|
99
|
+
def uniqid
|
100
|
+
@auto_inc += 1
|
101
|
+
end
|
102
|
+
|
103
|
+
def mutate(left, right)
|
104
|
+
if type(left) == :Variable || type(left) == :Declaration
|
105
|
+
compile right
|
106
|
+
output :set, left.name.intern
|
107
|
+
elsif type(left) == :MemberAccess
|
108
|
+
compile left.object
|
109
|
+
compile right
|
110
|
+
output :setprop, left.member.intern
|
111
|
+
elsif type(left) == :Index
|
112
|
+
compile left.object
|
113
|
+
compile left.index
|
114
|
+
compile right
|
115
|
+
output :setindex
|
116
|
+
else
|
117
|
+
error! "Bad lval in assignment"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# code generation
|
122
|
+
|
123
|
+
{ Addition: :add, Subtraction: :sub, Multiplication: :mul, Division: :div,
|
124
|
+
Equality: :eq, StrictEquality: :seq, LessThan: :lt, GreaterThan: :gt,
|
125
|
+
LessThanEqual: :lte, GreaterThanEqual: :gte, BitwiseAnd: :and,
|
126
|
+
BitwiseOr: :or, BitwiseXor: :xor, In: :in, RightArithmeticShift: :sar,
|
127
|
+
LeftShift: :sal, RightLogicalShift: :slr, InstanceOf: :instanceof,
|
128
|
+
Modulus: :mod
|
129
|
+
}.each do |method,op|
|
130
|
+
define_method method do |node|
|
131
|
+
if node.assign_result_left
|
132
|
+
if type(node.left) == :Variable || type(node.left) == :Declaration
|
133
|
+
compile node.left
|
134
|
+
compile node.right
|
135
|
+
output op
|
136
|
+
output :set, node.left.name.intern
|
137
|
+
elsif type(node.left) == :MemberAccess
|
138
|
+
compile node.left.object
|
139
|
+
dup
|
140
|
+
output :member, node.left.member.intern
|
141
|
+
compile node.right
|
142
|
+
output op
|
143
|
+
output :setprop, node.left.member.intern
|
144
|
+
elsif type(node.left) == :Index
|
145
|
+
compile node.left.object
|
146
|
+
compile node.left.index
|
147
|
+
output :dup, 2
|
148
|
+
output :index
|
149
|
+
compile node.right
|
150
|
+
output op
|
151
|
+
output :setindex
|
152
|
+
else
|
153
|
+
error! "Bad lval in combined operation/assignment"
|
154
|
+
end
|
155
|
+
else
|
156
|
+
compile node.left
|
157
|
+
compile node.right
|
158
|
+
output op
|
159
|
+
end
|
160
|
+
end
|
161
|
+
private method
|
162
|
+
end
|
163
|
+
def StrictInequality(node)
|
164
|
+
StrictEquality(node)
|
165
|
+
output :not
|
166
|
+
end
|
167
|
+
def Inequality(node)
|
168
|
+
Equality(node)
|
169
|
+
output :not
|
170
|
+
end
|
171
|
+
|
172
|
+
def post_mutate(left, op)
|
173
|
+
if type(left) == :Variable || type(left) == :Declaration
|
174
|
+
output :push, left.name.intern
|
175
|
+
output :dup
|
176
|
+
output op
|
177
|
+
output :set, left.name.intern
|
178
|
+
output :pop
|
179
|
+
elsif type(left) == :MemberAccess
|
180
|
+
compile left.object
|
181
|
+
output :dup
|
182
|
+
output :member, left.member.intern
|
183
|
+
output op
|
184
|
+
output :setprop, left.member.intern
|
185
|
+
elsif type(left) == :Index
|
186
|
+
compile left.object
|
187
|
+
compile left.index
|
188
|
+
output :dup, 2
|
189
|
+
output :index
|
190
|
+
output op
|
191
|
+
output :setindex
|
192
|
+
else
|
193
|
+
error! "Bad lval in post-mutation"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def PostIncrement(node)
|
198
|
+
post_mutate node.value, :inc
|
199
|
+
end
|
200
|
+
|
201
|
+
def PostDecrement(node)
|
202
|
+
post_mutate node.value, :dec
|
203
|
+
end
|
204
|
+
|
205
|
+
def pre_mutate(left, op)
|
206
|
+
if type(left) == :Variable || type(left) == :Declaration
|
207
|
+
output :push, left.name.intern
|
208
|
+
output op
|
209
|
+
output :set, left.name.intern
|
210
|
+
elsif type(left) == :MemberAccess
|
211
|
+
compile left.object
|
212
|
+
output :dup
|
213
|
+
output :member, left.member.intern
|
214
|
+
output op
|
215
|
+
output :setprop, left.member.intern
|
216
|
+
elsif type(left) == :Index
|
217
|
+
error! "pre-mutatation of array index not supported yet" # @TODO
|
218
|
+
else
|
219
|
+
error! "Bad lval in post-mutation"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def PreIncrement(node)
|
224
|
+
pre_mutate node.value, :inc
|
225
|
+
end
|
226
|
+
|
227
|
+
def PreDecrement(node)
|
228
|
+
pre_mutate node.value, :dec
|
229
|
+
end
|
230
|
+
|
231
|
+
def Call(node)
|
232
|
+
if type(node.callee) == :MemberAccess
|
233
|
+
compile node.callee.object
|
234
|
+
output :dup
|
235
|
+
output :member, node.callee.member.intern
|
236
|
+
node.arguments.each { |n| compile n }
|
237
|
+
output :thiscall, node.arguments.size
|
238
|
+
elsif type(node.callee) == :Index
|
239
|
+
compile node.callee.object
|
240
|
+
output :dup
|
241
|
+
output node.callee.index
|
242
|
+
output :index
|
243
|
+
node.arguments.each { |n| compile n }
|
244
|
+
output :thiscall, node.arguments.size
|
245
|
+
else
|
246
|
+
compile node.callee
|
247
|
+
node.arguments.each { |n| compile n }
|
248
|
+
output :call, node.arguments.size
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def New(node)
|
253
|
+
compile node.callee
|
254
|
+
node.arguments.each { |n| compile n }
|
255
|
+
output :newcall, node.arguments.size
|
256
|
+
end
|
257
|
+
|
258
|
+
def Variable(node)
|
259
|
+
output :push, node.name.intern
|
260
|
+
end
|
261
|
+
|
262
|
+
def Null(node)
|
263
|
+
output :null
|
264
|
+
end
|
265
|
+
|
266
|
+
def True(node)
|
267
|
+
output :true
|
268
|
+
end
|
269
|
+
|
270
|
+
def False(node)
|
271
|
+
output :false
|
272
|
+
end
|
273
|
+
|
274
|
+
def Regexp(node)
|
275
|
+
output :regexp, node.regexp
|
276
|
+
end
|
277
|
+
|
278
|
+
def Function(node)
|
279
|
+
fnid = :"#{@prefix}fn_#{uniqid}"
|
280
|
+
|
281
|
+
section fnid
|
282
|
+
output :".name", node.name if node.name
|
283
|
+
node.arguments.each do |arg|
|
284
|
+
output :".arg", arg.intern
|
285
|
+
end
|
286
|
+
output :".local", node.name.intern if node.name
|
287
|
+
node.statements.each { |s| hoist s }
|
288
|
+
if node.name
|
289
|
+
output :callee
|
290
|
+
output :set, node.name.intern
|
291
|
+
end
|
292
|
+
node.statements.each { |s| compile s }
|
293
|
+
output :undefined
|
294
|
+
output :ret
|
295
|
+
pop_section
|
296
|
+
|
297
|
+
output :close, fnid
|
298
|
+
output :set, node.name.intern if node.name
|
299
|
+
end
|
300
|
+
|
301
|
+
def Declaration(node)
|
302
|
+
# no-op since declarations have already been hoisted
|
303
|
+
end
|
304
|
+
|
305
|
+
def MultiExpression(node)
|
306
|
+
output :pushsp
|
307
|
+
compile node.left
|
308
|
+
output :popsp
|
309
|
+
compile node.right
|
310
|
+
end
|
311
|
+
|
312
|
+
def Assignment(node)
|
313
|
+
mutate node.left, node.right
|
314
|
+
end
|
315
|
+
|
316
|
+
def String(node)
|
317
|
+
output :push, node.string
|
318
|
+
end
|
319
|
+
|
320
|
+
def Return(node)
|
321
|
+
if node.expression
|
322
|
+
compile node.expression
|
323
|
+
else
|
324
|
+
output :undefined
|
325
|
+
end
|
326
|
+
output :ret
|
327
|
+
end
|
328
|
+
|
329
|
+
def Delete(node)
|
330
|
+
if node.expression.is_a?(Twostroke::AST::Variable)
|
331
|
+
output :deleteg, node.expression.name
|
332
|
+
elsif node.expression.is_a?(Twostroke::AST::MemberAccess)
|
333
|
+
compile node.expression.object
|
334
|
+
output :delete, node.expression.member
|
335
|
+
elsif node.expression.is_a?(Twostroke::AST::Index)
|
336
|
+
compile node.expression.object
|
337
|
+
output :delete, node.expression.index
|
338
|
+
else
|
339
|
+
output :true
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def Throw(node)
|
344
|
+
compile node.expression
|
345
|
+
output :_throw
|
346
|
+
end
|
347
|
+
|
348
|
+
def Try(node)
|
349
|
+
if node.catch_variable
|
350
|
+
catch_label = uniqid
|
351
|
+
output :pushcatch, catch_label
|
352
|
+
end
|
353
|
+
finally_label = uniqid
|
354
|
+
if node.finally_statements
|
355
|
+
output :pushfinally, finally_label
|
356
|
+
end
|
357
|
+
end_label = uniqid
|
358
|
+
compile node.try_statements
|
359
|
+
# no exceptions? clean up
|
360
|
+
output :popcatch if node.catch_variable
|
361
|
+
output :popfinally if node.catch_variable
|
362
|
+
output :jmp, finally_label
|
363
|
+
|
364
|
+
if node.catch_variable
|
365
|
+
output :".label", catch_label
|
366
|
+
output :".catch", node.catch_variable.intern
|
367
|
+
output :popcatch
|
368
|
+
compile node.catch_statements
|
369
|
+
end
|
370
|
+
output :".label", finally_label
|
371
|
+
if node.finally_statements
|
372
|
+
output :popfinally
|
373
|
+
compile node.finally_statements
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
def Or(node)
|
378
|
+
compile node.left
|
379
|
+
output :dup
|
380
|
+
end_label = uniqid
|
381
|
+
output :jit, end_label
|
382
|
+
output :pop
|
383
|
+
compile node.right
|
384
|
+
output :".label", end_label
|
385
|
+
end
|
386
|
+
|
387
|
+
def And(node)
|
388
|
+
compile node.left
|
389
|
+
output :dup
|
390
|
+
end_label = uniqid
|
391
|
+
output :jif, end_label
|
392
|
+
output :pop
|
393
|
+
compile node.right
|
394
|
+
output :".label", end_label
|
395
|
+
end
|
396
|
+
|
397
|
+
def ObjectLiteral(node)
|
398
|
+
args = []
|
399
|
+
node.items.each do |k,v|
|
400
|
+
args << k
|
401
|
+
compile v
|
402
|
+
end
|
403
|
+
output :object, args.map(&:val)
|
404
|
+
end
|
405
|
+
|
406
|
+
def Array(node)
|
407
|
+
node.items.each do |item|
|
408
|
+
compile item
|
409
|
+
end
|
410
|
+
output :array, node.items.size
|
411
|
+
end
|
412
|
+
|
413
|
+
def While(node)
|
414
|
+
start_label = uniqid
|
415
|
+
end_label = uniqid
|
416
|
+
@continue_stack.push start_label
|
417
|
+
@break_stack.push end_label
|
418
|
+
output :".label", start_label
|
419
|
+
compile node.condition
|
420
|
+
output :jif, end_label
|
421
|
+
compile node.body
|
422
|
+
output :jmp, start_label
|
423
|
+
output :".label", end_label
|
424
|
+
@continue_stack.pop
|
425
|
+
@break_stack.pop
|
426
|
+
end
|
427
|
+
|
428
|
+
def MemberAccess(node)
|
429
|
+
compile node.object
|
430
|
+
output :member, node.member.intern
|
431
|
+
end
|
432
|
+
|
433
|
+
def Index(node)
|
434
|
+
compile node.object
|
435
|
+
compile node.index
|
436
|
+
output :index
|
437
|
+
end
|
438
|
+
|
439
|
+
def Number(node)
|
440
|
+
output :push, node.number
|
441
|
+
end
|
442
|
+
|
443
|
+
def UnaryPlus(node)
|
444
|
+
compile node.value
|
445
|
+
output :number
|
446
|
+
end
|
447
|
+
|
448
|
+
def This(node)
|
449
|
+
output :this
|
450
|
+
end
|
451
|
+
|
452
|
+
def With(node)
|
453
|
+
compile node.object
|
454
|
+
output :with
|
455
|
+
compile node.statement
|
456
|
+
output :popscope
|
457
|
+
end
|
458
|
+
|
459
|
+
def If(node)
|
460
|
+
compile node.condition
|
461
|
+
else_label = uniqid
|
462
|
+
output :jif, else_label
|
463
|
+
compile node.then
|
464
|
+
if node.else
|
465
|
+
end_label = uniqid
|
466
|
+
output :jmp, end_label
|
467
|
+
output :".label", else_label
|
468
|
+
compile node.else
|
469
|
+
output :".label", end_label
|
470
|
+
else
|
471
|
+
output :".label", else_label
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
def Ternary(node)
|
476
|
+
compile node.condition
|
477
|
+
else_label = uniqid
|
478
|
+
end_label = uniqid
|
479
|
+
output :jif, else_label
|
480
|
+
compile node.if_true
|
481
|
+
output :jmp, end_label
|
482
|
+
output :".label", else_label
|
483
|
+
compile node.if_false
|
484
|
+
output :".label", end_label
|
485
|
+
end
|
486
|
+
|
487
|
+
def Switch(node)
|
488
|
+
cases = node.cases.map { |c| [uniqid, c] }
|
489
|
+
default = cases.select { |l,c| c.expression.nil? }.first
|
490
|
+
end_label = uniqid
|
491
|
+
compile node.expression
|
492
|
+
output :pushsp
|
493
|
+
|
494
|
+
@break_stack.push end_label
|
495
|
+
|
496
|
+
cases.select { |l,c| c.expression }.each do |label, c|
|
497
|
+
output :popsp
|
498
|
+
output :pushsp
|
499
|
+
output :dup
|
500
|
+
compile c.expression
|
501
|
+
output :seq
|
502
|
+
output :jit, label
|
503
|
+
end
|
504
|
+
output :popsp # restore sp stack
|
505
|
+
output :jmp, (default ? default[0] : end_label)
|
506
|
+
|
507
|
+
cases.each do |label, c|
|
508
|
+
output :".label", label
|
509
|
+
compile c.statements
|
510
|
+
end
|
511
|
+
|
512
|
+
output :".label", end_label
|
513
|
+
@break_stack.pop
|
514
|
+
end
|
515
|
+
|
516
|
+
def Body(node)
|
517
|
+
node.statements.each { |s| compile s }
|
518
|
+
end
|
519
|
+
|
520
|
+
def ForLoop(node)
|
521
|
+
compile node.initializer if node.initializer
|
522
|
+
start_label = uniqid
|
523
|
+
end_label = uniqid
|
524
|
+
@continue_stack.push start_label
|
525
|
+
@break_stack.push end_label
|
526
|
+
output :".label", start_label
|
527
|
+
compile node.condition if node.condition
|
528
|
+
output :jif, end_label
|
529
|
+
compile node.body if node.body
|
530
|
+
compile node.increment if node.increment
|
531
|
+
output :jmp, start_label
|
532
|
+
output :".label", end_label
|
533
|
+
@continue_stack.pop
|
534
|
+
@break_stack.pop
|
535
|
+
end
|
536
|
+
|
537
|
+
def _enum_next
|
538
|
+
output :enumnext
|
539
|
+
end
|
540
|
+
|
541
|
+
def ForIn(node)
|
542
|
+
end_label = uniqid
|
543
|
+
loop_label = uniqid
|
544
|
+
@break_stack.push end_label
|
545
|
+
@continue_stack.push loop_label
|
546
|
+
compile node.object
|
547
|
+
output :enum
|
548
|
+
output :".label", loop_label
|
549
|
+
output :jiee, end_label
|
550
|
+
mutate node.lval, :_enum_next
|
551
|
+
compile node.body
|
552
|
+
output :jmp, loop_label
|
553
|
+
output :".label", end_label
|
554
|
+
output :popenum
|
555
|
+
@break_stack.pop
|
556
|
+
@continue_stack.pop
|
557
|
+
end
|
558
|
+
|
559
|
+
def Not(node)
|
560
|
+
compile node.value
|
561
|
+
output :not
|
562
|
+
end
|
563
|
+
|
564
|
+
def Break(node)
|
565
|
+
output :jmp, @break_stack.last
|
566
|
+
end
|
567
|
+
|
568
|
+
def Continue(node)
|
569
|
+
output :jmp, @continue_stack.last
|
570
|
+
end
|
571
|
+
|
572
|
+
def TypeOf(node)
|
573
|
+
if node.value.is_a?(Twostroke::AST::Variable)
|
574
|
+
output :typeof, node.value.name.intern
|
575
|
+
else
|
576
|
+
compile node.value
|
577
|
+
output :typeof
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
def BracketedExpression(node)
|
582
|
+
compile node.value
|
583
|
+
end
|
584
|
+
|
585
|
+
def Void(node)
|
586
|
+
compile node.value
|
587
|
+
output :pop
|
588
|
+
output :undefined
|
589
|
+
end
|
590
|
+
|
591
|
+
def Negation(node)
|
592
|
+
compile node.value
|
593
|
+
output :negate
|
594
|
+
end
|
595
|
+
end
|