metal 0.0.1 → 0.0.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.
data/bin/metal CHANGED
@@ -7,6 +7,9 @@ opts = {
7
7
 
8
8
  op = OptionParser.new
9
9
 
10
+ require 'metal/version'
11
+ op.version = Metal::VERSION::STRING
12
+
10
13
  op.on('-o OUTPUT', 'output file name') {|v|
11
14
  opts[:output] = v
12
15
  }
data/bin/metal-run CHANGED
@@ -18,7 +18,7 @@ after = Object.constants
18
18
  parsers = (after - before) \
19
19
  .map {|c| Object.const_get(c) } \
20
20
  .select {|c| c.is_a?(Class) } \
21
- .select {|c| c.public_instance_methods.include?('rule_main') } \
21
+ .select {|c| c.public_instance_methods.map{|m|m.to_sym}.include?(:rule_main) } \
22
22
  .sort_by {|c| c.ancestors.length } \
23
23
  .reverse
24
24
 
data/lib/metal/boot.metal CHANGED
@@ -106,6 +106,8 @@ MetalParser {
106
106
  rule_name:r apply_args?:a {*
107
107
  if r == "super"
108
108
  Super.new(a)
109
+ elsif r == "self"
110
+ Self.new(a || [])
109
111
  else
110
112
  Apply.new(r, a || [])
111
113
  end *}
data/lib/metal/boot.rb CHANGED
@@ -87,7 +87,7 @@ end
87
87
  def rule_precode()
88
88
  act_token('@{')
89
89
  s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token('@')})
90
- rule_anything
90
+ act_any
91
91
  },
92
92
  lambda{act_token('@')
93
93
  act_not(lambda{act_token('}')})
@@ -222,6 +222,8 @@ a = act_may(lambda{apply(:apply_args)})
222
222
 
223
223
  if r == "super"
224
224
  Super.new(a)
225
+ elsif r == "self"
226
+ Self.new(a || [])
225
227
  else
226
228
  Apply.new(r, a || [])
227
229
  end
@@ -249,11 +251,11 @@ end
249
251
  def rule_action()
250
252
  act_token('{*')
251
253
  s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token('*')})
252
- rule_anything
254
+ act_any
253
255
  },
254
256
  lambda{act_token('*')
255
257
  act_not(lambda{act_token('}')})
256
- ''
258
+ '*'
257
259
  },
258
260
  ])
259
261
  })
@@ -263,11 +265,11 @@ end
263
265
  def rule_where()
264
266
  act_token('?{*')
265
267
  s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token('*')})
266
- rule_anything
268
+ act_any
267
269
  },
268
270
  lambda{act_token('*')
269
271
  act_not(lambda{act_token('}')})
270
- ''
272
+ '*'
271
273
  },
272
274
  ])
273
275
  })
@@ -275,24 +277,24 @@ act_token('*}')
275
277
  Where.new(s.join)
276
278
  end
277
279
  def rule_rule_name()
278
- x = rule_charset(%[a-z_])
279
- xs = act_many(lambda{rule_charset(%[a-zA-Z_0-9])})
280
+ x = act_charset(%[a-z_])
281
+ xs = act_many(lambda{act_charset(%[a-zA-Z_0-9])})
280
282
  ([x] + xs).join
281
283
  end
282
284
  def rule_var_name()
283
- x = rule_charset(%[a-z_])
284
- xs = act_many(lambda{rule_charset(%[a-zA-Z_0-9])})
285
+ x = act_charset(%[a-z_])
286
+ xs = act_many(lambda{act_charset(%[a-zA-Z_0-9])})
285
287
  ([x] + xs).join
286
288
  end
287
289
  def rule_grammar_name()
288
- x = rule_charset(%[A-Z])
289
- xs = act_many(lambda{rule_charset(%[a-zA-Z_0-9])})
290
+ x = act_charset(%[A-Z])
291
+ xs = act_many(lambda{act_charset(%[a-zA-Z_0-9])})
290
292
  ([x] + xs).join
291
293
  end
292
294
  def rule_dq_string()
293
295
  act_token('"')
294
296
  s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token('"')})
295
- rule_anything
297
+ act_any
296
298
  },
297
299
  lambda{act_token('\"')
298
300
  },
@@ -304,7 +306,7 @@ end
304
306
  def rule_q_string()
305
307
  act_token("'")
306
308
  s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token("'")})
307
- rule_anything
309
+ act_any
308
310
  },
309
311
  lambda{act_token("\\'")
310
312
  },
@@ -316,7 +318,7 @@ end
316
318
  def rule_charclass()
317
319
  act_token('[')
318
320
  s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token(']')})
319
- rule_anything
321
+ act_any
320
322
  },
321
323
  lambda{act_token('\]')
322
324
  },
@@ -328,7 +330,7 @@ end
328
330
  def rule_s()
329
331
  act_many(lambda{act_or([lambda{apply(:comment)
330
332
  },
331
- lambda{rule_charset(%[ \t\r\n])
333
+ lambda{act_charset(%[ \t\r\n])
332
334
  },
333
335
  ])
334
336
  })
@@ -336,7 +338,7 @@ end
336
338
  def rule_fs()
337
339
  act_many1(lambda{act_or([lambda{apply(:comment)
338
340
  },
339
- lambda{rule_charset(%[ \t\r\n])
341
+ lambda{act_charset(%[ \t\r\n])
340
342
  },
341
343
  ])
342
344
  })
@@ -344,7 +346,7 @@ end
344
346
  def rule_comment()
345
347
  act_token('#')
346
348
  act_many(lambda{act_not(lambda{act_token("\n")})
347
- rule_anything
349
+ act_any
348
350
  })
349
351
  act_token("\n")
350
352
  end
@@ -19,10 +19,22 @@
19
19
  module Metal
20
20
  module Generator
21
21
 
22
+ class Context
23
+ def initialize(out)
24
+ @out = out
25
+ @rule = nil
26
+ @grammar = nil
27
+ end
28
+ attr_reader :out
29
+ attr_accessor :rule
30
+ attr_accessor :grammar
31
+ end
32
+
22
33
  class Generator
23
- def generate(lang, buf = '')
24
- __send__("gen_#{lang}", buf)
25
- buf
34
+ def generate(lang, out = '')
35
+ ctx = Context.new(out)
36
+ __send__("gen_#{lang}", ctx)
37
+ ctx.out
26
38
  end
27
39
  end
28
40
 
@@ -30,9 +42,9 @@ module Metal
30
42
  def initialize(grammars)
31
43
  @grammars = grammars
32
44
  end
33
- def gen_ruby(buf)
45
+ def gen_ruby(ctx)
34
46
  @grammars.each {|r|
35
- r.gen_ruby(buf)
47
+ r.gen_ruby(ctx)
36
48
  }
37
49
  end
38
50
 
@@ -50,16 +62,17 @@ module Metal
50
62
  @interface = interface
51
63
  end
52
64
  attr_reader :name
53
- def gen_ruby(buf)
65
+ def gen_ruby(ctx)
66
+ ctx.grammar = @name
54
67
  if @interface
55
- buf << %[module #{@name}\n]
68
+ ctx.out << %[module #{@name}\n]
56
69
  else
57
- buf << %[class #{@name} < #{@base || "Metal::ParserBase"}\n]
70
+ ctx.out << %[class #{@name} < #{@base || "Metal::ParserBase"}\n]
58
71
  end
59
72
  @rules.each {|r|
60
- r.gen_ruby(buf)
73
+ r.gen_ruby(ctx)
61
74
  }
62
- buf << %[end\n]
75
+ ctx.out << %[end\n]
63
76
  end
64
77
 
65
78
  def [](name)
@@ -72,8 +85,8 @@ module Metal
72
85
  def initialize(code)
73
86
  @code = code
74
87
  end
75
- def gen_ruby(buf)
76
- buf << @code << "\n"
88
+ def gen_ruby(ctx)
89
+ ctx.out << @code << "\n"
77
90
  end
78
91
  end
79
92
 
@@ -81,8 +94,8 @@ module Metal
81
94
  def initialize(name)
82
95
  @name = name
83
96
  end
84
- def gen_ruby(buf)
85
- buf << "include #{@name}\n"
97
+ def gen_ruby(ctx)
98
+ ctx.out << "include #{@name}\n"
86
99
  end
87
100
  end
88
101
 
@@ -92,10 +105,11 @@ module Metal
92
105
  @or_set = or_set
93
106
  @args = args
94
107
  end
95
- def gen_ruby(buf)
96
- buf << %[def rule_#{@name}(#{@args.join(',')})\n]
97
- @or_set.gen_ruby(buf)
98
- buf << %[end\n]
108
+ def gen_ruby(ctx)
109
+ ctx.rule = @name
110
+ ctx.out << %[def rule_#{@name}(#{@args.join(',')})\n]
111
+ @or_set.gen_ruby(ctx)
112
+ ctx.out << %[end\n]
99
113
  end
100
114
  end
101
115
 
@@ -103,18 +117,18 @@ module Metal
103
117
  def initialize(and_set)
104
118
  @and_set = and_set
105
119
  end
106
- def gen_ruby(buf)
120
+ def gen_ruby(ctx)
107
121
  if @and_set.length == 1
108
122
  # OPTIMIZE
109
- @and_set[0].gen_ruby(buf)
123
+ @and_set[0].gen_ruby(ctx)
110
124
  elsif @and_set.length > 1
111
- buf << "act_or(["
125
+ ctx.out << "act_or(["
112
126
  @and_set.each {|r|
113
- buf << "lambda{"
114
- r.gen_ruby(buf)
115
- buf << "},\n"
127
+ ctx.out << "lambda{"
128
+ r.gen_ruby(ctx)
129
+ ctx.out << "},\n"
116
130
  }
117
- buf << "])\n"
131
+ ctx.out << "])\n"
118
132
  end
119
133
  end
120
134
  end
@@ -123,10 +137,10 @@ module Metal
123
137
  def initialize(exprs)
124
138
  @exprs = exprs
125
139
  end
126
- def gen_ruby(buf)
140
+ def gen_ruby(ctx)
127
141
  @exprs.each {|r|
128
- r.gen_ruby(buf)
129
- buf << "\n"
142
+ r.gen_ruby(ctx)
143
+ ctx.out << "\n"
130
144
  }
131
145
  end
132
146
  end
@@ -137,9 +151,9 @@ module Metal
137
151
  @var = var
138
152
  end
139
153
 
140
- def gen_ruby(buf)
141
- buf << "#{@var} = " if @var
142
- @pred.gen_ruby(buf)
154
+ def gen_ruby(ctx)
155
+ ctx.out << "#{@var} = " if @var
156
+ @pred.gen_ruby(ctx)
143
157
  end
144
158
  end
145
159
 
@@ -147,10 +161,10 @@ module Metal
147
161
  def initialize(pred)
148
162
  @pred = pred
149
163
  end
150
- def gen_ruby(buf)
151
- buf << "act_many(lambda{"
152
- @pred.gen_ruby(buf)
153
- buf << "})"
164
+ def gen_ruby(ctx)
165
+ ctx.out << "act_many(lambda{"
166
+ @pred.gen_ruby(ctx)
167
+ ctx.out << "})"
154
168
  end
155
169
  end
156
170
 
@@ -158,10 +172,10 @@ module Metal
158
172
  def initialize(pred)
159
173
  @pred = pred
160
174
  end
161
- def gen_ruby(buf)
162
- buf << "act_many1(lambda{"
163
- @pred.gen_ruby(buf)
164
- buf << "})"
175
+ def gen_ruby(ctx)
176
+ ctx.out << "act_many1(lambda{"
177
+ @pred.gen_ruby(ctx)
178
+ ctx.out << "})"
165
179
  end
166
180
  end
167
181
 
@@ -169,10 +183,10 @@ module Metal
169
183
  def initialize(pred)
170
184
  @pred = pred
171
185
  end
172
- def gen_ruby(buf)
173
- buf << "act_may(lambda{"
174
- @pred.gen_ruby(buf)
175
- buf << "})"
186
+ def gen_ruby(ctx)
187
+ ctx.out << "act_may(lambda{"
188
+ @pred.gen_ruby(ctx)
189
+ ctx.out << "})"
176
190
  end
177
191
  end
178
192
 
@@ -180,8 +194,8 @@ module Metal
180
194
  def initialize(action)
181
195
  @action = action
182
196
  end
183
- def gen_ruby(buf)
184
- buf << @action.to_s
197
+ def gen_ruby(ctx)
198
+ ctx.out << @action.to_s
185
199
  end
186
200
  end
187
201
 
@@ -189,8 +203,8 @@ module Metal
189
203
  def initialize(action)
190
204
  @action = action
191
205
  end
192
- def gen_ruby(buf)
193
- buf << "act_where(lambda{#{@action.to_s}})"
206
+ def gen_ruby(ctx)
207
+ ctx.out << "act_where(lambda{#{@action.to_s}})"
194
208
  end
195
209
  end
196
210
 
@@ -199,8 +213,8 @@ module Metal
199
213
  @name = name
200
214
  @vars = vars
201
215
  end
202
- def gen_ruby(buf)
203
- buf << "apply(:#{@name}#{@vars.map{|v|",#{v}"}})"
216
+ def gen_ruby(ctx)
217
+ ctx.out << "apply(:#{@name}#{@vars.map{|v|",#{v}"}})"
204
218
  end
205
219
  end
206
220
 
@@ -208,23 +222,34 @@ module Metal
208
222
  def initialize(vars)
209
223
  @vars = vars
210
224
  end
211
- def gen_ruby(buf)
225
+ def gen_ruby(ctx)
212
226
  if @vars == nil
213
- buf << "super"
227
+ ctx.out << "super"
214
228
  else
215
- buf << "super(#{@vars.join(',')})"
229
+ ctx.out << "super(#{@vars.join(',')})"
216
230
  end
217
231
  end
218
232
  end
219
233
 
234
+ class Self
235
+ def initialize(vars)
236
+ @vars = vars
237
+ end
238
+ def gen_ruby(ctx)
239
+ #name = "caller.find{|c|n = c.to_s.scan(/`rule_(.*)'/).flatten.first; break n if n}.to_sym"
240
+ name = ctx.rule
241
+ ctx.out << "apply(:#{name}#{@vars.map{|v|",#{v}"}})"
242
+ end
243
+ end
244
+
220
245
  class Other
221
246
  def initialize(grammar, rule, args)
222
247
  @grammar = grammar
223
248
  @rule = rule
224
249
  @args = args
225
250
  end
226
- def gen_ruby(buf)
227
- buf << "#{@grammar}.new(:#{@rule}).parse(@input#{@args.map{|v|",#{v}"}})"
251
+ def gen_ruby(ctx)
252
+ ctx.out << "#{@grammar}.new(:#{@rule}).parse(@input#{@args.map{|v|",#{v}"}})"
228
253
  end
229
254
  end
230
255
 
@@ -232,8 +257,8 @@ module Metal
232
257
  def initialize(str)
233
258
  @str = str
234
259
  end
235
- def gen_ruby(buf)
236
- buf << "act_token('#{@str}')"
260
+ def gen_ruby(ctx)
261
+ ctx.out << "act_token('#{@str}')"
237
262
  end
238
263
  end
239
264
 
@@ -241,8 +266,8 @@ module Metal
241
266
  def initialize(str)
242
267
  @str = str
243
268
  end
244
- def gen_ruby(buf)
245
- buf << "act_token(\"#{@str}\")"
269
+ def gen_ruby(ctx)
270
+ ctx.out << "act_token(\"#{@str}\")"
246
271
  end
247
272
  end
248
273
 
@@ -250,14 +275,14 @@ module Metal
250
275
  def initialize(set)
251
276
  @set = set
252
277
  end
253
- def gen_ruby(buf)
254
- buf << "rule_charset(%[#{@set}])"
278
+ def gen_ruby(ctx)
279
+ ctx.out << "act_charset(%[#{@set}])"
255
280
  end
256
281
  end
257
282
 
258
283
  class LiteralAny
259
- def gen_ruby(buf)
260
- buf << "rule_anything"
284
+ def gen_ruby(ctx)
285
+ ctx.out << "act_any"
261
286
  end
262
287
  end
263
288
 
@@ -265,10 +290,10 @@ module Metal
265
290
  def initialize(expr)
266
291
  @expr = expr
267
292
  end
268
- def gen_ruby(buf)
269
- buf << "act_not(lambda{"
270
- @expr.gen_ruby(buf)
271
- buf << "})"
293
+ def gen_ruby(ctx)
294
+ ctx.out << "act_not(lambda{"
295
+ @expr.gen_ruby(ctx)
296
+ ctx.out << "})"
272
297
  end
273
298
  end
274
299
 
@@ -276,10 +301,10 @@ module Metal
276
301
  def initialize(expr)
277
302
  @expr = expr
278
303
  end
279
- def gen_ruby(buf)
280
- buf << "act_lookahead(lambda{"
281
- @expr.gen_ruby(buf)
282
- buf << "})"
304
+ def gen_ruby(ctx)
305
+ ctx.out << "act_lookahead(lambda{"
306
+ @expr.gen_ruby(ctx)
307
+ ctx.out << "})"
283
308
  end
284
309
  end
285
310
 
data/lib/metal/runtime.rb CHANGED
@@ -17,397 +17,370 @@
17
17
  #
18
18
 
19
19
  module Metal
20
-
21
- class Input
22
- def initialize
23
- @marks = []
24
- @pos = 0
25
- @memo = {}
26
- @error = []
27
- end
28
- attr_reader :pos
29
- attr_reader :error
30
-
31
- def get_memo(name)
32
- @memo["#{@pos} #{name}"]
33
- end
34
-
35
- def set_memo(pos, name, rec)
36
- @memo["#{pos} #{name}"] = rec
37
- end
38
-
39
- def next
40
- val = self[@pos]
41
- raise EOFError, "unexpected EOF." unless val
42
- @pos += 1
43
- val
44
- end
45
-
46
- def prev
47
- @pos -= 1
48
- end
49
-
50
- def mark
51
- @marks.push @pos
52
- @marks.length-1
53
- end
54
-
55
- def unmark(mark)
56
- @marks[mark] = nil
57
- end
58
-
59
- def rewind(mark)
60
- @pos = @marks[mark]
61
- end
62
-
63
- def seek(pos)
64
- @pos = pos
65
- end
66
-
67
- def leaked_marks # FIXME
68
- @marks.compact.length
69
- end
70
-
71
- def inspect_at(index)
72
- "at #{index}"
73
- end
74
- end
75
-
76
-
77
- class StringInput < Input
78
- def initialize(source)
79
- @source = source.scan(/./m) # FIXME Ruby 1.9
80
- super()
81
- end
82
- def [](index)
83
- @source[index]
84
- end
85
- def inspect_at(pos)
86
- parsed = @source[0, pos].join.split("\n")
87
- line = parsed.length
88
- column = (line == 0 ? 0 : parsed.last.length)
89
- "at line #{line}, col #{column}"
20
+ class ParserBase
21
+ def initialize(root = :main)
22
+ @root = root
90
23
  end
91
- end
92
-
93
24
 
94
- class ParseError < RuntimeError
95
- def initialize(msg, input)
96
- super(msg)
97
- @pos = input.pos
98
- @error = input.error
99
- @input = input
25
+ def parse(source, *args)
26
+ parser = self.dup
27
+ parser.initialize_parser(source, *args)
28
+ parser.apply(@root)
100
29
  end
101
- attr_reader :pos
102
- attr_reader :error
103
30
 
104
- def message
105
- msg = super
106
- @error.each {|e|
107
- msg << "\n\t\t" << e.to_s
31
+ def initialize_parser(source, *args)
32
+ @input = case source
33
+ when IO
34
+ source.read.scan(/./m)
35
+ when String
36
+ source.scan(/./m)
37
+ when Array
38
+ source
39
+ else
40
+ source
41
+ end
42
+ @cache = Hash.new {|hash, key| hash[key] = {} }
43
+ @index = 0
44
+ @error_history = []
45
+ @call_stack = []
46
+ @label_stack = []
47
+ @current_rule = nil
48
+ input = @input
49
+ error_history = @error_history
50
+ @error_class = Class.new(ParseError) {
51
+ const_set(:INPUT, input)
52
+ const_set(:ERROR_HISTORY, error_history)
108
53
  }
109
- msg << "\n"
110
- end
111
- def to_s
112
- stdmsg(super)
113
54
  end
114
55
 
115
- private
116
- def stdmsg(msg)
117
- msg << " " << @input.inspect_at(@pos)
56
+ class ParseError < RuntimeError
57
+ def initialize(msg, index, call_stack)
58
+ super(msg)
59
+ @index = index
60
+ @call_stack = call_stack
61
+ end
62
+ attr_reader :index
63
+ def to_s
64
+ super.gsub("\n", "\n ")
65
+ end
66
+ def message(rec = false)
67
+ if rec
68
+ input = self.class::INPUT
69
+ parsed = input[0, @index].to_s.split("\n")
70
+ line = parsed.length
71
+ column = (line == 0 ? 0 : parsed.last.length)
72
+ help = input[@index, 10]
73
+ help = help.join if help.is_a?(Array)
74
+ help << '...' if help.length == 10
75
+ help.gsub!("\r", '\r')
76
+ help.gsub!("\n", '\n')
77
+ help.gsub!("\t", '\t')
78
+ help = "'#{help}'"
79
+ msg = " #{@call_stack.join('> ')}\n at line #{line}, column #{column} #{help.ljust(18)} #{super()}"
80
+ else
81
+ msg = "parse error:\n"
82
+ s = 0
83
+ self.class::ERROR_HISTORY.dup.push(self).sort_by{|e| [-e.index, s+=1] }.each_with_index {|(err,s), i|
84
+ #self.class::ERROR_HISTORY.dup.push(self).reverse.each_with_index {|err, i|
85
+ msg << "\n" << err.message(true)
86
+ if i > 5
87
+ msg << "\n ...\n"
88
+ break
89
+ end
90
+ }
91
+ end
92
+ msg
93
+ end
118
94
  end
119
- end
120
95
 
121
- class LeftRecursion
122
- def initialize
123
- @detected = false
96
+ class LeftRecursion
97
+ def initialize
98
+ @call_stack = nil
99
+ end
100
+ attr_accessor :call_stack
124
101
  end
125
- attr_accessor :detected
126
- end
127
102
 
128
- class Memo
129
- def initialize(ret, pos)
130
- @ret = ret
131
- @pos = pos
103
+ class Memo
104
+ def initialize(ret, pos)
105
+ @ret = ret
106
+ @pos = pos
107
+ end
108
+ attr_accessor :ret, :pos
132
109
  end
133
- attr_reader :ret
134
- attr_reader :pos
135
- end
136
110
 
137
- class ParserBase
138
- DEFAULT_ROOT = :main
139
-
140
- def initialize(root = nil)
141
- @root = root
142
- @me = 0 # FIXME
143
- end
144
- attr_accessor :root
111
+ def apply(rule, *args)
112
+ @current_rule = rule
113
+ @call_stack.push rule
145
114
 
146
- attr_accessor :me # FIXME
115
+ #p @label_stack.map {|l| l.join(':') }.join(',')
116
+ #cache_name = "#{rule}@#{@label_stack.map{|l|l.join(':')}.join(',')}"
117
+ cache_name = "#{rule}" # FIXME left recursion
118
+ # cache_name = "#{rule}@#{@label_stack.inspect}"
147
119
 
148
- def parse(source, *args)
149
- @input = case source
150
- when Input
151
- source
152
- when IO
153
- StringInput.new(source.read) #FIXME
154
- when String
155
- StringInput.new(source)
156
- else
157
- StringInput.new(source)
158
- end
159
- apply(@root || self.class::DEFAULT_ROOT, *args)
160
- end
161
- attr_reader :input
120
+ method_name = "rule_#{rule}"
162
121
 
163
- def apply(rule, *args)
164
- rule_method = "rule_#{rule}"
165
122
  unless args.empty?
166
- return __send__(rule_method, *args)
123
+ return __send__(method_name, *args)
167
124
  end
168
125
 
169
- memo_name = "#{self.class}.#{rule}"
170
- if memorized = @input.get_memo(memo_name)
171
- @me += 1 # FIXME
172
- # memorized rule
173
- if memorized.class == LeftRecursion
174
- memorized.detected = true
175
- raise ParseError.new("Left recursion detected", @input)
126
+ #labeled = nil
127
+ #if @label_stack.last
128
+ # labeled = true
129
+ #end
130
+ # if @label_stack.last && !@label_stack.last.shift
131
+ # @label_stack.pop
132
+ # #labeled = false
133
+ # end
134
+
135
+ #puts "#{rule}@#{@label_stack.inspect}: cache: #{@cache["#{rule}@#{@label_stack.inspect}"].inspect}"
136
+
137
+ if memo = @cache[cache_name][@index]
138
+ if memo.ret.class == LeftRecursion
139
+ memo.ret.call_stack = @call_stack[0..-1]
140
+ parse_error "left recursion"
176
141
  end
177
- @input.seek(memorized.pos)
178
- return memorized.ret
179
- end
180
-
181
- # non-memorized rule
182
- m = @input.mark
183
- begin
184
- save_pos = @input.pos
185
- lr = LeftRecursion.new
186
- @input.set_memo(save_pos, memo_name, lr)
187
- ret = __send__(rule_method)
188
- @input.set_memo(save_pos, memo_name, Memo.new(ret, @input.pos))
189
- rescue
190
- @input.unmark(m)
191
- raise $!
142
+ #puts "#{cache_name}: cached #{@index} to #{memo.pos} (#{memo.ret.inspect})"
143
+ @index = memo.pos
144
+ return memo.ret
145
+ else
146
+ #begin XXX
147
+ start_pos = @index
148
+ lr = LeftRecursion.new
149
+ memo = @cache[cache_name][start_pos] = Memo.new(lr, start_pos)
150
+ memo.ret = __send__(method_name)
151
+ memo.pos = @index
152
+ #puts "#{cache_name}: uncached #{start_pos} to #{@index} (#{memo.ret.inspect})"
153
+ #if labeled != nil
154
+ # cache_name = "#{rule}@#{@label_stack.inspect}"
155
+ # puts "ncn: #{cache_name} #{start_pos} -> #{memo.inspect}"
156
+ # memo = @cache[cache_name][start_pos] = Memo.new(memo.ret, memo.pos)
157
+ #end
158
+ if lr.call_stack
159
+ $stderr.puts "#{@call_stack.inspect}: left recursion" # FIXME left recursion
160
+ parse_error "left recursion" # FIXME left recursion
161
+ # #puts "#{cache_name}: lr start"
162
+ # finish_pos = @index
163
+ # #puts "#{cache_name}: detected on #{@index} from #{memo.pos}"
164
+ # #puts "#{cache_name}: rewind stack: #{lr.call_stack[@call_stack.length..-1].inspect}"
165
+ # @label_stack.push(lr.call_stack[@call_stack.length..-1])
166
+ # while true
167
+ # @index = start_pos
168
+ # memo.ret = __send__(method_name)
169
+ # #puts "#{cache_name}: recalled, moved to #{@index}"
170
+ # memo.pos = @index
171
+ # break if finish_pos <= @index
172
+ # #if finish_pos <= @index
173
+ # # p "lr growed #{cache_name} #{start_pos} to #{@index} #{memo.ret.inspect}"
174
+ # # #p memo
175
+ # # #p @cache[cache_name][start_pos]
176
+ # # #nmemo = @cache[cache_name][start_pos]
177
+ # # #if nmemo && memo.pos <= nmemo.pos
178
+ # # # @index = nmemo.pos
179
+ # # # memo = nmemo
180
+ # # #end
181
+ # # #break
182
+ # # nmemo = @cache[cache_name][start_pos]
183
+ # # if nmemo && memo.pos <= nmemo.pos
184
+ # # memo = nmemo
185
+ # # @index = memo.pos
186
+ # # end
187
+ # # #begin
188
+ # # # @index = start_pos
189
+ # # # p "JKJK"
190
+ # # # ret = __send__(method_name)
191
+ # # # if memo.pos <= @index
192
+ # # # memo.ret = ret
193
+ # # # memo.pos = @index
194
+ # # # end
195
+ # # #rescue
196
+ # # # break
197
+ # # # p $!
198
+ # # #end
199
+ # # break
200
+ # #end
201
+ # end
202
+ # #puts "#{cache_name}: lr end #{start_pos} -> #{@index}"
203
+ end
204
+ memo.ret
205
+ #rescue ParseError # XXX
206
+ # @cache[cache_name][@index] = nil
207
+ # raise
208
+ #end
192
209
  end
193
210
 
194
- if lr.detected
195
- sentinel = @input.pos
196
- @input.rewind(m)
197
- while true
198
- n = @input.mark
199
- begin
200
- ret = __send__(rule_method)
201
- break if @input.pos == sentinel
202
- memorized = @input.set_memo(save_pos, memo_name, Memo.new(ret, @input.pos))
203
- @input.rewind(n)
204
- rescue ParseError
205
- @input.unmark(n)
206
- break
207
- end
208
- end
211
+ #rescue
212
+ # if $!.to_s == '"k" is expected'
213
+ # require 'pp'
214
+ # pp caller
215
+ # end
216
+ # raise
217
+ ensure
218
+ @call_stack.pop
219
+ end
209
220
 
210
- else
211
- @input.unmark(m)
212
- end
221
+ def act_or_message(err)
222
+ msg = "One of following expressions expected:"
223
+ err.each {|e| msg << "\n " << e.to_s }
224
+ msg
225
+ end
226
+ private :act_or_message
213
227
 
214
- ret
228
+ def act_or(blocks)
229
+ err = []
230
+ pos = @index
231
+ blocks.each {|block|
232
+ begin
233
+ ret = block.call
234
+ @error_history.concat err
235
+ return ret
236
+ rescue ParseError
237
+ @index = pos
238
+ err.push $!
239
+ end
240
+ }
241
+ parse_error act_or_message(err)
215
242
  end
216
243
 
217
- def act_many(block, *rets)
218
- @input.error.clear
244
+ def act_many(block)
245
+ ret = []
219
246
  while true
220
- m = @input.mark
247
+ pos = @index
221
248
  begin
222
- rets.push block.call
249
+ ret.push block.call
250
+ return ret if pos == @index # XXX many in many avoidance
223
251
  rescue ParseError
224
- @input.error.push $!
225
- @input.rewind(m)
226
- break
227
- ensure
228
- @input.unmark(m)
252
+ @index = pos
253
+ @error_history.push $!
254
+ return ret
229
255
  end
230
256
  end
231
- rets
232
257
  end
233
258
 
234
- def act_many1(block, *rets)
235
- rets.push block.call
236
- act_many(block, *rets)
259
+ def act_many1(block)
260
+ ret = []
261
+ while true
262
+ pos = @index
263
+ begin
264
+ ret.push block.call
265
+ return ret if pos == @index # XXX many in many avoidance
266
+ rescue ParseError
267
+ @index = pos
268
+ raise if ret.empty?
269
+ @error_history.push $!
270
+ return ret
271
+ end
272
+ end
237
273
  end
238
274
 
239
275
  def act_may(block)
240
- m = @input.mark
241
- rets = nil
242
- @input.error.clear
276
+ pos = @index
243
277
  begin
244
- rets = block.call
278
+ block.call
245
279
  rescue ParseError
246
- @input.error.push $!
247
- @input.rewind(m)
248
- ensure
249
- @input.unmark(m)
280
+ @index = pos
281
+ @error_history.push $!
282
+ nil
250
283
  end
251
- rets
252
284
  end
253
285
 
254
- def act_or(blocks)
255
- ex = []
256
- blocks.each {|block|
257
- m = @input.mark
258
- begin
259
- ret = block.call
260
- return ret
261
- rescue ParseError
262
- ex.push $!
263
- @input.rewind(m)
264
- ensure
265
- @input.unmark(m)
266
- end
267
- }
268
- msg = "All expression failed:"
269
- ex.each {|e| msg << "\n\t\t\t" << e.to_s }
270
- raise ParseError.new(msg, @input)
271
- end
272
286
 
273
287
  def act_not(block)
274
- m = @input.mark
275
- unless begin
276
- block.call
277
- nil
278
- rescue ParseError
279
- true
280
- ensure
281
- @input.rewind(m)
282
- @input.unmark(m)
283
- end
284
- raise ParseError.new("unexpectedly succeeded", @input)
288
+ pos = @index
289
+ unless begin
290
+ block.call
291
+ nil
292
+ rescue ParseError
293
+ true
294
+ ensure
295
+ @index = pos
296
+ end
297
+ parse_error "not prediction failed"
285
298
  end
286
299
  end
287
300
 
288
301
  def act_lookahead(block)
289
- m = @input.mark
302
+ pos = @index
290
303
  begin
291
- block.call # FIXME
304
+ block.call
292
305
  ensure
293
- @input.rewind(m)
294
- @input.unmark(m)
306
+ @index = pos
295
307
  end
296
308
  end
297
309
 
298
310
  def act_where(block)
299
311
  unless block.call
300
- raise ParseError.new("where block failed", @input)
312
+ parse_error "where prediction failed"
301
313
  end
302
314
  end
303
315
 
304
- def act_exactly(wanted)
305
- m = @input.mark
306
- begin
307
- val = @input.next
308
- unless val == wanted
309
- @input.rewind(m)
310
- raise ParseError.new("#{wanted.inspect} is expected", @input)
311
- end
312
- val
313
- rescue EOFError
314
- @input.rewind(m)
315
- raise ParseError.new("#{wanted.inspect} is expected but EOF comes", @input)
316
- ensure
317
- @input.unmark(m)
316
+ def act_any
317
+ next_char
318
+ end
319
+
320
+ def act_char(c)
321
+ pos = @index
322
+ n = next_char
323
+ unless c == n
324
+ @index = pos
325
+ parse_error "#{c.inspect} is expected"
326
+ end
327
+ n
328
+ end
329
+
330
+ def act_charset(set)
331
+ pos = @index
332
+ n = next_char
333
+ if n.count(set) == 0
334
+ @index = pos
335
+ parse_error "character set [#{set.inspect[1..-2]}] is expected"
318
336
  end
337
+ n
319
338
  end
320
339
 
321
340
  def act_token(str)
322
- return act_exactly(str) if str.length == 1
323
- m = @input.mark
341
+ pos = @index
324
342
  begin
325
- str.scan(/./m) {|c| # FIXME Ruby 1.9
326
- act_exactly(c)
343
+ str.scan(/./m) {|c|
344
+ act_char(c)
327
345
  }
328
346
  str
329
347
  rescue ParseError
330
- @input.rewind(m)
331
- raise ParseError.new("#{str.inspect} is expected", @input)
332
- ensure
333
- @input.unmark(m)
348
+ @index = pos
349
+ parse_error "#{str.inspect} is expected"
334
350
  end
335
351
  end
336
352
 
337
- def rule_anything
338
- @input.next
339
- rescue EOFError
340
- raise ParseError.new($!.to_s, @input)
341
- end
342
-
343
353
  def rule_end
344
- m = @input.mark
345
- begin
346
- @input.next
347
- raise ParseError.new("EOF expected", @input)
348
- rescue EOFError
349
- nil
350
- ensure
351
- @input.rewind(m)
352
- @input.unmark(m)
353
- end
354
- end
355
-
356
- def rule_charset(set)
357
- x = @input.next
358
- if x.count(set) == 0
359
- @input.prev
360
- raise ParseError.new("one of character in #{set.inspect} expected", @input)
354
+ if begin
355
+ c = next_char
356
+ @index -= 1
357
+ true
358
+ rescue
359
+ nil
360
+ end
361
+ parse_error "unexpected character '#{c}', EOF expected"
361
362
  end
362
- x
363
- rescue EOFError
364
- raise ParseError.new($!.to_s, @input)
365
- end
366
-
367
- def rule_empty
368
- nil
369
- end
370
-
371
- =begin
372
- def rule_letter
373
- rule_charset("a-zA-Z")
374
- end
375
-
376
- def rule_digit
377
- rule_charset("0-9")
378
- end
379
-
380
- def rule_letter_or_digit
381
- rule_charset("a-zA-Z0-9")
382
363
  end
383
364
 
384
- def rule_space
385
- rule_charset(" \t\r\n")
365
+ protected
366
+ def error(msg)
367
+ parse_error(msg)
386
368
  end
387
369
 
388
- def rule_spaces
389
- while @input.next.count(" \t\r\n") != 0
390
- true
370
+ private
371
+ def next_char
372
+ unless c = @input[@index]
373
+ parse_error "Unexpected end of input"
391
374
  end
375
+ @index += 1
376
+ c
392
377
  end
393
- =end
394
378
 
395
- protected
396
- def error(msg)
397
- raise ParseError.new(msg, @input)
379
+ def parse_error(msg)
380
+ raise @error_class.new(msg, @index, @call_stack.dup)
398
381
  end
399
382
 
400
383
  end
401
384
  end
402
385
 
403
- EXTEND_GRAMMER = <<EOF
404
- MetaUtility {
405
- -letter
406
- <charset "a-zA-Z">
407
- }
408
- EOF
409
-
410
-
411
-
412
-
413
386
 
data/lib/metal/version.rb CHANGED
@@ -2,7 +2,7 @@ module Metal
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- TINY = 1
5
+ TINY = 2
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - FURUHASHI Sadayuki
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-06-30 00:00:00 +09:00
12
+ date: 2008-07-24 00:00:00 +09:00
13
13
  default_executable:
14
14
  dependencies: []
15
15