twostroke 0.1.0 → 0.2.0

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/ast/case.rb +1 -1
  2. data/lib/twostroke/ast/function.rb +2 -2
  3. data/lib/twostroke/ast/label.rb +20 -0
  4. data/lib/twostroke/ast/switch.rb +1 -0
  5. data/lib/twostroke/ast/try.rb +3 -3
  6. data/lib/twostroke/ast/unary_operators.rb +1 -1
  7. data/lib/twostroke/ast.rb +1 -0
  8. data/lib/twostroke/compiler/javascript.rb +20 -2
  9. data/lib/twostroke/compiler/tsasm.rb +89 -35
  10. data/lib/twostroke/compiler.rb +1 -1
  11. data/lib/twostroke/error.rb +3 -0
  12. data/lib/twostroke/lexer.rb +3 -2
  13. data/lib/twostroke/parser.rb +309 -227
  14. data/lib/twostroke/runtime/lib/array.js +9 -3
  15. data/lib/twostroke/runtime/lib/array.rb +15 -7
  16. data/lib/twostroke/runtime/lib/console.rb +3 -2
  17. data/lib/twostroke/runtime/lib/error.rb +1 -1
  18. data/lib/twostroke/runtime/lib/etc.js +38 -0
  19. data/lib/twostroke/runtime/lib/etc.rb +29 -0
  20. data/lib/twostroke/runtime/lib/math.rb +31 -0
  21. data/lib/twostroke/runtime/lib/number.rb +7 -1
  22. data/lib/twostroke/runtime/lib/object.rb +1 -1
  23. data/lib/twostroke/runtime/lib/regexp.rb +1 -0
  24. data/lib/twostroke/runtime/lib/string.rb +62 -22
  25. data/lib/twostroke/runtime/scope.rb +23 -2
  26. data/lib/twostroke/runtime/types/array.rb +5 -0
  27. data/lib/twostroke/runtime/types/function.rb +5 -2
  28. data/lib/twostroke/runtime/types/object.rb +3 -4
  29. data/lib/twostroke/runtime/types/regexp.rb +45 -2
  30. data/lib/twostroke/runtime/types.rb +1 -1
  31. data/lib/twostroke/runtime/vm.rb +2 -2
  32. data/lib/twostroke/runtime/vm_frame.rb +47 -8
  33. data/lib/twostroke/tokens.rb +32 -16
  34. metadata +5 -5
  35. data/lib/twostroke/ast/delete.rb +0 -15
  36. data/lib/twostroke/ast/unsorted_binop.rb +0 -97
  37. data/lib/twostroke/runtime/lib/function.js +0 -0
@@ -18,12 +18,13 @@ module Twostroke::Runtime
18
18
  end
19
19
 
20
20
  def execute(scope, this = nil, args = [])
21
- @scope = scope || Scope.new(vm.global_scope)
21
+ @scope = scope || vm.global_scope
22
22
  @stack = []
23
23
  @sp_stack = []
24
24
  @catch_stack = []
25
25
  @finally_stack = []
26
26
  @enum_stack = []
27
+ @temp_slot = nil
27
28
  @ip = 0
28
29
  @return = false
29
30
  @this = this || @scope.global_scope.root_object
@@ -35,13 +36,18 @@ module Twostroke::Runtime
35
36
  end
36
37
 
37
38
  until @return
38
- ins, arg = *insns[ip]
39
+ ins, arg = insns[ip]
39
40
  st = @stack.size
40
41
  @ip += 1
41
42
  if respond_to? ins
42
43
  if @exception = catch(:exception) { public_send ins, arg; nil }
43
- throw :exception, @exception if catch_stack.empty?
44
- @ip = catch_stack.last
44
+ # puts "--> #{Types.to_string(exception).string} #{@name || "(anonymous function)"}:#{@line} <#{@section}+#{@ip}>"
45
+ throw :exception, @exception if catch_stack.empty? && finally_stack.empty?
46
+ if catch_stack.any?
47
+ @ip = catch_stack.last
48
+ else
49
+ @ip = finally_stack.last
50
+ end
45
51
  end
46
52
  else
47
53
  error! "unknown instruction #{ins}"
@@ -51,7 +57,12 @@ module Twostroke::Runtime
51
57
  stack.last
52
58
  end
53
59
 
60
+ define_method ".line" do |arg|
61
+ @line = arg
62
+ end
63
+
54
64
  define_method ".name" do |arg|
65
+ @name = arg
55
66
  scope.declare arg.intern
56
67
  scope.set_var arg.intern, @callee
57
68
  end
@@ -68,6 +79,7 @@ module Twostroke::Runtime
68
79
  define_method ".catch" do |arg|
69
80
  scope.declare arg.intern
70
81
  scope.set_var arg.intern, @exception
82
+ @exception = nil
71
83
  end
72
84
 
73
85
  ## instructions
@@ -91,7 +103,7 @@ module Twostroke::Runtime
91
103
  arg.times { args.unshift @stack.pop }
92
104
  fun = stack.pop
93
105
  Lib.throw_type_error "called non callable" unless fun.respond_to?(:call)
94
- stack.push fun.call(scope, scope.global_scope.root_object, args)
106
+ stack.push fun.call(scope, fun.inherits_caller_this ? @this : scope.global_scope.root_object, args)
95
107
  end
96
108
 
97
109
  def thiscall(arg)
@@ -99,7 +111,8 @@ module Twostroke::Runtime
99
111
  arg.times { args.unshift stack.pop }
100
112
  fun = stack.pop
101
113
  Lib.throw_type_error "called non callable" unless fun.respond_to?(:call)
102
- stack.push fun.call(scope, Types.to_object(stack.pop), args)
114
+ this_arg = Types.to_object stack.pop
115
+ stack.push fun.call(scope, fun.inherits_caller_this ? @this : this_arg, args)
103
116
  end
104
117
 
105
118
  def newcall(arg)
@@ -123,16 +136,33 @@ module Twostroke::Runtime
123
136
  stack.push *stack[-n..-1]
124
137
  end
125
138
 
139
+ def tst(arg)
140
+ @temp_slot = stack.pop
141
+ end
142
+
143
+ def tld(arg)
144
+ stack.push @temp_slot
145
+ end
146
+
126
147
  def member(arg)
127
148
  stack.push Types.to_object(stack.pop).get(arg.to_s)
128
149
  end
129
150
 
130
151
  def deleteg(arg)
131
- scope.global_scope.root_object.delete arg.to_s
152
+ scope.delete arg
153
+ stack.push Types::Boolean.true
132
154
  end
133
155
 
134
156
  def delete(arg)
135
157
  Types.to_object(stack.pop).delete arg.to_s
158
+ stack.push Types::Boolean.true
159
+ end
160
+
161
+ def deleteindex(arg)
162
+ obj = Types.to_object stack.pop
163
+ idx = Types.to_string stack.pop
164
+ obj.delete idx.string
165
+ stack.push Types::Boolean.true
136
166
  end
137
167
 
138
168
  def in(arg)
@@ -169,7 +199,7 @@ module Twostroke::Runtime
169
199
 
170
200
  def setprop(arg)
171
201
  val = stack.pop
172
- obj = stack.pop
202
+ obj = Types.to_object(stack.pop)
173
203
  obj.put arg.to_s, val
174
204
  stack.push val
175
205
  end
@@ -338,6 +368,11 @@ module Twostroke::Runtime
338
368
  stack.push Types::Number.new(left ^ right)
339
369
  end
340
370
 
371
+ def bnot(arg)
372
+ val = Types.to_int32 stack.pop
373
+ stack.push Types::Number.new ~val
374
+ end
375
+
341
376
  def setindex(arg)
342
377
  val = stack.pop
343
378
  index = Types.to_string(stack.pop).string
@@ -436,6 +471,10 @@ module Twostroke::Runtime
436
471
  finally_stack.pop
437
472
  end
438
473
 
474
+ def endfinally(arg)
475
+ throw :exception, @exception if @exception
476
+ end
477
+
439
478
  def this(arg)
440
479
  stack.push @this
441
480
  end
@@ -7,9 +7,10 @@ module Twostroke
7
7
  TOKENS = [
8
8
 
9
9
  [ :MULTI_COMMENT, %r{/\*.*?\*/} ],
10
- [ :SINGLE_COMMENT, /\/\/.*?$/ ],
10
+ [ :SINGLE_COMMENT, /\/\/.*?($|\r|\u2029|\u2028)/ ],
11
11
 
12
- [ :WHITESPACE, /\s+/ ],
12
+ [ :LINE_TERMINATOR, /[\n\r\u2028\u2029]/ ],
13
+ [ :WHITESPACE, /[[:space:]]+/ ],
13
14
  [ :NUMBER, /((?<oct>0[0-7]+)|(?<hex>0x[A-Fa-f0-9]+)|(?<to_f>(\d+(\.?\d*([eE][+-]?\d+)?)?|\.\d+([eE][+-]?\d+)?)))/, ->m do
14
15
  method, number = m.names.zip(m.captures).select { |k,v| v }.first
15
16
  n = number.send method
@@ -25,21 +26,24 @@ module Twostroke
25
26
  end,
26
27
  [ :BAREWORD, /[a-zA-Z_\$][\$a-zA-Z_0-9]*/, ->m { m[0] } ],
27
28
 
28
- [ :STRING, /(["'])((\\\n|\\.|[^\1])*?[^\1\\]?)\1/, ->m do
29
- m[2]
30
- .gsub(/\\([0-6]{1,3})/) { |m| m[1].to_i(7).chr }
31
- .gsub(/\\x([a-f0-9]{2})/i) { |m| m[1].to_i(16).chr }
32
- .gsub(/\\u([a-f0-9]{4})/i) { |m| m[1].to_i(16).chr }
33
- .gsub(/\\(.)/m) { |m|
34
- case m[1]
35
- when "b"; "\b"
36
- when "n"; "\n"
37
- when "f"; "\f"
38
- when "r"; "\r"
39
- when "t"; "\t"
40
- else; m[1]
29
+ [ :STRING, /(["'])((\\\n|\\.|[^\n\r\u2028\u2029\1])*?[^\1\\]?)\1/, ->m do
30
+ m[2].gsub(/\\(([0-6]{1,3})|u([a-f0-9]{4})|x([a-f0-9]{2})|\n|.)/i) do |m|
31
+ case m
32
+ when /\\([0-6]{1,3})/; m[1..-1].to_i(7).chr "utf-8"
33
+ when /\\u([a-f0-9]{4})/i; m[2..-1].to_i(16).chr "utf-8"
34
+ when /\\x([a-f0-9]{2})/i; m[2..-1].to_i(16).chr "utf-8"
35
+ else case m[1]
36
+ when "b"; "\b"
37
+ when "n"; "\n"
38
+ when "f"; "\f"
39
+ when "v"; "\v"
40
+ when "r"; "\r"
41
+ when "t"; "\t"
42
+ when "\n"; ""
43
+ else; m[1]
44
+ end
41
45
  end
42
- }
46
+ end
43
47
  end ],
44
48
 
45
49
  [ :REGEXP, %r{/(?<src>(\\.|[^\1])*?[^\1\\]?)/(?<opts>[gim]+)?}, ->m { [m[:src], m[:opts]] } ],
@@ -53,6 +57,18 @@ module Twostroke
53
57
 
54
58
  [ :MEMBER_ACCESS, /\./ ],
55
59
 
60
+ [ :ADD_EQUALS, /\+=/ ],
61
+ [ :MINUS_EQUALS, /-=/ ],
62
+ [ :TIMES_EQUALS, /\*=/ ], # textmate barfs it's syntax highlighting on this one lol
63
+ [ :DIVIDE_EQUALS, /\/=/ ],
64
+ [ :MOD_EQUALS, /%=/ ],
65
+ [ :LEFT_SHIFT_EQUALS, /<<=/ ],
66
+ [ :RIGHT_TRIPLE_SHIFT_EQUALS, />>>=/ ],
67
+ [ :RIGHT_SHIFT_EQUALS, />>=/ ],
68
+ [ :BITWISE_AND_EQUALS, /&=/ ],
69
+ [ :BITWISE_XOR_EQUALS, /\^=/ ],
70
+ [ :BITWISE_OR_EQUALS, /\|=/ ],
71
+
56
72
  [ :INCREMENT, /\+\+/ ],
57
73
  [ :DECREMENT, /--/ ],
58
74
  [ :PLUS, /\+/ ],
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.1.0
4
+ version: 0.2.0
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: 2011-11-09 00:00:00.000000000 Z
12
+ date: 2012-01-10 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
@@ -29,7 +29,6 @@ files:
29
29
  - lib/twostroke/ast/case.rb
30
30
  - lib/twostroke/ast/continue.rb
31
31
  - lib/twostroke/ast/declaration.rb
32
- - lib/twostroke/ast/delete.rb
33
32
  - lib/twostroke/ast/do_while.rb
34
33
  - lib/twostroke/ast/false.rb
35
34
  - lib/twostroke/ast/for_in.rb
@@ -37,6 +36,7 @@ files:
37
36
  - lib/twostroke/ast/function.rb
38
37
  - lib/twostroke/ast/if.rb
39
38
  - lib/twostroke/ast/index.rb
39
+ - lib/twostroke/ast/label.rb
40
40
  - lib/twostroke/ast/member_access.rb
41
41
  - lib/twostroke/ast/multi_expression.rb
42
42
  - lib/twostroke/ast/new.rb
@@ -53,7 +53,6 @@ files:
53
53
  - lib/twostroke/ast/true.rb
54
54
  - lib/twostroke/ast/try.rb
55
55
  - lib/twostroke/ast/unary_operators.rb
56
- - lib/twostroke/ast/unsorted_binop.rb
57
56
  - lib/twostroke/ast/variable.rb
58
57
  - lib/twostroke/ast/while.rb
59
58
  - lib/twostroke/ast/with.rb
@@ -70,7 +69,8 @@ files:
70
69
  - lib/twostroke/runtime/lib/console.rb
71
70
  - lib/twostroke/runtime/lib/date.rb
72
71
  - lib/twostroke/runtime/lib/error.rb
73
- - lib/twostroke/runtime/lib/function.js
72
+ - lib/twostroke/runtime/lib/etc.js
73
+ - lib/twostroke/runtime/lib/etc.rb
74
74
  - lib/twostroke/runtime/lib/function.rb
75
75
  - lib/twostroke/runtime/lib/math.rb
76
76
  - lib/twostroke/runtime/lib/number.rb
@@ -1,15 +0,0 @@
1
- module Twostroke::AST
2
- class Delete < Base
3
- attr_accessor :expression
4
-
5
- def collapse
6
- self.class.new expression: expression.collapse
7
- end
8
-
9
- def walk(&bk)
10
- if yield self
11
- expression.walk &bk
12
- end
13
- end
14
- end
15
- end
@@ -1,97 +0,0 @@
1
- module Twostroke::AST
2
- class UnsortedBinop < Base
3
- attr_accessor :left, :op, :right
4
-
5
- def self.operator_class
6
- @@classes ||= {
7
- :ASTERISK => Multiplication,
8
- :SLASH => Division,
9
- :MOD => Modulus,
10
- :PLUS => Addition,
11
- :MINUS => Subtraction,
12
- :LEFT_SHIFT => LeftShift,
13
- :RIGHT_SHIFT => RightArithmeticShift,
14
- :RIGHT_TRIPLE_SHIFT => RightLogicalShift,
15
- :LT => LessThan,
16
- :LTE => LessThanEqual,
17
- :GT => GreaterThan,
18
- :GTE => GreaterThanEqual,
19
- :IN => In,
20
- :INSTANCEOF => InstanceOf,
21
- :DOUBLE_EQUALS => Equality,
22
- :NOT_EQUALS => Inequality,
23
- :TRIPLE_EQUALS => StrictEquality,
24
- :NOT_DOUBLE_EQUALS => StrictInequality,
25
- :AMPERSAND => BitwiseAnd,
26
- :CARET => BitwiseXor,
27
- :PIPE => BitwiseOr,
28
- :AND => And,
29
- :OR => Or
30
- }
31
- end
32
-
33
- def self.operator_precedence
34
- @precedences ||= {
35
- :ASTERISK => 5,
36
- :SLASH => 5,
37
- :MOD => 5,
38
- :PLUS => 6,
39
- :MINUS => 6,
40
- :LEFT_SHIFT => 7,
41
- :RIGHT_SHIFT => 7,
42
- :RIGHT_TRIPLE_SHIFT => 7,
43
- :LT => 8,
44
- :LTE => 8,
45
- :GT => 8,
46
- :GTE => 8,
47
- :IN => 8,
48
- :INSTANCEOF => 8,
49
- :DOUBLE_EQUALS => 9,
50
- :NOT_EQUALS => 9,
51
- :TRIPLE_EQUALS => 9,
52
- :NOT_DOUBLE_EQUALS => 9,
53
- :AMPERSAND => 10,
54
- :CARET => 11,
55
- :PIPE => 12,
56
- :AND => 13,
57
- :OR => 14
58
- }
59
- end
60
-
61
- def collapse(called_by_binop = false)
62
- left_collapsed = left.is_a?(UnsortedBinop) ? left.collapse(true) : left.collapse
63
- right_collapsed = right.is_a?(UnsortedBinop) ? right.collapse(true) : right.collapse
64
- input = [*left_collapsed, op, *right_collapsed]
65
-
66
- unless called_by_binop
67
- stack = []
68
- output = []
69
- input.each do |token|
70
- if token.is_a? Symbol
71
- while stack.size > 0 && UnsortedBinop.operator_precedence[stack.last] <= UnsortedBinop.operator_precedence[token]
72
- output.push stack.pop
73
- end
74
- stack.push token
75
- else
76
- output.push token
77
- end
78
- end
79
- output.push stack.pop until stack.empty?
80
-
81
- output.each do |token|
82
- if token.is_a? Symbol
83
- r = stack.pop
84
- l = stack.pop
85
- stack.push UnsortedBinop.operator_class[token].new(left: l, right: r)
86
- else
87
- stack.push token
88
- end
89
- end
90
-
91
- stack.last
92
- else
93
- input
94
- end
95
- end
96
- end
97
- end
File without changes