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.
- data/lib/twostroke/ast/case.rb +1 -1
- data/lib/twostroke/ast/function.rb +2 -2
- data/lib/twostroke/ast/label.rb +20 -0
- data/lib/twostroke/ast/switch.rb +1 -0
- data/lib/twostroke/ast/try.rb +3 -3
- data/lib/twostroke/ast/unary_operators.rb +1 -1
- data/lib/twostroke/ast.rb +1 -0
- data/lib/twostroke/compiler/javascript.rb +20 -2
- data/lib/twostroke/compiler/tsasm.rb +89 -35
- data/lib/twostroke/compiler.rb +1 -1
- data/lib/twostroke/error.rb +3 -0
- data/lib/twostroke/lexer.rb +3 -2
- data/lib/twostroke/parser.rb +309 -227
- data/lib/twostroke/runtime/lib/array.js +9 -3
- data/lib/twostroke/runtime/lib/array.rb +15 -7
- data/lib/twostroke/runtime/lib/console.rb +3 -2
- data/lib/twostroke/runtime/lib/error.rb +1 -1
- data/lib/twostroke/runtime/lib/etc.js +38 -0
- data/lib/twostroke/runtime/lib/etc.rb +29 -0
- data/lib/twostroke/runtime/lib/math.rb +31 -0
- data/lib/twostroke/runtime/lib/number.rb +7 -1
- data/lib/twostroke/runtime/lib/object.rb +1 -1
- data/lib/twostroke/runtime/lib/regexp.rb +1 -0
- data/lib/twostroke/runtime/lib/string.rb +62 -22
- data/lib/twostroke/runtime/scope.rb +23 -2
- data/lib/twostroke/runtime/types/array.rb +5 -0
- data/lib/twostroke/runtime/types/function.rb +5 -2
- data/lib/twostroke/runtime/types/object.rb +3 -4
- data/lib/twostroke/runtime/types/regexp.rb +45 -2
- data/lib/twostroke/runtime/types.rb +1 -1
- data/lib/twostroke/runtime/vm.rb +2 -2
- data/lib/twostroke/runtime/vm_frame.rb +47 -8
- data/lib/twostroke/tokens.rb +32 -16
- metadata +5 -5
- data/lib/twostroke/ast/delete.rb +0 -15
- data/lib/twostroke/ast/unsorted_binop.rb +0 -97
- 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 ||
|
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 =
|
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
|
-
|
44
|
-
@
|
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
|
-
|
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.
|
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
|
data/lib/twostroke/tokens.rb
CHANGED
@@ -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
|
-
[ :
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
case m[1]
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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.
|
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:
|
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/
|
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
|
data/lib/twostroke/ast/delete.rb
DELETED
@@ -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
|