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 +3 -0
- data/bin/metal-run +1 -1
- data/lib/metal/boot.metal +2 -0
- data/lib/metal/boot.rb +19 -17
- data/lib/metal/generator.rb +95 -70
- data/lib/metal/runtime.rb +284 -311
- data/lib/metal/version.rb +1 -1
- metadata +2 -2
data/bin/metal
CHANGED
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?(
|
|
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
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
279
|
-
xs = act_many(lambda{
|
|
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 =
|
|
284
|
-
xs = act_many(lambda{
|
|
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 =
|
|
289
|
-
xs = act_many(lambda{
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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{
|
|
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{
|
|
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
|
-
|
|
349
|
+
act_any
|
|
348
350
|
})
|
|
349
351
|
act_token("\n")
|
|
350
352
|
end
|
data/lib/metal/generator.rb
CHANGED
|
@@ -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,
|
|
24
|
-
|
|
25
|
-
|
|
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(
|
|
45
|
+
def gen_ruby(ctx)
|
|
34
46
|
@grammars.each {|r|
|
|
35
|
-
r.gen_ruby(
|
|
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(
|
|
65
|
+
def gen_ruby(ctx)
|
|
66
|
+
ctx.grammar = @name
|
|
54
67
|
if @interface
|
|
55
|
-
|
|
68
|
+
ctx.out << %[module #{@name}\n]
|
|
56
69
|
else
|
|
57
|
-
|
|
70
|
+
ctx.out << %[class #{@name} < #{@base || "Metal::ParserBase"}\n]
|
|
58
71
|
end
|
|
59
72
|
@rules.each {|r|
|
|
60
|
-
r.gen_ruby(
|
|
73
|
+
r.gen_ruby(ctx)
|
|
61
74
|
}
|
|
62
|
-
|
|
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(
|
|
76
|
-
|
|
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(
|
|
85
|
-
|
|
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(
|
|
96
|
-
|
|
97
|
-
@
|
|
98
|
-
|
|
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(
|
|
120
|
+
def gen_ruby(ctx)
|
|
107
121
|
if @and_set.length == 1
|
|
108
122
|
# OPTIMIZE
|
|
109
|
-
@and_set[0].gen_ruby(
|
|
123
|
+
@and_set[0].gen_ruby(ctx)
|
|
110
124
|
elsif @and_set.length > 1
|
|
111
|
-
|
|
125
|
+
ctx.out << "act_or(["
|
|
112
126
|
@and_set.each {|r|
|
|
113
|
-
|
|
114
|
-
r.gen_ruby(
|
|
115
|
-
|
|
127
|
+
ctx.out << "lambda{"
|
|
128
|
+
r.gen_ruby(ctx)
|
|
129
|
+
ctx.out << "},\n"
|
|
116
130
|
}
|
|
117
|
-
|
|
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(
|
|
140
|
+
def gen_ruby(ctx)
|
|
127
141
|
@exprs.each {|r|
|
|
128
|
-
r.gen_ruby(
|
|
129
|
-
|
|
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(
|
|
141
|
-
|
|
142
|
-
@pred.gen_ruby(
|
|
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(
|
|
151
|
-
|
|
152
|
-
@pred.gen_ruby(
|
|
153
|
-
|
|
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(
|
|
162
|
-
|
|
163
|
-
@pred.gen_ruby(
|
|
164
|
-
|
|
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(
|
|
173
|
-
|
|
174
|
-
@pred.gen_ruby(
|
|
175
|
-
|
|
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(
|
|
184
|
-
|
|
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(
|
|
193
|
-
|
|
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(
|
|
203
|
-
|
|
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(
|
|
225
|
+
def gen_ruby(ctx)
|
|
212
226
|
if @vars == nil
|
|
213
|
-
|
|
227
|
+
ctx.out << "super"
|
|
214
228
|
else
|
|
215
|
-
|
|
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(
|
|
227
|
-
|
|
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(
|
|
236
|
-
|
|
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(
|
|
245
|
-
|
|
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(
|
|
254
|
-
|
|
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(
|
|
260
|
-
|
|
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(
|
|
269
|
-
|
|
270
|
-
@expr.gen_ruby(
|
|
271
|
-
|
|
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(
|
|
280
|
-
|
|
281
|
-
@expr.gen_ruby(
|
|
282
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
@
|
|
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
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
138
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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__(
|
|
123
|
+
return __send__(method_name, *args)
|
|
167
124
|
end
|
|
168
125
|
|
|
169
|
-
|
|
170
|
-
if
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
@
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
|
|
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
|
|
218
|
-
|
|
244
|
+
def act_many(block)
|
|
245
|
+
ret = []
|
|
219
246
|
while true
|
|
220
|
-
|
|
247
|
+
pos = @index
|
|
221
248
|
begin
|
|
222
|
-
|
|
249
|
+
ret.push block.call
|
|
250
|
+
return ret if pos == @index # XXX many in many avoidance
|
|
223
251
|
rescue ParseError
|
|
224
|
-
@
|
|
225
|
-
@
|
|
226
|
-
|
|
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
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
241
|
-
rets = nil
|
|
242
|
-
@input.error.clear
|
|
276
|
+
pos = @index
|
|
243
277
|
begin
|
|
244
|
-
|
|
278
|
+
block.call
|
|
245
279
|
rescue ParseError
|
|
246
|
-
@
|
|
247
|
-
@
|
|
248
|
-
|
|
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
|
-
|
|
275
|
-
unless
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
302
|
+
pos = @index
|
|
290
303
|
begin
|
|
291
|
-
block.call
|
|
304
|
+
block.call
|
|
292
305
|
ensure
|
|
293
|
-
@
|
|
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
|
-
|
|
312
|
+
parse_error "where prediction failed"
|
|
301
313
|
end
|
|
302
314
|
end
|
|
303
315
|
|
|
304
|
-
def
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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
|
-
|
|
323
|
-
m = @input.mark
|
|
341
|
+
pos = @index
|
|
324
342
|
begin
|
|
325
|
-
str.scan(/./m) {|c|
|
|
326
|
-
|
|
343
|
+
str.scan(/./m) {|c|
|
|
344
|
+
act_char(c)
|
|
327
345
|
}
|
|
328
346
|
str
|
|
329
347
|
rescue ParseError
|
|
330
|
-
@
|
|
331
|
-
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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
|
-
|
|
385
|
-
|
|
365
|
+
protected
|
|
366
|
+
def error(msg)
|
|
367
|
+
parse_error(msg)
|
|
386
368
|
end
|
|
387
369
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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
|
-
|
|
396
|
-
|
|
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
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.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-
|
|
12
|
+
date: 2008-07-24 00:00:00 +09:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies: []
|
|
15
15
|
|