twostroke 0.2.2 → 0.2.3
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.rb +2 -1
- data/lib/twostroke/ast/break.rb +2 -0
- data/lib/twostroke/ast/continue.rb +2 -0
- data/lib/twostroke/compiler/tsasm.rb +45 -18
- data/lib/twostroke/context.rb +58 -0
- data/lib/twostroke/context/object_proxy.rb +42 -0
- data/lib/twostroke/lexer.rb +10 -2
- data/lib/twostroke/parser.rb +36 -8
- data/lib/twostroke/runtime/lib.rb +3 -1
- data/lib/twostroke/runtime/lib/boolean.rb +4 -10
- data/lib/twostroke/runtime/lib/console.rb +1 -1
- data/lib/twostroke/runtime/lib/date.rb +18 -4
- data/lib/twostroke/runtime/lib/etc.rb +1 -15
- data/lib/twostroke/runtime/lib/function.rb +2 -8
- data/lib/twostroke/runtime/lib/math.rb +14 -2
- data/lib/twostroke/runtime/lib/number.js +3 -0
- data/lib/twostroke/runtime/lib/number.rb +12 -5
- data/lib/twostroke/runtime/lib/object.rb +4 -4
- data/lib/twostroke/runtime/lib/regexp.rb +2 -2
- data/lib/twostroke/runtime/scope.rb +1 -5
- data/lib/twostroke/runtime/types.rb +17 -2
- data/lib/twostroke/runtime/types/array.rb +4 -0
- data/lib/twostroke/runtime/types/boolean.rb +5 -1
- data/lib/twostroke/runtime/types/boolean_object.rb +2 -2
- data/lib/twostroke/runtime/types/function.rb +4 -4
- data/lib/twostroke/runtime/types/number.rb +8 -0
- data/lib/twostroke/runtime/types/number_object.rb +2 -2
- data/lib/twostroke/runtime/types/object.rb +5 -7
- data/lib/twostroke/runtime/types/regexp.rb +3 -3
- data/lib/twostroke/runtime/types/string.rb +4 -0
- data/lib/twostroke/runtime/types/string_object.rb +7 -4
- data/lib/twostroke/runtime/types/value.rb +4 -4
- data/lib/twostroke/runtime/vm.rb +12 -0
- data/lib/twostroke/runtime/vm_frame.rb +11 -19
- data/lib/twostroke/tokens.rb +2 -2
- metadata +5 -3
- data/lib/twostroke/compiler/javascript.rb +0 -414
@@ -38,18 +38,14 @@ module Twostroke::Runtime
|
|
38
38
|
until @return
|
39
39
|
ins, arg = insns[ip]
|
40
40
|
@ip += 1
|
41
|
-
if
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
@ip = finally_stack.last
|
49
|
-
end
|
41
|
+
if @exception = catch(:exception) { send ins, arg; nil }
|
42
|
+
# puts "--> #{Types.to_string(exception).string} #{@name || "(anonymous function)"}:#{@line} <#{@section}+#{@ip}>"
|
43
|
+
throw :exception, @exception if catch_stack.empty? && finally_stack.empty?
|
44
|
+
if catch_stack.any?
|
45
|
+
@ip = catch_stack.last
|
46
|
+
else
|
47
|
+
@ip = finally_stack.last
|
50
48
|
end
|
51
|
-
else
|
52
|
-
error! "unknown instruction #{ins}"
|
53
49
|
end
|
54
50
|
end
|
55
51
|
|
@@ -88,12 +84,8 @@ module Twostroke::Runtime
|
|
88
84
|
stack.push scope.get_var(arg)
|
89
85
|
elsif arg.is_a?(Fixnum) || arg.is_a?(Float)
|
90
86
|
stack.push Types::Number.new(arg)
|
91
|
-
elsif arg.is_a?(Bignum)
|
92
|
-
stack.push Types::Number.new(arg.to_f)
|
93
87
|
elsif arg.is_a?(String)
|
94
88
|
stack.push Types::String.new(arg)
|
95
|
-
else
|
96
|
-
error! "bad argument to push instruction"
|
97
89
|
end
|
98
90
|
end
|
99
91
|
|
@@ -232,11 +224,11 @@ module Twostroke::Runtime
|
|
232
224
|
end
|
233
225
|
|
234
226
|
def true(arg)
|
235
|
-
stack.push Types::Boolean.
|
227
|
+
stack.push Types::Boolean.true
|
236
228
|
end
|
237
229
|
|
238
230
|
def false(arg)
|
239
|
-
stack.push Types::Boolean.
|
231
|
+
stack.push Types::Boolean.false
|
240
232
|
end
|
241
233
|
|
242
234
|
def jmp(arg)
|
@@ -300,13 +292,13 @@ module Twostroke::Runtime
|
|
300
292
|
stack.push Types::Number.new(l << r)
|
301
293
|
end
|
302
294
|
|
303
|
-
def
|
295
|
+
def slr(arg)
|
304
296
|
r = Types.to_uint32(stack.pop) & 31
|
305
297
|
l = Types.to_int32 stack.pop
|
306
298
|
stack.push Types::Number.new(l >> r)
|
307
299
|
end
|
308
300
|
|
309
|
-
def
|
301
|
+
def sar(arg)
|
310
302
|
r = Types.to_uint32(stack.pop) & 31
|
311
303
|
l = Types.to_uint32 stack.pop
|
312
304
|
stack.push Types::Number.new(l >> r)
|
data/lib/twostroke/tokens.rb
CHANGED
@@ -10,7 +10,7 @@ module Twostroke
|
|
10
10
|
[ :SINGLE_COMMENT, /\/\/.*?($|\r|\u2029|\u2028)/ ],
|
11
11
|
|
12
12
|
[ :LINE_TERMINATOR, /[\n\r\u2028\u2029]/ ],
|
13
|
-
[ :WHITESPACE, /[
|
13
|
+
[ :WHITESPACE, /[ \t\r\v\f]+/ ],
|
14
14
|
[ :NUMBER, /((?<oct>0[0-7]+)|(?<hex>0x[A-Fa-f0-9]+)|(?<to_f>(\d+(\.?\d*([eE][+-]?\d+)?)?|\.\d+([eE][+-]?\d+)?)))/, ->m do
|
15
15
|
method, number = m.names.zip(m.captures).select { |k,v| v }.first
|
16
16
|
n = number.send method
|
@@ -29,7 +29,7 @@ module Twostroke
|
|
29
29
|
[ :STRING, /(["'])((\\\n|\\.|[^\n\r\u2028\u2029\1])*?[^\1\\]?)\1/, ->m do
|
30
30
|
m[2].gsub(/\\(([0-6]{1,3})|u([a-f0-9]{4})|x([a-f0-9]{2})|\n|.)/i) do |m|
|
31
31
|
case m
|
32
|
-
when /\\([0-6]{1,3})/; m[1..-1].to_i(
|
32
|
+
when /\\([0-6]{1,3})/; m[1..-1].to_i(8).chr "utf-8"
|
33
33
|
when /\\u([a-f0-9]{4})/i; m[2..-1].to_i(16).chr "utf-8"
|
34
34
|
when /\\x([a-f0-9]{2})/i; m[2..-1].to_i(16).chr "utf-8"
|
35
35
|
else case m[1]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twostroke
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-17 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: An implementation of Javascript written in pure Ruby. Twostroke contains
|
15
15
|
a parser, a bytecode compiler, a VM, and a minimal implementation of the Javascript
|
@@ -57,9 +57,10 @@ files:
|
|
57
57
|
- lib/twostroke/ast/while.rb
|
58
58
|
- lib/twostroke/ast/with.rb
|
59
59
|
- lib/twostroke/ast.rb
|
60
|
-
- lib/twostroke/compiler/javascript.rb
|
61
60
|
- lib/twostroke/compiler/tsasm.rb
|
62
61
|
- lib/twostroke/compiler.rb
|
62
|
+
- lib/twostroke/context/object_proxy.rb
|
63
|
+
- lib/twostroke/context.rb
|
63
64
|
- lib/twostroke/error.rb
|
64
65
|
- lib/twostroke/lexer.rb
|
65
66
|
- lib/twostroke/parser.rb
|
@@ -73,6 +74,7 @@ files:
|
|
73
74
|
- lib/twostroke/runtime/lib/etc.rb
|
74
75
|
- lib/twostroke/runtime/lib/function.rb
|
75
76
|
- lib/twostroke/runtime/lib/math.rb
|
77
|
+
- lib/twostroke/runtime/lib/number.js
|
76
78
|
- lib/twostroke/runtime/lib/number.rb
|
77
79
|
- lib/twostroke/runtime/lib/object.js
|
78
80
|
- lib/twostroke/runtime/lib/object.rb
|
@@ -1,414 +0,0 @@
|
|
1
|
-
class Twostroke::Compiler::Javascript
|
2
|
-
attr_accessor :src, :ast
|
3
|
-
|
4
|
-
def initialize(ast)
|
5
|
-
@methods = Hash[self.class.private_instance_methods(false).map { |name| [name, true] }]
|
6
|
-
@ast = ast
|
7
|
-
end
|
8
|
-
|
9
|
-
def compile(node = nil)
|
10
|
-
if node
|
11
|
-
if node.respond_to? :each
|
12
|
-
# hoist named functions to top
|
13
|
-
node.select { |n| n.is_a?(Twostroke::AST::Function) && n.name }.each { |n| compile n }
|
14
|
-
node.reject { |n| n.is_a?(Twostroke::AST::Function) && n.name }.each { |n| compile n }
|
15
|
-
else
|
16
|
-
if @methods[type(node)]
|
17
|
-
send type(node), node if node
|
18
|
-
else
|
19
|
-
error! "#{type node} not implemented"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
else
|
23
|
-
@indent = 0
|
24
|
-
@src = ""
|
25
|
-
prologue
|
26
|
-
ast.each { |node| compile node }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
# utility methods
|
32
|
-
|
33
|
-
def error!(msg)
|
34
|
-
raise Twostroke::Compiler::CompileError, msg
|
35
|
-
end
|
36
|
-
|
37
|
-
def type(node)
|
38
|
-
node.class.name.split("::").last.intern
|
39
|
-
end
|
40
|
-
|
41
|
-
def indent
|
42
|
-
@indent += 1
|
43
|
-
end
|
44
|
-
|
45
|
-
def dedent
|
46
|
-
@indent -= 1
|
47
|
-
end
|
48
|
-
|
49
|
-
def output(line)
|
50
|
-
@src << "#{"\t" * @indent}#{line}\n"
|
51
|
-
end
|
52
|
-
|
53
|
-
def stack
|
54
|
-
"__stack"
|
55
|
-
end
|
56
|
-
|
57
|
-
def prologue
|
58
|
-
output "var #{stack} = [], #{stack}_sizes = [], __tmp;"
|
59
|
-
end
|
60
|
-
|
61
|
-
def binop(op, node)
|
62
|
-
if node.assign_result_left
|
63
|
-
compile node.right
|
64
|
-
mutate node.left, "%s #{op}= #{stack}.pop()"
|
65
|
-
else
|
66
|
-
compile node.right
|
67
|
-
compile node.left
|
68
|
-
output "#{stack}.push(#{stack}.pop() #{op} #{stack}.pop());"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def escape(str)
|
73
|
-
escaped = str.gsub("\\","\\\\").gsub('"','\\"').gsub(/[^\x20-\x7e]/) do |m|
|
74
|
-
if m.ord < 256
|
75
|
-
sprintf '\x%02x', m.ord
|
76
|
-
else
|
77
|
-
sprintf '\u%04x', m.ord
|
78
|
-
end
|
79
|
-
end
|
80
|
-
"\"#{escaped}\""
|
81
|
-
end
|
82
|
-
|
83
|
-
def lval(node)
|
84
|
-
if type(left) == :Variable
|
85
|
-
left.name
|
86
|
-
elsif type(left) == :Declaration
|
87
|
-
left.name
|
88
|
-
elsif type(left) == :MemberAccess
|
89
|
-
compile left.object
|
90
|
-
"#{stack}.pop().#{left.member}"
|
91
|
-
elsif type(left) == :Index
|
92
|
-
compile left.object
|
93
|
-
compile left.index
|
94
|
-
output "var __A = stack.pop(), __B = stack.pop();"
|
95
|
-
"__B[__A]"
|
96
|
-
else
|
97
|
-
"bad lval!"
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def mutate(left, fmt)
|
102
|
-
lval = nil
|
103
|
-
if type(left) == :Variable
|
104
|
-
lval = left.name
|
105
|
-
elsif type(left) == :Declaration
|
106
|
-
compile left
|
107
|
-
lval = left.name
|
108
|
-
elsif type(left) == :MemberAccess
|
109
|
-
compile left.object
|
110
|
-
lval = "#{stack}.pop().#{left.member}"
|
111
|
-
elsif type(left) == :Index
|
112
|
-
compile left.index
|
113
|
-
compile left.object
|
114
|
-
lval = "#{stack}.pop()[#{stack}.pop()]"
|
115
|
-
else
|
116
|
-
error! "Invalid left hand side in assignment"
|
117
|
-
end
|
118
|
-
output "#{stack}.push(#{sprintf(fmt, lval)});"
|
119
|
-
end
|
120
|
-
|
121
|
-
# code generation methods
|
122
|
-
|
123
|
-
def Call(node)
|
124
|
-
compile node.arguments.reverse_each
|
125
|
-
callee = nil
|
126
|
-
if type(node.callee) == :MemberAccess
|
127
|
-
compile node.callee.object
|
128
|
-
callee = "#{stack}.pop().#{node.callee.member}"
|
129
|
-
elsif type(node.callee) == :Index
|
130
|
-
compile node.callee.index
|
131
|
-
compile node.callee.object
|
132
|
-
callee = "#{stack}.pop()[#{stack}.pop()]"
|
133
|
-
else
|
134
|
-
compile node.callee
|
135
|
-
callee = "#{stack}.pop()"
|
136
|
-
end
|
137
|
-
args = (["#{stack}.pop()"] * node.arguments.size).join ", "
|
138
|
-
output "#{stack}.push(#{callee}(#{args}));"
|
139
|
-
end
|
140
|
-
|
141
|
-
def Variable(node)
|
142
|
-
output "#{stack}.push(#{node.name});"
|
143
|
-
end
|
144
|
-
|
145
|
-
def String(node)
|
146
|
-
output "#{stack}.push(#{escape node.string});"
|
147
|
-
end
|
148
|
-
|
149
|
-
def MultiExpression(node)
|
150
|
-
output "#{stack}_sizes.push(#{stack}.length);"
|
151
|
-
compile node.left
|
152
|
-
output "#{stack}.length = #{stack}_sizes.pop();" # so we don't unbalance the stack
|
153
|
-
compile node.right
|
154
|
-
end
|
155
|
-
|
156
|
-
def Declaration(node)
|
157
|
-
output "var #{node.name};"
|
158
|
-
end
|
159
|
-
|
160
|
-
def Assignment(node)
|
161
|
-
compile node.right
|
162
|
-
mutate node.left, "%s = #{stack}.pop()"
|
163
|
-
end
|
164
|
-
|
165
|
-
def Function(node)
|
166
|
-
if node.name
|
167
|
-
output "function #{node.name}(#{node.arguments.join ", "}) {"
|
168
|
-
else
|
169
|
-
output "#{stack}.push(function(#{node.arguments.join ", "}) {"
|
170
|
-
end
|
171
|
-
indent
|
172
|
-
prologue
|
173
|
-
compile node.statements
|
174
|
-
dedent
|
175
|
-
if node.name
|
176
|
-
output "}"
|
177
|
-
output "#{stack}.push(#{node.name});"
|
178
|
-
else
|
179
|
-
output "});"
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def Return(node)
|
184
|
-
compile node.expression
|
185
|
-
output "return #{stack}.pop();"
|
186
|
-
end
|
187
|
-
|
188
|
-
def Addition(node); binop "+", node; end
|
189
|
-
def Subtraction(node); binop "-", node; end
|
190
|
-
def Multiplication(node); binop "*", node; end
|
191
|
-
def Division(node); binop "/", node; end
|
192
|
-
def Equality(node); binop "==", node; end
|
193
|
-
def Inequality(node); binop "!=", node; end
|
194
|
-
def StrictEquality(node); binop "===", node; end
|
195
|
-
def StrictInequality(node); binop "!==", node; end
|
196
|
-
def LessThan(node); binop "<", node; end
|
197
|
-
def LessThanEqual(node); binop "<=", node; end
|
198
|
-
def GreaterThan(node); binop ">", node; end
|
199
|
-
def GreaterThanEqual(node); binop ">=", node; end
|
200
|
-
|
201
|
-
def And(node)
|
202
|
-
compile node.left
|
203
|
-
output "if(#{stack}[#{stack}.length - 1]) {"
|
204
|
-
indent
|
205
|
-
compile node.right
|
206
|
-
dedent
|
207
|
-
output "}"
|
208
|
-
end
|
209
|
-
def Or(node)
|
210
|
-
compile node.left
|
211
|
-
output "if(!#{stack}[#{stack}.length - 1]) {"
|
212
|
-
indent
|
213
|
-
compile node.right
|
214
|
-
dedent
|
215
|
-
output "}"
|
216
|
-
end
|
217
|
-
|
218
|
-
def If(node)
|
219
|
-
compile node.condition
|
220
|
-
output "if(#{stack}.pop()) {"
|
221
|
-
indent
|
222
|
-
compile node.then
|
223
|
-
dedent
|
224
|
-
output "} else {"
|
225
|
-
indent
|
226
|
-
compile node.else if node.else
|
227
|
-
dedent
|
228
|
-
output "}"
|
229
|
-
end
|
230
|
-
|
231
|
-
def Null(node)
|
232
|
-
output "#{stack}.push(null);"
|
233
|
-
end
|
234
|
-
|
235
|
-
def This(node)
|
236
|
-
output "#{stack}.push(this);"
|
237
|
-
end
|
238
|
-
|
239
|
-
def Array(node)
|
240
|
-
compile node.items.reverse
|
241
|
-
args = ["#{stack}.pop()"] * node.items.size
|
242
|
-
output "#{stack}.push([#{args.join ", "}]);"
|
243
|
-
end
|
244
|
-
|
245
|
-
def ObjectLiteral(node)
|
246
|
-
compile node.items.map(&:last).reverse
|
247
|
-
keys = []
|
248
|
-
node.items.each do |k,v|
|
249
|
-
keys << "#{escape k.val}: #{stack}.pop()"
|
250
|
-
end
|
251
|
-
output "#{stack}.push({ #{keys.join ", "} });"
|
252
|
-
end
|
253
|
-
|
254
|
-
def Number(node)
|
255
|
-
output "#{stack}.push(#{node.number});"
|
256
|
-
end
|
257
|
-
|
258
|
-
def Index(node)
|
259
|
-
compile node.index
|
260
|
-
compile node.object
|
261
|
-
output "#{stack}.push(#{stack}.pop()[#{stack}.pop()]);"
|
262
|
-
end
|
263
|
-
|
264
|
-
def Negation(node)
|
265
|
-
compile node.value
|
266
|
-
output "#{stack}.push(-#{stack}.pop());"
|
267
|
-
end
|
268
|
-
|
269
|
-
def Not(node)
|
270
|
-
compile node.value
|
271
|
-
output "#{stack}.push(!#{stack}.pop());"
|
272
|
-
end
|
273
|
-
|
274
|
-
def Body(node)
|
275
|
-
compile node.statements
|
276
|
-
end
|
277
|
-
|
278
|
-
def Ternary(node)
|
279
|
-
compile node.condition
|
280
|
-
output "if(#{stack}.pop()) {"
|
281
|
-
indent
|
282
|
-
compile node.if_true
|
283
|
-
dedent
|
284
|
-
output "} else {"
|
285
|
-
indent
|
286
|
-
compile node.if_false
|
287
|
-
dedent
|
288
|
-
output "}"
|
289
|
-
end
|
290
|
-
|
291
|
-
def MemberAccess(node)
|
292
|
-
compile node.object
|
293
|
-
output "#{stack}.push(#{stack}.pop().#{node.member});"
|
294
|
-
end
|
295
|
-
|
296
|
-
def ForLoop(node)
|
297
|
-
compile node.initializer
|
298
|
-
output "while(true) {"
|
299
|
-
indent
|
300
|
-
compile node.condition
|
301
|
-
output "if(!#{stack}.pop()) break;"
|
302
|
-
compile node.body
|
303
|
-
compile node.increment
|
304
|
-
dedent
|
305
|
-
output "}"
|
306
|
-
end
|
307
|
-
|
308
|
-
def ForIn(node)
|
309
|
-
compile node.object
|
310
|
-
output "for(var __tmp_lval in #{stack}.pop()) {"
|
311
|
-
indent
|
312
|
-
mutate node.lval, "%s = __tmp_lval"
|
313
|
-
compile node.body
|
314
|
-
dedent
|
315
|
-
output "}"
|
316
|
-
end
|
317
|
-
|
318
|
-
def PostIncrement(node)
|
319
|
-
mutate node.value, "%s++"
|
320
|
-
end
|
321
|
-
def PostDecrement(node)
|
322
|
-
mutate node.value, "%s--"
|
323
|
-
end
|
324
|
-
def PreIncrement(node)
|
325
|
-
mutate node.value, "++%s"
|
326
|
-
end
|
327
|
-
def PreDecrement(node)
|
328
|
-
mutate node.value, "--%s"
|
329
|
-
end
|
330
|
-
|
331
|
-
def While(node)
|
332
|
-
output "while(true) {"
|
333
|
-
indent
|
334
|
-
compile node.condition
|
335
|
-
output "if(!#{stack}.pop()) break;"
|
336
|
-
compile node.body
|
337
|
-
dedent
|
338
|
-
output "}"
|
339
|
-
end
|
340
|
-
|
341
|
-
def Try(node)
|
342
|
-
output "try {"
|
343
|
-
indent
|
344
|
-
compile node.try_statements
|
345
|
-
dedent
|
346
|
-
if node.catch_variable
|
347
|
-
output "} catch(#{node.catch_variable}) {"
|
348
|
-
indent
|
349
|
-
compile node.catch_statements
|
350
|
-
dedent
|
351
|
-
end
|
352
|
-
if node.finally_statements
|
353
|
-
output "} finally {"
|
354
|
-
indent
|
355
|
-
compile node.finally_statements
|
356
|
-
dedent
|
357
|
-
end
|
358
|
-
output "}"
|
359
|
-
end
|
360
|
-
|
361
|
-
def Void(node)
|
362
|
-
compile node.value
|
363
|
-
output "#{stack}.push(void #{stack}.pop());"
|
364
|
-
end
|
365
|
-
|
366
|
-
def TypeOf(node)
|
367
|
-
puts type(node.value)
|
368
|
-
if type(node.value) == :VARIABLE
|
369
|
-
output "#{stack}.push(typeof #{node.value.name});"
|
370
|
-
else
|
371
|
-
compile node.value
|
372
|
-
output "#{stack}.push(typeof #{stack}.pop());"
|
373
|
-
end
|
374
|
-
end
|
375
|
-
|
376
|
-
def New(node)
|
377
|
-
compile node.arguments.reverse
|
378
|
-
compile node.callee
|
379
|
-
args = ["#{stack}.pop()"] * node.arguments.size
|
380
|
-
output "__tmp = #{stack}.pop();"
|
381
|
-
output "#{stack}.push(new __tmp(#{args.join ", "}));"
|
382
|
-
end
|
383
|
-
|
384
|
-
def Switch(node)
|
385
|
-
compile node.cases.reverse.map { |c| c.expression }.reject(&:nil?)
|
386
|
-
cases = ["#{stack}.pop()"] * node.cases.size
|
387
|
-
output "__tmp = [#{cases.join ", "}]"
|
388
|
-
compile node.expression
|
389
|
-
output "switch(#{stack}.pop()) {"
|
390
|
-
indent
|
391
|
-
i = 0
|
392
|
-
node.cases.each do |c|
|
393
|
-
dedent
|
394
|
-
if c.expression
|
395
|
-
output "case __tmp[#{i}]:"
|
396
|
-
i += 1
|
397
|
-
else
|
398
|
-
output "default:"
|
399
|
-
end
|
400
|
-
indent
|
401
|
-
compile c.statements
|
402
|
-
end
|
403
|
-
dedent
|
404
|
-
output "}"
|
405
|
-
end
|
406
|
-
|
407
|
-
def Break(node)
|
408
|
-
output "break;"
|
409
|
-
end
|
410
|
-
|
411
|
-
def Continue(node)
|
412
|
-
output "continue;"
|
413
|
-
end
|
414
|
-
end
|