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.
- checksums.yaml +4 -4
- data/Rakefile +7 -0
- data/exe/minjs +2 -1
- data/lib/minjs.rb +1 -5
- data/lib/minjs/compressor.rb +3 -1140
- data/lib/minjs/compressor/compressor.rb +1146 -0
- data/lib/minjs/ctype.rb +71 -28
- data/lib/minjs/ecma262.rb +9 -4
- data/lib/minjs/ecma262/base.rb +89 -8
- data/lib/minjs/ecma262/env.rb +39 -16
- data/lib/minjs/ecma262/{exp.rb → expression.rb} +988 -281
- data/lib/minjs/ecma262/{lit.rb → literal.rb} +429 -48
- data/lib/minjs/ecma262/punctuator.rb +141 -0
- data/lib/minjs/ecma262/{st.rb → statement.rb} +328 -76
- data/lib/minjs/lex.rb +8 -1009
- data/lib/minjs/{exceptions.rb → lex/exceptions.rb} +3 -1
- data/lib/minjs/lex/expression.rb +1092 -0
- data/lib/minjs/{func.rb → lex/function.rb} +43 -23
- data/lib/minjs/lex/parser.rb +1147 -0
- data/lib/minjs/lex/program.rb +56 -0
- data/lib/minjs/{statement.rb → lex/statement.rb} +136 -126
- data/lib/minjs/minjs_compressor.rb +1 -1
- data/lib/minjs/version.rb +2 -1
- data/minjs.gemspec +1 -1
- metadata +28 -11
- data/lib/minjs/ecma262/punc.rb +0 -92
- data/lib/minjs/expression.rb +0 -833
- data/lib/minjs/program.rb +0 -32
data/lib/minjs/lex.rb
CHANGED
@@ -1,1012 +1,11 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
require 'minjs/ctype'
|
3
|
-
|
4
1
|
module Minjs
|
5
|
-
|
6
|
-
|
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"
|