twostroke 0.0.1 → 0.0.2

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