minjs 0.3.0 → 0.4.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.
@@ -1,4 +1,5 @@
1
- module Minjs
1
+ module Minjs::Lex
2
+ # ParseError
2
3
  class ParseError < StandardError
3
4
  def initialize(error_message = nil, lex = nil)
4
5
  super(error_message)
@@ -8,6 +9,7 @@ module Minjs
8
9
  end
9
10
  end
10
11
 
12
+ # to string
11
13
  def to_s
12
14
  t = ''
13
15
  t << super
@@ -0,0 +1,1092 @@
1
+ # coding: utf-8
2
+ module Minjs::Lex
3
+ # Expression
4
+ module Expression
5
+ include Minjs
6
+ # Tests next literal is PrimaryExpression or not.
7
+ #
8
+ # If literal is PrimaryExpression
9
+ # return ECMA262::Base object and
10
+ # forward lexical parser position.
11
+ # Otherwise return nil and position is not changed.
12
+ #
13
+ # @param context [Context] Lexical Environment
14
+ #
15
+ # @return [ECMA262::ECMA262Object] expression
16
+ #
17
+ # @see ECMA262 11.1
18
+ def primary_exp(context)
19
+ @logger.debug "*** primary_exp"
20
+
21
+ if lex.eql_lit?(ECMA262::ID_THIS)
22
+ @logger.debug "*** primary_exp => this"
23
+ return ECMA262::This.new(context)
24
+ end
25
+ # (exp)
26
+ if lex.eql_lit?(ECMA262::PUNC_LPARENTHESIS)
27
+ if a=exp(context, {}) and lex.eql_lit?(ECMA262::PUNC_RPARENTHESIS)
28
+ @logger.debug "*** primary_exp => ()"
29
+ return ECMA262::ExpParen.new(a)
30
+ else
31
+ raise ParseError.new("no `)' at end of expression", lex)
32
+ end
33
+ end
34
+
35
+ t = literal(context) ||
36
+ identifier(context) ||
37
+ array_literal(context) ||
38
+ object_literal(context)
39
+
40
+ @logger.debug {
41
+ "*** primary_exp => #{t ? t.to_js : t}"
42
+ }
43
+ t
44
+ end
45
+
46
+ # Tests next literal is Literal or not
47
+ #
48
+ # If literal is Literal,
49
+ # return ECMA262::Base object correspoding to expression and
50
+ # forward lexical parser position.
51
+ # Otherwise return nil and position is not changed.
52
+ #
53
+ # @param context [Context] Lexical Environment
54
+ # @return [ECMA262::Base] expression
55
+ #
56
+ # @see ECMA262 7.8, 7.8.1, 7.8.2
57
+ def literal(context)
58
+ # Literal ::
59
+ # NullLiteral
60
+ # BooleanLiteral
61
+ # NumericLiteral
62
+ # StringLiteral
63
+ # RegularExpressionLiteral
64
+ a = lex.peek_lit(:regexp)
65
+ if a.kind_of? ECMA262::ECMA262Numeric or a.kind_of? ECMA262::ECMA262String or a.kind_of? ECMA262::ECMA262RegExp
66
+ lex.fwd_after_peek
67
+ a
68
+ elsif a .eql? ECMA262::ID_NULL
69
+ lex.fwd_after_peek
70
+ ECMA262::Null.get
71
+ elsif a .eql? ECMA262::ID_TRUE
72
+ lex.fwd_after_peek
73
+ ECMA262::Boolean.get(:true)
74
+ elsif a .eql? ECMA262::ID_FALSE
75
+ lex.fwd_after_peek
76
+ ECMA262::Boolean.get(:false)
77
+ else
78
+ nil
79
+ end
80
+ end
81
+
82
+ # Tests next literal is Identifier or not.
83
+ #
84
+ # If literal is Identifier
85
+ # return ECMA262::Lit object and
86
+ # forward lexical parser position.
87
+ # Otherwise return nil and position is not changed.
88
+ #
89
+ # @param context [Context] Lexical Environment
90
+ #
91
+ # @return [ECMA262::Literal] expression
92
+ #
93
+ # @see ECMA262 11.1.2
94
+ def identifier(context)
95
+ a = lex.peek_lit(:regexp)
96
+ if a.kind_of? ECMA262::IdentifierName and !a.reserved?
97
+ lex.fwd_after_peek
98
+ a.context = context
99
+ a
100
+ else
101
+ nil
102
+ end
103
+ end
104
+ # Tests next literal is ArrayLiteral or not.
105
+ #
106
+ # If literal is ArrayLiteral
107
+ # return ECMA262::ECMA262Array object and
108
+ # forward lexical parser position.
109
+ # Otherwise return nil and position is not changed.
110
+ #
111
+ # @param context [Context] Lexical Environment
112
+ #
113
+ # @return [ECMA262::ECMA262Array] expression
114
+ #
115
+ # @see ECMA262 11.1.4
116
+ def array_literal(context)
117
+ return nil unless lex.eql_lit?(ECMA262::PUNC_LSQBRAC)
118
+ t = []
119
+ while true
120
+ if lex.eql_lit?(ECMA262::PUNC_COMMA)
121
+ t.push(nil)
122
+ elsif lex.eql_lit?(ECMA262::PUNC_RSQBRAC)
123
+ break
124
+ elsif a = assignment_exp(context, {})
125
+ t.push(a)
126
+ lex.eql_lit?(ECMA262::PUNC_COMMA)
127
+ else
128
+ raise ParseError.new("no `]' end of array", lex)
129
+ end
130
+ end
131
+ ECMA262::ECMA262Array.new(t)
132
+ end
133
+ # Tests next literal is ObjectLiteral or not.
134
+ #
135
+ # If literal is ObjectLiteral
136
+ # return ECMA262::ECMA262Object object and
137
+ # forward lexical parser position.
138
+ # Otherwise return nil and position is not changed.
139
+ #
140
+ # @param context [Context] Lexical Environment
141
+ #
142
+ # @return [ECMA262::ECMA262Object] expression
143
+ #
144
+ # @see ECMA262 11.1.5
145
+ def object_literal(context)
146
+ #
147
+ # 11.1.5
148
+ #
149
+ # ObjectLiteral :
150
+ # { }
151
+ # { PropertyNameAndValueList }
152
+ # { PropertyNameAndValueList , }
153
+ #
154
+ return nil unless lex.eql_lit?(ECMA262::PUNC_LCURLYBRAC)
155
+ #{}
156
+ if lex.eql_lit?(ECMA262::PUNC_RCURLYBRAC)
157
+ ECMA262::ECMA262Object.new([])
158
+ else
159
+ ECMA262::ECMA262Object.new(property_name_and_value_list(context))
160
+ end
161
+ end
162
+
163
+ # Tests next literal is PropertyNameAndValueList or not.
164
+ #
165
+ # If literal is PropertyNameAndValueList
166
+ # return Array object and
167
+ # forward lexical parser position.
168
+ # Otherwise return nil and position is not changed.
169
+ #
170
+ # @param context [Context] Lexical Environment
171
+ #
172
+ # @return [Array<Array>] expression
173
+ #
174
+ # @see ECMA262 11.1.5
175
+ #
176
+ def property_name_and_value_list(context)
177
+ # PropertyNameAndValueList :
178
+ # PropertyAssignment
179
+ # PropertyNameAndValueList , PropertyAssignment
180
+ #
181
+ # PropertyAssignment :
182
+ # PropertyName : AssignmentExpression
183
+ # get PropertyName ( ) { FunctionBody }
184
+ # set PropertyName ( PropertySetParameterList ) { FunctionBody }
185
+ h = []
186
+ while !lex.eof?
187
+ #get
188
+ if lex.match_lit? ECMA262::ID_GET
189
+ # {get : val}
190
+ if lex.eql_lit? ECMA262::PUNC_COLON
191
+ b = assignment_exp(context, {})
192
+ h.push([ECMA262::ID_GET, b])
193
+ # {get name(){}}
194
+ else
195
+ new_context = ECMA262::Context.new
196
+ new_context.lex_env = context.lex_env.new_declarative_env()
197
+ new_context.var_env = context.var_env.new_declarative_env()
198
+ if(a = property_name(context) and
199
+ lex.eql_lit? ECMA262::PUNC_LPARENTHESIS and
200
+ lex.eql_lit? ECMA262::PUNC_RPARENTHESIS and
201
+ lex.eql_lit? ECMA262::PUNC_LCURLYBRAC and
202
+ b = func_body(new_context) and
203
+ lex.eql_lit? ECMA262::PUNC_RCURLYBRAC)
204
+ h.push([a, ECMA262::StFunc.new(new_context, ECMA262::ID_GET, [], b, :getter => true)])
205
+ else
206
+ raise ParseError.new("unexpceted token", lex)
207
+ end
208
+ end
209
+ #set
210
+ elsif lex.match_lit?(ECMA262::ID_SET)
211
+ # {set : val}
212
+ if lex.eql_lit? ECMA262::PUNC_COLON
213
+ b = assignment_exp(context, {})
214
+ h.push([ECMA262::ID_SET, b])
215
+ # {set name(arg){}}
216
+ else
217
+ new_context = ECMA262::Context.new
218
+ new_context.lex_env = context.lex_env.new_declarative_env()
219
+ new_context.var_env = context.var_env.new_declarative_env()
220
+ if(a = property_name(context) and
221
+ lex.eql_lit? ECMA262::PUNC_LPARENTHESIS and
222
+ arg = property_set_parameter_list(new_context) and
223
+ lex.eql_lit? ECMA262::PUNC_RPARENTHESIS and
224
+ lex.eql_lit? ECMA262::PUNC_LCURLYBRAC and
225
+ b = func_body(new_context) and
226
+ lex.eql_lit? ECMA262::PUNC_RCURLYBRAC)
227
+ h.push([a, ECMA262::StFunc.new(new_context, ECMA262::ID_SET, arg, b, :setter => true)])
228
+ else
229
+ raise ParseError.new("unexpceted token", lex)
230
+ end
231
+ end
232
+ #property
233
+ elsif(a = property_name(context) and
234
+ lex.eql_lit? ECMA262::PUNC_COLON and
235
+ b = assignment_exp(context, {}))
236
+ h.push([a, b])
237
+ else
238
+ raise ParseError.new("unexpceted token", lex)
239
+ end
240
+
241
+ if lex.eql_lit?(ECMA262::PUNC_COMMA)
242
+ break if lex.eql_lit?(ECMA262::PUNC_RCURLYBRAC)
243
+ elsif lex.eql_lit?(ECMA262::PUNC_RCURLYBRAC)
244
+ break
245
+ else
246
+ raise ParseError.new("no `}' end of object", lex)
247
+ end
248
+ end
249
+ h
250
+ end
251
+
252
+ # Tests next literal is PropertyName or not.
253
+ #
254
+ # If literal is PropertyName
255
+ # return ECMA262::Base object and
256
+ # forward lexical parser position.
257
+ # Otherwise return nil and position is not changed.
258
+ #
259
+ # @param context [Context] Lexical Environment
260
+ #
261
+ # @return [ECMA262::Base] expression
262
+ #
263
+ # @see ECMA262 11.1.5
264
+ # 11.1.5
265
+ #
266
+ #
267
+ def property_name(context)
268
+ # PropertyName :
269
+ # IdentifierName
270
+ # StringLiteral
271
+ # NumericLiteral
272
+ a = lex.fwd_lit(nil)
273
+ if a.kind_of?(ECMA262::ECMA262String)
274
+ a
275
+ elsif a.kind_of?(ECMA262::IdentifierName)
276
+ ECMA262::ECMA262String.new(a.to_js)
277
+ elsif a.kind_of?(ECMA262::ECMA262Numeric)
278
+ a
279
+ elsif a.eql?(ECMA262::PUNC_COLON)
280
+ nil
281
+ else
282
+ raise ParseError.new("unexpceted token", lex)
283
+ end
284
+ end
285
+
286
+ # Tests next literal is PropertySetParameterList or not.
287
+ #
288
+ # If literal is PropertySetParameterList
289
+ # return them and
290
+ # forward lexical parser position.
291
+ # Otherwise return nil and position is not changed.
292
+ #
293
+ # @param context [Context] Lexical Environment
294
+ #
295
+ # @return [Array<ECMA262::Base>] arguments
296
+ #
297
+ # @see ECMA262 11.1.5
298
+ def property_set_parameter_list(context)
299
+ # PropertySetParameterList :
300
+ # Identifier
301
+ argName = identifier(context)
302
+ context.var_env.record.create_mutable_binding(argName, nil)
303
+ context.var_env.record.set_mutable_binding(argName, :undefined, nil, {:_parameter_list => true})
304
+ context.lex_env.record.create_mutable_binding(argName, nil)
305
+ context.lex_env.record.set_mutable_binding(argName, :undefined, nil, {:_parameter_list => true})
306
+ [argName]
307
+ end
308
+
309
+ # Tests next literal is LeftHandSideExpression or not.
310
+ #
311
+ # If literal is LeftHandSideExpression,
312
+ # return ECMA262::Base object correspoding to expression and
313
+ # forward lexical parser position.
314
+ # Otherwise return nil and position is not changed.
315
+ #
316
+ # @param context [Context] Lexical Environment
317
+ # @return [ECMA262::Base] expression
318
+ #
319
+ # @see ECMA262 11.2
320
+ def left_hand_side_exp(context)
321
+ #
322
+ # LeftHandSideExpression :
323
+ # NewExpression
324
+ # CallExpression
325
+ #
326
+ @logger.debug "*** left_hand_side_exp"
327
+
328
+ t = call_exp(context) || new_exp(context)
329
+ #t = new_exp(context) || call_exp(context)
330
+
331
+ @logger.debug{
332
+ "*** left_hand_side_exp => #{t ? t.to_js: t}"
333
+ }
334
+ t
335
+ end
336
+
337
+ # Tests next literal is NewExpression or not.
338
+ #
339
+ # If literal is NewExpression,
340
+ # return ECMA262::Base object correspoding to expression and
341
+ # forward lexical parser position.
342
+ # Otherwise return nil and position is not changed.
343
+ #
344
+ # The NewExpression only matchs no-arguments-constructor because
345
+ # member expression also has "new MemberExpression Arguments"
346
+ #
347
+ # For example,
348
+ #
349
+ # 1. new A;
350
+ # 2. new A[B];
351
+ # 3. new A.B;
352
+ # 4. new A.B();
353
+ # 5. new new B();
354
+ # 6. A();
355
+ #
356
+ # 1 to 3 are NewExpression.
357
+ # 4 is MemberExpression.
358
+ # 5 's first new is NewExpression and second one is MemberExpression.
359
+ # 6 is CallExpression
360
+ #
361
+ # In the results, NewExpression can be rewritten as follows:
362
+ #
363
+ # NewExpression :
364
+ # MemberExpression [lookahead ∉ {(}]
365
+ # new NewExpression [lookahead ∉ {(}]
366
+ #
367
+ # @param context [Context] Lexical Environment
368
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
369
+ #
370
+ # @return [ECMA262::Base] expression
371
+ #
372
+ # @see ECMA262 11.2
373
+ # @see #call_exp
374
+ def new_exp(context)
375
+ # NewExpression :
376
+ # MemberExpression
377
+ # new NewExpression
378
+ if lex.eql_lit?(ECMA262::ID_NEW)
379
+ if a = new_exp(context)
380
+ if lex.eql_lit? ECMA262::PUNC_LPARENTHESIS
381
+ # minjs evaluate CallExpression first, so
382
+ # program never falls to here.
383
+ raise ParseError.new("unexpceted token", lex)
384
+ nil # this is not NewExpression, may be MemberExpression.
385
+ end
386
+ #puts "new_exp> #{a.to_js}"
387
+ ECMA262::ExpNew.new(a, nil)
388
+ else
389
+ # minjs evaluate CallExpression first, so
390
+ # raise exception when program falls to here.
391
+ raise ParseError.new("unexpceted token", lex)
392
+ #nil
393
+ end
394
+ else
395
+ member_exp(context)
396
+ end
397
+ end
398
+ # Tests next literal is CallExpression or not.
399
+ #
400
+ # If literal is CallExpression,
401
+ # return ECMA262::Base object correspoding to expression and
402
+ # forward lexical parser position.
403
+ # Otherwise return nil and position is not changed.
404
+ #
405
+ # @see ECMA262 11.2
406
+ # @see #new_exp
407
+ def call_exp(context)
408
+ # CallExpression :
409
+ # MemberExpression Arguments
410
+ # CallExpression Arguments
411
+ # CallExpression [ Expression ]
412
+ # CallExpression . IdentifierName
413
+ if a = member_exp(context)
414
+ if b = arguments(context)
415
+ t = ECMA262::ExpCall.new(a, b)
416
+ # if b is nil, this may be MemberExpression of NewExpression
417
+ else
418
+ return a
419
+ end
420
+ else
421
+ return nil
422
+ end
423
+
424
+ while true
425
+ if b = arguments(context)
426
+ t = ECMA262::ExpCall.new(t, b)
427
+ elsif lex.eql_lit?(ECMA262::PUNC_LSQBRAC)
428
+ if b=exp(context, {}) and lex.eql_lit?(ECMA262::PUNC_RSQBRAC)
429
+ t = ECMA262::ExpPropBrac.new(t, b)
430
+ else
431
+ raise ParseError.new("unexpceted token", lex)
432
+ end
433
+ elsif lex.eql_lit?(ECMA262::PUNC_PERIOD)
434
+ if (b=lex.fwd_lit(nil)).kind_of?(ECMA262::IdentifierName)
435
+ t = ECMA262::ExpProp.new(t, b)
436
+ else
437
+ raise ParseError.new("unexpceted token", lex)
438
+ end
439
+ else
440
+ break
441
+ end
442
+ end
443
+ t
444
+ end
445
+
446
+ # Tests next literal is MemberExpression or not.
447
+ #
448
+ # If literal is MemberExpression,
449
+ # return ECMA262::Base object correspoding to expression and
450
+ # forward lexical parser position.
451
+ # Otherwise return nil and position is not changed.
452
+ #
453
+ # @param context [Context] Lexical Environment
454
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
455
+ #
456
+ # @return [ECMA262::Base] expression
457
+ #
458
+ # @see ECMA262 11.2
459
+ #
460
+ def member_exp(context)
461
+ # MemberExpression :
462
+ # PrimaryExpression
463
+ # FunctionExpression
464
+ # MemberExpression [ Expression ]
465
+ # MemberExpression . IdentifierName
466
+ # new MemberExpression Arguments
467
+ #
468
+ t = lex.eval_lit{
469
+ if lex.eql_lit? ECMA262::ID_NEW
470
+ if a = member_exp(context)
471
+ b = arguments(context)
472
+ # if b is nil, this may be NewExpression
473
+ if b
474
+ s = b.collect{|x| x.to_js}.join(',');
475
+ #puts "member_exp> [new] #{a.to_js} (#{s})"
476
+ next ECMA262::ExpNew.new(a, b)
477
+ else
478
+ return nil
479
+ end
480
+ else
481
+ return nil
482
+ end
483
+ end
484
+ } || primary_exp(context) || func_exp(context)
485
+ return nil if t.nil?
486
+
487
+ while true
488
+ if lex.eql_lit?(ECMA262::PUNC_LSQBRAC)
489
+ if b=exp(context, {}) and lex.eql_lit?(ECMA262::PUNC_RSQBRAC)
490
+ t = ECMA262::ExpPropBrac.new(t, b)
491
+ else
492
+ raise ParseError.new("unexpceted token", lex)
493
+ end
494
+ elsif lex.eql_lit?(ECMA262::PUNC_PERIOD)
495
+ if (b=lex.fwd_lit(nil)).kind_of?(ECMA262::IdentifierName)
496
+ t = ECMA262::ExpProp.new(t, b)
497
+ else
498
+ raise ParseError.new("unexpceted token", lex)
499
+ end
500
+ else
501
+ break
502
+ end
503
+ end
504
+ t
505
+ end
506
+ # Tests next literal is Arguments or not.
507
+ #
508
+ # If literal is Arguments
509
+ # return them and
510
+ # forward lexical parser position.
511
+ # Otherwise return nil and position is not changed.
512
+ #
513
+ # @param context [Context] Lexical Environment
514
+ #
515
+ # @return [Array<ECMA262::Base>] arguments
516
+ #
517
+ # @see ECMA262 11.2
518
+ def arguments(context)
519
+ # Arguments :
520
+ # ( )
521
+ # ( ArgumentList )
522
+ return nil if lex.eql_lit?(ECMA262::PUNC_LPARENTHESIS).nil?
523
+ return [] if lex.eql_lit?(ECMA262::PUNC_RPARENTHESIS)
524
+
525
+ args = []
526
+ while true
527
+ if t = assignment_exp(context, {})
528
+ args.push(t)
529
+ else
530
+ raise ParseError.new("unexpected token", lex)
531
+ end
532
+ if lex.eql_lit?(ECMA262::PUNC_COMMA)
533
+ ;
534
+ elsif lex.eql_lit?(ECMA262::PUNC_RPARENTHESIS)
535
+ break
536
+ else
537
+ raise ParseError.new("unexpected token", lex)
538
+ end
539
+ end
540
+ args
541
+ end
542
+
543
+ # Tests next literal is PostfixExpression or not.
544
+ #
545
+ # If literal is PostfixExpression
546
+ # return ECMA262::Base object and
547
+ # forward lexical parser position.
548
+ # Otherwise return nil and position is not changed.
549
+ #
550
+ # @param context [Context] Lexical Environment
551
+ #
552
+ # @return [ECMA262::ECMA262Object] expression
553
+ #
554
+ # @see ECMA262 11.3
555
+ def postfix_exp(context)
556
+ exp = left_hand_side_exp(context)
557
+ return nil if exp.nil?
558
+ if punc = (lex.eql_lit_nolt?(ECMA262::PUNC_INC) ||
559
+ lex.eql_lit_nolt?(ECMA262::PUNC_DEC))
560
+ if punc == ECMA262::PUNC_INC
561
+ ECMA262::ExpPostInc.new(exp)
562
+ else
563
+ ECMA262::ExpPostDec.new(exp)
564
+ end
565
+ else
566
+ exp
567
+ end
568
+ end
569
+
570
+ # Tests next literal is UnaryExpression or not.
571
+ #
572
+ # If literal is UnaryExpression,
573
+ # return ECMA262::Base object correspoding to expression and
574
+ # forward lexical parser position.
575
+ # Otherwise return nil and position is not changed.
576
+ #
577
+ # @param context [Context] Lexical Environment
578
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
579
+ # @return [ECMA262::Base] expression
580
+ #
581
+ # see ECMA262 11.4
582
+ def unary_exp(context)
583
+ if punc = (lex.eql_lit?(ECMA262::ID_DELETE) ||
584
+ lex.eql_lit?(ECMA262::ID_VOID) ||
585
+ lex.eql_lit?(ECMA262::ID_TYPEOF) ||
586
+ lex.eql_lit?(ECMA262::PUNC_INC) ||
587
+ lex.eql_lit?(ECMA262::PUNC_DEC) ||
588
+ lex.eql_lit?(ECMA262::PUNC_ADD) ||
589
+ lex.eql_lit?(ECMA262::PUNC_SUB) ||
590
+ lex.eql_lit?(ECMA262::PUNC_NOT) ||
591
+ lex.eql_lit?(ECMA262::PUNC_LNOT))
592
+ exp = unary_exp(context)
593
+ if exp.nil?
594
+ raise ParseError.new("unexpceted token", lex)
595
+ elsif punc == ECMA262::PUNC_INC
596
+ ECMA262::ExpPreInc.new(exp)
597
+ elsif punc == ECMA262::PUNC_DEC
598
+ ECMA262::ExpPreDec.new(exp)
599
+ elsif punc == ECMA262::PUNC_ADD
600
+ ECMA262::ExpPositive.new(exp)
601
+ elsif punc == ECMA262::PUNC_SUB
602
+ ECMA262::ExpNegative.new(exp)
603
+ elsif punc == ECMA262::PUNC_NOT
604
+ ECMA262::ExpBitwiseNot.new(exp)
605
+ elsif punc == ECMA262::PUNC_LNOT
606
+ ECMA262::ExpLogicalNot.new(exp)
607
+ elsif punc.respond_to?(:val)
608
+ if punc.val == :delete
609
+ ECMA262::ExpDelete.new(exp)
610
+ elsif punc.val == :void
611
+ ECMA262::ExpVoid.new(exp)
612
+ elsif punc.val == :typeof
613
+ ECMA262::ExpTypeof.new(exp)
614
+ end
615
+ end
616
+ else
617
+ postfix_exp(context)
618
+ end
619
+ end
620
+
621
+ # Tests next literal is MultiplicativeExpression or not.
622
+ #
623
+ # If literal is MultiplicativeExpression,
624
+ # return ECMA262::Base object correspoding to expression and
625
+ # forward lexical parser position.
626
+ # Otherwise return nil and position is not changed.
627
+ #
628
+ # @param context [Context] Lexical Environment
629
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
630
+ #
631
+ # @return [ECMA262::Base] expression
632
+ #
633
+ # @see ECMA262 11.5
634
+ def multiplicative_exp(context)
635
+ a = unary_exp(context)
636
+ return nil if !a
637
+ t = a
638
+ while punc = lex.eql_lit?(ECMA262::PUNC_MUL) ||
639
+ lex.eql_lit?(ECMA262::PUNC_DIV, :div) ||
640
+ lex.eql_lit?(ECMA262::PUNC_MOD)
641
+
642
+ if b = unary_exp(context)
643
+ if punc == ECMA262::PUNC_MUL
644
+ t = ECMA262::ExpMul.new(t, b)
645
+ elsif punc == ECMA262::PUNC_DIV
646
+ t = ECMA262::ExpDiv.new(t, b)
647
+ else
648
+ t = ECMA262::ExpMod.new(t, b)
649
+ end
650
+ else
651
+ raise ParseError.new("unexpceted token", lex)
652
+ end
653
+ end
654
+ t
655
+ end
656
+
657
+ # Tests next literal is AdditiveExpression or not.
658
+ #
659
+ # If literal is AdditiveExpression,
660
+ # return ECMA262::Base object correspoding to expression and
661
+ # forward lexical parser position.
662
+ # Otherwise return nil and position is not changed.
663
+ #
664
+ # @param context [Context] Lexical Environment
665
+ #
666
+ # @return [ECMA262::Base] expression
667
+ #
668
+ # @see ECMA262 11.6
669
+ def additive_exp(context)
670
+ # AdditiveExpression :
671
+ # MultiplicativeExpression AdditiveExpression +
672
+ # MultiplicativeExpression AdditiveExpression -
673
+ # MultiplicativeExpression
674
+ a = multiplicative_exp(context)
675
+ return nil if !a
676
+
677
+ t = a
678
+ while punc = lex.eql_lit?(ECMA262::PUNC_ADD) || lex.eql_lit?(ECMA262::PUNC_SUB)
679
+ if b = multiplicative_exp(context)
680
+ if punc == ECMA262::PUNC_ADD
681
+ t = ECMA262::ExpAdd.new(t, b)
682
+ else
683
+ t = ECMA262::ExpSub.new(t, b)
684
+ end
685
+ else
686
+ raise ParseError.new("unexpceted token", lex)
687
+ end
688
+ end
689
+ t
690
+ end
691
+ # Tests next literal is ShiftExpression or not.
692
+ #
693
+ # If literal is ShiftExpression,
694
+ # return ECMA262::Base object correspoding to expression and
695
+ # forward lexical parser position.
696
+ # Otherwise return nil and position is not changed.
697
+ #
698
+ # @param context [Context] Lexical Environment
699
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
700
+ # @return [ECMA262::Base] expression
701
+ #
702
+ # see ECMA262 11.8
703
+ def shift_exp(context)
704
+ a = additive_exp(context)
705
+ return nil if !a
706
+
707
+ t = a
708
+ while punc = lex.eql_lit?(ECMA262::PUNC_LSHIFT) ||
709
+ lex.eql_lit?(ECMA262::PUNC_RSHIFT) ||
710
+ lex.eql_lit?(ECMA262::PUNC_URSHIFT)
711
+ if b = additive_exp(context)
712
+ if punc == ECMA262::PUNC_LSHIFT
713
+ t = ECMA262::ExpLShift.new(t, b)
714
+ elsif punc == ECMA262::PUNC_RSHIFT
715
+ t = ECMA262::ExpRShift.new(t, b)
716
+ elsif punc == ECMA262::PUNC_URSHIFT
717
+ t = ECMA262::ExpURShift.new(t, b)
718
+ end
719
+ else
720
+ raise ParseError.new("unexpceted token", lex)
721
+ end
722
+ end
723
+ t
724
+ end
725
+ # Tests next literal is RelationalExpression or not.
726
+ #
727
+ # If literal is RelationalExpression,
728
+ # return ECMA262::Base object correspoding to expression and
729
+ # forward lexical parser position.
730
+ # Otherwise return nil and position is not changed.
731
+ #
732
+ # @param context [Context] Lexical Environment
733
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
734
+ # @return [ECMA262::Base] expression
735
+ #
736
+ # see ECMA262 11.8
737
+ def relational_exp(context, options)
738
+ #RelationalExpression :
739
+ # ShiftExpression
740
+ # RelationalExpression < ShiftExpression
741
+ # RelationalExpression > ShiftExpression
742
+ # RelationalExpression <= ShiftExpression
743
+ # RelationalExpression >= ShiftExpression
744
+ # RelationalExpression instanceof ShiftExpression
745
+ # RelationalExpression in ShiftExpression
746
+ a = shift_exp(context)
747
+ return nil if !a
748
+
749
+ t = a
750
+ while (punc = lex.eql_lit?(ECMA262::PUNC_LT) || lex.eql_lit?(ECMA262::PUNC_GT) ||
751
+ lex.eql_lit?(ECMA262::PUNC_LTEQ) || lex.eql_lit?(ECMA262::PUNC_GTEQ) ||
752
+ lex.eql_lit?(ECMA262::ID_INSTANCEOF) || (!options[:no_in] && lex.eql_lit?(ECMA262::ID_IN)))
753
+ if b = shift_exp(context)
754
+ if punc == ECMA262::PUNC_LT
755
+ t = ECMA262::ExpLt.new(t, b)
756
+ elsif punc == ECMA262::PUNC_GT
757
+ t = ECMA262::ExpGt.new(t, b)
758
+ elsif punc == ECMA262::PUNC_LTEQ
759
+ t = ECMA262::ExpLtEq.new(t, b)
760
+ elsif punc == ECMA262::PUNC_GTEQ
761
+ t = ECMA262::ExpGtEq.new(t, b)
762
+ elsif punc.val == :instanceof
763
+ t = ECMA262::ExpInstanceOf.new(t, b)
764
+ elsif !options[:no_in] and punc.val == :in
765
+ t = ECMA262::ExpIn.new(t, b)
766
+ else
767
+ end
768
+ else
769
+ raise ParseError.new("unexpceted token", lex)
770
+ end
771
+ end
772
+ t
773
+ end
774
+ # Tests next literal is EqualityExpression or not.
775
+ #
776
+ # If literal is EqualityExpression,
777
+ # return ECMA262::Base object correspoding to expression and
778
+ # forward lexical parser position.
779
+ # Otherwise return nil and position is not changed.
780
+ #
781
+ # @param context [Context] Lexical Environment
782
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
783
+ #
784
+ # @return [ECMA262::Base] expression
785
+ #
786
+ # @see ECMA262 11.9
787
+ def equality_exp(context, options)
788
+ a = relational_exp(context, options)
789
+ return nil if !a
790
+
791
+ t = a
792
+ while punc = lex.eql_lit?(ECMA262::PUNC_EQ) ||
793
+ lex.eql_lit?(ECMA262::PUNC_NEQ) ||
794
+ lex.eql_lit?(ECMA262::PUNC_SEQ) ||
795
+ lex.eql_lit?(ECMA262::PUNC_SNEQ)
796
+ if b = relational_exp(context, options)
797
+ if punc == ECMA262::PUNC_EQ
798
+ t = ECMA262::ExpEq.new(t, b)
799
+ elsif punc == ECMA262::PUNC_NEQ
800
+ t = ECMA262::ExpNotEq.new(t, b)
801
+ elsif punc == ECMA262::PUNC_SEQ
802
+ t = ECMA262::ExpStrictEq.new(t, b)
803
+ elsif punc == ECMA262::PUNC_SNEQ
804
+ t = ECMA262::ExpStrictNotEq.new(t, b)
805
+ end
806
+ else
807
+ raise ParseError.new("unexpceted token", lex)
808
+ end
809
+ end
810
+ t
811
+ end
812
+
813
+ # Tests next literal is BitwiseAndExpression or not.
814
+ #
815
+ # If literal is BitwiseAndExpression,
816
+ # return ECMA262::Base object correspoding to expression and
817
+ # forward lexical parser position.
818
+ # Otherwise return nil and position is not changed.
819
+ #
820
+ # @param context [Context] Lexical Environment
821
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
822
+ #
823
+ # @return [ECMA262::Base] expression
824
+ #
825
+ # @see ECMA262 11.10
826
+ def bitwise_and_exp(context, options)
827
+ a = equality_exp(context, options)
828
+ return nil if !a
829
+
830
+ t = a
831
+ while punc = lex.eql_lit?(ECMA262::PUNC_AND)
832
+ if b = equality_exp(context, options)
833
+ t = ECMA262::ExpAnd.new(t, b)
834
+ else
835
+ raise ParseError.new("unexpceted token", lex)
836
+ end
837
+ end
838
+ t
839
+ end
840
+
841
+ # Tests next literal is BitwiseXorExpression or not.
842
+ #
843
+ # If literal is BitwiseXorExpression,
844
+ # return ECMA262::Base object correspoding to expression and
845
+ # forward lexical parser position.
846
+ # Otherwise return nil and position is not changed.
847
+ #
848
+ # @param context [Context] Lexical Environment
849
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
850
+ #
851
+ # @return [ECMA262::Base] expression
852
+ #
853
+ # @see ECMA262 11.10
854
+ def bitwise_xor_exp(context, options)
855
+ a = bitwise_and_exp(context, options)
856
+ return nil if !a
857
+
858
+ t = a
859
+ while punc = lex.eql_lit?(ECMA262::PUNC_XOR)
860
+ if b = bitwise_and_exp(context, options)
861
+ t = ECMA262::ExpXor.new(t, b)
862
+ else
863
+ raise ParseError.new("unexpceted token", lex)
864
+ end
865
+ end
866
+
867
+ t
868
+ end
869
+
870
+ # Tests next literal is BitwiseOrExpression or not.
871
+ #
872
+ # If literal is BitwiseOrExpression,
873
+ # return ECMA262::Base object correspoding to expression and
874
+ # forward lexical parser position.
875
+ # Otherwise return nil and position is not changed.
876
+ #
877
+ # @param context [Context] Lexical Environment
878
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
879
+ #
880
+ # @return [ECMA262::Base] expression
881
+ #
882
+ # @see ECMA262 11.10
883
+ def bitwise_or_exp(context, options)
884
+ a = bitwise_xor_exp(context, options)
885
+ return nil if !a
886
+
887
+ t = a
888
+ while punc = lex.eql_lit?(ECMA262::PUNC_OR)
889
+ if b = bitwise_xor_exp(context, options)
890
+ t = ECMA262::ExpOr.new(t, b)
891
+ else
892
+ raise ParseError.new("unexpceted token", lex)
893
+ end
894
+ end
895
+ t
896
+ end
897
+
898
+ # Tests next literal is LogicalAndExpression or not
899
+ #
900
+ # If literal is LogicalAndExpression,
901
+ # return ECMA262::Base object correspoding to expression and
902
+ # forward lexical parser position.
903
+ # Otherwise return nil and position is not changed.
904
+ #
905
+ # @param context [Context] Lexical Environment
906
+ # @return [ECMA262::Base] expression
907
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
908
+ #
909
+ # @see ECMA262 11.11
910
+ def logical_and_exp(context, options)
911
+ a = bitwise_or_exp(context, options)
912
+ return nil if !a
913
+
914
+ t = a
915
+ while punc = lex.eql_lit?(ECMA262::PUNC_LAND)
916
+ if b = bitwise_or_exp(context, options)
917
+ t = ECMA262::ExpLogicalAnd.new(t, b)
918
+ else
919
+ raise ParseError.new("unexpceted token", lex)
920
+ end
921
+ end
922
+
923
+ t
924
+ end
925
+
926
+ # Tests next literal is LogicalOrExpression or not
927
+ #
928
+ # If literal is LogicalOrExpression,
929
+ # return ECMA262::Base object correspoding to expression and
930
+ # forward lexical parser position.
931
+ # Otherwise return nil and position is not changed.
932
+ #
933
+ # @param context [Context] Lexical Environment
934
+ # @return [ECMA262::Base] expression
935
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
936
+ #
937
+ # @see ECMA262 11.12
938
+ def logical_or_exp(context, options)
939
+ a = logical_and_exp(context, options)
940
+ return nil if !a
941
+
942
+ t = a
943
+ while punc = lex.eql_lit?(ECMA262::PUNC_LOR)
944
+ if b = logical_and_exp(context, options)
945
+ t = ECMA262::ExpLogicalOr.new(t, b)
946
+ else
947
+ raise ParseError.new("unexpceted token", lex)
948
+ end
949
+ end
950
+
951
+ t
952
+ end
953
+ # Tests next literal is ConditionalExpression or not.
954
+ #
955
+ # If literal is ConditionalExpression,
956
+ # return ECMA262::Base object correspoding to expression and
957
+ # forward lexical parser position.
958
+ # Otherwise return nil and position is not changed.
959
+ #
960
+ # @param context [Context] Lexical Environment
961
+ #
962
+ # @return [ECMA262::Base] expression
963
+ #
964
+ # @see ECMA262 11.12
965
+ def cond_exp(context, options)
966
+ a = logical_or_exp(context, options)
967
+ return nil if !a
968
+
969
+ if lex.eql_lit?(ECMA262::PUNC_CONDIF)
970
+ if b=assignment_exp(context, options) and lex.eql_lit?(ECMA262::PUNC_COLON) and c=assignment_exp(context, options)
971
+ ECMA262::ExpCond.new(a, b, c)
972
+ else
973
+ raise ParseError.new("unexpceted token", lex)
974
+ end
975
+ else
976
+ a
977
+ end
978
+ end
979
+ # Tests next literal is AssignmentExpression or not.
980
+ #
981
+ # If literal is AssignmentExpression,
982
+ # return ECMA262::Base object correspoding to expression and
983
+ # forward lexical parser position.
984
+ # Otherwise return nil and position is not changed.
985
+ #
986
+ # @param context [Context] Lexical Environment
987
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
988
+ #
989
+ # @see ECMA262 11.13
990
+ def assignment_exp(context, options)
991
+ # AssignmentExpression :
992
+ # ConditionalExpression
993
+ # LeftHandSideExpression = AssignmentExpression
994
+ # LeftHandSideExpression AssignmentOperator AssignmentExpression
995
+ @logger.debug "*** assignment_exp"
996
+
997
+ t = cond_exp(context, options)
998
+ return nil if t.nil?
999
+
1000
+ if !t.left_hand_side_exp?
1001
+ return t
1002
+ end
1003
+ left_hand = t
1004
+ punc = lex.peek_lit(:div)
1005
+ if punc == ECMA262::PUNC_ASSIGN ||
1006
+ punc == ECMA262::PUNC_DIVASSIGN ||
1007
+ punc == ECMA262::PUNC_MULASSIGN ||
1008
+ punc == ECMA262::PUNC_MODASSIGN ||
1009
+ punc == ECMA262::PUNC_ADDASSIGN ||
1010
+ punc == ECMA262::PUNC_SUBASSIGN ||
1011
+ punc == ECMA262::PUNC_LSHIFTASSIGN ||
1012
+ punc == ECMA262::PUNC_RSHIFTASSIGN ||
1013
+ punc == ECMA262::PUNC_URSHIFTASSIGN ||
1014
+ punc == ECMA262::PUNC_ANDASSIGN ||
1015
+ punc == ECMA262::PUNC_ORASSIGN ||
1016
+ punc == ECMA262::PUNC_XORASSIGN
1017
+ lex.fwd_after_peek
1018
+ if b = assignment_exp(context, options)
1019
+ case punc
1020
+ when ECMA262::PUNC_ASSIGN
1021
+ ECMA262::ExpAssign.new(left_hand, b)
1022
+ when ECMA262::PUNC_DIVASSIGN
1023
+ ECMA262::ExpDivAssign.new(left_hand, b)
1024
+ when ECMA262::PUNC_MULASSIGN
1025
+ ECMA262::ExpMulAssign.new(left_hand, b)
1026
+ when ECMA262::PUNC_MODASSIGN
1027
+ ECMA262::ExpModAssign.new(left_hand, b)
1028
+ when ECMA262::PUNC_ADDASSIGN
1029
+ ECMA262::ExpAddAssign.new(left_hand, b)
1030
+ when ECMA262::PUNC_SUBASSIGN
1031
+ ECMA262::ExpSubAssign.new(left_hand, b)
1032
+ when ECMA262::PUNC_LSHIFTASSIGN
1033
+ ECMA262::ExpLShiftAssign.new(left_hand, b)
1034
+ when ECMA262::PUNC_RSHIFTASSIGN
1035
+ ECMA262::ExpRShiftAssign.new(left_hand, b)
1036
+ when ECMA262::PUNC_URSHIFTASSIGN
1037
+ ECMA262::ExpURShiftAssign.new(left_hand, b)
1038
+ when ECMA262::PUNC_ANDASSIGN
1039
+ ECMA262::ExpAndAssign.new(left_hand, b)
1040
+ when ECMA262::PUNC_ORASSIGN
1041
+ ECMA262::ExpOrAssign.new(left_hand, b)
1042
+ when ECMA262::PUNC_XORASSIGN
1043
+ ECMA262::ExpXorAssign.new(left_hand, b)
1044
+ else
1045
+ raise "internal error"
1046
+ end
1047
+ else
1048
+ raise ParseError.new("unexpceted token", lex)
1049
+ end
1050
+ else
1051
+ @logger.debug {
1052
+ "*** assignment_exp => #{t ? t.to_js : t}"
1053
+ }
1054
+ t
1055
+ end
1056
+ end
1057
+
1058
+ # Tests next literal is Expression or not.
1059
+ #
1060
+ # If literal is Expression,
1061
+ # return ECMA262::Base object correspoding to expression and
1062
+ # forward lexical parser position.
1063
+ # Otherwise return nil and position is not changed.
1064
+ #
1065
+ # @param context [Context] Lexical Environment
1066
+ # @option options :no_in [Boolean] If set, the parser interpret as RelationExpressionNoIn
1067
+ #
1068
+ # @return [ECMA262::Base] expression
1069
+ #
1070
+ # @see ECMA262 11.14
1071
+ def exp(context, options)
1072
+ # Expression :
1073
+ # AssignmentExpression
1074
+ # Expression , AssignmentExpression
1075
+ @logger.debug "*** expression"
1076
+
1077
+ t = assignment_exp(context, options)
1078
+ return nil if t.nil?
1079
+ while punc = lex.eql_lit?(ECMA262::PUNC_COMMA)
1080
+ if b = assignment_exp(context, options)
1081
+ t = ECMA262::ExpComma.new(t, b)
1082
+ else
1083
+ raise ParseError.new("unexpceted token", lex)
1084
+ end
1085
+ end
1086
+ @logger.debug{
1087
+ "*** expression => #{t ? t.to_js : t}"
1088
+ }
1089
+ t
1090
+ end
1091
+ end
1092
+ end