metal 0.0.2 → 0.0.3
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/Manifest.txt +14 -1
- data/bin/metal +63 -16
- data/bin/metal-run +16 -13
- data/config/hoe.rb +4 -2
- data/ext/metal/boot/metal_boot.h +32 -0
- data/{lib/metal/boot.metal → ext/metal/boot/metal_boot.metal} +40 -53
- data/ext/metal/boot/metal_boot.mm +1294 -0
- data/ext/metal/boot/metal_boot_extconf.rb +16 -0
- data/ext/metal/boot/metal_boot_rb.mm +20 -0
- data/ext/metal/runtime/extconf.rb +35 -0
- data/ext/metal/runtime/input.mm +99 -0
- data/ext/metal/runtime/rbinit.mm +17 -0
- data/ext/metal/runtime/runtime.mm +660 -0
- data/include/metal.h +4 -0
- data/include/metal/exception.h +15 -0
- data/include/metal/input.h +42 -0
- data/include/metal/rbcode.h +24 -0
- data/include/metal/runtime.h +97 -0
- data/lib/metal/boot.rb +1 -353
- data/lib/metal/generator.rb +313 -203
- data/lib/metal/runtime.rb +1 -386
- data/lib/metal/version.rb +1 -1
- metadata +32 -8
data/lib/metal/runtime.rb
CHANGED
|
@@ -1,386 +1 @@
|
|
|
1
|
-
|
|
2
|
-
# Metal Runtime
|
|
3
|
-
#
|
|
4
|
-
# Copyright (C) 2008 FURUHASHI Sadayuki
|
|
5
|
-
#
|
|
6
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
-
# you may not use this file except in compliance with the License.
|
|
8
|
-
# You may obtain a copy of the License at
|
|
9
|
-
#
|
|
10
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
-
#
|
|
12
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
-
# See the License for the specific language governing permissions and
|
|
16
|
-
# limitations under the License.
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
module Metal
|
|
20
|
-
class ParserBase
|
|
21
|
-
def initialize(root = :main)
|
|
22
|
-
@root = root
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def parse(source, *args)
|
|
26
|
-
parser = self.dup
|
|
27
|
-
parser.initialize_parser(source, *args)
|
|
28
|
-
parser.apply(@root)
|
|
29
|
-
end
|
|
30
|
-
|
|
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)
|
|
53
|
-
}
|
|
54
|
-
end
|
|
55
|
-
|
|
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
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
class LeftRecursion
|
|
97
|
-
def initialize
|
|
98
|
-
@call_stack = nil
|
|
99
|
-
end
|
|
100
|
-
attr_accessor :call_stack
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
class Memo
|
|
104
|
-
def initialize(ret, pos)
|
|
105
|
-
@ret = ret
|
|
106
|
-
@pos = pos
|
|
107
|
-
end
|
|
108
|
-
attr_accessor :ret, :pos
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def apply(rule, *args)
|
|
112
|
-
@current_rule = rule
|
|
113
|
-
@call_stack.push rule
|
|
114
|
-
|
|
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}"
|
|
119
|
-
|
|
120
|
-
method_name = "rule_#{rule}"
|
|
121
|
-
|
|
122
|
-
unless args.empty?
|
|
123
|
-
return __send__(method_name, *args)
|
|
124
|
-
end
|
|
125
|
-
|
|
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"
|
|
141
|
-
end
|
|
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
|
|
209
|
-
end
|
|
210
|
-
|
|
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
|
|
220
|
-
|
|
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
|
|
227
|
-
|
|
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)
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
def act_many(block)
|
|
245
|
-
ret = []
|
|
246
|
-
while true
|
|
247
|
-
pos = @index
|
|
248
|
-
begin
|
|
249
|
-
ret.push block.call
|
|
250
|
-
return ret if pos == @index # XXX many in many avoidance
|
|
251
|
-
rescue ParseError
|
|
252
|
-
@index = pos
|
|
253
|
-
@error_history.push $!
|
|
254
|
-
return ret
|
|
255
|
-
end
|
|
256
|
-
end
|
|
257
|
-
end
|
|
258
|
-
|
|
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
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def act_may(block)
|
|
276
|
-
pos = @index
|
|
277
|
-
begin
|
|
278
|
-
block.call
|
|
279
|
-
rescue ParseError
|
|
280
|
-
@index = pos
|
|
281
|
-
@error_history.push $!
|
|
282
|
-
nil
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
def act_not(block)
|
|
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"
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
def act_lookahead(block)
|
|
302
|
-
pos = @index
|
|
303
|
-
begin
|
|
304
|
-
block.call
|
|
305
|
-
ensure
|
|
306
|
-
@index = pos
|
|
307
|
-
end
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
def act_where(block)
|
|
311
|
-
unless block.call
|
|
312
|
-
parse_error "where prediction failed"
|
|
313
|
-
end
|
|
314
|
-
end
|
|
315
|
-
|
|
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"
|
|
336
|
-
end
|
|
337
|
-
n
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
def act_token(str)
|
|
341
|
-
pos = @index
|
|
342
|
-
begin
|
|
343
|
-
str.scan(/./m) {|c|
|
|
344
|
-
act_char(c)
|
|
345
|
-
}
|
|
346
|
-
str
|
|
347
|
-
rescue ParseError
|
|
348
|
-
@index = pos
|
|
349
|
-
parse_error "#{str.inspect} is expected"
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
def rule_end
|
|
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"
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
protected
|
|
366
|
-
def error(msg)
|
|
367
|
-
parse_error(msg)
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
private
|
|
371
|
-
def next_char
|
|
372
|
-
unless c = @input[@index]
|
|
373
|
-
parse_error "Unexpected end of input"
|
|
374
|
-
end
|
|
375
|
-
@index += 1
|
|
376
|
-
c
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
def parse_error(msg)
|
|
380
|
-
raise @error_class.new(msg, @index, @call_stack.dup)
|
|
381
|
-
end
|
|
382
|
-
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
|
|
1
|
+
require 'metal_runtime'
|
data/lib/metal/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- FURUHASHI Sadayuki
|
|
@@ -9,18 +9,28 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2008-
|
|
12
|
+
date: 2008-08-06 00:00:00 +09:00
|
|
13
13
|
default_executable:
|
|
14
|
-
dependencies:
|
|
15
|
-
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: hoe
|
|
17
|
+
type: :development
|
|
18
|
+
version_requirement:
|
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: 1.7.0
|
|
24
|
+
version:
|
|
16
25
|
description: An object-oriented parser generator based on Parser Expression Grammar
|
|
17
26
|
email:
|
|
18
27
|
- fr _at_ syuki.skr.jp
|
|
19
28
|
executables:
|
|
20
29
|
- metal
|
|
21
30
|
- metal-run
|
|
22
|
-
extensions:
|
|
23
|
-
|
|
31
|
+
extensions:
|
|
32
|
+
- ext/metal/runtime/extconf.rb
|
|
33
|
+
- ext/metal/boot/metal_boot_extconf.rb
|
|
24
34
|
extra_rdoc_files:
|
|
25
35
|
- License.txt
|
|
26
36
|
- Manifest.txt
|
|
@@ -34,8 +44,21 @@ files:
|
|
|
34
44
|
- bin/metal-run
|
|
35
45
|
- config/hoe.rb
|
|
36
46
|
- config/requirements.rb
|
|
47
|
+
- ext/metal/boot/metal_boot.h
|
|
48
|
+
- ext/metal/boot/metal_boot.metal
|
|
49
|
+
- ext/metal/boot/metal_boot.mm
|
|
50
|
+
- ext/metal/boot/metal_boot_extconf.rb
|
|
51
|
+
- ext/metal/boot/metal_boot_rb.mm
|
|
52
|
+
- ext/metal/runtime/extconf.rb
|
|
53
|
+
- ext/metal/runtime/input.mm
|
|
54
|
+
- ext/metal/runtime/rbinit.mm
|
|
55
|
+
- ext/metal/runtime/runtime.mm
|
|
56
|
+
- include/metal.h
|
|
57
|
+
- include/metal/exception.h
|
|
58
|
+
- include/metal/input.h
|
|
59
|
+
- include/metal/rbcode.h
|
|
60
|
+
- include/metal/runtime.h
|
|
37
61
|
- lib/metal.rb
|
|
38
|
-
- lib/metal/boot.metal
|
|
39
62
|
- lib/metal/boot.rb
|
|
40
63
|
- lib/metal/generator.rb
|
|
41
64
|
- lib/metal/runtime.rb
|
|
@@ -56,6 +79,7 @@ rdoc_options:
|
|
|
56
79
|
- README.txt
|
|
57
80
|
require_paths:
|
|
58
81
|
- lib
|
|
82
|
+
- ext
|
|
59
83
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
84
|
requirements:
|
|
61
85
|
- - ">="
|
|
@@ -71,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
71
95
|
requirements: []
|
|
72
96
|
|
|
73
97
|
rubyforge_project: metal
|
|
74
|
-
rubygems_version: 1.
|
|
98
|
+
rubygems_version: 1.2.0
|
|
75
99
|
signing_key:
|
|
76
100
|
specification_version: 2
|
|
77
101
|
summary: An object-oriented parser generator based on Parser Expression Grammar
|