minjs 0.1.2
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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +7 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/minjs +12 -0
- data/lib/minjs/compressor.rb +418 -0
- data/lib/minjs/ctype.rb +846 -0
- data/lib/minjs/ecma262/base.rb +128 -0
- data/lib/minjs/ecma262/env.rb +78 -0
- data/lib/minjs/ecma262/exp.rb +630 -0
- data/lib/minjs/ecma262/lit.rb +552 -0
- data/lib/minjs/ecma262/punc.rb +84 -0
- data/lib/minjs/ecma262/st.rb +808 -0
- data/lib/minjs/ecma262.rb +6 -0
- data/lib/minjs/exceptions.rb +15 -0
- data/lib/minjs/expression.rb +714 -0
- data/lib/minjs/func.rb +86 -0
- data/lib/minjs/lex.rb +745 -0
- data/lib/minjs/literal.rb +45 -0
- data/lib/minjs/minjs_compressor.rb +47 -0
- data/lib/minjs/program.rb +32 -0
- data/lib/minjs/statement.rb +438 -0
- data/lib/minjs/version.rb +3 -0
- data/lib/minjs.rb +16 -0
- data/minjs.gemspec +31 -0
- metadata +132 -0
data/lib/minjs/lex.rb
ADDED
@@ -0,0 +1,745 @@
|
|
1
|
+
require 'minjs/ctype'
|
2
|
+
|
3
|
+
module Minjs
|
4
|
+
class Lex
|
5
|
+
include Ctype
|
6
|
+
|
7
|
+
attr_reader :pos
|
8
|
+
attr_reader :error_pos
|
9
|
+
attr_reader :codes
|
10
|
+
|
11
|
+
def initialize(str = "", options = {})
|
12
|
+
str = str.gsub(/\r\n/, "\n")
|
13
|
+
@codes = str.codepoints
|
14
|
+
@pos = 0
|
15
|
+
@lit_cache = []
|
16
|
+
@lit_nextpos = []
|
17
|
+
if options[:debug]
|
18
|
+
@debug = true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def next_input_element(options = {})
|
23
|
+
if @lit_cache[@pos]
|
24
|
+
ret = @lit_cache[@pos]
|
25
|
+
@pos = @lit_nextpos[@pos]
|
26
|
+
@error_pos = @pos
|
27
|
+
return ret
|
28
|
+
end
|
29
|
+
pos0 = @pos
|
30
|
+
if ret = (white_space || line_terminator || comment || token)
|
31
|
+
if ret
|
32
|
+
@lit_cache[pos0] = ret
|
33
|
+
@lit_nextpos[pos0] = @pos
|
34
|
+
end
|
35
|
+
@error_pos = @pos
|
36
|
+
return ret
|
37
|
+
end
|
38
|
+
#
|
39
|
+
# ECMA262 say:
|
40
|
+
#
|
41
|
+
# There are no syntactic grammar contexts where both a leading division
|
42
|
+
# or division-assignment, and a leading RegularExpressionLiteral are permitted.
|
43
|
+
# This is not affected by semicolon insertion (see 7.9); in examples such as the following:
|
44
|
+
# To determine `/' is regular expression or not
|
45
|
+
#
|
46
|
+
#
|
47
|
+
if options[:hint] == :div
|
48
|
+
ret = div_punctuator
|
49
|
+
if ret
|
50
|
+
@lit_cache[pos0] = ret
|
51
|
+
@lit_nextpos[pos0] = @pos
|
52
|
+
end
|
53
|
+
@error_pos = @pos
|
54
|
+
return ret
|
55
|
+
elsif options[:hint] == :regexp
|
56
|
+
ret = regexp_literal
|
57
|
+
if ret
|
58
|
+
@lit_cache[pos0] = ret
|
59
|
+
@lit_nextpos[pos0] = @pos
|
60
|
+
end
|
61
|
+
@error_pos = @pos
|
62
|
+
return ret
|
63
|
+
else
|
64
|
+
# p pos0
|
65
|
+
# p @pos
|
66
|
+
#@error_pos = @pos
|
67
|
+
#debug_lit
|
68
|
+
#raise 'no hint'
|
69
|
+
#regexp_literal
|
70
|
+
#div_punctuator
|
71
|
+
#nil #unknown
|
72
|
+
ECMA262::LIT_DIV_OR_REGEXP_LITERAL
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# 7.2
|
77
|
+
def white_space
|
78
|
+
code = @codes[@pos]
|
79
|
+
if white_space?(code)
|
80
|
+
while true
|
81
|
+
@pos += 1
|
82
|
+
code = @codes[@pos]
|
83
|
+
break unless white_space?(code)
|
84
|
+
end
|
85
|
+
return ECMA262::WhiteSpace.get
|
86
|
+
else
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
#7.3
|
92
|
+
def line_terminator
|
93
|
+
code = @codes[@pos]
|
94
|
+
if line_terminator?(code)
|
95
|
+
while true
|
96
|
+
@pos += 1
|
97
|
+
code = @codes[@pos]
|
98
|
+
break unless line_terminator?(code)
|
99
|
+
end
|
100
|
+
return ECMA262::LineFeed.get
|
101
|
+
else
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#7.4
|
107
|
+
def comment
|
108
|
+
multi_line_comment || single_line_comment
|
109
|
+
end
|
110
|
+
|
111
|
+
def multi_line_comment
|
112
|
+
if @codes[@pos] == 0x2f and @codes[@pos + 1] == 0x2a
|
113
|
+
@pos = @pos + 2
|
114
|
+
pos0 = @pos
|
115
|
+
lf = false
|
116
|
+
while (@codes[@pos] != 0x2a or @codes[@pos + 1] != 0x2f)
|
117
|
+
if @codes[@pos].nil?
|
118
|
+
raise ParseError.new("no `*/' at end of comment")
|
119
|
+
end
|
120
|
+
if line_terminator?(@codes[@pos])
|
121
|
+
lf = true
|
122
|
+
end
|
123
|
+
@pos = @pos + 1
|
124
|
+
end
|
125
|
+
@pos = @pos + 2
|
126
|
+
return ECMA262::MultiLineComment.new(@codes[pos0...(@pos-2)].pack("U*"), lf)
|
127
|
+
else
|
128
|
+
nil
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def single_line_comment
|
133
|
+
if @codes[@pos] == 0x2f and @codes[@pos + 1] == 0x2f
|
134
|
+
@pos = @pos + 2
|
135
|
+
pos0 = @pos
|
136
|
+
while !line_terminator?(@codes[@pos]) and @codes[@pos]
|
137
|
+
@pos += 1
|
138
|
+
end
|
139
|
+
if @codes[@pos].nil?
|
140
|
+
return ECMA262::SingleLineComment.new(@codes[pos0...@pos].pack("U*") + "\n")
|
141
|
+
else
|
142
|
+
return ECMA262::SingleLineComment.new(@codes[pos0...@pos].pack("U*"))
|
143
|
+
end
|
144
|
+
else
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
#
|
150
|
+
# 7.5 tokens
|
151
|
+
#
|
152
|
+
def token
|
153
|
+
pos0 = @pos
|
154
|
+
ret = (identifier_name || numeric_literal || punctuator || string_literal)
|
155
|
+
if ret
|
156
|
+
@lit_cache[pos0] = ret
|
157
|
+
@lit_nextpos[pos0] = @pos
|
158
|
+
end
|
159
|
+
ret
|
160
|
+
end
|
161
|
+
|
162
|
+
def identifier_name
|
163
|
+
pos0 = @pos
|
164
|
+
code = @codes[@pos]
|
165
|
+
return nil if code.nil?
|
166
|
+
if identifier_start?(code)
|
167
|
+
while true
|
168
|
+
@pos += 1
|
169
|
+
code = @codes[@pos]
|
170
|
+
if code.nil?
|
171
|
+
break
|
172
|
+
elsif identifier_part?(code)
|
173
|
+
;#
|
174
|
+
else
|
175
|
+
return ECMA262::IdentifierName.new(nil, @codes[pos0...@pos].pack("U*").to_sym)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def punctuator
|
182
|
+
code0 = @codes[@pos]
|
183
|
+
code1 = @codes[@pos+1]
|
184
|
+
code2 = @codes[@pos+2]
|
185
|
+
code3 = @codes[@pos+3]
|
186
|
+
if false
|
187
|
+
elsif (code0 == 0x3e and code1 == 0x3e and code2 == 0x3e and code3 == 0x3d)
|
188
|
+
@pos += 4
|
189
|
+
return ECMA262::Punctuator.get('>>>=')
|
190
|
+
elsif (code0 == 0x3d and code1 == 0x3d and code2 == 0x3d)
|
191
|
+
@pos += 3
|
192
|
+
return ECMA262::Punctuator.get('===')
|
193
|
+
elsif (code0 == 0x21 and code1 == 0x3d and code2 == 0x3d)
|
194
|
+
@pos += 3
|
195
|
+
return ECMA262::Punctuator.get('!==')
|
196
|
+
elsif (code0 == 0x3e and code1 == 0x3e and code2 == 0x3e)
|
197
|
+
@pos += 3
|
198
|
+
return ECMA262::Punctuator.get('>>>')
|
199
|
+
elsif (code0 == 0x3c and code1 == 0x3c and code2 == 0x3d)
|
200
|
+
@pos += 3
|
201
|
+
return ECMA262::Punctuator.get('<<=')
|
202
|
+
elsif (code0 == 0x3e and code1 == 0x3e and code2 == 0x3d)
|
203
|
+
@pos += 3
|
204
|
+
return ECMA262::Punctuator.get('>>=')
|
205
|
+
elsif (code0 == 0x3e and code1 == 0x3e)
|
206
|
+
@pos += 2
|
207
|
+
return ECMA262::Punctuator.get('>>')
|
208
|
+
elsif (code0 == 0x3c and code1 == 0x3d)
|
209
|
+
@pos += 2
|
210
|
+
return ECMA262::Punctuator.get('<=')
|
211
|
+
elsif (code0 == 0x3e and code1 == 0x3d)
|
212
|
+
@pos += 2
|
213
|
+
return ECMA262::Punctuator.get('>=')
|
214
|
+
elsif (code0 == 0x3d and code1 == 0x3d)
|
215
|
+
@pos += 2
|
216
|
+
return ECMA262::Punctuator.get('==')
|
217
|
+
elsif (code0 == 0x21 and code1 == 0x3d)
|
218
|
+
@pos += 2
|
219
|
+
return ECMA262::Punctuator.get('!=')
|
220
|
+
elsif (code0 == 0x2b and code1 == 0x2b)
|
221
|
+
@pos += 2
|
222
|
+
return ECMA262::Punctuator.get('++')
|
223
|
+
elsif (code0 == 0x2d and code1 == 0x2d)
|
224
|
+
@pos += 2
|
225
|
+
return ECMA262::Punctuator.get('--')
|
226
|
+
elsif (code0 == 0x3c and code1 == 0x3c)
|
227
|
+
@pos += 2
|
228
|
+
return ECMA262::Punctuator.get('<<')
|
229
|
+
elsif (code0 == 0x3e and code1 == 0x3e)
|
230
|
+
@pos += 2
|
231
|
+
return ECMA262::Punctuator.get('>>')
|
232
|
+
elsif (code0 == 0x26 and code1 == 0x26)
|
233
|
+
@pos += 2
|
234
|
+
return ECMA262::Punctuator.get('&&')
|
235
|
+
elsif (code0 == 0x7c and code1 == 0x7c)
|
236
|
+
@pos += 2
|
237
|
+
return ECMA262::Punctuator.get('||')
|
238
|
+
elsif (code0 == 0x2b and code1 == 0x3d)
|
239
|
+
@pos += 2
|
240
|
+
return ECMA262::Punctuator.get('+=')
|
241
|
+
elsif (code0 == 0x2d and code1 == 0x3d)
|
242
|
+
@pos += 2
|
243
|
+
return ECMA262::Punctuator.get('-=')
|
244
|
+
elsif (code0 == 0x2a and code1 == 0x3d)
|
245
|
+
@pos += 2
|
246
|
+
return ECMA262::Punctuator.get('*=')
|
247
|
+
elsif (code0 == 0x25 and code1 == 0x3d)
|
248
|
+
@pos += 2
|
249
|
+
return ECMA262::Punctuator.get('%=')
|
250
|
+
elsif (code0 == 0x26 and code1 == 0x3d)
|
251
|
+
@pos += 2
|
252
|
+
return ECMA262::Punctuator.get('&=')
|
253
|
+
elsif (code0 == 0x7c and code1 == 0x3d)
|
254
|
+
@pos += 2
|
255
|
+
return ECMA262::Punctuator.get('|=')
|
256
|
+
elsif (code0 == 0x5e and code1 == 0x3d)
|
257
|
+
@pos += 2
|
258
|
+
return ECMA262::Punctuator.get('^=')
|
259
|
+
elsif (code0 == 0x7b)
|
260
|
+
@pos += 1
|
261
|
+
return ECMA262::Punctuator.get('{')
|
262
|
+
elsif (code0 == 0x7d)
|
263
|
+
@pos += 1
|
264
|
+
return ECMA262::Punctuator.get('}')
|
265
|
+
elsif (code0 == 0x28)
|
266
|
+
@pos += 1
|
267
|
+
return ECMA262::Punctuator.get('(')
|
268
|
+
elsif (code0 == 0x29)
|
269
|
+
@pos += 1
|
270
|
+
return ECMA262::Punctuator.get(')')
|
271
|
+
elsif (code0 == 0x5b)
|
272
|
+
@pos += 1
|
273
|
+
return ECMA262::Punctuator.get('[')
|
274
|
+
elsif (code0 == 0x5d)
|
275
|
+
@pos += 1
|
276
|
+
return ECMA262::Punctuator.get(']')
|
277
|
+
elsif (code0 == 0x2e)
|
278
|
+
@pos += 1
|
279
|
+
return ECMA262::Punctuator.get('.')
|
280
|
+
elsif (code0 == 0x3b)
|
281
|
+
@pos += 1
|
282
|
+
return ECMA262::Punctuator.get(';')
|
283
|
+
elsif (code0 == 0x2c)
|
284
|
+
@pos += 1
|
285
|
+
return ECMA262::Punctuator.get(',')
|
286
|
+
elsif (code0 == 0x3c)
|
287
|
+
@pos += 1
|
288
|
+
return ECMA262::Punctuator.get('<')
|
289
|
+
elsif (code0 == 0x3e)
|
290
|
+
@pos += 1
|
291
|
+
return ECMA262::Punctuator.get('>')
|
292
|
+
elsif (code0 == 0x2b)
|
293
|
+
@pos += 1
|
294
|
+
return ECMA262::Punctuator.get('+')
|
295
|
+
elsif (code0 == 0x2d)
|
296
|
+
@pos += 1
|
297
|
+
return ECMA262::Punctuator.get('-')
|
298
|
+
elsif (code0 == 0x2a)
|
299
|
+
@pos += 1
|
300
|
+
return ECMA262::Punctuator.get('*')
|
301
|
+
elsif (code0 == 0x25)
|
302
|
+
@pos += 1
|
303
|
+
return ECMA262::Punctuator.get('%')
|
304
|
+
elsif (code0 == 0x26)
|
305
|
+
@pos += 1
|
306
|
+
return ECMA262::Punctuator.get('&')
|
307
|
+
elsif (code0 == 0x7c)
|
308
|
+
@pos += 1
|
309
|
+
return ECMA262::Punctuator.get('|')
|
310
|
+
elsif (code0 == 0x5e)
|
311
|
+
@pos += 1
|
312
|
+
return ECMA262::Punctuator.get('^')
|
313
|
+
elsif (code0 == 0x21)
|
314
|
+
@pos += 1
|
315
|
+
return ECMA262::Punctuator.get('!')
|
316
|
+
elsif (code0 == 0x7e)
|
317
|
+
@pos += 1
|
318
|
+
return ECMA262::Punctuator.get('~')
|
319
|
+
elsif (code0 == 0x3f)
|
320
|
+
@pos += 1
|
321
|
+
return ECMA262::Punctuator.get('?')
|
322
|
+
elsif (code0 == 0x3a)
|
323
|
+
@pos += 1
|
324
|
+
return ECMA262::Punctuator.get(':')
|
325
|
+
elsif (code0 == 0x3d)
|
326
|
+
@pos += 1
|
327
|
+
return ECMA262::Punctuator.get('=')
|
328
|
+
end
|
329
|
+
nil
|
330
|
+
end
|
331
|
+
|
332
|
+
def div_punctuator
|
333
|
+
if @codes[@pos] == 0x2f
|
334
|
+
if @codes[@pos+1] == 0x3d
|
335
|
+
@pos += 2
|
336
|
+
return ECMA262::PUNC_DIVLET
|
337
|
+
else
|
338
|
+
@pos += 1
|
339
|
+
return ECMA262::PUNC_DIV
|
340
|
+
end
|
341
|
+
end
|
342
|
+
nil
|
343
|
+
end
|
344
|
+
|
345
|
+
#
|
346
|
+
# 7.8.5
|
347
|
+
#
|
348
|
+
# RegularExpressionLiteral::
|
349
|
+
# / RegularExpressionBody / RegularExpressionFlags
|
350
|
+
#
|
351
|
+
def regexp_literal
|
352
|
+
pos0 = @pos
|
353
|
+
return nil unless @codes[@pos] == 0x2f
|
354
|
+
|
355
|
+
body = regexp_body
|
356
|
+
flags = regexp_flags
|
357
|
+
return ECMA262::ECMA262RegExp.new(body, flags)
|
358
|
+
end
|
359
|
+
|
360
|
+
def regexp_body
|
361
|
+
if @codes[@pos] == 0x2a
|
362
|
+
raise ParseError.new("first character of regular expression is `*'")
|
363
|
+
end
|
364
|
+
pos0 = @pos
|
365
|
+
@pos += 1
|
366
|
+
while !(@codes[@pos] == 0x2f)
|
367
|
+
if @codes[@pos].nil?
|
368
|
+
raise ParseError.new("no `/' end of regular expression")
|
369
|
+
end
|
370
|
+
if line_terminator?(@codes[@pos])
|
371
|
+
debug_lit
|
372
|
+
raise ParseError.new("regular expression has line terminator in body")
|
373
|
+
end
|
374
|
+
if @codes[@pos] == 0x5c # \
|
375
|
+
@pos += 1
|
376
|
+
if line_terminator?(@codes[@pos])
|
377
|
+
raise ParseError.new("regular expression has line terminator in body")
|
378
|
+
end
|
379
|
+
@pos += 1
|
380
|
+
elsif @codes[@pos] == 0x5b # [
|
381
|
+
regexp_class
|
382
|
+
else
|
383
|
+
@pos += 1
|
384
|
+
end
|
385
|
+
end
|
386
|
+
@pos += 1
|
387
|
+
return @codes[(pos0+1)...(@pos-1)].pack("U*")
|
388
|
+
end
|
389
|
+
|
390
|
+
def regexp_class
|
391
|
+
if @codes[@pos] != 0x5b
|
392
|
+
raise ParseError.new('bad regular expression')
|
393
|
+
end
|
394
|
+
@pos += 1
|
395
|
+
while !(@codes[@pos] == 0x5d)
|
396
|
+
if @codes[@pos].nil?
|
397
|
+
raise ParseError.new("no `]' end of regular expression class")
|
398
|
+
end
|
399
|
+
if line_terminator?(@codes[@pos])
|
400
|
+
raise ParseError.new("regular expression has line terminator in body")
|
401
|
+
end
|
402
|
+
if @codes[@pos] == 0x5c # \
|
403
|
+
@pos += 1
|
404
|
+
if line_terminator?(@codes[@pos])
|
405
|
+
raise ParseError.new("regular expression has line terminator in body")
|
406
|
+
end
|
407
|
+
@pos += 1
|
408
|
+
else
|
409
|
+
@pos += 1
|
410
|
+
end
|
411
|
+
end
|
412
|
+
@pos += 1
|
413
|
+
end
|
414
|
+
|
415
|
+
def regexp_flags
|
416
|
+
pos0 = @pos
|
417
|
+
while(identifier_part?(@codes[@pos]))
|
418
|
+
@pos += 1
|
419
|
+
end
|
420
|
+
return @codes[pos0...@pos].pack("U*")
|
421
|
+
end
|
422
|
+
|
423
|
+
#7.8.3
|
424
|
+
def numeric_literal
|
425
|
+
code = @codes[@pos]
|
426
|
+
return nil if code.nil?
|
427
|
+
|
428
|
+
hex_integer_literal || decimal_literal
|
429
|
+
end
|
430
|
+
|
431
|
+
def hex_integer_literal
|
432
|
+
pos0 = @pos
|
433
|
+
# 0x.... or 0X....
|
434
|
+
code = @codes[@pos]
|
435
|
+
if code == 0x30 and (@codes[@pos+1] == 0x78 || @codes[@pos+1] == 0x58) #hex integer
|
436
|
+
@pos += 2
|
437
|
+
while true
|
438
|
+
code = @codes[@pos]
|
439
|
+
if (code >= 0x30 and code <= 0x39) || (code >= 0x41 and code <= 0x4f) || (code >= 0x61 and code <= 0x6f)
|
440
|
+
else
|
441
|
+
raw = @codes[pos0...@pos].pack("U*")
|
442
|
+
return ECMA262::ECMA262Numeric.new(raw, @codes[(pos0+2)...@pos].pack("U*").to_i(16))
|
443
|
+
end
|
444
|
+
@pos += 1
|
445
|
+
end
|
446
|
+
else
|
447
|
+
nil
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
def decimal_literal
|
452
|
+
pos0 = @pos
|
453
|
+
code = @codes[@pos]
|
454
|
+
if code == 0x2e #.
|
455
|
+
@pos += 1
|
456
|
+
f = decimal_digits
|
457
|
+
if f.nil?
|
458
|
+
@pos = pos0
|
459
|
+
return nil
|
460
|
+
end
|
461
|
+
if @codes[@pos] == 0x65 || @codes[@pos] == 0x45
|
462
|
+
@pos += 1
|
463
|
+
e = exp_part
|
464
|
+
end
|
465
|
+
raw = @codes[pos0...@pos].pack("U*")
|
466
|
+
return ECMA262::ECMA262Numeric.new(raw, 0, f, e)
|
467
|
+
else
|
468
|
+
nil
|
469
|
+
end
|
470
|
+
if code >= 0x30 and code <= 0x39
|
471
|
+
i = decimal_digits
|
472
|
+
if @codes[@pos] == 0x2e
|
473
|
+
@pos += 1
|
474
|
+
f = decimal_digits
|
475
|
+
if @codes[@pos] == 0x65 || @codes[@pos] == 0x45
|
476
|
+
@pos += 1
|
477
|
+
e = exp_part
|
478
|
+
end
|
479
|
+
elsif @codes[@pos] == 0x65 || @codes[@pos] == 0x45
|
480
|
+
@pos += 1
|
481
|
+
e = exp_part
|
482
|
+
end
|
483
|
+
raw = @codes[pos0...@pos].pack("U*")
|
484
|
+
return ECMA262::ECMA262Numeric.new(raw, i, f, e)
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
def exp_part
|
489
|
+
if @codes[@pos] == 0x2b
|
490
|
+
@pos += 1
|
491
|
+
elsif @codes[@pos] == 0x2d
|
492
|
+
@pos += 1
|
493
|
+
neg = true
|
494
|
+
end
|
495
|
+
if neg
|
496
|
+
e = -decimal_digits
|
497
|
+
else
|
498
|
+
e = decimal_digits
|
499
|
+
end
|
500
|
+
e
|
501
|
+
end
|
502
|
+
|
503
|
+
def decimal_digits
|
504
|
+
pos0 = @pos
|
505
|
+
code = @codes[@pos]
|
506
|
+
if code >= 0x30 and code <= 0x39
|
507
|
+
@pos += 1
|
508
|
+
while true
|
509
|
+
code = @codes[@pos]
|
510
|
+
if code >= 0x30 and code <= 0x39
|
511
|
+
@pos += 1
|
512
|
+
else
|
513
|
+
return @codes[pos0...@pos].pack("U*").to_i
|
514
|
+
end
|
515
|
+
end
|
516
|
+
else
|
517
|
+
nil
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
#7.8.4
|
522
|
+
def string_literal
|
523
|
+
code = @codes[@pos]
|
524
|
+
return nil if code.nil?
|
525
|
+
pos0 = @pos
|
526
|
+
if code == 0x27 #'
|
527
|
+
term = 0x27
|
528
|
+
elsif code == 0x22 #"
|
529
|
+
term = 0x22
|
530
|
+
else
|
531
|
+
return nil
|
532
|
+
end
|
533
|
+
|
534
|
+
str = ''
|
535
|
+
while @codes[@pos]
|
536
|
+
@pos += 1
|
537
|
+
code = @codes[@pos]
|
538
|
+
if code.nil?
|
539
|
+
raise ParseError.new("no `#{term}' at end of string")
|
540
|
+
elsif line_terminator?(code)
|
541
|
+
raise ParseError.new("string has line terminator in body")
|
542
|
+
elsif code == 0x5c #\
|
543
|
+
@pos += 1
|
544
|
+
str << esc_string
|
545
|
+
elsif code == term
|
546
|
+
@pos += 1
|
547
|
+
return ECMA262::ECMA262String.new(str)
|
548
|
+
else
|
549
|
+
str << code
|
550
|
+
end
|
551
|
+
end
|
552
|
+
nil
|
553
|
+
end
|
554
|
+
|
555
|
+
# Annex B
|
556
|
+
def octal?(char)
|
557
|
+
char >= 0x30 and char <= 0x39
|
558
|
+
end
|
559
|
+
|
560
|
+
def esc_string
|
561
|
+
case @codes[@pos]
|
562
|
+
# when 0x30
|
563
|
+
# "\u{0}"
|
564
|
+
when 0x27
|
565
|
+
"\'"
|
566
|
+
when 0x22
|
567
|
+
"\""
|
568
|
+
when 0x5c
|
569
|
+
"\\"
|
570
|
+
when 0x62 #b
|
571
|
+
"\u{0008}"
|
572
|
+
when 0x74 #t
|
573
|
+
"\u{0009}"
|
574
|
+
when 0x6e #n
|
575
|
+
"\u{000a}"
|
576
|
+
when 0x76 #v
|
577
|
+
"\u{000b}"
|
578
|
+
when 0x66 #f
|
579
|
+
"\u{000c}"
|
580
|
+
when 0x72 #r
|
581
|
+
"\u{000d}"
|
582
|
+
when 0x78 #x
|
583
|
+
t = [[@codes[@pos+1], @codes[@pos+2]].pack("U*").to_i(16)].pack("U*")
|
584
|
+
@pos += 2
|
585
|
+
t
|
586
|
+
when 0x75 #u
|
587
|
+
t = [[@codes[@pos+1], @codes[@pos+2], @codes[@pos+3], @codes[@pos+4]].pack("U*").to_i(16)].pack("U*")
|
588
|
+
@pos += 4
|
589
|
+
t
|
590
|
+
else
|
591
|
+
#
|
592
|
+
# octal
|
593
|
+
# Annex B
|
594
|
+
if octal?(@codes[@pos])
|
595
|
+
oct = 0
|
596
|
+
while octal?(@codes[@pos])
|
597
|
+
oct *= 8
|
598
|
+
oct += (@codes[@pos] - 0x30)
|
599
|
+
@pos += 1
|
600
|
+
end
|
601
|
+
[oct].pack("U*")
|
602
|
+
else
|
603
|
+
[@codes[@pos]].pack("U*")
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
def eof?(pos = nil)
|
609
|
+
if pos.nil?
|
610
|
+
pos = @pos
|
611
|
+
end
|
612
|
+
@codes[pos].nil?
|
613
|
+
end
|
614
|
+
|
615
|
+
#
|
616
|
+
# check next literal is 'l' or not
|
617
|
+
# if next literal is not 'l', position is not forwarded
|
618
|
+
# if next literal is 'l', position is forwarded
|
619
|
+
#
|
620
|
+
def match_lit(l, options = {})
|
621
|
+
eval_lit {
|
622
|
+
t = fwd_lit(options)
|
623
|
+
STDERR.puts "match_lit #{t} <=> #{l} #{t==l}" if @debug
|
624
|
+
t == l ? t : nil
|
625
|
+
}
|
626
|
+
end
|
627
|
+
|
628
|
+
def next_lit(options = {})
|
629
|
+
lit = nil
|
630
|
+
pos0 = @pos
|
631
|
+
return nil if eof?
|
632
|
+
while lit = next_input_element(options)
|
633
|
+
if lit and (lit.ws? or lit.lt?)
|
634
|
+
;
|
635
|
+
else
|
636
|
+
break
|
637
|
+
end
|
638
|
+
end
|
639
|
+
@pos = pos0
|
640
|
+
lit
|
641
|
+
end
|
642
|
+
|
643
|
+
def fwd_lit(options = {})
|
644
|
+
lit = nil
|
645
|
+
return nil if eof?
|
646
|
+
if options[:nolt]
|
647
|
+
while lit = next_input_element(options)
|
648
|
+
if lit and lit.ws?
|
649
|
+
;
|
650
|
+
else
|
651
|
+
break
|
652
|
+
end
|
653
|
+
end
|
654
|
+
else
|
655
|
+
while lit = next_input_element(options)
|
656
|
+
if lit and (lit.ws? or lit.lt?)
|
657
|
+
;
|
658
|
+
else
|
659
|
+
break
|
660
|
+
end
|
661
|
+
end
|
662
|
+
end
|
663
|
+
lit
|
664
|
+
end
|
665
|
+
|
666
|
+
def ws_lit(options = {})
|
667
|
+
ret = next_input_element(options)
|
668
|
+
if ret and (ret.ws? or ret.lt?)
|
669
|
+
ret
|
670
|
+
else
|
671
|
+
nil
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
def rewind_pos
|
676
|
+
if @pos > 0
|
677
|
+
@pos -= 1
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
def debug_code(from, to = nil)
|
682
|
+
if to.nil?
|
683
|
+
to = (@error_pos || @pos)
|
684
|
+
end
|
685
|
+
@codes[from,to].pack("U*")
|
686
|
+
end
|
687
|
+
|
688
|
+
def debug_str(pos = nil)
|
689
|
+
if pos.nil?
|
690
|
+
pos = @error_pos
|
691
|
+
if pos.nil?
|
692
|
+
pos = @pos
|
693
|
+
end
|
694
|
+
end
|
695
|
+
if pos > 20
|
696
|
+
pos -= 20
|
697
|
+
pos0 = 20
|
698
|
+
elsif pos >= 0
|
699
|
+
pos0 = pos
|
700
|
+
pos = 0
|
701
|
+
end
|
702
|
+
t = ''
|
703
|
+
t << @codes[pos..(pos+80)].collect{|u| u == 10 ? 0x20 : u}.pack("U*")
|
704
|
+
t << "\n"
|
705
|
+
t << (' ' * pos0) + "^"
|
706
|
+
t
|
707
|
+
end
|
708
|
+
|
709
|
+
def debug_lit(pos = nil)
|
710
|
+
if pos.nil?
|
711
|
+
pos = @error_pos
|
712
|
+
if pos.nil?
|
713
|
+
pos = @pos
|
714
|
+
end
|
715
|
+
end
|
716
|
+
if pos > 20
|
717
|
+
pos -= 20
|
718
|
+
pos0 = 20
|
719
|
+
elsif pos >= 0
|
720
|
+
pos0 = pos
|
721
|
+
pos = 0
|
722
|
+
end
|
723
|
+
#STDERR.puts pos0
|
724
|
+
STDERR.puts @codes[pos..(pos+80)].collect{|u| u == 10 ? 0x20 : u}.pack("U*")
|
725
|
+
STDERR.puts (' ' * pos0) + "^"
|
726
|
+
end
|
727
|
+
#
|
728
|
+
# break <val> => position is rewind, then break with <val>
|
729
|
+
# return <val> => position is rewind, then return <val>
|
730
|
+
# next <val> => position is not rewind, then break with <val>
|
731
|
+
#
|
732
|
+
def eval_lit(&block)
|
733
|
+
begin
|
734
|
+
saved_pos = @pos
|
735
|
+
ret = yield
|
736
|
+
ensure
|
737
|
+
if ret.nil?
|
738
|
+
#@error_pos = @pos
|
739
|
+
@pos = saved_pos
|
740
|
+
nil
|
741
|
+
end
|
742
|
+
end
|
743
|
+
end
|
744
|
+
end
|
745
|
+
end
|