pegparse 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +13 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +21 -0
- data/README.md +133 -0
- data/Rakefile +16 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/pegparse/biop_rule_chain.rb +113 -0
- data/lib/pegparse/borrowed_areas.rb +35 -0
- data/lib/pegparse/line_counter.rb +61 -0
- data/lib/pegparse/parser_base.rb +139 -0
- data/lib/pegparse/parser_context.rb +19 -0
- data/lib/pegparse/parser_core.rb +243 -0
- data/lib/pegparse/parser_errors.rb +97 -0
- data/lib/pegparse/version.rb +5 -0
- data/lib/pegparse.rb +9 -0
- data/pegparse.gemspec +37 -0
- data/samples/bsh_parser.rb +337 -0
- data/samples/calc_parser.rb +55 -0
- data/samples/json_parser.rb +92 -0
- data/samples/xml_parser.rb +182 -0
- metadata +67 -0
@@ -0,0 +1,337 @@
|
|
1
|
+
require_relative '../lib/pegparse'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Pegparse::Sample
|
5
|
+
end
|
6
|
+
|
7
|
+
class Pegparse::Sample::BshParser < Pegparse::ParserBase
|
8
|
+
def initialize(context_or_scanner)
|
9
|
+
super(context_or_scanner)
|
10
|
+
self.start_rule_symbol = :start_rule
|
11
|
+
end
|
12
|
+
|
13
|
+
def line_comment
|
14
|
+
read(/#.*/)
|
15
|
+
end
|
16
|
+
|
17
|
+
def inline_sp
|
18
|
+
read(/( |\\\n)*/)
|
19
|
+
end
|
20
|
+
|
21
|
+
def lf
|
22
|
+
choice(
|
23
|
+
->{ super() },
|
24
|
+
->{
|
25
|
+
sp()
|
26
|
+
read(';')
|
27
|
+
},
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def keyword(key)
|
32
|
+
read(key)
|
33
|
+
backtrack if peek(/[A-Za-z0-9_]/)
|
34
|
+
end
|
35
|
+
|
36
|
+
def start_rule
|
37
|
+
ret = pipelines()
|
38
|
+
sp()
|
39
|
+
ret
|
40
|
+
end
|
41
|
+
|
42
|
+
def pipelines
|
43
|
+
zero_or_more {
|
44
|
+
sp()
|
45
|
+
pipeline()
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
BshBiopParser = Pegparse::BiopRuleChain.based_on(self) do
|
50
|
+
def operator_sp
|
51
|
+
inline_sp()
|
52
|
+
end
|
53
|
+
|
54
|
+
def operand_sp
|
55
|
+
inline_sp()
|
56
|
+
end
|
57
|
+
end
|
58
|
+
rule def pipeline
|
59
|
+
biop_parser = BshBiopParser.new(nil)
|
60
|
+
biop_parser
|
61
|
+
.left_op(['&&', '||'])
|
62
|
+
.left_op('|')
|
63
|
+
.term(->{ sentence() })
|
64
|
+
ret = biop_parser.parse(@context)
|
65
|
+
|
66
|
+
pipeline_closer = optional{
|
67
|
+
inline_sp()
|
68
|
+
read(/[&;]/)
|
69
|
+
}
|
70
|
+
if pipeline_closer == '&'
|
71
|
+
[:bg, ret]
|
72
|
+
else
|
73
|
+
ret
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
rule def sentence
|
78
|
+
choice(
|
79
|
+
->{ if_sentence() },
|
80
|
+
->{ while_sentence() },
|
81
|
+
->{ for_sentence() },
|
82
|
+
->{ case_sentence() },
|
83
|
+
->{ command_sentence() },
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
rule def if_sentence
|
88
|
+
keyword('if')
|
89
|
+
sp()
|
90
|
+
cond = pipeline()
|
91
|
+
sp()
|
92
|
+
keyword('then')
|
93
|
+
sp()
|
94
|
+
if_body = pipelines()
|
95
|
+
elif_cond_bodies = zero_or_more {
|
96
|
+
sp()
|
97
|
+
keyword('elif')
|
98
|
+
sp()
|
99
|
+
elif_cond = pipeline()
|
100
|
+
sp()
|
101
|
+
keyword('then')
|
102
|
+
sp()
|
103
|
+
elif_body = pipelines()
|
104
|
+
[elif_cond, elif_body]
|
105
|
+
}
|
106
|
+
else_body = optional{
|
107
|
+
sp()
|
108
|
+
keyword('else')
|
109
|
+
sp()
|
110
|
+
pipelines()
|
111
|
+
}
|
112
|
+
sp()
|
113
|
+
keyword('fi')
|
114
|
+
if else_body
|
115
|
+
[:if, [cond, if_body], *elif_cond_bodies, [nil, else_body]]
|
116
|
+
else
|
117
|
+
[:if, [cond, if_body], *elif_cond_bodies]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
rule def while_sentence
|
122
|
+
keyword('while')
|
123
|
+
sp()
|
124
|
+
backtrack
|
125
|
+
end
|
126
|
+
|
127
|
+
rule def for_sentence
|
128
|
+
keyword('for')
|
129
|
+
sp()
|
130
|
+
var = assign_varname()
|
131
|
+
sp()
|
132
|
+
keyword('in')
|
133
|
+
list = zero_or_more {
|
134
|
+
inline_sp()
|
135
|
+
normal_operand()
|
136
|
+
}
|
137
|
+
lf()
|
138
|
+
sp()
|
139
|
+
keyword('do')
|
140
|
+
body = pipelines()
|
141
|
+
keyword('done')
|
142
|
+
[:for, var, list, body]
|
143
|
+
end
|
144
|
+
|
145
|
+
rule def case_sentence
|
146
|
+
keyword('case')
|
147
|
+
sp()
|
148
|
+
backtrack
|
149
|
+
end
|
150
|
+
|
151
|
+
rule def command_sentence
|
152
|
+
envs = zero_or_more {
|
153
|
+
inline_sp()
|
154
|
+
assign_exp()
|
155
|
+
}
|
156
|
+
main = optional{
|
157
|
+
inline_sp()
|
158
|
+
cmd = execute_target_exp()
|
159
|
+
|
160
|
+
operands = zero_or_more {
|
161
|
+
inline_sp()
|
162
|
+
choice(
|
163
|
+
->{ redirect_operand() },
|
164
|
+
->{ normal_operand() }
|
165
|
+
)
|
166
|
+
}
|
167
|
+
|
168
|
+
redirects, normals = operands.partition{|op| op[0] == :redirect}
|
169
|
+
[cmd, redirects, operands]
|
170
|
+
}
|
171
|
+
backtrack if envs.empty? && !main
|
172
|
+
|
173
|
+
main ? [:command, envs, main[1], main[0], *main[2]] : [:env, envs]
|
174
|
+
end
|
175
|
+
|
176
|
+
rule def assign_exp
|
177
|
+
varname = assign_varname()
|
178
|
+
read('=')
|
179
|
+
val = assign_value()
|
180
|
+
['=', varname, val]
|
181
|
+
end
|
182
|
+
|
183
|
+
def assign_varname
|
184
|
+
read(/[A-Za-z][A-Za-z0-9_]*/)
|
185
|
+
end
|
186
|
+
|
187
|
+
def assign_value
|
188
|
+
normal_operand()
|
189
|
+
end
|
190
|
+
|
191
|
+
def execute_target_exp
|
192
|
+
normal_operand()
|
193
|
+
end
|
194
|
+
|
195
|
+
rule def redirect_operand
|
196
|
+
src_fd = optional{
|
197
|
+
read(/[0-9]+/)
|
198
|
+
}
|
199
|
+
redirect = read(/>|>>|<|&>/)
|
200
|
+
inline_sp()
|
201
|
+
dest = normal_operand()
|
202
|
+
[:redirect, redirect, src_fd, dest]
|
203
|
+
end
|
204
|
+
|
205
|
+
rule def normal_operand
|
206
|
+
concats = one_or_more {
|
207
|
+
choice(
|
208
|
+
->{ string_double_quote() },
|
209
|
+
->{ string_single_quote() },
|
210
|
+
->{ backquote_operand() },
|
211
|
+
->{ raw_operand() },
|
212
|
+
)
|
213
|
+
}
|
214
|
+
if concats.size > 1
|
215
|
+
[:concat, *concats]
|
216
|
+
else
|
217
|
+
concats.first
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def string_double_quote_special_process
|
222
|
+
choice(
|
223
|
+
->{
|
224
|
+
read('\\')
|
225
|
+
escaped = read(/./m)
|
226
|
+
case escaped
|
227
|
+
when 'n'
|
228
|
+
"\n"
|
229
|
+
when "\n"
|
230
|
+
""
|
231
|
+
else
|
232
|
+
escaped
|
233
|
+
end
|
234
|
+
},
|
235
|
+
->{
|
236
|
+
inline_command()
|
237
|
+
},
|
238
|
+
->{
|
239
|
+
variable_reference()
|
240
|
+
}
|
241
|
+
)
|
242
|
+
end
|
243
|
+
|
244
|
+
rule def string_double_quote
|
245
|
+
read('"')
|
246
|
+
ret = string_like('"', /[^"\\$]*/) {
|
247
|
+
string_double_quote_special_process()
|
248
|
+
}
|
249
|
+
read('"')
|
250
|
+
[:dquote, *ret]
|
251
|
+
end
|
252
|
+
|
253
|
+
rule def inline_command
|
254
|
+
read('$(')
|
255
|
+
body = pipelines()
|
256
|
+
read(')')
|
257
|
+
[:inline, body]
|
258
|
+
end
|
259
|
+
|
260
|
+
rule def variable_reference
|
261
|
+
read('$')
|
262
|
+
ref = choice(
|
263
|
+
->{
|
264
|
+
name = read(/[A-Za-z0-9_]+/)
|
265
|
+
[name, nil]
|
266
|
+
},
|
267
|
+
->{
|
268
|
+
read('{')
|
269
|
+
name = read(/[A-Za-z0-9_]+/)
|
270
|
+
substr = optional {
|
271
|
+
variable_expansion()
|
272
|
+
}
|
273
|
+
read('}')
|
274
|
+
[name, substr]
|
275
|
+
},
|
276
|
+
)
|
277
|
+
[:var, *ref]
|
278
|
+
end
|
279
|
+
|
280
|
+
rule def variable_expansion
|
281
|
+
choice(
|
282
|
+
->{
|
283
|
+
read(':-')
|
284
|
+
backtrack
|
285
|
+
},
|
286
|
+
->{
|
287
|
+
read('-')
|
288
|
+
exp = variable_expansion_string()
|
289
|
+
['-', exp]
|
290
|
+
},
|
291
|
+
)
|
292
|
+
end
|
293
|
+
|
294
|
+
rule def variable_expansion_string
|
295
|
+
ret = string_like('}', /[^\\$}]*/) {
|
296
|
+
string_double_quote_special_process()
|
297
|
+
}
|
298
|
+
if ret.size > 1
|
299
|
+
ret
|
300
|
+
elsif ret.size == 1
|
301
|
+
ret.first
|
302
|
+
else
|
303
|
+
''
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
rule def string_single_quote
|
308
|
+
read("'")
|
309
|
+
val = read(/[^']*/)
|
310
|
+
read("'")
|
311
|
+
val
|
312
|
+
end
|
313
|
+
|
314
|
+
rule def backquote_operand
|
315
|
+
read('`')
|
316
|
+
read('`')
|
317
|
+
backtrack
|
318
|
+
end
|
319
|
+
|
320
|
+
RESERVED_WORDS = %w(
|
321
|
+
if then elif else fi while do for in done
|
322
|
+
).to_set
|
323
|
+
rule def raw_operand
|
324
|
+
backtrack if RESERVED_WORDS.include?(peek(/[^\s]*/))
|
325
|
+
|
326
|
+
ret = string_like(/[\s&|><;]/, /[^\s&|><;\\$]*/) {
|
327
|
+
string_double_quote_special_process()
|
328
|
+
}
|
329
|
+
if ret.size > 1
|
330
|
+
ret
|
331
|
+
elsif ret.size == 0 || ret.first.size == 0
|
332
|
+
backtrack()
|
333
|
+
else
|
334
|
+
ret.first
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative '../lib/pegparse'
|
2
|
+
|
3
|
+
module Pegparse::Sample
|
4
|
+
end
|
5
|
+
|
6
|
+
class Pegparse::Sample::CalcParser < Pegparse::ParserBase
|
7
|
+
def initialize(context_or_scanner)
|
8
|
+
super(context_or_scanner)
|
9
|
+
self.start_rule_symbol = :expression
|
10
|
+
end
|
11
|
+
|
12
|
+
CalcBiopParser = Pegparse::BiopRuleChain.based_on(self) do
|
13
|
+
def operator_sp
|
14
|
+
read(/ */)
|
15
|
+
end
|
16
|
+
def operand_sp
|
17
|
+
read(/ */)
|
18
|
+
end
|
19
|
+
def construct_result(lhs, op, rhs)
|
20
|
+
case op
|
21
|
+
when '+'
|
22
|
+
lhs + rhs
|
23
|
+
when '-'
|
24
|
+
lhs - rhs
|
25
|
+
when '*'
|
26
|
+
lhs * rhs
|
27
|
+
when '/'
|
28
|
+
lhs / rhs
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rule def expression
|
33
|
+
biop = CalcBiopParser.new(nil)
|
34
|
+
biop
|
35
|
+
.left_op(['+', '-'])
|
36
|
+
.left_op(['*', '/'])
|
37
|
+
.term(->{ term() })
|
38
|
+
biop.parse(@context)
|
39
|
+
end
|
40
|
+
|
41
|
+
rule def term
|
42
|
+
choice(
|
43
|
+
->{
|
44
|
+
read(/[0-9]+(\.[0-9]+)?/).to_f
|
45
|
+
},
|
46
|
+
->{
|
47
|
+
read('(')
|
48
|
+
exp = expression()
|
49
|
+
read(')')
|
50
|
+
exp
|
51
|
+
}
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require_relative '../lib/pegparse'
|
2
|
+
|
3
|
+
module Pegparse::Sample
|
4
|
+
end
|
5
|
+
|
6
|
+
class Pegparse::Sample::JsonParser < Pegparse::ParserBase
|
7
|
+
class JsonNullNode
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(context_or_scanner)
|
11
|
+
super(context_or_scanner)
|
12
|
+
self.start_rule_symbol = :start_rule
|
13
|
+
end
|
14
|
+
|
15
|
+
def start_rule
|
16
|
+
sp()
|
17
|
+
json_node()
|
18
|
+
end
|
19
|
+
|
20
|
+
rule def json_node
|
21
|
+
choice(
|
22
|
+
->{ json_number_node() },
|
23
|
+
->{ json_string_node() },
|
24
|
+
->{ json_null_node() },
|
25
|
+
->{ json_bool_node() },
|
26
|
+
->{ json_object_node() },
|
27
|
+
->{ json_array_node() },
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def json_number_node
|
32
|
+
str = read(/[0-9]+(\.[0-9]+)?/)
|
33
|
+
str.to_f
|
34
|
+
end
|
35
|
+
|
36
|
+
rule def json_string_node
|
37
|
+
read('"')
|
38
|
+
ret = string_like('"', /[^"\\]*/){
|
39
|
+
read("\\")
|
40
|
+
read(/./m)
|
41
|
+
}
|
42
|
+
read('"')
|
43
|
+
ret[0]
|
44
|
+
end
|
45
|
+
|
46
|
+
def json_null_node
|
47
|
+
read('null')
|
48
|
+
JsonNullNode.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def json_bool_node
|
52
|
+
choice(
|
53
|
+
->{
|
54
|
+
read('true')
|
55
|
+
true
|
56
|
+
},
|
57
|
+
->{
|
58
|
+
read('false')
|
59
|
+
false
|
60
|
+
},
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
rule def json_object_node
|
65
|
+
read('{')
|
66
|
+
sp()
|
67
|
+
pairs = separative(',') {
|
68
|
+
key = json_object_key()
|
69
|
+
sp()
|
70
|
+
read(':')
|
71
|
+
sp()
|
72
|
+
val = json_node()
|
73
|
+
[key, val]
|
74
|
+
}
|
75
|
+
sp()
|
76
|
+
read('}')
|
77
|
+
pairs.to_h
|
78
|
+
end
|
79
|
+
|
80
|
+
def json_object_key
|
81
|
+
json_string_node()
|
82
|
+
end
|
83
|
+
|
84
|
+
rule def json_array_node
|
85
|
+
read('[')
|
86
|
+
sp()
|
87
|
+
elements = separative(',') { json_node() }
|
88
|
+
sp()
|
89
|
+
read(']')
|
90
|
+
elements
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require_relative '../lib/pegparse'
|
2
|
+
|
3
|
+
module Pegparse::Sample
|
4
|
+
end
|
5
|
+
|
6
|
+
class Pegparse::Sample::XmlParser < Pegparse::ParserBase
|
7
|
+
XmlNode = Struct.new(
|
8
|
+
:tag, :attrs, :inner_nodes,
|
9
|
+
keyword_init: true,
|
10
|
+
)
|
11
|
+
|
12
|
+
XmlAttr = Struct.new(
|
13
|
+
:name, :value,
|
14
|
+
keyword_init: true,
|
15
|
+
)
|
16
|
+
|
17
|
+
def initialize(context_or_scanner)
|
18
|
+
super(context_or_scanner)
|
19
|
+
self.start_rule_symbol = :start_rule
|
20
|
+
end
|
21
|
+
|
22
|
+
rule def block_comment
|
23
|
+
read('<!--')
|
24
|
+
read(/.*?-->/m)
|
25
|
+
end
|
26
|
+
|
27
|
+
def start_rule
|
28
|
+
sp()
|
29
|
+
decl = optional{ doc_declaration() }
|
30
|
+
nodes = xml_nodes()
|
31
|
+
[decl, nodes]
|
32
|
+
end
|
33
|
+
|
34
|
+
def intag_sp!
|
35
|
+
read(/\s+/)
|
36
|
+
end
|
37
|
+
|
38
|
+
def intag_sp
|
39
|
+
read(/\s*/)
|
40
|
+
end
|
41
|
+
|
42
|
+
def doc_declaration
|
43
|
+
choice(
|
44
|
+
->{ xml_declaration() },
|
45
|
+
->{ html_declaration() },
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
rule def xml_declaration
|
50
|
+
read('<?xml')
|
51
|
+
attrs = xml_attributes()
|
52
|
+
intag_sp()
|
53
|
+
read('>')
|
54
|
+
attrs
|
55
|
+
end
|
56
|
+
|
57
|
+
rule def html_declaration
|
58
|
+
read(/<!doctype html>/i)
|
59
|
+
end
|
60
|
+
|
61
|
+
def xml_attributes
|
62
|
+
attrs = zero_or_more {
|
63
|
+
intag_sp!()
|
64
|
+
xml_attribute_pair()
|
65
|
+
}
|
66
|
+
attrs
|
67
|
+
end
|
68
|
+
|
69
|
+
def xml_attribute_pair
|
70
|
+
name = xml_attribute_name()
|
71
|
+
read('=')
|
72
|
+
val = xml_attribute_value()
|
73
|
+
XmlAttr.new(name: name, value: val)
|
74
|
+
end
|
75
|
+
|
76
|
+
rule def xml_attribute_name
|
77
|
+
read(/[A-Za-z][A-Za-z0-9\-]*/)
|
78
|
+
end
|
79
|
+
|
80
|
+
rule def xml_tag_name
|
81
|
+
read(/[A-Za-z][A-Za-z0-9\-]*/)
|
82
|
+
end
|
83
|
+
|
84
|
+
rule def xml_attribute_value
|
85
|
+
choice(
|
86
|
+
->{ single_quote_string() },
|
87
|
+
->{ double_quote_string() },
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
def single_quote_string
|
92
|
+
read("'")
|
93
|
+
ret = string_like("'", /[^'\\]*/){
|
94
|
+
read('\\')
|
95
|
+
read(/./m)
|
96
|
+
}
|
97
|
+
read("'")
|
98
|
+
ret[0]
|
99
|
+
end
|
100
|
+
|
101
|
+
def double_quote_string
|
102
|
+
read('"')
|
103
|
+
ret = string_like('"', /[^"\\]*/){
|
104
|
+
read('\\')
|
105
|
+
read(/./m)
|
106
|
+
}
|
107
|
+
read('"')
|
108
|
+
ret[0]
|
109
|
+
end
|
110
|
+
|
111
|
+
rule def xml_open_tag
|
112
|
+
read('<')
|
113
|
+
name = xml_tag_name()
|
114
|
+
attrs = xml_attributes()
|
115
|
+
intag_sp()
|
116
|
+
read('>')
|
117
|
+
[name, attrs]
|
118
|
+
end
|
119
|
+
|
120
|
+
rule def xml_close_tag
|
121
|
+
read('</')
|
122
|
+
intag_sp()
|
123
|
+
name = xml_tag_name()
|
124
|
+
intag_sp()
|
125
|
+
read('>')
|
126
|
+
name
|
127
|
+
end
|
128
|
+
|
129
|
+
rule def xml_empty_element_tag
|
130
|
+
read('<')
|
131
|
+
name = xml_tag_name()
|
132
|
+
attrs = xml_attributes()
|
133
|
+
intag_sp()
|
134
|
+
read('/>')
|
135
|
+
[name, attrs]
|
136
|
+
end
|
137
|
+
|
138
|
+
SPECIAL_NONEST_TAG = %w(meta br)
|
139
|
+
rule def html_special_empty_element_tag
|
140
|
+
read('<')
|
141
|
+
name = xml_tag_name()
|
142
|
+
backtrack() unless SPECIAL_NONEST_TAG.include?(name)
|
143
|
+
attrs = xml_attributes()
|
144
|
+
intag_sp()
|
145
|
+
read(/\/?>/)
|
146
|
+
[name, attrs]
|
147
|
+
end
|
148
|
+
|
149
|
+
def xml_node
|
150
|
+
choice(
|
151
|
+
->{
|
152
|
+
block_comment()
|
153
|
+
},
|
154
|
+
->{
|
155
|
+
text = read(/[^<]+/)
|
156
|
+
text
|
157
|
+
},
|
158
|
+
->{
|
159
|
+
tag = xml_empty_element_tag()
|
160
|
+
XmlNode.new(tag: tag[0], attrs: tag[1], inner_nodes: nil)
|
161
|
+
},
|
162
|
+
->{
|
163
|
+
tag = html_special_empty_element_tag()
|
164
|
+
XmlNode.new(tag: tag[0], attrs: tag[1], inner_nodes: nil)
|
165
|
+
},
|
166
|
+
->{
|
167
|
+
opentag = xml_open_tag()
|
168
|
+
inner = xml_nodes()
|
169
|
+
closetag = xml_close_tag()
|
170
|
+
backtrack if opentag[0] != closetag
|
171
|
+
XmlNode.new(tag: opentag[0], attrs: opentag[1], inner_nodes: inner)
|
172
|
+
}
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
def xml_nodes
|
177
|
+
nodes = zero_or_more {
|
178
|
+
xml_node()
|
179
|
+
}
|
180
|
+
nodes
|
181
|
+
end
|
182
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pegparse
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Riki Ishikawa
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-12-20 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: provide base class for PEG like recursive descent parser.
|
14
|
+
email:
|
15
|
+
- riki.ishikawa@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".gitignore"
|
21
|
+
- ".rubocop.yml"
|
22
|
+
- Gemfile
|
23
|
+
- LICENSE.txt
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- bin/console
|
27
|
+
- bin/setup
|
28
|
+
- lib/pegparse.rb
|
29
|
+
- lib/pegparse/biop_rule_chain.rb
|
30
|
+
- lib/pegparse/borrowed_areas.rb
|
31
|
+
- lib/pegparse/line_counter.rb
|
32
|
+
- lib/pegparse/parser_base.rb
|
33
|
+
- lib/pegparse/parser_context.rb
|
34
|
+
- lib/pegparse/parser_core.rb
|
35
|
+
- lib/pegparse/parser_errors.rb
|
36
|
+
- lib/pegparse/version.rb
|
37
|
+
- pegparse.gemspec
|
38
|
+
- samples/bsh_parser.rb
|
39
|
+
- samples/calc_parser.rb
|
40
|
+
- samples/json_parser.rb
|
41
|
+
- samples/xml_parser.rb
|
42
|
+
homepage: https://github.com/jljse/pegparse
|
43
|
+
licenses:
|
44
|
+
- MIT
|
45
|
+
metadata:
|
46
|
+
homepage_uri: https://github.com/jljse/pegparse
|
47
|
+
source_code_uri: https://github.com/jljse/pegparse
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 3.0.0
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubygems_version: 3.2.22
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: library to create recursive descent parser.
|
67
|
+
test_files: []
|