twostroke 0.1.0 → 0.2.0

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