twostroke 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/lib/twostroke.rb +2 -1
  2. data/lib/twostroke/ast/break.rb +2 -0
  3. data/lib/twostroke/ast/continue.rb +2 -0
  4. data/lib/twostroke/compiler/tsasm.rb +45 -18
  5. data/lib/twostroke/context.rb +58 -0
  6. data/lib/twostroke/context/object_proxy.rb +42 -0
  7. data/lib/twostroke/lexer.rb +10 -2
  8. data/lib/twostroke/parser.rb +36 -8
  9. data/lib/twostroke/runtime/lib.rb +3 -1
  10. data/lib/twostroke/runtime/lib/boolean.rb +4 -10
  11. data/lib/twostroke/runtime/lib/console.rb +1 -1
  12. data/lib/twostroke/runtime/lib/date.rb +18 -4
  13. data/lib/twostroke/runtime/lib/etc.rb +1 -15
  14. data/lib/twostroke/runtime/lib/function.rb +2 -8
  15. data/lib/twostroke/runtime/lib/math.rb +14 -2
  16. data/lib/twostroke/runtime/lib/number.js +3 -0
  17. data/lib/twostroke/runtime/lib/number.rb +12 -5
  18. data/lib/twostroke/runtime/lib/object.rb +4 -4
  19. data/lib/twostroke/runtime/lib/regexp.rb +2 -2
  20. data/lib/twostroke/runtime/scope.rb +1 -5
  21. data/lib/twostroke/runtime/types.rb +17 -2
  22. data/lib/twostroke/runtime/types/array.rb +4 -0
  23. data/lib/twostroke/runtime/types/boolean.rb +5 -1
  24. data/lib/twostroke/runtime/types/boolean_object.rb +2 -2
  25. data/lib/twostroke/runtime/types/function.rb +4 -4
  26. data/lib/twostroke/runtime/types/number.rb +8 -0
  27. data/lib/twostroke/runtime/types/number_object.rb +2 -2
  28. data/lib/twostroke/runtime/types/object.rb +5 -7
  29. data/lib/twostroke/runtime/types/regexp.rb +3 -3
  30. data/lib/twostroke/runtime/types/string.rb +4 -0
  31. data/lib/twostroke/runtime/types/string_object.rb +7 -4
  32. data/lib/twostroke/runtime/types/value.rb +4 -4
  33. data/lib/twostroke/runtime/vm.rb +12 -0
  34. data/lib/twostroke/runtime/vm_frame.rb +11 -19
  35. data/lib/twostroke/tokens.rb +2 -2
  36. metadata +5 -3
  37. 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 respond_to? ins
42
- if @exception = catch(:exception) { send ins, arg; nil }
43
- # puts "--> #{Types.to_string(exception).string} #{@name || "(anonymous function)"}:#{@line} <#{@section}+#{@ip}>"
44
- throw :exception, @exception if catch_stack.empty? && finally_stack.empty?
45
- if catch_stack.any?
46
- @ip = catch_stack.last
47
- else
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.new(true)
227
+ stack.push Types::Boolean.true
236
228
  end
237
229
 
238
230
  def false(arg)
239
- stack.push Types::Boolean.new(false)
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 sar(arg)
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 slr(arg)
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)
@@ -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, /[[:space:]]+/ ],
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(7).chr "utf-8"
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.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-11 00:00:00.000000000 Z
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