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,1012 +1,11 @@
1
- # coding: utf-8
2
- require 'minjs/ctype'
3
-
4
1
  module Minjs
5
- class Lex
6
- include Ctype
7
-
8
- attr_reader :pos
9
- attr_reader :codes
10
-
11
- def initialize(str = "", options = {})
12
- str = str.gsub(/\r\n/, "\n")
13
- @codes = str.codepoints
14
- if !str.match(/\n\z/)
15
- @codes.push(10)
16
- end
17
- @pos = 0
18
- @lit_cache = []
19
- @lit_nextpos = []
20
- @logger = options[:logger]
21
-
22
- @eval_nest = 0
23
- end
24
-
25
- def clear_cache
26
- @lit_cache = []
27
- @lit_nextpos = []
28
- end
29
-
30
- #
31
- # Fetch next literal
32
- #
33
- # hint:
34
- # :regexp
35
- # :div
36
- # nil
37
- #
38
- # ECMA262 says:
39
- #
40
- # There are no syntactic grammar contexts where both a leading division
41
- # or division-assignment, and a leading RegularExpressionLiteral are permitted.
42
- # This is not affected by semicolon insertion (see 7.9); in examples such as the following:
43
- # To determine `/' is regular expression or not
44
- #
45
- def next_input_element(hint)
46
- if ret = @lit_cache[@pos]
47
- @pos = @lit_nextpos[@pos]
48
- @head_pos = @pos
49
- return ret
50
- end
51
- pos0 = @pos
52
- #
53
- # skip white space here, because ECMA262(5.1.2) says:
54
- #
55
- # Simple white space and single-line comments are discarded and
56
- # do not appear in the stream of input elements for the
57
- # syntactic grammar.
58
- #
59
- while white_space or single_line_comment
60
- end
61
-
62
- ret = line_terminator || multi_line_comment || token
63
- if ret
64
- @lit_cache[pos0] = ret
65
- @lit_nextpos[pos0] = @pos
66
- @head_pos = @pos
67
- return ret
68
- end
69
-
70
- if @codes[@pos].nil?
71
- return nil
72
- end
73
- if hint.nil?
74
- ECMA262::LIT_DIV_OR_REGEXP_LITERAL
75
- elsif hint == :div
76
- ret = div_punctuator
77
- if ret
78
- @lit_cache[pos0] = ret
79
- @lit_nextpos[pos0] = @pos
80
- end
81
- @head_pos = @pos
82
- return ret
83
- elsif hint == :regexp
84
- ret = regexp_literal
85
- if ret
86
- @lit_cache[pos0] = ret
87
- @lit_nextpos[pos0] = @pos
88
- end
89
- @head_pos = @pos
90
- return ret
91
- else
92
- ECMA262::LIT_DIV_OR_REGEXP_LITERAL
93
- end
94
- end
95
-
96
- # 7.2
97
- def white_space
98
- if white_space?(@codes[@pos])
99
- begin
100
- @pos += 1
101
- end until !white_space?(@codes[@pos])
102
- return ECMA262::WhiteSpace.get
103
- else
104
- nil
105
- end
106
- end
107
-
108
- #7.3
109
- def line_terminator
110
- if line_terminator?(@codes[@pos])
111
- begin
112
- @pos += 1
113
- end until !line_terminator?(@codes[@pos])
114
- return ECMA262::LineFeed.get
115
- else
116
- nil
117
- end
118
- end
119
-
120
- #7.4
121
- def comment
122
- multi_line_comment || single_line_comment
123
- end
124
-
125
- def multi_line_comment
126
- # /*
127
- if @codes[@pos] == 0x2f and @codes[@pos + 1] == 0x2a
128
- @pos += 2
129
- pos0 = @pos
130
- # */
131
- while (code = @codes[@pos] != 0x2a) or @codes[@pos + 1] != 0x2f
132
- raise ParseError.new("no `*/' at end of comment", self) if code.nil?
133
- @pos += 1
134
- end
135
- @pos +=2
136
- return ECMA262::MultiLineComment.new(@codes[pos0...(@pos-2)].pack("U*"))
137
- else
138
- nil
139
- end
140
- end
141
-
142
- def single_line_comment
143
- # //
144
- if @codes[@pos] == 0x2f and @codes[@pos + 1] == 0x2f
145
- @pos += 2
146
- pos0 = @pos
147
- while (code = @codes[@pos]) and !line_terminator?(code)
148
- @pos += 1
149
- end
150
- return ECMA262::SingleLineComment.new(@codes[pos0...@pos].pack("U*"))
151
- else
152
- nil
153
- end
154
- end
155
-
156
- #
157
- # 7.5 tokens
158
- #
159
- def token
160
- identifier_name || numeric_literal || punctuator || string_literal
161
- end
162
-
163
- #
164
- def unicode_escape?
165
- # @codes[@pos] == 0x5c
166
- if @codes[@pos+1] == 0x75 #u
167
- if hex_digit?(@codes[@pos+2]) and
168
- hex_digit?(@codes[@pos+3]) and
169
- hex_digit?(@codes[@pos+4]) and
170
- hex_digit?(@codes[@pos+5])
171
- @codes[(@pos+2)..(@pos+5)].pack("U*").to_i(16)
172
- else
173
- raise ParseError.new("bad unicode escpae sequence", self)
174
- end
175
- else
176
- nil
177
- end
178
- end
179
-
180
- def identifier_name
181
- return nil if (code = @codes[@pos]).nil?
182
-
183
- pos0 = @pos
184
- chars = []
185
- if code == 0x5c and ucode = unicode_escape? and identifier_start?(ucode)
186
- chars.push(ucode)
187
- @pos += 6
188
- elsif identifier_start?(code)
189
- chars.push(code)
190
- @pos += 1
191
- else
192
- return nil
193
- end
194
-
195
- while true
196
- code = @codes[@pos]
197
- if code == 0x5c and ucode = unicode_escape? and identifier_part?(ucode)
198
- chars.push(ucode)
199
- @pos += 6
200
- elsif identifier_part?(code)
201
- chars.push(code)
202
- @pos += 1
203
- else
204
- name = chars.pack("U*").to_sym
205
- return ECMA262::IdentifierName.get(nil, name)
206
- end
207
- end
208
- end
209
-
210
- def punctuator
211
- code0 = @codes[@pos]
212
- code1 = @codes[@pos+1]
213
- code2 = @codes[@pos+2]
214
- code3 = @codes[@pos+3]
215
- if code0 == 0x21 # !
216
- if code1 == 0x3d and code2 == 0x3d # !==
217
- @pos += 3
218
- return ECMA262::PUNC_SNEQ
219
- end
220
- if code1 == 0x3d # !=
221
- @pos += 2
222
- return ECMA262::PUNC_NEQ
223
- end
224
- @pos += 1 # !
225
- return ECMA262::PUNC_LNOT
226
- elsif code0 == 0x25 # %
227
- if code1 == 0x3d # %=
228
- @pos += 2
229
- return ECMA262::PUNC_MODLET
230
- end
231
- @pos += 1 # %
232
- return ECMA262::PUNC_MOD
233
- elsif code0 == 0x26 # &
234
- if code1 == 0x3d # &=
235
- @pos += 2
236
- return ECMA262::PUNC_ANDLET
237
- end
238
- if code1 == 0x26 # &&
239
- @pos += 2
240
- return ECMA262::PUNC_LAND
241
- end
242
- @pos += 1 # &
243
- return ECMA262::PUNC_AND
244
- elsif code0 == 0x28 # (
245
- @pos += 1 # (
246
- return ECMA262::PUNC_LPARENTHESIS
247
- elsif code0 == 0x29 # )
248
- @pos += 1 # )
249
- return ECMA262::PUNC_RPARENTHESIS
250
- elsif code0 == 0x2a # *
251
- if code1 == 0x3d # *=
252
- @pos += 2
253
- return ECMA262::PUNC_MULLET
254
- end
255
- @pos += 1 # *
256
- return ECMA262::PUNC_MUL
257
- elsif code0 == 0x2b # +
258
- if code1 == 0x3d # +=
259
- @pos += 2
260
- return ECMA262::PUNC_ADDLET
261
- end
262
- if code1 == 0x2b # ++
263
- @pos += 2
264
- return ECMA262::PUNC_INC
265
- end
266
- @pos += 1 # +
267
- return ECMA262::PUNC_ADD
268
- elsif code0 == 0x2c # ,
269
- @pos += 1 # ,
270
- return ECMA262::PUNC_COMMA
271
- elsif code0 == 0x2d # -
272
- if code1 == 0x3d # -=
273
- @pos += 2
274
- return ECMA262::PUNC_SUBLET
275
- end
276
- if code1 == 0x2d # --
277
- @pos += 2
278
- return ECMA262::PUNC_DEC
279
- end
280
- @pos += 1 # -
281
- return ECMA262::PUNC_SUB
282
- elsif code0 == 0x2e # .
283
- @pos += 1 # .
284
- return ECMA262::PUNC_PERIOD
285
- elsif code0 == 0x3a # :
286
- @pos += 1 # :
287
- return ECMA262::PUNC_COLON
288
- elsif code0 == 0x3b # ;
289
- @pos += 1 # ;
290
- return ECMA262::PUNC_SEMICOLON
291
- elsif code0 == 0x3c # <
292
- if code1 == 0x3d # <=
293
- @pos += 2
294
- return ECMA262::PUNC_LTEQ
295
- end
296
- if code1 == 0x3c and code2 == 0x3d # <<=
297
- @pos += 3
298
- return ECMA262::PUNC_LSHIFTLET
299
- end
300
- if code1 == 0x3c # <<
301
- @pos += 2
302
- return ECMA262::PUNC_LSHIFT
303
- end
304
- @pos += 1 # <
305
- return ECMA262::PUNC_LT
306
- elsif code0 == 0x3d # =
307
- if code1 == 0x3d and code2 == 0x3d # ===
308
- @pos += 3
309
- return ECMA262::PUNC_SEQ
310
- end
311
- if code1 == 0x3d # ==
312
- @pos += 2
313
- return ECMA262::PUNC_EQ
314
- end
315
- @pos += 1 # =
316
- return ECMA262::PUNC_LET
317
- elsif code0 == 0x3e # >
318
- if code1 == 0x3e and code2 == 0x3e and code3 == 0x3d # >>>=
319
- @pos += 4
320
- return ECMA262::PUNC_URSHIFTLET
321
- end
322
- if code1 == 0x3e and code2 == 0x3e # >>>
323
- @pos += 3
324
- return ECMA262::PUNC_URSHIFT
325
- end
326
- if code1 == 0x3e and code2 == 0x3d # >>=
327
- @pos += 3
328
- return ECMA262::PUNC_RSHIFTLET
329
- end
330
- if code1 == 0x3e # >>
331
- @pos += 2
332
- return ECMA262::PUNC_RSHIFT
333
- end
334
- if code1 == 0x3d # >=
335
- @pos += 2
336
- return ECMA262::PUNC_GTEQ
337
- end
338
- @pos += 1 # >
339
- return ECMA262::PUNC_GT
340
- elsif code0 == 0x3f # ?
341
- @pos += 1 # ?
342
- return ECMA262::PUNC_CONDIF
343
- elsif code0 == 0x5b # [
344
- @pos += 1 # [
345
- return ECMA262::PUNC_LSQBRAC
346
- elsif code0 == 0x5d # ]
347
- @pos += 1 # ]
348
- return ECMA262::PUNC_RSQBRAC
349
- elsif code0 == 0x5e # ^
350
- if code1 == 0x3d # ^=
351
- @pos += 2
352
- return ECMA262::PUNC_XORLET
353
- end
354
- @pos += 1 # ^
355
- return ECMA262::PUNC_XOR
356
- elsif code0 == 0x7b # {
357
- @pos += 1 # {
358
- return ECMA262::PUNC_LCURLYBRAC
359
- elsif code0 == 0x7c # |
360
- if code1 == 0x7c # ||
361
- @pos += 2
362
- return ECMA262::PUNC_LOR
363
- end
364
- if code1 == 0x3d # |=
365
- @pos += 2
366
- return ECMA262::PUNC_ORLET
367
- end
368
- @pos += 1 # |
369
- return ECMA262::PUNC_OR
370
- elsif code0 == 0x7d # }
371
- @pos += 1 # }
372
- return ECMA262::PUNC_RCURLYBRAC
373
- elsif code0 == 0x7e # ~
374
- @pos += 1 # ~
375
- return ECMA262::PUNC_NOT
376
- end
377
- nil
378
- end
379
-
380
- def div_punctuator
381
- if @codes[@pos] == 0x2f
382
- if @codes[@pos+1] == 0x3d
383
- @pos += 2
384
- return ECMA262::PUNC_DIVLET
385
- else
386
- @pos += 1
387
- return ECMA262::PUNC_DIV
388
- end
389
- end
390
- nil
391
- end
392
-
393
- #
394
- # 7.8.5
395
- #
396
- # RegularExpressionLiteral::
397
- # / RegularExpressionBody / RegularExpressionFlags
398
- #
399
- def regexp_literal
400
- pos0 = @pos
401
- return nil unless @codes[@pos] == 0x2f
402
-
403
- body = regexp_body
404
- flags = regexp_flags
405
- return ECMA262::ECMA262RegExp.new(body, flags)
406
- end
407
-
408
- def regexp_body
409
- if @codes[@pos] == 0x2a
410
- raise ParseError.new("first character of regular expression is `*'", self)
411
- end
412
- pos0 = @pos
413
- @pos += 1
414
- while !(@codes[@pos] == 0x2f)
415
- if @codes[@pos].nil?
416
- raise ParseError.new("no `/' end of regular expression", self)
417
- end
418
- if line_terminator?(@codes[@pos])
419
- raise ParseError.new("regular expression has line terminator in body", self)
420
- end
421
- if @codes[@pos] == 0x5c # \
422
- @pos += 1
423
- if line_terminator?(@codes[@pos])
424
- raise ParseError.new("regular expression has line terminator in body", self)
425
- end
426
- @pos += 1
427
- elsif @codes[@pos] == 0x5b # [
428
- regexp_class
429
- else
430
- @pos += 1
431
- end
432
- end
433
- @pos += 1
434
- return @codes[(pos0+1)...(@pos-1)].pack("U*")
435
- end
436
-
437
- def regexp_class
438
- if @codes[@pos] != 0x5b
439
- raise ParseError.new('bad regular expression', self)
440
- end
441
- @pos += 1
442
- while !(@codes[@pos] == 0x5d)
443
- if @codes[@pos].nil?
444
- raise ParseError.new("no `]' end of regular expression class", self)
445
- end
446
- if line_terminator?(@codes[@pos])
447
- raise ParseError.new("regular expression has line terminator in body", self)
448
- end
449
- if @codes[@pos] == 0x5c # \
450
- @pos += 1
451
- if line_terminator?(@codes[@pos])
452
- raise ParseError.new("regular expression has line terminator in body", self)
453
- end
454
- @pos += 1
455
- else
456
- @pos += 1
457
- end
458
- end
459
- @pos += 1
460
- end
461
-
462
- def regexp_flags
463
- pos0 = @pos
464
- while(identifier_part?(@codes[@pos]))
465
- @pos += 1
466
- end
467
- return @codes[pos0...@pos].pack("U*")
468
- end
469
-
470
- #7.8.3
471
- #B.1.1
472
- def numeric_literal
473
- hex_integer_literal || octal_integer_literal || decimal_literal
474
- end
475
-
476
- #7.8.3
477
- #
478
- # HexIntegerLiteral ::
479
- # 0x HexDigit
480
- # 0X HexDigit
481
- # HexIntegerLiteral HexDigit
482
- #
483
- def hex_integer_literal
484
- code = @codes[@pos]
485
- if code.nil?
486
- return nil
487
- #0x / 0X
488
- elsif code == 0x30 and (@codes[@pos+1] == 0x78 || @codes[@pos+1] == 0x58)
489
- @pos += 2
490
- pos0 = @pos
491
- while code = @codes[@pos] and hex_digit?(code)
492
- @pos += 1;
493
- end
494
- if identifier_start?(code)
495
- raise ParseError.new("The source character immediately following a NumericLiteral must not be an IdentifierStart or DecimalDigit", self)
496
- else
497
- return ECMA262::ECMA262Numeric.new(@codes[pos0...@pos].pack("U*").to_i(16))
498
- end
499
- else
500
- nil
501
- end
502
- end
503
-
504
- #B.1.1
505
- # OctalIntegerLiteral ::
506
- # 0 OctalDigit
507
- # OctalIntegerLiteral OctalDigit
508
- #
509
- def octal_integer_literal
510
- code = @codes[@pos]
511
- if code.nil?
512
- return nil
513
- elsif code == 0x30 and (code1 = @codes[@pos + 1]) >= 0x30 and code1 <= 0x37
514
- @pos += 1
515
- pos0 = @pos
516
- while code = @codes[@pos] and code >= 0x30 and code <= 0x37
517
- @pos += 1
518
- end
519
- if identifier_start?(code)
520
- raise ParseError.new("The source character immediately following a NumericLiteral must not be an IdentifierStart or DecimalDigit", self)
521
- else
522
- return ECMA262::ECMA262Numeric.new(@codes[pos0...@pos].pack("U*").to_i(8))
523
- end
524
- else
525
- nil
526
- end
527
- end
528
-
529
- # 7.8.3
530
- #
531
- # DecimalLiteral ::
532
- # DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt
533
- # . DecimalDigits ExponentPartopt
534
- # DecimalIntegerLiteral ExponentPartopt
535
- #
536
- def decimal_literal
537
- pos0 = @pos
538
- code = @codes[@pos]
539
-
540
- if code.nil?
541
- return nil
542
- elsif code == 0x2e #.
543
- @pos += 1
544
- f = decimal_digits
545
- if f.nil? #=> this period is punctuator
546
- @pos = pos0 + 1
547
- return ECMA262::PUNC_PERIOD
548
- end
549
- if (code = @codes[@pos]) == 0x65 || code == 0x45
550
- @pos += 1
551
- e = exponent_part
552
- end
553
- if identifier_start?(@codes[@pos])
554
- raise ParseError.new("The source character immediately following a NumericLiteral must not be an IdentifierStart or DecimalDigit", self)
555
- end
556
-
557
- return ECMA262::ECMA262Numeric.new('0', f, e)
558
- elsif code == 0x30 # zero
559
- i = "0"
560
- @pos += 1
561
- if @codes[@pos] == 0x2e #.
562
- @pos += 1
563
- f = decimal_digits
564
- if (code = @codes[@pos]) == 0x65 || code == 0x45 #e or E
565
- @pos += 1
566
- e = exponent_part
567
- end
568
- elsif (code = @codes[@pos]) == 0x65 || code == 0x45 #e or E
569
- @pos += 1
570
- e = exponent_part
571
- end
572
- if identifier_start?(@codes[@pos])
573
- raise ParseError.new("The source character immediately following a NumericLiteral must not be an IdentifierStart or DecimalDigit", self)
574
- end
575
-
576
- return ECMA262::ECMA262Numeric.new(i, f, e)
577
- elsif code >= 0x31 and code <= 0x39
578
- i = decimal_digits
579
- if @codes[@pos] == 0x2e #.
580
- @pos += 1
581
- f = decimal_digits
582
- if (code = @codes[@pos]) == 0x65 || code == 0x45 #e or E
583
- @pos += 1
584
- e = exponent_part
585
- end
586
- elsif (code = @codes[@pos]) == 0x65 || code == 0x45 #e or E
587
- @pos += 1
588
- e = exponent_part
589
- end
590
- if identifier_start?(@codes[@pos])
591
- raise ParseError.new("The source character immediately following a NumericLiteral must not be an IdentifierStart or DecimalDigit", self)
592
- end
593
-
594
- return ECMA262::ECMA262Numeric.new(i, f, e)
595
- end
596
-
597
- nil
598
- end
599
-
600
- # 7.8.3
601
- #
602
- # ExponentPart ::
603
- # ExponentIndicator SignedInteger
604
- #
605
- def exponent_part
606
- if (code = @codes[@pos]) == 0x2b
607
- @pos += 1
608
- elsif code == 0x2d
609
- @pos += 1
610
- neg = true
611
- end
612
- d = decimal_digits
613
- raise ParseError.new("unexpecting token", self) if d.nil?
614
- if neg
615
- e = "-#{d}"
616
- else
617
- e = d
618
- end
619
- e
620
- end
621
-
622
- #7.8.3
623
- #
624
- # DecimalDigit :: one of
625
- # 0 1 2 3 4 5 6 7 8 9
626
- #
627
- def decimal_digits
628
- pos0 = @pos
629
- if (code = @codes[@pos]) >= 0x30 and code <= 0x39
630
- @pos += 1
631
- while code = @codes[@pos] and code >= 0x30 and code <= 0x39
632
- @pos += 1
633
- end
634
- return @codes[pos0...@pos].pack("U*")
635
- else
636
- nil
637
- end
638
- end
639
-
640
- #7.8.4
641
- #
642
- # StringLiteral ::
643
- # " DoubleStringCharactersopt "
644
- # ' SingleStringCharactersopt '
645
- #
646
- # DoubleStringCharacters ::
647
- # DoubleStringCharacter DoubleStringCharactersopt
648
- #
649
- # SingleStringCharacters ::
650
- # SingleStringCharacter SingleStringCharactersopt
651
- #
652
- # DoubleStringCharacter ::
653
- # SourceCharacter but not one of " or \ or LineTerminator
654
- # \ EscapeSequence
655
- # LineContinuation
656
- #
657
- # SingleStringCharacter ::
658
- # SourceCharacter but not one of ' or \ or LineTerminator
659
- # \ EscapeSequence
660
- # LineContinuation
661
- #
662
- def string_literal
663
- if (code = @codes[@pos]) == 0x27 #'
664
- term = 0x27
665
- elsif code == 0x22 #"
666
- term = 0x22
667
- else
668
- return nil
669
- end
670
- @pos += 1
671
- pos0 = @pos
672
-
673
- str = []
674
- while (code = @codes[@pos])
675
- if code.nil?
676
- raise ParseError.new("no `#{term}' at end of string", self)
677
- elsif line_terminator?(code)
678
- raise ParseError.new("string has line terminator in body", self)
679
- elsif code == 0x5c #\
680
- @pos += 1
681
- str.push(escape_sequence)
682
- elsif code == term
683
- @pos += 1
684
- return ECMA262::ECMA262String.new(str.compact.pack("U*"))
685
- else
686
- @pos += 1
687
- str.push(code)
688
- end
689
- end
690
- nil
691
- end
692
-
693
- # 7.8.4
694
- # B.1.2
695
- #
696
- # EscapeSequence ::
697
- # CharacterEscapeSequence
698
- # 0 [lookahead ∉ DecimalDigit]
699
- # HexEscapeSequence
700
- # UnicodeEscapeSequence
701
- # OctalEscapeSequence
702
-
703
- def escape_sequence
704
- case (code = @codes[@pos])
705
- # when 0x30
706
- # @pos += 1
707
- # 0
708
- when 0x27 #'
709
- @pos += 1
710
- 0x27
711
- when 0x22 #"
712
- @pos += 1
713
- 0x22
714
- when 0x5c #\
715
- @pos += 1
716
- 0x5c
717
- when 0x62 #b
718
- @pos += 1
719
- 0x08
720
- when 0x74 #t
721
- @pos += 1
722
- 0x09
723
- when 0x6e #n
724
- @pos += 1
725
- 0x0a
726
- when 0x76 #v
727
- @pos += 1
728
- 0x0b
729
- when 0x66 #f
730
- @pos += 1
731
- 0x0c
732
- when 0x72 #r
733
- @pos += 1
734
- 0x0d
735
- when 0x78 #x
736
- #check
737
- t = @codes[(@pos+1)..(@pos+2)].pack("U*").to_i(16)
738
- @pos += 3
739
- t
740
- when 0x75 #u
741
- #check
742
- t = @codes[(@pos+1)..(@pos+4)].pack("U*").to_i(16)
743
- @pos += 5
744
- t
745
- else
746
- # line continuation
747
- if line_terminator?(code)
748
- @pos += 1
749
- nil
750
- # Annex B.1.2
751
- #
752
- # OctalEscapeSequence ::
753
- # OctalDigit [lookahead ∉ DecimalDigit]
754
- # ZeroToThree OctalDigit [lookahead ∉ DecimalDigit]
755
- # FourToSeven OctalDigit
756
- # ZeroToThree OctalDigit OctalDigit
757
- #
758
- # Note:
759
- #
760
- # A string such as the following is invalid
761
- # as a octal escape sequence.
762
- #
763
- # \19 or \319
764
- #
765
- # However, it is not to an error in most implementations.
766
- # Therefore, minjs also intepret it such way.
767
- #
768
- elsif octal_digit?(code)
769
- code1 = @codes[@pos+1]
770
- code2 = @codes[@pos+2]
771
- if code >= 0x30 and code <= 0x33
772
- if octal_digit?(code1)
773
- if octal_digit?(code2)
774
- @pos += 3
775
- (code - 0x30) * 64 + (code1 - 0x30) * 8 + (code2 - 0x30)
776
- else
777
- @pos += 2
778
- (code - 0x30) * 8 + (code1 - 0x30)
779
- end
780
- else
781
- @pos += 1
782
- code - 0x30
783
- end
784
- else #if code >= 0x34 and code <= 0x37
785
- if octal_digit?(code1)
786
- @pos += 2
787
- (code - 0x30) * 8 + (code1 - 0x30)
788
- else
789
- @pos += 1
790
- code - 0x30
791
- end
792
- end
793
- else
794
- @pos += 1
795
- code
796
- end
797
- end
798
- end
799
-
800
- def eof?
801
- peek_lit(nil).nil?
802
- end
803
-
804
- #
805
- # check next literal is strictly equal to 'l' or not.
806
- # white spaces and line terminators are skipped and ignored.
807
- #
808
- # if next literal is not 'l', position is not forwarded
809
- # if next literal is 'l', position is forwarded
810
- #
811
- def eql_lit?(l, hint = nil)
812
- lit = peek_lit(hint)
813
- if lit.eql? l
814
- fwd_after_peek
815
- lit
816
- else
817
- nil
818
- end
819
- end
820
-
821
- #
822
- # check next literal is strictly equal to 'l' or not.
823
- # white spaces are skipped and ignored.
824
- # line terminators are not ignored.
825
- #
826
- # if next literal is not 'l', position is not forwarded
827
- # if next literal is 'l', position is forwarded
828
- #
829
- def eql_lit_nolt?(l, hint = nil)
830
- lit = peek_lit_nolt(hint)
831
- if lit.eql? l
832
- fwd_after_peek
833
- lit
834
- else
835
- nil
836
- end
837
- end
838
-
839
- #
840
- # check next literal is equal to 'l' or not.
841
- # white spaces and line terminators are skipped and ignored.
842
- #
843
- # if next literal is not 'l', position is not forwarded
844
- # if next literal is 'l', position is forwarded
845
- #
846
- def match_lit?(l, hint = nil)
847
- lit = peek_lit(hint)
848
- if lit == l
849
- fwd_after_peek
850
- lit
851
- else
852
- nil
853
- end
854
- end
855
-
856
- #
857
- # check next literal is equal to 'l' or not.
858
- # white spaces are skipped and ignored.
859
- # line terminators are not ignored.
860
- #
861
- # if next literal is not 'l', position is not forwarded
862
- # if next literal is 'l', position is forwarded
863
- #
864
- def match_lit_nolt?(l, hint = nil)
865
- lit = peek_lit_nolt(hint)
866
- if lit == l
867
- fwd_after_peek
868
- lit
869
- else
870
- nil
871
- end
872
- end
873
-
874
- #
875
- # fetch next literal.
876
- # position is not forwarded.
877
- # white spaces and line terminators are skipped and ignored.
878
- #
879
- def peek_lit(hint)
880
- pos0 = @pos
881
- while lit = next_input_element(hint) and (lit.ws? or lit.lt?)
882
- end
883
- @pos = pos0
884
- lit
885
- end
886
-
887
- #
888
- # fetch next literal.
889
- # position is not forwarded.
890
- # white spaces are skipped and ignored.
891
- # line terminators are not ignored.
892
- #
893
- def peek_lit_nolt(hint)
894
- pos0 = @pos
895
- while lit = next_input_element(hint) and lit.ws?
896
- end
897
- @pos = pos0
898
- lit
899
- end
900
-
901
- def fwd_after_peek
902
- @pos = @head_pos
903
- end
904
-
905
- #
906
- # fetch next literal.
907
- # position is forwarded.
908
- # white spaces and line terminators are skipped and ignored.
909
- #
910
- def fwd_lit(hint)
911
- while lit = next_input_element(hint) and (lit.ws? or lit.lt?)
912
- end
913
- lit
914
- end
915
-
916
- #
917
- # fetch next literal.
918
- # position is forwarded.
919
- # white spaces are skipped and ignored.
920
- # line terminators are not ignored.
921
- #
922
- def fwd_lit_nolt(hint)
923
- while lit = next_input_element(hint) and lit.ws?
924
- end
925
- lit
926
- end
927
-
928
- #
929
- # break <val> => position is rewind, then break with <val>
930
- # return <val> => position is rewind, then return <val>
931
- # next <val> => position is not rewind, then break with <val>
932
- #
933
- def eval_lit(&block)
934
- begin
935
- saved_pos = @pos
936
- @eval_nest += 1
937
- ret = yield
938
- ensure
939
- @eval_nest -= 1
940
- if ret.nil?
941
- @pos = saved_pos
942
- nil
943
- else
944
- if @eval_nest == 0
945
- #STDERR.puts "clear_cache [#{saved_pos}..#{@pos}]"
946
- clear_cache
947
- end
948
- end
949
- end
950
- end
951
-
952
- #
953
- # position to [row, col]
954
- #
955
- def row_col(pos)
956
- _pos = 0
957
- row = 0
958
- col = 1
959
- @codes.each do |code|
960
- break if _pos >= pos
961
- if line_terminator?(code)
962
- row += 1
963
- col = 0
964
- else
965
- col += 1
966
- end
967
- _pos += 1
968
- end
969
- return [row+1, col+1]
970
- end
971
-
972
- #
973
- # position to line
974
- #
975
- def line(pos)
976
- pos0 = pos1 = pos
977
- while true
978
- pos0 -= 1
979
- break if line_terminator?(@codes[pos0])
980
- end
981
- pos0 += 1
982
-
983
- while true
984
- break if line_terminator?(@codes[pos1])
985
- pos1 += 1
986
- end
987
-
988
- @codes[pos0..pos1].pack("U*")
989
- end
990
-
991
- def debug_str(pos = nil, row = nil, col = nil)
992
- if pos.nil?
993
- pos = @head_pos or @pos
994
- end
995
-
996
- t = ''
997
- if col >= 80
998
- t << @codes[(pos-80)..(pos+80)].pack("U*")
999
- col = 81
1000
- else
1001
- t << line(pos)
1002
- end
1003
-
1004
- if col and col >= 1
1005
- col = col - 1;
1006
- end
1007
- t << "\n"
1008
- t << (' ' * col) + "^"
1009
- t
1010
- end
2
+ #Lex
3
+ module Lex
1011
4
  end
1012
5
  end
6
+ require "minjs/lex/exceptions"
7
+ require "minjs/lex/expression"
8
+ require "minjs/lex/function"
9
+ require "minjs/lex/program"
10
+ require "minjs/lex/statement"
11
+ require "minjs/lex/parser"