twostroke 0.0.3 → 0.0.4

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