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.
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