twostroke 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/lib/twostroke/ast/array.rb +8 -0
  2. data/lib/twostroke/ast/assignment.rb +7 -0
  3. data/lib/twostroke/ast/binary_operators.rb +7 -0
  4. data/lib/twostroke/ast/body.rb +6 -0
  5. data/lib/twostroke/ast/break.rb +4 -0
  6. data/lib/twostroke/ast/call.rb +7 -0
  7. data/lib/twostroke/ast/case.rb +9 -1
  8. data/lib/twostroke/ast/continue.rb +11 -0
  9. data/lib/twostroke/ast/declaration.rb +4 -0
  10. data/lib/twostroke/ast/delete.rb +6 -0
  11. data/lib/twostroke/ast/do_while.rb +7 -0
  12. data/lib/twostroke/ast/false.rb +11 -0
  13. data/lib/twostroke/ast/for_in.rb +8 -0
  14. data/lib/twostroke/ast/for_loop.rb +10 -1
  15. data/lib/twostroke/ast/function.rb +6 -0
  16. data/lib/twostroke/ast/if.rb +8 -0
  17. data/lib/twostroke/ast/index.rb +7 -0
  18. data/lib/twostroke/ast/member_access.rb +6 -0
  19. data/lib/twostroke/ast/multi_expression.rb +7 -0
  20. data/lib/twostroke/ast/new.rb +7 -0
  21. data/lib/twostroke/ast/null.rb +4 -0
  22. data/lib/twostroke/ast/number.rb +4 -0
  23. data/lib/twostroke/ast/object_literal.rb +6 -0
  24. data/lib/twostroke/ast/regexp.rb +4 -0
  25. data/lib/twostroke/ast/return.rb +6 -0
  26. data/lib/twostroke/ast/string.rb +4 -0
  27. data/lib/twostroke/ast/switch.rb +7 -0
  28. data/lib/twostroke/ast/ternary.rb +8 -0
  29. data/lib/twostroke/ast/this.rb +4 -0
  30. data/lib/twostroke/ast/throw.rb +6 -0
  31. data/lib/twostroke/ast/true.rb +11 -0
  32. data/lib/twostroke/ast/try.rb +8 -0
  33. data/lib/twostroke/ast/unary_operators.rb +7 -1
  34. data/lib/twostroke/ast/variable.rb +4 -0
  35. data/lib/twostroke/ast/while.rb +8 -1
  36. data/lib/twostroke/ast/with.rb +16 -0
  37. data/lib/twostroke/compiler/javascript.rb +396 -0
  38. data/lib/twostroke/compiler/tsasm.rb +595 -0
  39. data/lib/twostroke/compiler.rb +8 -0
  40. data/lib/twostroke/parser.rb +47 -9
  41. data/lib/twostroke/runtime/lib/array.js +144 -0
  42. data/lib/twostroke/runtime/lib/array.rb +71 -0
  43. data/lib/twostroke/runtime/lib/boolean.rb +23 -0
  44. data/lib/twostroke/runtime/lib/console.rb +13 -0
  45. data/lib/twostroke/runtime/lib/date.rb +65 -0
  46. data/lib/twostroke/runtime/lib/error.rb +36 -0
  47. data/lib/twostroke/runtime/lib/function.js +0 -0
  48. data/lib/twostroke/runtime/lib/function.rb +45 -0
  49. data/lib/twostroke/runtime/lib/math.rb +36 -0
  50. data/lib/twostroke/runtime/lib/number.rb +65 -0
  51. data/lib/twostroke/runtime/lib/object.js +0 -0
  52. data/lib/twostroke/runtime/lib/object.rb +55 -0
  53. data/lib/twostroke/runtime/lib/regexp.rb +28 -0
  54. data/lib/twostroke/runtime/lib/string.rb +86 -0
  55. data/lib/twostroke/runtime/lib/undefined.rb +7 -0
  56. data/lib/twostroke/runtime/lib.rb +42 -0
  57. data/lib/twostroke/runtime/scope.rb +120 -0
  58. data/lib/twostroke/runtime/types/array.rb +79 -0
  59. data/lib/twostroke/runtime/types/boolean.rb +23 -0
  60. data/lib/twostroke/runtime/types/boolean_object.rb +25 -0
  61. data/lib/twostroke/runtime/types/function.rb +83 -0
  62. data/lib/twostroke/runtime/types/null.rb +11 -3
  63. data/lib/twostroke/runtime/types/number.rb +31 -0
  64. data/lib/twostroke/runtime/types/number_object.rb +25 -0
  65. data/lib/twostroke/runtime/types/object.rb +169 -20
  66. data/lib/twostroke/runtime/types/regexp.rb +31 -0
  67. data/lib/twostroke/runtime/types/string.rb +16 -0
  68. data/lib/twostroke/runtime/types/string_object.rb +52 -0
  69. data/lib/twostroke/runtime/types/undefined.rb +11 -3
  70. data/lib/twostroke/runtime/types/value.rb +14 -0
  71. data/lib/twostroke/runtime/types.rb +133 -4
  72. data/lib/twostroke/runtime/vm.rb +25 -0
  73. data/lib/twostroke/runtime/vm_frame.rb +459 -0
  74. data/lib/twostroke/runtime.rb +6 -5
  75. data/lib/twostroke/tokens.rb +20 -8
  76. data/lib/twostroke.rb +3 -1
  77. metadata +41 -7
  78. data/lib/twostroke/runtime/context.rb +0 -33
  79. data/lib/twostroke/runtime/environment.rb +0 -13
  80. data/lib/twostroke/runtime/types/basic_type.rb +0 -5
@@ -0,0 +1,396 @@
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 mutate(left, fmt)
84
+ lval = nil
85
+ if type(left) == :Variable
86
+ lval = "#{left.name}"
87
+ elsif type(left) == :Declaration
88
+ compile left
89
+ lval = "#{left.name}"
90
+ elsif type(left) == :MemberAccess
91
+ compile left.object
92
+ lval = "#{stack}.pop().#{left.member}"
93
+ elsif type(left) == :Index
94
+ compile left.index
95
+ compile left.object
96
+ lval = "#{stack}.pop()[#{stack}.pop()]"
97
+ else
98
+ error! "Invalid left hand side in assignment"
99
+ end
100
+ output "#{stack}.push(#{sprintf(fmt, lval)});"
101
+ end
102
+
103
+ # code generation methods
104
+
105
+ def Call(node)
106
+ compile node.arguments.reverse_each
107
+ callee = nil
108
+ if type(node.callee) == :MemberAccess
109
+ compile node.callee.object
110
+ callee = "#{stack}.pop().#{node.callee.member}"
111
+ elsif type(node.callee) == :Index
112
+ compile node.callee.index
113
+ compile node.callee.object
114
+ callee = "#{stack}.pop()[#{stack}.pop()]"
115
+ else
116
+ compile node.callee
117
+ callee = "#{stack}.pop()"
118
+ end
119
+ args = (["#{stack}.pop()"] * node.arguments.size).join ", "
120
+ output "#{stack}.push(#{callee}(#{args}));"
121
+ end
122
+
123
+ def Variable(node)
124
+ output "#{stack}.push(#{node.name});"
125
+ end
126
+
127
+ def String(node)
128
+ output "#{stack}.push(#{escape node.string});"
129
+ end
130
+
131
+ def MultiExpression(node)
132
+ output "#{stack}_sizes.push(#{stack}.length);"
133
+ compile node.left
134
+ output "#{stack}.length = #{stack}_sizes.pop();" # so we don't unbalance the stack
135
+ compile node.right
136
+ end
137
+
138
+ def Declaration(node)
139
+ output "var #{node.name};"
140
+ end
141
+
142
+ def Assignment(node)
143
+ compile node.right
144
+ mutate node.left, "%s = #{stack}.pop()"
145
+ end
146
+
147
+ def Function(node)
148
+ if node.name
149
+ output "function #{node.name}(#{node.arguments.join ", "}) {"
150
+ else
151
+ output "#{stack}.push(function(#{node.arguments.join ", "}) {"
152
+ end
153
+ indent
154
+ prologue
155
+ compile node.statements
156
+ dedent
157
+ if node.name
158
+ output "}"
159
+ output "#{stack}.push(#{node.name});"
160
+ else
161
+ output "});"
162
+ end
163
+ end
164
+
165
+ def Return(node)
166
+ compile node.expression
167
+ output "return #{stack}.pop();"
168
+ end
169
+
170
+ def Addition(node); binop "+", node; end
171
+ def Subtraction(node); binop "-", node; end
172
+ def Multiplication(node); binop "*", node; end
173
+ def Division(node); binop "/", node; end
174
+ def Equality(node); binop "==", node; end
175
+ def Inequality(node); binop "!=", node; end
176
+ def StrictEquality(node); binop "===", node; end
177
+ def StrictInequality(node); binop "!==", node; end
178
+ def LessThan(node); binop "<", node; end
179
+ def LessThanEqual(node); binop "<=", node; end
180
+ def GreaterThan(node); binop ">", node; end
181
+ def GreaterThanEqual(node); binop ">=", node; end
182
+
183
+ def And(node)
184
+ compile node.left
185
+ output "if(#{stack}[#{stack}.length - 1]) {"
186
+ indent
187
+ compile node.right
188
+ dedent
189
+ output "}"
190
+ end
191
+ def Or(node)
192
+ compile node.left
193
+ output "if(!#{stack}[#{stack}.length - 1]) {"
194
+ indent
195
+ compile node.right
196
+ dedent
197
+ output "}"
198
+ end
199
+
200
+ def If(node)
201
+ compile node.condition
202
+ output "if(#{stack}.pop()) {"
203
+ indent
204
+ compile node.then
205
+ dedent
206
+ output "} else {"
207
+ indent
208
+ compile node.else if node.else
209
+ dedent
210
+ output "}"
211
+ end
212
+
213
+ def Null(node)
214
+ output "#{stack}.push(null);"
215
+ end
216
+
217
+ def This(node)
218
+ output "#{stack}.push(this);"
219
+ end
220
+
221
+ def Array(node)
222
+ compile node.items.reverse
223
+ args = ["#{stack}.pop()"] * node.items.size
224
+ output "#{stack}.push([#{args.join ", "}]);"
225
+ end
226
+
227
+ def ObjectLiteral(node)
228
+ compile node.items.map(&:last).reverse
229
+ keys = []
230
+ node.items.each do |k,v|
231
+ keys << "#{escape k.val}: #{stack}.pop()"
232
+ end
233
+ output "#{stack}.push({ #{keys.join ", "} });"
234
+ end
235
+
236
+ def Number(node)
237
+ output "#{stack}.push(#{node.number});"
238
+ end
239
+
240
+ def Index(node)
241
+ compile node.index
242
+ compile node.object
243
+ output "#{stack}.push(#{stack}.pop()[#{stack}.pop()]);"
244
+ end
245
+
246
+ def Negation(node)
247
+ compile node.value
248
+ output "#{stack}.push(-#{stack}.pop());"
249
+ end
250
+
251
+ def Not(node)
252
+ compile node.value
253
+ output "#{stack}.push(!#{stack}.pop());"
254
+ end
255
+
256
+ def Body(node)
257
+ compile node.statements
258
+ end
259
+
260
+ def Ternary(node)
261
+ compile node.condition
262
+ output "if(#{stack}.pop()) {"
263
+ indent
264
+ compile node.if_true
265
+ dedent
266
+ output "} else {"
267
+ indent
268
+ compile node.if_false
269
+ dedent
270
+ output "}"
271
+ end
272
+
273
+ def MemberAccess(node)
274
+ compile node.object
275
+ output "#{stack}.push(#{stack}.pop().#{node.member});"
276
+ end
277
+
278
+ def ForLoop(node)
279
+ compile node.initializer
280
+ output "while(true) {"
281
+ indent
282
+ compile node.condition
283
+ output "if(!#{stack}.pop()) break;"
284
+ compile node.body
285
+ compile node.increment
286
+ dedent
287
+ output "}"
288
+ end
289
+
290
+ def ForIn(node)
291
+ compile node.object
292
+ output "for(var __tmp_lval in #{stack}.pop()) {"
293
+ indent
294
+ mutate node.lval, "%s = __tmp_lval"
295
+ compile node.body
296
+ dedent
297
+ output "}"
298
+ end
299
+
300
+ def PostIncrement(node)
301
+ mutate node.value, "%s++"
302
+ end
303
+ def PostDecrement(node)
304
+ mutate node.value, "%s--"
305
+ end
306
+ def PreIncrement(node)
307
+ mutate node.value, "++%s"
308
+ end
309
+ def PreDecrement(node)
310
+ mutate node.value, "--%s"
311
+ end
312
+
313
+ def While(node)
314
+ output "while(true) {"
315
+ indent
316
+ compile node.condition
317
+ output "if(!#{stack}.pop()) break;"
318
+ compile node.body
319
+ dedent
320
+ output "}"
321
+ end
322
+
323
+ def Try(node)
324
+ output "try {"
325
+ indent
326
+ compile node.try_statements
327
+ dedent
328
+ if node.catch_variable
329
+ output "} catch(#{node.catch_variable}) {"
330
+ indent
331
+ compile node.catch_statements
332
+ dedent
333
+ end
334
+ if node.finally_statements
335
+ output "} finally {"
336
+ indent
337
+ compile node.finally_statements
338
+ dedent
339
+ end
340
+ output "}"
341
+ end
342
+
343
+ def Void(node)
344
+ compile node.value
345
+ output "#{stack}.push(void #{stack}.pop());"
346
+ end
347
+
348
+ def TypeOf(node)
349
+ puts type(node.value)
350
+ if type(node.value) == :VARIABLE
351
+ output "#{stack}.push(typeof #{node.value.name});"
352
+ else
353
+ compile node.value
354
+ output "#{stack}.push(typeof #{stack}.pop());"
355
+ end
356
+ end
357
+
358
+ def New(node)
359
+ compile node.arguments.reverse
360
+ compile node.callee
361
+ args = ["#{stack}.pop()"] * node.arguments.size
362
+ output "__tmp = #{stack}.pop();"
363
+ output "#{stack}.push(new __tmp(#{args.join ", "}));"
364
+ end
365
+
366
+ def Switch(node)
367
+ compile node.cases.reverse.map { |c| c.expression }.reject(&:nil?)
368
+ cases = ["#{stack}.pop()"] * node.cases.size
369
+ output "__tmp = [#{cases.join ", "}]"
370
+ compile node.expression
371
+ output "switch(#{stack}.pop()) {"
372
+ indent
373
+ i = 0
374
+ node.cases.each do |c|
375
+ dedent
376
+ if c.expression
377
+ output "case __tmp[#{i}]:"
378
+ i += 1
379
+ else
380
+ output "default:"
381
+ end
382
+ indent
383
+ compile c.statements
384
+ end
385
+ dedent
386
+ output "}"
387
+ end
388
+
389
+ def Break(node)
390
+ output "break;"
391
+ end
392
+
393
+ def Continue(node)
394
+ output "continue;"
395
+ end
396
+ end