twostroke 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,7 +6,16 @@ module Twostroke::AST
6
6
  StrictInequality BitwiseAnd BitwiseXor BitwiseOr
7
7
  And Or).each do |op|
8
8
  klass = Class.new Base do
9
- attr_accessor :left, :right
9
+ attr_accessor :left, :right, :assign_result_left
10
+
11
+ def initialize(*args)
12
+ @assign_result_left = false
13
+ super *args
14
+ end
15
+
16
+ def collapse
17
+ self.class.new left: left.collapse, right: right.collapse, assign_result_left: assign_result_left
18
+ end
10
19
  end
11
20
  const_set op, klass
12
21
  end
@@ -0,0 +1,9 @@
1
+ module Twostroke::AST
2
+ class ForIn < Base
3
+ attr_accessor :lval, :object, :body
4
+
5
+ def collapse
6
+ self.class.new lval: lval.collapse, object: object.collapse, body: body.collapse
7
+ end
8
+ end
9
+ end
@@ -1,4 +1,3 @@
1
- require 'pry'
2
1
  module Twostroke::AST
3
2
  class If < Base
4
3
  attr_accessor :condition, :then, :else
@@ -0,0 +1,14 @@
1
+ module Twostroke::AST
2
+ class New < Base
3
+ attr_accessor :callee, :arguments
4
+
5
+ def initialize(*args)
6
+ @arguments = []
7
+ super *args
8
+ end
9
+
10
+ def collapse
11
+ self.class.new callee: callee.collapse, arguments: arguments.map(&:collapse)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ module Twostroke::AST
2
+ class Null < Base
3
+ def collapse
4
+ self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module Twostroke::AST
2
+ class This < Base
3
+ def collapse; self; end
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module Twostroke::AST
2
+ class Try < Base
3
+ attr_accessor :try_statements, :catch_variable, :catch_statements, :finally_statements
4
+
5
+ def collapse
6
+ self.class.new try_statements: try_statements.map(&:collapse), catch_variable: catch_variable,
7
+ catch_statements: (catch_statements && catch_statements.map(&:collapse)),
8
+ finally_statements: (finally_statements && finally_statements.map(&:collapse))
9
+ end
10
+ end
11
+ end
@@ -1,6 +1,6 @@
1
1
  module Twostroke::AST
2
2
  [ :PostIncrement, :PreIncrement, :PostDecrement, :PreDecrement,
3
- :BinaryNot, :UnaryPlus, :Negation, :TypeOf, :Not ].each do |op|
3
+ :BinaryNot, :UnaryPlus, :Negation, :TypeOf, :Not, :Void ].each do |op|
4
4
  klass = Class.new Base do
5
5
  attr_accessor :value
6
6
 
@@ -27,7 +27,6 @@ module Twostroke::AST
27
27
  :PIPE => BitwiseOr,
28
28
  :AND => And,
29
29
  :OR => Or
30
-
31
30
  }
32
31
  end
33
32
 
@@ -83,7 +82,6 @@ module Twostroke::AST
83
82
  if token.is_a? Symbol
84
83
  r = stack.pop
85
84
  l = stack.pop
86
- puts token
87
85
  stack.push UnsortedBinop.operator_class[token].new(left: l, right: r)
88
86
  else
89
87
  stack.push token
@@ -0,0 +1,9 @@
1
+ module Twostroke::AST
2
+ class While < Base
3
+ attr_accessor :condition, :body
4
+
5
+ def collapse
6
+ self.class.new condition: condition.collapse, body: body.collapse
7
+ end
8
+ end
9
+ end
@@ -56,7 +56,10 @@ module Twostroke
56
56
  when :VAR; var
57
57
  when :IF; consume_semicolon = false; send :if
58
58
  when :FOR; consume_semicolon = false; send :for
59
+ when :WHILE; consume_semicolon = false; send :while
60
+ when :TRY; consume_semicolon = false; try
59
61
  when :OPEN_BRACE; consume_semicolon = false; body
62
+ when :FUNCTION; consume_semicolon = false; function
60
63
  when :SEMICOLON; nil
61
64
  else; expression
62
65
  end
@@ -67,29 +70,58 @@ module Twostroke
67
70
  st
68
71
  end
69
72
 
70
- def expression(no_comma = false)
73
+ def expression(no_comma = false, no_in = false, no_ternary = false)
71
74
  expr = expression_after_unary no_comma
72
- if [:PLUS, :MINUS, :ASTERISK, :SLASH, :GT, :LT,
73
- :GTE, :LTE, :DOUBLE_EQUALS, :TRIPLE_EQUALS,
74
- :NOT_EQUALS, :NOT_DOUBLE_EQUALS, :AND, :OR,
75
- :AMPERSAND, :PIPE, :CARET, :MOD, :LEFT_SHIFT,
76
- :RIGHT_SHIFT, :RIGHT_TRIPLE_SHIFT, ].include? peek_token.type
77
- binop expr
75
+ new_expr = if [:PLUS, :MINUS, :ASTERISK, :SLASH, :MOD,
76
+ :LEFT_SHIFT, :RIGHT_SHIFT, :RIGHT_TRIPLE_SHIFT,
77
+ :AMPERSAND, :CARET, :PIPE ].include? peek_token.type
78
+ # these operators can be combined with assignment
79
+ if look_ahead(2).type == :EQUALS
80
+ # combination assignment
81
+ op = next_token.type
82
+ assert_type next_token, :EQUALS
83
+ AST::UnsortedBinop.operator_class[op].new left: expr, assign_result_left: true, right: expression
84
+ else
85
+ binop expr
86
+ end
87
+ elsif [ :GT, :LT, :GTE, :LTE, :DOUBLE_EQUALS,
88
+ :TRIPLE_EQUALS, :NOT_EQUALS, :NOT_DOUBLE_EQUALS,
89
+ :AND, :OR, :LEFT_SHIFT, :RIGHT_SHIFT,
90
+ :RIGHT_TRIPLE_SHIFT, :INSTANCEOF,
91
+ *(no_in ? [] : [:IN]) ].include? peek_token.type
92
+ expr = binop expr
93
+ # this has a higher precedence than the ternary
94
+ # so we'll hackily check for a ternary after this
95
+ if try_peek_token && peek_token.type == :QUESTION
96
+ ternary(expr)
97
+ else
98
+ expr
99
+ end
78
100
  elsif peek_token.type == :EQUALS
79
101
  next_token
80
- AST::Assignment.new left: expr, right: expression(no_comma)
81
- elsif peek_token.type == :QUESTION
102
+ AST::Assignment.new left: expr, right: expression(true)
103
+ elsif !no_ternary && peek_token.type == :QUESTION
82
104
  ternary(expr)
83
105
  else
84
106
  expr
85
107
  end
108
+
109
+ if !no_comma && peek_token.type == :COMMA
110
+ next_token
111
+ AST::MultiExpression.new left: new_expr, right: expression
112
+ else
113
+ new_expr
114
+ end
86
115
  end
87
116
 
88
- def expression_after_unary(no_comma = false)
117
+ def expression_after_unary(no_comma = false, no_call = false)
89
118
  expr = case peek_token.type
90
119
  when :FUNCTION; function
91
120
  when :STRING; string
92
121
  when :NUMBER; number
122
+ when :THIS; this
123
+ when :NULL; null
124
+ when :NEW; send :new
93
125
  when :BAREWORD; bareword
94
126
  when :OPEN_PAREN; parens
95
127
  when :OPEN_BRACE; object_literal
@@ -98,13 +130,14 @@ module Twostroke
98
130
  when :TILDE; tilde
99
131
  when :INCREMENT; pre_increment
100
132
  when :DECREMENT; pre_decrement
133
+ when :VOID; void
101
134
  when :PLUS; unary_plus
102
135
  when :MINUS; unary_minus
103
136
  when :TYPEOF; typeof
104
137
  else error! "Unexpected #{peek_token.type}"
105
138
  end
106
139
  loop do
107
- if peek_token.type == :OPEN_PAREN
140
+ if !no_call && peek_token.type == :OPEN_PAREN
108
141
  expr = call expr
109
142
  elsif peek_token.type == :OPEN_BRACKET
110
143
  expr = index expr
@@ -125,7 +158,7 @@ module Twostroke
125
158
 
126
159
  def binop(left)
127
160
  next_token
128
- AST::UnsortedBinop.new left: left, op: token.type, right: expression
161
+ AST::UnsortedBinop.new left: left, op: token.type, right: expression(false, false, true)
129
162
  end
130
163
 
131
164
  def body
@@ -138,6 +171,16 @@ module Twostroke
138
171
  body
139
172
  end
140
173
 
174
+ def this
175
+ assert_type next_token, :THIS
176
+ AST::This.new
177
+ end
178
+
179
+ def null
180
+ assert_type next_token, :NULL
181
+ AST::Null.new
182
+ end
183
+
141
184
  def bareword
142
185
  assert_type next_token, :BAREWORD
143
186
  AST::Variable.new name: token.val
@@ -169,11 +212,29 @@ module Twostroke
169
212
  assert_type next_token, :FOR
170
213
  assert_type next_token, :OPEN_PAREN
171
214
  # decide if this is a for(... in ...) or a for(;;) loop
172
- stmt = statement(false)
173
- assert_type next_token, :SEMICOLON, :CLOSE_PAREN
174
- if token.type == :CLOSE_PAREN
175
- # this is a for(... in ...) loop. we'll figure out how to deal with that in a sec
176
- error! "for..in loops not implemented yet!" # @TODO
215
+ for_in = false
216
+ saved_i = @i
217
+ if @i + 3 < @tokens.length && look_ahead(1).type == :VAR &&
218
+ look_ahead(2).type == :BAREWORD && look_ahead(3).type == :IN
219
+ for_in = true
220
+ else
221
+ stmt = statement(false)
222
+ assert_type next_token, :SEMICOLON, :CLOSE_PAREN
223
+ for_in = (token.type == :CLOSE_PAREN)
224
+ end
225
+ if for_in
226
+ @i = saved_i # no luck parsing for(;;), reparse as for(..in..)
227
+ if peek_token.type == :VAR
228
+ next_token
229
+ assert_type next_token, :BAREWORD
230
+ lval = AST::Declaration.new name: token.val
231
+ else
232
+ lval = expression(false, true)
233
+ end
234
+ assert_type next_token, :IN
235
+ obj = expression
236
+ assert_type next_token, :CLOSE_PAREN
237
+ AST::ForIn.new lval: lval, object: obj, body: statement
177
238
  else
178
239
  initializer = stmt
179
240
  condition = statement(false)
@@ -184,6 +245,48 @@ module Twostroke
184
245
  end
185
246
  end
186
247
 
248
+ def while
249
+ assert_type next_token, :WHILE
250
+ assert_type next_token, :OPEN_PAREN
251
+ node = AST::While.new condition: expression
252
+ assert_type next_token, :CLOSE_PAREN
253
+ node.body = statement
254
+ node
255
+ end
256
+
257
+ def try
258
+ try = AST::Try.new try_statements: []
259
+ assert_type next_token, :TRY
260
+ assert_type next_token, :OPEN_BRACE
261
+ while peek_token.type != :CLOSE_BRACE
262
+ try.try_statements << statement
263
+ end
264
+ assert_type next_token, :CLOSE_BRACE
265
+ assert_type next_token, :CATCH, :FINALLY
266
+ if token.type == :CATCH
267
+ try.catch_statements = []
268
+ assert_type next_token, :OPEN_PAREN
269
+ assert_type next_token, :BAREWORD
270
+ try.catch_variable = token.val
271
+ assert_type next_token, :CLOSE_PAREN
272
+ assert_type next_token, :OPEN_BRACE
273
+ while peek_token.type != :CLOSE_BRACE
274
+ try.catch_statements << statement
275
+ end
276
+ assert_type next_token, :CLOSE_BRACE
277
+ end
278
+ if try_peek_token && peek_token.type == :FINALLY
279
+ try.finally_statements = []
280
+ assert_type next_token, :FINALLY
281
+ assert_type next_token, :OPEN_BRACE
282
+ while peek_token.type != :CLOSE_BRACE
283
+ try.finally_statements << statement
284
+ end
285
+ assert_type next_token, :CLOSE_BRACE
286
+ end
287
+ try
288
+ end
289
+
187
290
  def member_access(obj)
188
291
  assert_type next_token, :MEMBER_ACCESS
189
292
  assert_type next_token, :BAREWORD
@@ -199,6 +302,17 @@ module Twostroke
199
302
  end
200
303
  end
201
304
 
305
+ def new
306
+ assert_type next_token, :NEW
307
+ node = AST::New.new
308
+ node.callee = expression_after_unary(false, true)
309
+ if try_peek_token && peek_token.type == :OPEN_PAREN
310
+ call = call(node.callee)
311
+ node.arguments = call.arguments
312
+ end
313
+ node
314
+ end
315
+
202
316
  def call(callee)
203
317
  assert_type next_token, :OPEN_PAREN
204
318
  c = AST::Call.new callee: callee
@@ -341,6 +455,11 @@ module Twostroke
341
455
  AST::BinaryNot.new value: expression_after_unary
342
456
  end
343
457
 
458
+ def void
459
+ assert_type next_token, :VOID
460
+ AST::Void.new value: expression_after_unary
461
+ end
462
+
344
463
  def unary_plus
345
464
  assert_type next_token, :PLUS
346
465
  AST::UnaryPlus.new value: expression_after_unary
@@ -357,7 +476,7 @@ module Twostroke
357
476
  end
358
477
 
359
478
  def post_decrement(obj)
360
- assert_type next_token, :INCREMENT
479
+ assert_type next_token, :DECREMENT
361
480
  AST::PostDecrement.new value: obj
362
481
  end
363
482
 
@@ -367,7 +486,7 @@ module Twostroke
367
486
  end
368
487
 
369
488
  def pre_decrement(obj)
370
- assert_type next_token, :INCREMENT
489
+ assert_type next_token, :DECREMENT
371
490
  AST::PreDecrement.new value: obj
372
491
  end
373
492
 
@@ -8,8 +8,8 @@ module Twostroke
8
8
  [ :WHITESPACE, /\s+/ ],
9
9
  [ :NUMBER, /\d+(\.\d*(e[+-]?\d+)?)?/, ->m { m[0].to_f } ],
10
10
 
11
- *%w(function var if instanceof in else for while do this return throw typeof try catch).map do |w|
12
- [ w.upcase.intern, /#{w}/ ]
11
+ *%w(function var if instanceof in else for while do this return throw typeof try catch finally void null new).map do |w|
12
+ [ w.upcase.intern, /#{w}(?=[^a-zA-Z_0-9])/ ]
13
13
  end,
14
14
  [ :BAREWORD, /[a-zA-Z_][a-zA-Z_0-9]*/, ->m { m[0] } ],
15
15
 
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.0.1
4
+ version: 0.0.2
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-10-04 00:00:00.000000000Z
12
+ date: 2011-10-05 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description: An implementation of Javascript written in pure Ruby. This project currently
15
15
  includes a WIP parser, and will include a runtime.
@@ -25,20 +25,26 @@ files:
25
25
  - lib/twostroke/ast/body.rb
26
26
  - lib/twostroke/ast/call.rb
27
27
  - lib/twostroke/ast/declaration.rb
28
+ - lib/twostroke/ast/for_in.rb
28
29
  - lib/twostroke/ast/for_loop.rb
29
30
  - lib/twostroke/ast/function.rb
30
31
  - lib/twostroke/ast/if.rb
31
32
  - lib/twostroke/ast/index.rb
32
33
  - lib/twostroke/ast/member_access.rb
33
34
  - lib/twostroke/ast/multi_expression.rb
35
+ - lib/twostroke/ast/new.rb
36
+ - lib/twostroke/ast/null.rb
34
37
  - lib/twostroke/ast/number.rb
35
38
  - lib/twostroke/ast/object_literal.rb
36
39
  - lib/twostroke/ast/return.rb
37
40
  - lib/twostroke/ast/string.rb
38
41
  - lib/twostroke/ast/ternary.rb
42
+ - lib/twostroke/ast/this.rb
43
+ - lib/twostroke/ast/try.rb
39
44
  - lib/twostroke/ast/unary_operators.rb
40
45
  - lib/twostroke/ast/unsorted_binop.rb
41
46
  - lib/twostroke/ast/variable.rb
47
+ - lib/twostroke/ast/while.rb
42
48
  - lib/twostroke/ast.rb
43
49
  - lib/twostroke/error.rb
44
50
  - lib/twostroke/lexer.rb