twostroke 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ module Twostroke::AST
2
+ class Break < Base
3
+ def collapse
4
+ self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ module Twostroke::AST
2
+ class Case < Base
3
+ attr_accessor :expression, :statements
4
+ def initialize(*args)
5
+ @statements = []
6
+ super *args
7
+ end
8
+ def collapse
9
+ self.class.new expression: expression.collapse, statements: statements.collect(&:collapse)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
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
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Twostroke::AST
2
+ class DoWhile < Base
3
+ attr_accessor :body, :condition
4
+
5
+ def collapse
6
+ self.class.new body: body.collapse, condition: condition.collapse
7
+ end
8
+ end
9
+ end
@@ -3,7 +3,10 @@ module Twostroke::AST
3
3
  attr_accessor :initializer, :condition, :increment, :body
4
4
 
5
5
  def collapse
6
- self.class.new initializer: initializer.collapse, condition: condition.collapse, increment: increment.collapse, body: body.collapse
6
+ self.class.new initializer: initializer && initializer.collapse,
7
+ condition: condition && condition.collapse,
8
+ increment: increment && increment.collapse,
9
+ body: body.collapse
7
10
  end
8
11
  end
9
12
  end
@@ -0,0 +1,9 @@
1
+ module Twostroke::AST
2
+ class Regexp < Base
3
+ attr_accessor :regexp
4
+
5
+ def collapse
6
+ self
7
+ end
8
+ end
9
+ end
@@ -3,7 +3,7 @@ module Twostroke::AST
3
3
  attr_accessor :expression
4
4
 
5
5
  def collapse
6
- self.class.new expression: expression.collapse
6
+ self.class.new expression: expression && expression.collapse
7
7
  end
8
8
  end
9
9
  end
@@ -0,0 +1,12 @@
1
+ module Twostroke::AST
2
+ class Switch < Base
3
+ attr_accessor :expression, :cases
4
+ def initialize(*args)
5
+ @cases = []
6
+ super *args
7
+ end
8
+ def collapse
9
+ self.class.new expression: expression.collapse, cases: cases.collect(&:collapse)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module Twostroke::AST
2
+ class Throw < Base
3
+ attr_accessor :expression
4
+
5
+ def collapse
6
+ self.class.new expression: expression.collapse
7
+ end
8
+ end
9
+ end
@@ -17,7 +17,7 @@ module Twostroke::AST
17
17
  :GT => GreaterThan,
18
18
  :GTE => GreaterThanEqual,
19
19
  :IN => In,
20
- :INSTANCE_OF => InstanceOf,
20
+ :INSTANCEOF => InstanceOf,
21
21
  :DOUBLE_EQUALS => Equality,
22
22
  :NOT_EQUALS => Inequality,
23
23
  :TRIPLE_EQUALS => StrictEquality,
@@ -45,7 +45,7 @@ module Twostroke::AST
45
45
  :GT => 8,
46
46
  :GTE => 8,
47
47
  :IN => 8,
48
- :INSTANCE_OF => 8,
48
+ :INSTANCEOF => 8,
49
49
  :DOUBLE_EQUALS => 9,
50
50
  :NOT_EQUALS => 9,
51
51
  :TRIPLE_EQUALS => 9,
@@ -9,43 +9,48 @@ module Twostroke
9
9
  send "#{k}=", v
10
10
  end
11
11
  end
12
- def is?(t)
13
- if t.is_a? Array
14
- t.include? type
15
- else
16
- t == type
17
- end
18
- end
19
12
  end
20
13
 
21
14
  class Lexer
22
- attr_reader :str, :col, :line, :tokens
15
+ attr_accessor :str, :col, :line
16
+
17
+ def state
18
+ { str: str, col: col, line: line }
19
+ end
20
+ def state=(state)
21
+ @str = state[:str]
22
+ @col = state[:col]
23
+ @line = state[:line]
24
+ end
25
+
23
26
  def initialize(str)
24
27
  @str = str
25
28
  @col = 1
26
29
  @line = 1
27
- @tokens = []
28
30
  end
29
- def lex
30
- until @str.empty?
31
- read_token
32
- end
33
- end
34
- private
35
- def read_token
36
- TOKENS.each do |token|
31
+
32
+ def read_token(allow_regexp = true)
33
+ TOKENS.select { |t| allow_regexp || t[0] != :REGEXP }.each do |token|
37
34
  m = token[1].match @str
38
35
  if m
39
- @tokens.push Token.new(:type => token[0], :val => token[2] ? token[2].call(m) : nil, :line => @line, :col => @col) unless [:WHITESPACE, :MULTI_COMMENT, :SINGLE_COMMENT].include? token[0]
36
+ tok = Token.new(:type => token[0], :val => token[2] ? token[2].call(m) : nil, :line => @line, :col => @col)
40
37
  @str = m.post_match
41
38
  newlines = m[0].count "\n"
42
39
  @col = 1 if !newlines.zero?
43
40
  @line += newlines
44
41
  @col += m[0].length - (m[0].rindex("\n") || 0)
45
- return
42
+ if [:WHITESPACE, :MULTI_COMMENT, :SINGLE_COMMENT].include? token[0]
43
+ return read_token(allow_regexp)
44
+ else
45
+ return tok
46
+ end
46
47
  end
47
48
  end
48
- raise LexError, "Illegal character '#{@str[0]}' at line #{@line}, col #{@col}. (read #{@tokens.count} tokens)"
49
+ if @str.size > 0
50
+ raise LexError, "Illegal character '#{@str[0]}' at line #{@line}, col #{@col}."
51
+ else
52
+ nil
53
+ end
49
54
  end
50
55
  end
51
56
  end
@@ -5,14 +5,14 @@ module Twostroke
5
5
  class Parser
6
6
  attr_reader :statements
7
7
 
8
- def initialize(tokens)
8
+ def initialize(lexer)
9
9
  @i = -1
10
- @tokens = tokens + [Token.new(type: :SEMICOLON)]
10
+ @lexer = lexer
11
11
  @statements = []
12
12
  end
13
13
 
14
14
  def parse
15
- while @i + 1 < @tokens.length
15
+ while try_peek_token
16
16
  st = statement
17
17
  statements.push st.collapse if st
18
18
  end
@@ -25,27 +25,29 @@ module Twostroke
25
25
  def assert_type(tok, *types)
26
26
  error! "Found #{tok.type}#{"<#{tok.val}>" if tok.val}, expected #{types.join ", "}" unless types.include? tok.type
27
27
  end
28
- def stack
29
- @stack
28
+
29
+ def save_state
30
+ { cur_token: @cur_token, peek_token: @peek_token, lexer_state: @lexer.state }
30
31
  end
31
- def stack_top
32
- @stack.last
32
+ def load_state(state)
33
+ @cur_token = state[:cur_token]
34
+ @peek_token = state[:peek_token]
35
+ @lexer.state = state[:lexer_state]
33
36
  end
37
+
34
38
  def token
35
- @tokens[@i] or raise ParseError, "unexpected end of input"
39
+ @cur_token or raise ParseError, "unexpected end of input"
36
40
  end
37
- def next_token
38
- @i += 1
41
+ def next_token(allow_regexp = true)
42
+ @cur_token = @peek_token || @lexer.read_token(allow_regexp)
43
+ @peek_token = nil
39
44
  token
40
45
  end
41
- def try_peek_token
42
- @i + 1 < @tokens.length ? peek_token : nil
43
- end
44
- def peek_token
45
- @tokens[@i + 1] or raise ParseError, "unexpected end of input"
46
+ def try_peek_token(allow_regexp = true)
47
+ @peek_token ||= @lexer.read_token(allow_regexp)
46
48
  end
47
- def look_ahead(n = 1)
48
- @tokens[@i + n]
49
+ def peek_token(allow_regexp = true)
50
+ @peek_token ||= @lexer.read_token(allow_regexp) or raise ParseError, "unexpected end of input"
49
51
  end
50
52
 
51
53
  ####################
@@ -53,9 +55,13 @@ module Twostroke
53
55
  def statement(consume_semicolon = true)
54
56
  st = case peek_token.type
55
57
  when :RETURN; send :return
58
+ when :BREAK; send :break
59
+ when :THROW; send :throw
56
60
  when :VAR; var
57
61
  when :IF; consume_semicolon = false; send :if
58
62
  when :FOR; consume_semicolon = false; send :for
63
+ when :SWITCH; consume_semicolon = false; send :switch
64
+ when :DO; send :do
59
65
  when :WHILE; consume_semicolon = false; send :while
60
66
  when :TRY; consume_semicolon = false; try
61
67
  when :OPEN_BRACE; consume_semicolon = false; body
@@ -64,64 +70,72 @@ module Twostroke
64
70
  else; expression
65
71
  end
66
72
  if consume_semicolon
67
- #next_token if try_peek_token && peek_token.type == :SEMICOLON
68
- assert_type next_token, :SEMICOLON
73
+ next_token if try_peek_token && peek_token.type == :SEMICOLON
74
+ #assert_type next_token, :SEMICOLON
69
75
  end
70
76
  st
71
77
  end
72
-
78
+
73
79
  def expression(no_comma = false, no_in = false, no_ternary = false)
74
80
  expr = expression_after_unary no_comma
75
- new_expr = if [:PLUS, :MINUS, :ASTERISK, :SLASH, :MOD,
81
+ expr = if [:PLUS, :MINUS, :ASTERISK, :SLASH, :MOD,
76
82
  :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
83
+ :AMPERSAND, :CARET, :PIPE ].include? peek_token(false).type
84
+ state = save_state
85
+ next_token
86
+ combined = (peek_token(false).type == :EQUALS)
87
+ load_state state
88
+ if combined
89
+ # combination assignment
90
+ op = next_token(false).type
91
+ assert_type next_token(false), :EQUALS
92
+ AST::UnsortedBinop.operator_class[op].new left: expr, assign_result_left: true, right: expression(true, false, true)
93
+ else
94
+ binop expr
95
+ end
87
96
  elsif [ :GT, :LT, :GTE, :LTE, :DOUBLE_EQUALS,
88
97
  :TRIPLE_EQUALS, :NOT_EQUALS, :NOT_DOUBLE_EQUALS,
89
98
  :AND, :OR, :LEFT_SHIFT, :RIGHT_SHIFT,
90
99
  :RIGHT_TRIPLE_SHIFT, :INSTANCEOF,
91
- *(no_in ? [] : [:IN]) ].include? peek_token.type
100
+ *(no_in ? [] : [:IN]) ].include? peek_token(false).type
92
101
  expr = binop expr
93
102
  # this has a higher precedence than the ternary
94
103
  # so we'll hackily check for a ternary after this
95
- if try_peek_token && peek_token.type == :QUESTION
104
+ if try_peek_token && peek_token(false).type == :QUESTION
96
105
  ternary(expr)
97
106
  else
98
107
  expr
99
108
  end
100
- elsif peek_token.type == :EQUALS
109
+ else
110
+ expr
111
+ end
112
+ expr = if peek_token(false).type == :EQUALS
101
113
  next_token
102
114
  AST::Assignment.new left: expr, right: expression(true)
103
- elsif !no_ternary && peek_token.type == :QUESTION
115
+ elsif !no_ternary && peek_token(false).type == :QUESTION
104
116
  ternary(expr)
105
117
  else
106
118
  expr
107
119
  end
108
120
 
109
- if !no_comma && peek_token.type == :COMMA
121
+ if !no_comma && peek_token(false).type == :COMMA
110
122
  next_token
111
- AST::MultiExpression.new left: new_expr, right: expression
123
+ AST::MultiExpression.new left: expr, right: expression
112
124
  else
113
- new_expr
125
+ expr
114
126
  end
115
127
  end
116
128
 
117
- def expression_after_unary(no_comma = false, no_call = false)
129
+ def expression_after_unary(no_comma = true, no_call = false)
118
130
  expr = case peek_token.type
119
131
  when :FUNCTION; function
120
132
  when :STRING; string
121
133
  when :NUMBER; number
134
+ when :REGEXP; regexp
122
135
  when :THIS; this
123
136
  when :NULL; null
124
137
  when :NEW; send :new
138
+ when :DELETE; delete
125
139
  when :BAREWORD; bareword
126
140
  when :OPEN_PAREN; parens
127
141
  when :OPEN_BRACE; object_literal
@@ -137,17 +151,17 @@ module Twostroke
137
151
  else error! "Unexpected #{peek_token.type}"
138
152
  end
139
153
  loop do
140
- if !no_call && peek_token.type == :OPEN_PAREN
154
+ if !no_call && peek_token(false).type == :OPEN_PAREN
141
155
  expr = call expr
142
- elsif peek_token.type == :OPEN_BRACKET
156
+ elsif peek_token(false).type == :OPEN_BRACKET
143
157
  expr = index expr
144
- elsif peek_token.type == :MEMBER_ACCESS
158
+ elsif peek_token(false).type == :MEMBER_ACCESS
145
159
  expr = member_access expr
146
- elsif !no_comma && peek_token.type == :COMMA
160
+ elsif !no_comma && peek_token(false).type == :COMMA
147
161
  expr = comma(expr)
148
- elsif peek_token.type == :INCREMENT
162
+ elsif peek_token(false).type == :INCREMENT
149
163
  expr = post_increment expr
150
- elsif peek_token.type == :DECREMENT
164
+ elsif peek_token(false).type == :DECREMENT
151
165
  expr = post_decrement expr
152
166
  else
153
167
  return expr
@@ -157,8 +171,8 @@ module Twostroke
157
171
  end
158
172
 
159
173
  def binop(left)
160
- next_token
161
- AST::UnsortedBinop.new left: left, op: token.type, right: expression(false, false, true)
174
+ op = next_token.type
175
+ AST::UnsortedBinop.new left: left, op: op, right: expression(true, false, true)
162
176
  end
163
177
 
164
178
  def body
@@ -189,9 +203,9 @@ module Twostroke
189
203
  def ternary(cond)
190
204
  assert_type next_token, :QUESTION
191
205
  ternary = AST::Ternary.new condition: cond
192
- ternary.if_true = expression
206
+ ternary.if_true = expression(true)
193
207
  assert_type next_token, :COLON
194
- ternary.if_false = expression
208
+ ternary.if_false = expression(true)
195
209
  ternary
196
210
  end
197
211
 
@@ -207,23 +221,24 @@ module Twostroke
207
221
  end
208
222
  node
209
223
  end
210
-
224
+
211
225
  def for
212
226
  assert_type next_token, :FOR
213
227
  assert_type next_token, :OPEN_PAREN
214
228
  # decide if this is a for(... in ...) or a for(;;) loop
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
229
+ saved_state = save_state
230
+ if next_token.type == :VAR && next_token.type == :BAREWORD && next_token.type == :IN
219
231
  for_in = true
232
+ load_state saved_state
220
233
  else
221
- stmt = statement(false)
234
+ load_state saved_state
235
+ stmt = statement(false) unless peek_token.type == :SEMICOLON
222
236
  assert_type next_token, :SEMICOLON, :CLOSE_PAREN
223
237
  for_in = (token.type == :CLOSE_PAREN)
224
238
  end
239
+ load_state saved_state
225
240
  if for_in
226
- @i = saved_i # no luck parsing for(;;), reparse as for(..in..)
241
+ # no luck parsing for(;;), reparse as for(..in..)
227
242
  if peek_token.type == :VAR
228
243
  next_token
229
244
  assert_type next_token, :BAREWORD
@@ -236,15 +251,39 @@ module Twostroke
236
251
  assert_type next_token, :CLOSE_PAREN
237
252
  AST::ForIn.new lval: lval, object: obj, body: statement
238
253
  else
239
- initializer = stmt
240
- condition = statement(false)
254
+ initializer = statement(false) unless peek_token.type == :SEMICOLON
241
255
  assert_type next_token, :SEMICOLON
242
- increment = statement(false)
256
+ condition = statement(false) unless peek_token.type == :SEMICOLON
257
+ assert_type next_token, :SEMICOLON
258
+ increment = statement(false) unless peek_token.type == :CLOSE_PAREN
243
259
  assert_type next_token, :CLOSE_PAREN
244
260
  AST::ForLoop.new initializer: initializer, condition: condition, increment: increment, body: statement
245
261
  end
246
262
  end
247
263
 
264
+ def switch
265
+ assert_type next_token, :SWITCH
266
+ assert_type next_token, :OPEN_PAREN
267
+ sw = AST::Switch.new expression: expression
268
+ assert_type next_token, :CLOSE_PAREN
269
+ assert_type next_token, :OPEN_BRACE
270
+ current_case = nil
271
+ while ![:CLOSE_BRACE].include? peek_token.type
272
+ if peek_token.type == :CASE
273
+ assert_type next_token, :CASE
274
+ expr = expression
275
+ current_case = AST::Case.new expression: expr
276
+ assert_type next_token, :COLON
277
+ sw.cases << current_case
278
+ else
279
+ error! "statements may only appear under a case" if current_case.nil?
280
+ current_case.statements << statement
281
+ end
282
+ end
283
+ assert_type next_token, :CLOSE_BRACE
284
+ sw
285
+ end
286
+
248
287
  def while
249
288
  assert_type next_token, :WHILE
250
289
  assert_type next_token, :OPEN_PAREN
@@ -254,6 +293,16 @@ module Twostroke
254
293
  node
255
294
  end
256
295
 
296
+ def do
297
+ assert_type next_token, :DO
298
+ node = AST::DoWhile.new body: body
299
+ assert_type next_token, :WHILE
300
+ assert_type next_token, :OPEN_PAREN
301
+ node.condition = expression(false)
302
+ assert_type next_token, :CLOSE_PAREN
303
+ node
304
+ end
305
+
257
306
  def try
258
307
  try = AST::Try.new try_statements: []
259
308
  assert_type next_token, :TRY
@@ -336,7 +385,23 @@ module Twostroke
336
385
 
337
386
  def return
338
387
  assert_type next_token, :RETURN
339
- AST::Return.new expression: expression
388
+ expr = expression unless peek_token.type == :SEMICOLON || peek_token.type == :CLOSE_BRACE
389
+ AST::Return.new expression: expr
390
+ end
391
+
392
+ def break
393
+ assert_type next_token, :BREAK
394
+ AST::Break.new
395
+ end
396
+
397
+ def throw
398
+ assert_type next_token, :THROW
399
+ AST::Throw.new expression: expression
400
+ end
401
+
402
+ def delete
403
+ assert_type next_token, :DELETE
404
+ AST::Delete.new expression: expression
340
405
  end
341
406
 
342
407
  def var
@@ -347,7 +412,7 @@ module Twostroke
347
412
  def var_rest
348
413
  assert_type next_token, :BAREWORD
349
414
  decl = AST::Declaration.new(name: token.val)
350
- return decl if peek_token.type == :SEMICOLON
415
+ return decl if peek_token.type == :SEMICOLON || peek_token.type == :CLOSE_BRACE
351
416
 
352
417
  assert_type next_token, :COMMA, :EQUALS
353
418
 
@@ -355,7 +420,7 @@ module Twostroke
355
420
  AST::MultiExpression.new left: decl, right: var_rest
356
421
  else
357
422
  assignment = AST::Assignment.new left: decl, right: expression(true)
358
- if peek_token.type == :SEMICOLON
423
+ if peek_token.type == :SEMICOLON || peek_token.type == :CLOSE_BRACE
359
424
  assignment
360
425
  elsif peek_token.type == :COMMA
361
426
  next_token
@@ -386,6 +451,11 @@ module Twostroke
386
451
  AST::String.new string: token.val
387
452
  end
388
453
 
454
+ def regexp
455
+ assert_type next_token, :REGEXP
456
+ AST::Regexp.new regexp: token.val
457
+ end
458
+
389
459
  def object_literal
390
460
  assert_type next_token, :OPEN_BRACE
391
461
  obj = AST::ObjectLiteral.new
@@ -480,14 +550,14 @@ module Twostroke
480
550
  AST::PostDecrement.new value: obj
481
551
  end
482
552
 
483
- def pre_increment(obj)
553
+ def pre_increment
484
554
  assert_type next_token, :INCREMENT
485
- AST::PreIncrement.new value: obj
555
+ AST::PreIncrement.new value: expression_after_unary
486
556
  end
487
557
 
488
- def pre_decrement(obj)
558
+ def pre_decrement
489
559
  assert_type next_token, :DECREMENT
490
- AST::PreDecrement.new value: obj
560
+ AST::PreDecrement.new value: expression_after_unary
491
561
  end
492
562
 
493
563
  def typeof
@@ -0,0 +1,33 @@
1
+ module Twostroke::Runtime
2
+ class Context
3
+ attr_accessor :variables, :parent
4
+
5
+ def initialize
6
+ variables = {}
7
+ end
8
+
9
+ def [](var)
10
+ if variables.key? var
11
+ variables[var]
12
+ elsif parent
13
+ parent[var]
14
+ else
15
+ raise "ReferenceError" # TODO
16
+ end
17
+ end
18
+
19
+ def []=(var, val)
20
+ if variables.key?(var) || parent.nil?
21
+ variables[var] = val
22
+ else
23
+ parent[var] = val
24
+ end
25
+ end
26
+
27
+ def create_context
28
+ context = Context.new
29
+ context.parent = self
30
+ context
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ module Twostroke::Runtime
2
+ class Environment
3
+ attr_accessor :root_context, :root_object
4
+
5
+ def initialize(root_name)
6
+ @root_object = Types::Object.new
7
+ @root_context = Context.new
8
+ @root_contect.variables = @root_object
9
+
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module Twostroke::Runtime::Types
2
+ class BasicType
3
+ #
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module Twostroke::Runtime::Types
2
+ class Null < BasicType
3
+ def self.null
4
+ @@null ||= Null.new
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ module Twostroke::Runtime::Types
2
+ class Object < BasicType
3
+ attr_accessor :properties, :accessor_properties
4
+
5
+ def initialize(env)
6
+ @properties = {}
7
+ @accessor_properties = {}
8
+ properties["__proto__"]
9
+ end
10
+
11
+ def [](key)
12
+ if accessor_properties.key? key
13
+ accessor_properties[key].get self
14
+ elsif properties.key? key
15
+ properties[key]
16
+ elsif properties.key? "__proto__"
17
+ properties["__proto__"][key]
18
+ else
19
+ Undefined.undefined
20
+ end
21
+ end
22
+
23
+ def []=(key, val)
24
+ if accessor_properties.key? key
25
+ accessor_properties[key].get self
26
+ elsif properties.key? key
27
+ properties[key]
28
+ else
29
+ Undefined.undefined
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,7 @@
1
+ module Twostroke::Runtime::Types
2
+ class Undefined < BasicType
3
+ def self.undefined
4
+ @@undefined ||= Undefined.new
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Twostroke::Runtime
2
+ module Types
3
+ Dir.glob File.expand_path("../types/*", __FILE__) do |f|
4
+ require f
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Twostroke
2
+ module Runtime
3
+ Dir.glob File.expand_path("../runtime/*", __FILE__) do |f|
4
+ require f
5
+ end
6
+ end
7
+ end
@@ -1,14 +1,15 @@
1
1
  module Twostroke
2
2
  class Lexer
3
+ RESERVED = %w(function var if instanceof in else for while do this return throw typeof try catch finally void null new delete switch case break)
3
4
  TOKENS = [
4
5
 
5
6
  [ :MULTI_COMMENT, %r{/\*.*?\*/} ],
6
7
  [ :SINGLE_COMMENT, /\/\/.*?$/ ],
7
8
 
8
9
  [ :WHITESPACE, /\s+/ ],
9
- [ :NUMBER, /\d+(\.\d*(e[+-]?\d+)?)?/, ->m { m[0].to_f } ],
10
+ [ :NUMBER, /((?<oct>0[0-7]+)|(?<hex>0x[A-Fa-f0-9]+)|(?<to_f>(\d+(\.?\d*([eE][+-]?\d+)?)?|\.\d+([eE][+-]?\d+)?)))/, ->m { m[0].send m.names.first } ],
10
11
 
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
+ *RESERVED.map do |w|
12
13
  [ w.upcase.intern, /#{w}(?=[^a-zA-Z_0-9])/ ]
13
14
  end,
14
15
  [ :BAREWORD, /[a-zA-Z_\$][\$a-zA-Z_0-9]*/, ->m { m[0] } ],
@@ -28,6 +29,8 @@ module Twostroke
28
29
  .gsub(/\\u([a-f0-9]{4})/i) { |m| m[1].to_i(16).chr }
29
30
  .gsub(/\\(.)/) { |m| m[1] }
30
31
  end ],
32
+
33
+ [ :REGEXP, %r{/(?<src>(\\.|[^\1])*?[^\1\\]?)/(?<opts>[gim]+)?}, ->m { [m[:src], m[:opts]] } ],
31
34
 
32
35
  [ :OPEN_PAREN, /\(/ ],
33
36
  [ :CLOSE_PAREN, /\)/ ],
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.3
4
+ version: 0.0.4
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-05 00:00:00.000000000Z
12
+ date: 2011-10-15 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.
@@ -23,8 +23,12 @@ files:
23
23
  - lib/twostroke/ast/assignment.rb
24
24
  - lib/twostroke/ast/binary_operators.rb
25
25
  - lib/twostroke/ast/body.rb
26
+ - lib/twostroke/ast/break.rb
26
27
  - lib/twostroke/ast/call.rb
28
+ - lib/twostroke/ast/case.rb
27
29
  - lib/twostroke/ast/declaration.rb
30
+ - lib/twostroke/ast/delete.rb
31
+ - lib/twostroke/ast/do_while.rb
28
32
  - lib/twostroke/ast/for_in.rb
29
33
  - lib/twostroke/ast/for_loop.rb
30
34
  - lib/twostroke/ast/function.rb
@@ -36,10 +40,13 @@ files:
36
40
  - lib/twostroke/ast/null.rb
37
41
  - lib/twostroke/ast/number.rb
38
42
  - lib/twostroke/ast/object_literal.rb
43
+ - lib/twostroke/ast/regexp.rb
39
44
  - lib/twostroke/ast/return.rb
40
45
  - lib/twostroke/ast/string.rb
46
+ - lib/twostroke/ast/switch.rb
41
47
  - lib/twostroke/ast/ternary.rb
42
48
  - lib/twostroke/ast/this.rb
49
+ - lib/twostroke/ast/throw.rb
43
50
  - lib/twostroke/ast/try.rb
44
51
  - lib/twostroke/ast/unary_operators.rb
45
52
  - lib/twostroke/ast/unsorted_binop.rb
@@ -49,6 +56,14 @@ files:
49
56
  - lib/twostroke/error.rb
50
57
  - lib/twostroke/lexer.rb
51
58
  - lib/twostroke/parser.rb
59
+ - lib/twostroke/runtime/context.rb
60
+ - lib/twostroke/runtime/environment.rb
61
+ - lib/twostroke/runtime/types/basic_type.rb
62
+ - lib/twostroke/runtime/types/null.rb
63
+ - lib/twostroke/runtime/types/object.rb
64
+ - lib/twostroke/runtime/types/undefined.rb
65
+ - lib/twostroke/runtime/types.rb
66
+ - lib/twostroke/runtime.rb
52
67
  - lib/twostroke/tokens.rb
53
68
  - lib/twostroke.rb
54
69
  homepage: http://github.com/charliesome/twostroke