minjs 0.2.2 → 0.3.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,92 +1,106 @@
1
1
  module Minjs
2
2
  module Func
3
- #
4
3
  #13
5
4
  #
5
+ # FunctionDeclaration :
6
+ # function Identifier ( FormalParameterListopt ) { FunctionBody }
7
+ #
8
+ # NOTE:
9
+ #
10
+ # The function declaration in statement(block) is not permitted by ECMA262.
11
+ # However, almost all implementation permit it.
12
+ #
6
13
  def func_declaration(lex, context)
7
- return nil if lex.match_lit(ECMA262::ID_FUNCTION).nil?
8
- lex.eval_lit {
9
- new_context = ECMA262::Context.new
10
- new_context.lex_env = context.lex_env.new_declarative_env()
11
- new_context.var_env = context.var_env.new_declarative_env()
14
+ return nil if lex.eql_lit?(ECMA262::ID_FUNCTION).nil?
15
+
16
+ new_context = ECMA262::Context.new
17
+ new_context.lex_env = context.lex_env.new_declarative_env()
18
+ new_context.var_env = context.var_env.new_declarative_env()
12
19
 
13
- if id=identifier(lex, context) and
14
- lex.match_lit(ECMA262::PUNC_LPARENTHESIS) and
15
- args = formal_parameter_list(lex, new_context) and
16
- lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and
17
- lex.match_lit(ECMA262::PUNC_LCURLYBRAC) and
18
- b=func_body(lex, new_context) and lex.match_lit(ECMA262::PUNC_RCURLYBRAC)
19
- f = ECMA262::StFunc.new(new_context, id, args, b, {:decl => true})
20
+ if id=identifier(lex, context) and
21
+ lex.eql_lit?(ECMA262::PUNC_LPARENTHESIS) and
22
+ args = formal_parameter_list(lex, new_context) and
23
+ lex.eql_lit?(ECMA262::PUNC_RPARENTHESIS) and
24
+ lex.eql_lit?(ECMA262::PUNC_LCURLYBRAC) and
25
+ b=func_body(lex, new_context) and lex.eql_lit?(ECMA262::PUNC_RCURLYBRAC)
26
+ f = ECMA262::StFunc.new(new_context, id, args, b, {:decl => true})
20
27
 
21
- context.var_env.record.create_mutable_binding(id, nil)
22
- context.var_env.record.set_mutable_binding(id, f, nil)
23
- context.lex_env.record.create_mutable_binding(id, nil)
24
- context.lex_env.record.set_mutable_binding(id, f, nil)
25
- f
28
+ context.var_env.record.create_mutable_binding(id, nil)
29
+ context.var_env.record.set_mutable_binding(id, f, nil)
30
+ context.lex_env.record.create_mutable_binding(id, nil)
31
+ context.lex_env.record.set_mutable_binding(id, f, nil)
32
+ f
33
+ else
34
+ if b
35
+ raise ParseError.new("No `}' at end of function", lex)
26
36
  else
27
- if b
28
- raise ParseError.new("No `}' at end of function", lex)
29
- else
30
- raise ParseError.new("Bad function declaration", lex)
31
- end
37
+ raise ParseError.new("Bad function declaration", lex)
32
38
  end
33
- }
39
+ end
34
40
  end
35
41
 
42
+ #13
43
+ #
44
+ # FunctionExpression :
45
+ # function Identifieropt ( FormalParameterListopt ) { FunctionBody }
46
+ #
36
47
  def func_exp(lex, context)
37
- return nil if lex.match_lit(ECMA262::ID_FUNCTION).nil?
48
+ return nil if lex.eql_lit?(ECMA262::ID_FUNCTION).nil?
38
49
  @logger.debug "*** func_exp"
39
50
 
40
- lex.eval_lit {
41
- id_opt = identifier(lex, context)
42
- new_context = ECMA262::Context.new
43
- new_context.lex_env = context.lex_env.new_declarative_env()
44
- new_context.var_env = context.var_env.new_declarative_env()
51
+ id_opt = identifier(lex, context)
52
+ new_context = ECMA262::Context.new
53
+ new_context.lex_env = context.lex_env.new_declarative_env()
54
+ new_context.var_env = context.var_env.new_declarative_env()
45
55
 
46
- if lex.match_lit(ECMA262::PUNC_LPARENTHESIS) and
47
- args = formal_parameter_list(lex, new_context) and
48
- lex.match_lit(ECMA262::PUNC_RPARENTHESIS) and
49
- lex.match_lit(ECMA262::PUNC_LCURLYBRAC) and
50
- b = func_body(lex, new_context) and lex.match_lit(ECMA262::PUNC_RCURLYBRAC)
51
- f = ECMA262::StFunc.new(new_context, id_opt, args, b)
52
- if id_opt
53
- new_context.var_env.record.create_mutable_binding(id_opt, nil)
54
- new_context.var_env.record.set_mutable_binding(id_opt, f, nil)
55
- new_context.lex_env.record.create_mutable_binding(id_opt, nil)
56
- new_context.lex_env.record.set_mutable_binding(id_opt, f, nil)
57
- id_opt.context = new_context
58
- end
59
- f
60
- else
61
- if b
62
- raise ParseError.new("No `}' at end of function", lex)
63
- else
64
- raise ParseError.new("Bad function declaration", lex)
65
- end
66
- end
67
- }
56
+ if lex.eql_lit?(ECMA262::PUNC_LPARENTHESIS) and
57
+ args = formal_parameter_list(lex, new_context) and
58
+ lex.eql_lit?(ECMA262::PUNC_RPARENTHESIS) and
59
+ lex.eql_lit?(ECMA262::PUNC_LCURLYBRAC) and
60
+ b = func_body(lex, new_context) and lex.eql_lit?(ECMA262::PUNC_RCURLYBRAC)
61
+ f = ECMA262::StFunc.new(new_context, id_opt, args, b)
62
+ if id_opt
63
+ new_context.var_env.record.create_mutable_binding(id_opt, nil)
64
+ new_context.var_env.record.set_mutable_binding(id_opt, f, nil)
65
+ new_context.lex_env.record.create_mutable_binding(id_opt, nil)
66
+ new_context.lex_env.record.set_mutable_binding(id_opt, f, nil)
67
+ id_opt.context = new_context
68
+ end
69
+ f
70
+ else
71
+ if b
72
+ raise ParseError.new("No `}' at end of function", lex)
73
+ else
74
+ raise ParseError.new("Bad function expression", lex)
75
+ end
76
+ end
68
77
  end
69
78
 
70
79
  def formal_parameter_list(lex, context)
71
- lex.eval_lit{
72
- ret = []
80
+ ret = []
81
+ unless lex.peek_lit(nil).eql? ECMA262::PUNC_RPARENTHESIS
73
82
  while true
74
- a = identifier(lex, context)
75
- if a
76
- ret.push(a)
77
- break if lex.match_lit(ECMA262::PUNC_COMMA).nil?
83
+ if arg = identifier(lex, context)
84
+ ret.push(arg)
78
85
  else
86
+ raise ParseError.new("unexpceted token", lex)
87
+ end
88
+ if lex.peek_lit(nil).eql? ECMA262::PUNC_RPARENTHESIS
79
89
  break
90
+ elsif lex.eql_lit? ECMA262::PUNC_COMMA
91
+ ;
92
+ else
93
+ raise ParseError.new("unexpceted token", lex)
80
94
  end
81
95
  end
82
- ret.each do |argName|
83
- context.var_env.record.create_mutable_binding(argName, nil)
84
- context.var_env.record.set_mutable_binding(argName, :undefined, nil, {:_parameter_list => true})
85
- context.lex_env.record.create_mutable_binding(argName, nil)
86
- context.lex_env.record.set_mutable_binding(argName, :undefined, nil, {:_parameter_list => true})
87
- end
88
- ret
89
- }
96
+ end
97
+ ret.each do |argName|
98
+ context.var_env.record.create_mutable_binding(argName, nil)
99
+ context.var_env.record.set_mutable_binding(argName, :undefined, nil, {:_parameter_list => true})
100
+ context.lex_env.record.create_mutable_binding(argName, nil)
101
+ context.lex_env.record.set_mutable_binding(argName, :undefined, nil, {:_parameter_list => true})
102
+ end
103
+ ret
90
104
  end
91
105
 
92
106
  def func_body(lex, context)
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  require 'minjs/ctype'
2
3
 
3
4
  module Minjs
@@ -5,58 +6,87 @@ module Minjs
5
6
  include Ctype
6
7
 
7
8
  attr_reader :pos
8
- attr_reader :error_pos
9
9
  attr_reader :codes
10
10
 
11
11
  def initialize(str = "", options = {})
12
12
  str = str.gsub(/\r\n/, "\n")
13
13
  @codes = str.codepoints
14
+ if !str.match(/\n\z/)
15
+ @codes.push(10)
16
+ end
14
17
  @pos = 0
15
18
  @lit_cache = []
16
19
  @lit_nextpos = []
17
20
  @logger = options[:logger]
21
+
22
+ @eval_nest = 0
23
+ end
24
+
25
+ def clear_cache
26
+ @lit_cache = []
27
+ @lit_nextpos = []
18
28
  end
19
29
 
20
- def next_input_element(options = {})
21
- if @lit_cache[@pos]
22
- ret = @lit_cache[@pos]
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]
23
47
  @pos = @lit_nextpos[@pos]
24
- @error_pos = @pos
48
+ @head_pos = @pos
25
49
  return ret
26
50
  end
27
51
  pos0 = @pos
28
- if ret = (white_space || line_terminator || comment || token)
29
- if ret
30
- @lit_cache[pos0] = ret
31
- @lit_nextpos[pos0] = @pos
32
- end
33
- @error_pos = @pos
34
- return ret
35
- end
36
- #
37
- # ECMA262 say:
38
52
  #
39
- # There are no syntactic grammar contexts where both a leading division
40
- # or division-assignment, and a leading RegularExpressionLiteral are permitted.
41
- # This is not affected by semicolon insertion (see 7.9); in examples such as the following:
42
- # To determine `/' is regular expression or not
53
+ # skip white space here, because ECMA262(5.1.2) says:
43
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.
44
58
  #
45
- if options[:hint] == :div
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
46
76
  ret = div_punctuator
47
77
  if ret
48
78
  @lit_cache[pos0] = ret
49
79
  @lit_nextpos[pos0] = @pos
50
80
  end
51
- @error_pos = @pos
81
+ @head_pos = @pos
52
82
  return ret
53
- elsif options[:hint] == :regexp
83
+ elsif hint == :regexp
54
84
  ret = regexp_literal
55
85
  if ret
56
86
  @lit_cache[pos0] = ret
57
87
  @lit_nextpos[pos0] = @pos
58
88
  end
59
- @error_pos = @pos
89
+ @head_pos = @pos
60
90
  return ret
61
91
  else
62
92
  ECMA262::LIT_DIV_OR_REGEXP_LITERAL
@@ -65,13 +95,10 @@ module Minjs
65
95
 
66
96
  # 7.2
67
97
  def white_space
68
- code = @codes[@pos]
69
- if white_space?(code)
70
- while true
98
+ if white_space?(@codes[@pos])
99
+ begin
71
100
  @pos += 1
72
- code = @codes[@pos]
73
- break unless white_space?(code)
74
- end
101
+ end until !white_space?(@codes[@pos])
75
102
  return ECMA262::WhiteSpace.get
76
103
  else
77
104
  nil
@@ -80,13 +107,10 @@ module Minjs
80
107
 
81
108
  #7.3
82
109
  def line_terminator
83
- code = @codes[@pos]
84
- if line_terminator?(code)
85
- while true
110
+ if line_terminator?(@codes[@pos])
111
+ begin
86
112
  @pos += 1
87
- code = @codes[@pos]
88
- break unless line_terminator?(code)
89
- end
113
+ end until !line_terminator?(@codes[@pos])
90
114
  return ECMA262::LineFeed.get
91
115
  else
92
116
  nil
@@ -99,38 +123,31 @@ module Minjs
99
123
  end
100
124
 
101
125
  def multi_line_comment
126
+ # /*
102
127
  if @codes[@pos] == 0x2f and @codes[@pos + 1] == 0x2a
103
- @pos = @pos + 2
128
+ @pos += 2
104
129
  pos0 = @pos
105
- lf = false
106
- while (@codes[@pos] != 0x2a or @codes[@pos + 1] != 0x2f)
107
- if @codes[@pos].nil?
108
- raise ParseError.new("no `*/' at end of comment", self)
109
- end
110
- if line_terminator?(@codes[@pos])
111
- lf = true
112
- end
113
- @pos = @pos + 1
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
114
134
  end
115
- @pos = @pos + 2
116
- return ECMA262::MultiLineComment.new(@codes[pos0...(@pos-2)].pack("U*"), lf)
135
+ @pos +=2
136
+ return ECMA262::MultiLineComment.new(@codes[pos0...(@pos-2)].pack("U*"))
117
137
  else
118
138
  nil
119
139
  end
120
140
  end
121
141
 
122
142
  def single_line_comment
143
+ # //
123
144
  if @codes[@pos] == 0x2f and @codes[@pos + 1] == 0x2f
124
- @pos = @pos + 2
145
+ @pos += 2
125
146
  pos0 = @pos
126
- while !line_terminator?(@codes[@pos]) and @codes[@pos]
147
+ while (code = @codes[@pos]) and !line_terminator?(code)
127
148
  @pos += 1
128
149
  end
129
- if @codes[@pos].nil?
130
- return ECMA262::SingleLineComment.new(@codes[pos0...@pos].pack("U*") + "\n")
131
- else
132
- return ECMA262::SingleLineComment.new(@codes[pos0...@pos].pack("U*"))
133
- end
150
+ return ECMA262::SingleLineComment.new(@codes[pos0...@pos].pack("U*"))
134
151
  else
135
152
  nil
136
153
  end
@@ -140,38 +157,36 @@ module Minjs
140
157
  # 7.5 tokens
141
158
  #
142
159
  def token
143
- pos0 = @pos
144
- ret = (identifier_name || numeric_literal || punctuator || string_literal)
145
- if ret
146
- @lit_cache[pos0] = ret
147
- @lit_nextpos[pos0] = @pos
148
- end
149
- ret
160
+ identifier_name || numeric_literal || punctuator || string_literal
150
161
  end
151
162
 
163
+ #
152
164
  def unicode_escape?
153
- if @codes[@pos] == 0x5c and
154
- @codes[@pos+1] == 0x75 and
155
- hex_number?(@codes[@pos+2]) and
156
- hex_number?(@codes[@pos+3]) and
157
- hex_number?(@codes[@pos+4]) and
158
- hex_number?(@codes[@pos+5])
159
- [@codes[@pos+2],@codes[@pos+3],@codes[@pos+4],@codes[@pos+5]].pack("U*").to_i(16)
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
160
175
  else
161
- false
176
+ nil
162
177
  end
163
178
  end
164
179
 
165
180
  def identifier_name
166
- pos0 = @pos
167
- return nil if @codes[@pos].nil?
181
+ return nil if (code = @codes[@pos]).nil?
168
182
 
183
+ pos0 = @pos
169
184
  chars = []
170
- if u=unicode_escape? and identifier_start?(u)
171
- chars.push(u)
185
+ if code == 0x5c and ucode = unicode_escape? and identifier_start?(ucode)
186
+ chars.push(ucode)
172
187
  @pos += 6
173
- elsif identifier_start?(@codes[@pos])
174
- chars.push(@codes[@pos])
188
+ elsif identifier_start?(code)
189
+ chars.push(code)
175
190
  @pos += 1
176
191
  else
177
192
  return nil
@@ -179,15 +194,15 @@ module Minjs
179
194
 
180
195
  while true
181
196
  code = @codes[@pos]
182
- if u=unicode_escape? and (identifier_start?(u) || identifier_part?(u))
183
- chars.push(u)
197
+ if code == 0x5c and ucode = unicode_escape? and identifier_part?(ucode)
198
+ chars.push(ucode)
184
199
  @pos += 6
185
- elsif identifier_part?(@codes[@pos])
186
- chars.push(@codes[@pos])
200
+ elsif identifier_part?(code)
201
+ chars.push(code)
187
202
  @pos += 1
188
203
  else
189
204
  name = chars.pack("U*").to_sym
190
- return ECMA262::IdentifierName.new(nil, name)
205
+ return ECMA262::IdentifierName.get(nil, name)
191
206
  end
192
207
  end
193
208
  end
@@ -197,148 +212,167 @@ module Minjs
197
212
  code1 = @codes[@pos+1]
198
213
  code2 = @codes[@pos+2]
199
214
  code3 = @codes[@pos+3]
200
- if false
201
- elsif (code0 == 0x3e and code1 == 0x3e and code2 == 0x3e and code3 == 0x3d)
202
- @pos += 4
203
- return ECMA262::Punctuator.get('>>>=')
204
- elsif (code0 == 0x3d and code1 == 0x3d and code2 == 0x3d)
205
- @pos += 3
206
- return ECMA262::Punctuator.get('===')
207
- elsif (code0 == 0x21 and code1 == 0x3d and code2 == 0x3d)
208
- @pos += 3
209
- return ECMA262::Punctuator.get('!==')
210
- elsif (code0 == 0x3e and code1 == 0x3e and code2 == 0x3e)
211
- @pos += 3
212
- return ECMA262::Punctuator.get('>>>')
213
- elsif (code0 == 0x3c and code1 == 0x3c and code2 == 0x3d)
214
- @pos += 3
215
- return ECMA262::Punctuator.get('<<=')
216
- elsif (code0 == 0x3e and code1 == 0x3e and code2 == 0x3d)
217
- @pos += 3
218
- return ECMA262::Punctuator.get('>>=')
219
- elsif (code0 == 0x3e and code1 == 0x3e)
220
- @pos += 2
221
- return ECMA262::Punctuator.get('>>')
222
- elsif (code0 == 0x3c and code1 == 0x3d)
223
- @pos += 2
224
- return ECMA262::Punctuator.get('<=')
225
- elsif (code0 == 0x3e and code1 == 0x3d)
226
- @pos += 2
227
- return ECMA262::Punctuator.get('>=')
228
- elsif (code0 == 0x3d and code1 == 0x3d)
229
- @pos += 2
230
- return ECMA262::Punctuator.get('==')
231
- elsif (code0 == 0x21 and code1 == 0x3d)
232
- @pos += 2
233
- return ECMA262::Punctuator.get('!=')
234
- elsif (code0 == 0x2b and code1 == 0x2b)
235
- @pos += 2
236
- return ECMA262::Punctuator.get('++')
237
- elsif (code0 == 0x2d and code1 == 0x2d)
238
- @pos += 2
239
- return ECMA262::Punctuator.get('--')
240
- elsif (code0 == 0x3c and code1 == 0x3c)
241
- @pos += 2
242
- return ECMA262::Punctuator.get('<<')
243
- elsif (code0 == 0x3e and code1 == 0x3e)
244
- @pos += 2
245
- return ECMA262::Punctuator.get('>>')
246
- elsif (code0 == 0x26 and code1 == 0x26)
247
- @pos += 2
248
- return ECMA262::Punctuator.get('&&')
249
- elsif (code0 == 0x7c and code1 == 0x7c)
250
- @pos += 2
251
- return ECMA262::Punctuator.get('||')
252
- elsif (code0 == 0x2b and code1 == 0x3d)
253
- @pos += 2
254
- return ECMA262::Punctuator.get('+=')
255
- elsif (code0 == 0x2d and code1 == 0x3d)
256
- @pos += 2
257
- return ECMA262::Punctuator.get('-=')
258
- elsif (code0 == 0x2a and code1 == 0x3d)
259
- @pos += 2
260
- return ECMA262::Punctuator.get('*=')
261
- elsif (code0 == 0x25 and code1 == 0x3d)
262
- @pos += 2
263
- return ECMA262::Punctuator.get('%=')
264
- elsif (code0 == 0x26 and code1 == 0x3d)
265
- @pos += 2
266
- return ECMA262::Punctuator.get('&=')
267
- elsif (code0 == 0x7c and code1 == 0x3d)
268
- @pos += 2
269
- return ECMA262::Punctuator.get('|=')
270
- elsif (code0 == 0x5e and code1 == 0x3d)
271
- @pos += 2
272
- return ECMA262::Punctuator.get('^=')
273
- elsif (code0 == 0x7b)
274
- @pos += 1
275
- return ECMA262::Punctuator.get('{')
276
- elsif (code0 == 0x7d)
277
- @pos += 1
278
- return ECMA262::Punctuator.get('}')
279
- elsif (code0 == 0x28)
280
- @pos += 1
281
- return ECMA262::Punctuator.get('(')
282
- elsif (code0 == 0x29)
283
- @pos += 1
284
- return ECMA262::Punctuator.get(')')
285
- elsif (code0 == 0x5b)
286
- @pos += 1
287
- return ECMA262::Punctuator.get('[')
288
- elsif (code0 == 0x5d)
289
- @pos += 1
290
- return ECMA262::Punctuator.get(']')
291
- elsif (code0 == 0x2e)
292
- @pos += 1
293
- return ECMA262::Punctuator.get('.')
294
- elsif (code0 == 0x3b)
295
- @pos += 1
296
- return ECMA262::Punctuator.get(';')
297
- elsif (code0 == 0x2c)
298
- @pos += 1
299
- return ECMA262::Punctuator.get(',')
300
- elsif (code0 == 0x3c)
301
- @pos += 1
302
- return ECMA262::Punctuator.get('<')
303
- elsif (code0 == 0x3e)
304
- @pos += 1
305
- return ECMA262::Punctuator.get('>')
306
- elsif (code0 == 0x2b)
307
- @pos += 1
308
- return ECMA262::Punctuator.get('+')
309
- elsif (code0 == 0x2d)
310
- @pos += 1
311
- return ECMA262::Punctuator.get('-')
312
- elsif (code0 == 0x2a)
313
- @pos += 1
314
- return ECMA262::Punctuator.get('*')
315
- elsif (code0 == 0x25)
316
- @pos += 1
317
- return ECMA262::Punctuator.get('%')
318
- elsif (code0 == 0x26)
319
- @pos += 1
320
- return ECMA262::Punctuator.get('&')
321
- elsif (code0 == 0x7c)
322
- @pos += 1
323
- return ECMA262::Punctuator.get('|')
324
- elsif (code0 == 0x5e)
325
- @pos += 1
326
- return ECMA262::Punctuator.get('^')
327
- elsif (code0 == 0x21)
328
- @pos += 1
329
- return ECMA262::Punctuator.get('!')
330
- elsif (code0 == 0x7e)
331
- @pos += 1
332
- return ECMA262::Punctuator.get('~')
333
- elsif (code0 == 0x3f)
334
- @pos += 1
335
- return ECMA262::Punctuator.get('?')
336
- elsif (code0 == 0x3a)
337
- @pos += 1
338
- return ECMA262::Punctuator.get(':')
339
- elsif (code0 == 0x3d)
340
- @pos += 1
341
- return ECMA262::Punctuator.get('=')
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
342
376
  end
343
377
  nil
344
378
  end
@@ -434,68 +468,124 @@ module Minjs
434
468
  end
435
469
 
436
470
  #7.8.3
471
+ #B.1.1
437
472
  def numeric_literal
438
- code = @codes[@pos]
439
- return nil if code.nil?
440
-
441
- hex_integer_literal || decimal_literal
473
+ hex_integer_literal || octal_integer_literal || decimal_literal
442
474
  end
443
475
 
476
+ #7.8.3
477
+ #
478
+ # HexIntegerLiteral ::
479
+ # 0x HexDigit
480
+ # 0X HexDigit
481
+ # HexIntegerLiteral HexDigit
482
+ #
444
483
  def hex_integer_literal
445
- pos0 = @pos
446
- # 0x.... or 0X....
447
484
  code = @codes[@pos]
448
- if code == 0x30 and (@codes[@pos+1] == 0x78 || @codes[@pos+1] == 0x58) #hex integer
485
+ if code.nil?
486
+ return nil
487
+ #0x / 0X
488
+ elsif code == 0x30 and (@codes[@pos+1] == 0x78 || @codes[@pos+1] == 0x58)
449
489
  @pos += 2
450
- while true
451
- code = @codes[@pos]
452
- if (code >= 0x30 and code <= 0x39) || (code >= 0x41 and code <= 0x4f) || (code >= 0x61 and code <= 0x6f)
453
- ;
454
- elsif identifier_start?(code)
455
- raise ParseError.new("The source character immediately following a NumericLiteral must not be an IdentifierStart or DecimalDigit", self)
456
- else
457
- return ECMA262::ECMA262Numeric.new(@codes[(pos0+2)...@pos].pack("U*").to_i(16))
458
- end
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
459
517
  @pos += 1
460
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
461
524
  else
462
525
  nil
463
526
  end
464
527
  end
465
528
 
529
+ # 7.8.3
530
+ #
531
+ # DecimalLiteral ::
532
+ # DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt
533
+ # . DecimalDigits ExponentPartopt
534
+ # DecimalIntegerLiteral ExponentPartopt
535
+ #
466
536
  def decimal_literal
467
537
  pos0 = @pos
468
538
  code = @codes[@pos]
469
- if code == 0x2e #.
539
+
540
+ if code.nil?
541
+ return nil
542
+ elsif code == 0x2e #.
470
543
  @pos += 1
471
544
  f = decimal_digits
472
- if f.nil?
473
- @pos = pos0
474
- return nil
545
+ if f.nil? #=> this period is punctuator
546
+ @pos = pos0 + 1
547
+ return ECMA262::PUNC_PERIOD
475
548
  end
476
- if @codes[@pos] == 0x65 || @codes[@pos] == 0x45
549
+ if (code = @codes[@pos]) == 0x65 || code == 0x45
477
550
  @pos += 1
478
- e = exp_part
551
+ e = exponent_part
479
552
  end
480
553
  if identifier_start?(@codes[@pos])
481
554
  raise ParseError.new("The source character immediately following a NumericLiteral must not be an IdentifierStart or DecimalDigit", self)
482
555
  end
483
556
 
484
557
  return ECMA262::ECMA262Numeric.new('0', f, e)
485
- end
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
486
575
 
487
- if code >= 0x30 and code <= 0x39
576
+ return ECMA262::ECMA262Numeric.new(i, f, e)
577
+ elsif code >= 0x31 and code <= 0x39
488
578
  i = decimal_digits
489
579
  if @codes[@pos] == 0x2e #.
490
580
  @pos += 1
491
581
  f = decimal_digits
492
- if @codes[@pos] == 0x65 || @codes[@pos] == 0x45 #e or E
582
+ if (code = @codes[@pos]) == 0x65 || code == 0x45 #e or E
493
583
  @pos += 1
494
- e = exp_part
584
+ e = exponent_part
495
585
  end
496
- elsif @codes[@pos] == 0x65 || @codes[@pos] == 0x45 #e or E
586
+ elsif (code = @codes[@pos]) == 0x65 || code == 0x45 #e or E
497
587
  @pos += 1
498
- e = exp_part
588
+ e = exponent_part
499
589
  end
500
590
  if identifier_start?(@codes[@pos])
501
591
  raise ParseError.new("The source character immediately following a NumericLiteral must not be an IdentifierStart or DecimalDigit", self)
@@ -507,251 +597,334 @@ module Minjs
507
597
  nil
508
598
  end
509
599
 
510
- def exp_part
511
- if @codes[@pos] == 0x2b
600
+ # 7.8.3
601
+ #
602
+ # ExponentPart ::
603
+ # ExponentIndicator SignedInteger
604
+ #
605
+ def exponent_part
606
+ if (code = @codes[@pos]) == 0x2b
512
607
  @pos += 1
513
- elsif @codes[@pos] == 0x2d
608
+ elsif code == 0x2d
514
609
  @pos += 1
515
610
  neg = true
516
611
  end
612
+ d = decimal_digits
613
+ raise ParseError.new("unexpecting token", self) if d.nil?
517
614
  if neg
518
- e = "-#{decimal_digits}"
615
+ e = "-#{d}"
519
616
  else
520
- e = decimal_digits
617
+ e = d
521
618
  end
522
619
  e
523
620
  end
524
621
 
622
+ #7.8.3
623
+ #
624
+ # DecimalDigit :: one of
625
+ # 0 1 2 3 4 5 6 7 8 9
626
+ #
525
627
  def decimal_digits
526
628
  pos0 = @pos
527
- code = @codes[@pos]
528
- return nil if code.nil?
529
- if code >= 0x30 and code <= 0x39
629
+ if (code = @codes[@pos]) >= 0x30 and code <= 0x39
530
630
  @pos += 1
531
- while true
532
- code = @codes[@pos]
533
- if code >= 0x30 and code <= 0x39
534
- @pos += 1
535
- else
536
- return @codes[pos0...@pos].pack("U*")
537
- end
631
+ while code = @codes[@pos] and code >= 0x30 and code <= 0x39
632
+ @pos += 1
538
633
  end
634
+ return @codes[pos0...@pos].pack("U*")
539
635
  else
540
636
  nil
541
637
  end
542
638
  end
543
639
 
544
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
+ #
545
662
  def string_literal
546
- code = @codes[@pos]
547
- return nil if code.nil?
548
- pos0 = @pos
549
- if code == 0x27 #'
663
+ if (code = @codes[@pos]) == 0x27 #'
550
664
  term = 0x27
551
665
  elsif code == 0x22 #"
552
666
  term = 0x22
553
667
  else
554
668
  return nil
555
669
  end
670
+ @pos += 1
671
+ pos0 = @pos
556
672
 
557
- str = ''
558
- while @codes[@pos]
559
- @pos += 1
560
- code = @codes[@pos]
673
+ str = []
674
+ while (code = @codes[@pos])
561
675
  if code.nil?
562
676
  raise ParseError.new("no `#{term}' at end of string", self)
563
677
  elsif line_terminator?(code)
564
678
  raise ParseError.new("string has line terminator in body", self)
565
679
  elsif code == 0x5c #\
566
680
  @pos += 1
567
- str << esc_string
681
+ str.push(escape_sequence)
568
682
  elsif code == term
569
- @pos += 1
570
- return ECMA262::ECMA262String.new(str)
683
+ @pos += 1
684
+ return ECMA262::ECMA262String.new(str.compact.pack("U*"))
571
685
  else
572
- str << code
686
+ @pos += 1
687
+ str.push(code)
573
688
  end
574
689
  end
575
690
  nil
576
691
  end
577
692
 
578
- # Annex B
579
- def octal?(char)
580
- char >= 0x30 and char <= 0x39
581
- end
582
-
583
- def esc_string
584
- case @codes[@pos]
585
- # when 0x30
586
- # "\u{0}"
587
- when 0x27
588
- "\'"
589
- when 0x22
590
- "\""
591
- when 0x5c
592
- "\\"
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
593
717
  when 0x62 #b
594
- "\u{0008}"
718
+ @pos += 1
719
+ 0x08
595
720
  when 0x74 #t
596
- "\u{0009}"
721
+ @pos += 1
722
+ 0x09
597
723
  when 0x6e #n
598
- "\u{000a}"
724
+ @pos += 1
725
+ 0x0a
599
726
  when 0x76 #v
600
- "\u{000b}"
727
+ @pos += 1
728
+ 0x0b
601
729
  when 0x66 #f
602
- "\u{000c}"
730
+ @pos += 1
731
+ 0x0c
603
732
  when 0x72 #r
604
- "\u{000d}"
733
+ @pos += 1
734
+ 0x0d
605
735
  when 0x78 #x
606
- t = [[@codes[@pos+1], @codes[@pos+2]].pack("U*").to_i(16)].pack("U*")
607
- @pos += 2
736
+ #check
737
+ t = @codes[(@pos+1)..(@pos+2)].pack("U*").to_i(16)
738
+ @pos += 3
608
739
  t
609
740
  when 0x75 #u
610
- t = [[@codes[@pos+1], @codes[@pos+2], @codes[@pos+3], @codes[@pos+4]].pack("U*").to_i(16)].pack("U*")
611
- @pos += 4
741
+ #check
742
+ t = @codes[(@pos+1)..(@pos+4)].pack("U*").to_i(16)
743
+ @pos += 5
612
744
  t
613
745
  else
614
746
  # line continuation
615
- if line_terminator?(@codes[@pos])
616
- ""
617
- # octal
618
- # Annex B
619
- elsif octal?(@codes[@pos])
620
- oct = (@codes[@pos] - 0x30)
621
- 2.times do
622
- break unless octal?(@codes[@pos+1])
623
- @pos += 1
624
- oct *= 8
625
- oct += (@codes[@pos] - 0x30)
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
626
792
  end
627
- [oct].pack("U*")
628
793
  else
629
- [@codes[@pos]].pack("U*")
794
+ @pos += 1
795
+ code
630
796
  end
631
797
  end
632
798
  end
633
799
 
634
- def eof?(pos = nil)
635
- if pos.nil?
636
- pos = @pos
637
- end
638
- @codes[pos].nil?
800
+ def eof?
801
+ peek_lit(nil).nil?
639
802
  end
640
803
 
641
804
  #
642
- # check next literal is 'l' or not
805
+ # check next literal is strictly equal to 'l' or not.
806
+ # white spaces and line terminators are skipped and ignored.
807
+ #
643
808
  # if next literal is not 'l', position is not forwarded
644
809
  # if next literal is 'l', position is forwarded
645
810
  #
646
- def match_lit(l, options = {})
647
- eval_lit {
648
- t = fwd_lit(options)
649
- t == l ? t : nil
650
- }
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
651
819
  end
652
820
 
653
- def next_lit(options = {})
654
- lit = nil
655
- pos0 = @pos
656
- return nil if eof?
657
- while lit = next_input_element(options)
658
- if lit and (lit.ws? or lit.lt?)
659
- ;
660
- else
661
- break
662
- end
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
663
836
  end
664
- @pos = pos0
665
- lit
666
837
  end
667
838
 
668
- def fwd_lit(options = {})
669
- lit = nil
670
- return nil if eof?
671
- if options[:nolt]
672
- while lit = next_input_element(options)
673
- if lit and lit.ws?
674
- ;
675
- else
676
- break
677
- end
678
- end
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
679
851
  else
680
- while lit = next_input_element(options)
681
- if lit and (lit.ws? or lit.lt?)
682
- ;
683
- else
684
- break
685
- end
686
- end
852
+ nil
687
853
  end
688
- lit
689
854
  end
690
855
 
691
- def ws_lit(options = {})
692
- ret = next_input_element(options)
693
- if ret and (ret.ws? or ret.lt?)
694
- ret
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
695
869
  else
696
870
  nil
697
871
  end
698
872
  end
699
873
 
700
- def rewind_pos
701
- if @pos > 0
702
- @pos -= 1
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?)
703
882
  end
883
+ @pos = pos0
884
+ lit
704
885
  end
705
886
 
706
- def debug_code(from, to = nil)
707
- if to.nil?
708
- to = (@error_pos || @pos)
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?
709
896
  end
710
- @codes[from,to].pack("U*")
897
+ @pos = pos0
898
+ lit
711
899
  end
712
900
 
713
- def debug_str(pos = nil, line = nil, col = nil)
714
- if pos.nil?
715
- pos = @error_pos
716
- if pos.nil?
717
- pos = @pos
718
- end
719
- end
720
- if pos > 20
721
- pos -= 20
722
- pos0 = 20
723
- elsif pos >= 0
724
- pos0 = pos
725
- pos = 0
726
- end
727
- if col and col >= 1
728
- pos0 = col - 1;
729
- end
730
- t = ''
731
- t << @codes[pos..(pos+80)].pack("U*")
732
- t << "\n"
733
- t << (' ' * pos0) + "^"
734
- t
901
+ def fwd_after_peek
902
+ @pos = @head_pos
735
903
  end
736
904
 
737
- def debug_lit(pos = nil)
738
- if pos.nil?
739
- pos = @error_pos
740
- if pos.nil?
741
- pos = @pos
742
- end
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?)
743
912
  end
744
- if pos > 20
745
- pos -= 20
746
- pos0 = 20
747
- elsif pos >= 0
748
- pos0 = pos
749
- pos = 0
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?
750
924
  end
751
- #STDERR.puts pos0
752
- STDERR.puts @codes[pos..(pos+80)].collect{|u| u == 10 ? 0x20 : u}.pack("U*")
753
- STDERR.puts (' ' * pos0) + "^"
925
+ lit
754
926
  end
927
+
755
928
  #
756
929
  # break <val> => position is rewind, then break with <val>
757
930
  # return <val> => position is rewind, then return <val>
@@ -760,17 +933,26 @@ module Minjs
760
933
  def eval_lit(&block)
761
934
  begin
762
935
  saved_pos = @pos
936
+ @eval_nest += 1
763
937
  ret = yield
764
938
  ensure
939
+ @eval_nest -= 1
765
940
  if ret.nil?
766
- #@error_pos = @pos
767
941
  @pos = saved_pos
768
942
  nil
943
+ else
944
+ if @eval_nest == 0
945
+ #STDERR.puts "clear_cache [#{saved_pos}..#{@pos}]"
946
+ clear_cache
947
+ end
769
948
  end
770
949
  end
771
950
  end
772
951
 
773
- def line_col(pos)
952
+ #
953
+ # position to [row, col]
954
+ #
955
+ def row_col(pos)
774
956
  _pos = 0
775
957
  row = 0
776
958
  col = 1
@@ -786,5 +968,45 @@ module Minjs
786
968
  end
787
969
  return [row+1, col+1]
788
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
789
1011
  end
790
1012
  end