kpeg 0.8.2 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +49 -21
- data/lib/kpeg/code_generator.rb +5 -1
- data/lib/kpeg/compiled_parser.rb +47 -5
- data/lib/kpeg/format_parser.rb +332 -127
- data/lib/kpeg/grammar.rb +13 -7
- data/lib/kpeg/grammar_renderer.rb +6 -2
- data/lib/kpeg/version.rb +1 -1
- data/test/test_kpeg_code_generator.rb +2 -2
- data/test/test_kpeg_format.rb +10 -2
- data/test/test_kpeg_grammar_renderer.rb +1 -1
- metadata +4 -4
data/README.md
CHANGED
@@ -15,10 +15,14 @@ All grammars start with with the class/module name that will be your parser
|
|
15
15
|
|
16
16
|
%% name = Example::Parser
|
17
17
|
|
18
|
-
After that a block of ruby code can be defined that will be added into the class body of your parser. Attributes that are
|
18
|
+
After that a block of ruby code can be defined that will be added into the class body of your parser. Attributes that are defined in this block can be accessed within your parser as instance variables. Methods can also be defined in this block and used in action blocks as well.
|
19
19
|
|
20
20
|
%% {
|
21
21
|
attr_accessor :something_cool
|
22
|
+
|
23
|
+
def something_awesome
|
24
|
+
# do something awesome
|
25
|
+
end
|
22
26
|
}
|
23
27
|
|
24
28
|
### Defining literals
|
@@ -36,52 +40,50 @@ Literals can also accept multiple definitions
|
|
36
40
|
|
37
41
|
vowel = "a" | "e" | "i" | "o" | "u"
|
38
42
|
alpha = /[A-Z]/ | /[a-z]/
|
39
|
-
|
40
43
|
|
41
44
|
### Defining Rules for Values
|
42
45
|
|
43
46
|
Before you can start parsing a string you will need to define rules that you will use to accept or reject that string. There are many different types of rules available in kpeg
|
44
47
|
|
45
48
|
The most basic of these rules is a string capture
|
46
|
-
|
49
|
+
|
47
50
|
alpha = < /[A-Za-z]/ > { text }
|
48
|
-
|
51
|
+
|
49
52
|
|
50
53
|
While this looks very much like the ALPHA literal defined above it differs in one important way, the text captured by the rule defined between the < and > symbols will be set as the text variable in block that follows. You can also explicitly define the variable that you would like but only with existing rules or literals.
|
51
|
-
|
54
|
+
|
52
55
|
letter = alpha:a { a }
|
53
|
-
|
56
|
+
|
54
57
|
Additionally blocks can return true or false values based upon an expression within the block. To return true if a test passes do the following:
|
55
58
|
|
56
59
|
match_greater_than_10 = < num:n > &{ n > 10 }
|
57
|
-
|
60
|
+
|
58
61
|
To test and return a false value if the test passes do the following:
|
59
62
|
|
60
63
|
do_not_match_greater_than_10 = < num:n > !{ n > 10 }
|
61
|
-
|
64
|
+
|
62
65
|
Rules can also act like functions and take parameters. An example of this is lifted from the [Email List Validator](https://github.com/larb/email_address_validator), where an ascii value is passed in and the character is evaluated against it returning a true if it matches
|
63
|
-
|
66
|
+
|
64
67
|
d(num) = <.> &{ text[0] == num }
|
65
68
|
|
66
69
|
Rules support some regular expression syntax for matching
|
67
|
-
|
70
|
+
|
68
71
|
+ maybe ?
|
69
|
-
+ many
|
70
|
-
+ kleene *
|
71
|
-
+ groupings ()
|
72
|
+
+ many +
|
73
|
+
+ kleene *
|
74
|
+
+ groupings ()
|
72
75
|
|
73
76
|
Examples
|
74
77
|
|
75
78
|
letters = alpha+
|
76
79
|
words = alpha+ space* period?
|
77
80
|
sentence = (letters+ | space+)+
|
78
|
-
|
81
|
+
|
79
82
|
Kpeg also allows a rule to define the acceptable number of matches in the form of a range. In regular expressions this is often denoted with syntax like {0,3}. Kpeg uses this syntax to accomplish match ranges [min, max].
|
80
83
|
|
81
84
|
matches_3_to_5_times = letter[3,5]
|
82
85
|
matches_3_to_any_times = letter[3,*]
|
83
|
-
|
84
|
-
|
86
|
+
|
85
87
|
### Defining Actions
|
86
88
|
|
87
89
|
Illustrated above in some of the examples, kpeg allows you to perform actions based upon a match that are described in block provided or in the rule definition itself.
|
@@ -89,6 +91,16 @@ Illustrated above in some of the examples, kpeg allows you to perform actions ba
|
|
89
91
|
num = /[1-9][0-9]*/
|
90
92
|
sum = < num:n1 "+" num:n2 > { n1 + n2 }
|
91
93
|
|
94
|
+
As of version 0.8 an alternate syntax has been added for calling defined methods as actions.
|
95
|
+
|
96
|
+
%% {
|
97
|
+
def add(n1, n2){
|
98
|
+
n1 + n2
|
99
|
+
}
|
100
|
+
}
|
101
|
+
num = /[1-9][0-9]*/
|
102
|
+
sum = < num:n1 "+" num:n2 > ~add(n1, n2)
|
103
|
+
|
92
104
|
### Referencing an external grammar
|
93
105
|
|
94
106
|
Kpeg allows you to run a rule that is defined in an external grammar. This is useful if there is a defined set of rules that you would like to reuse in another parser. To do this, create your grammar and generate a parser using the kpeg command line tool.
|
@@ -100,7 +112,7 @@ Once you have the generated parser, include that file into your new grammar
|
|
100
112
|
%{
|
101
113
|
require "literals.kpeg.rb"
|
102
114
|
}
|
103
|
-
|
115
|
+
|
104
116
|
Then create a variable to hold to foreign interface and pass it the class name of your parser. In this case my parser class name is Literal
|
105
117
|
|
106
118
|
%foreign_grammer = Literal
|
@@ -114,21 +126,21 @@ You can then use rules defined in the foreign grammar in the local grammar file
|
|
114
126
|
Kpeg allows comments to be added to the grammar file by using the # symbol
|
115
127
|
|
116
128
|
# This is a comment in my grammar
|
117
|
-
|
129
|
+
|
118
130
|
## Generating and running your parser
|
119
131
|
|
120
132
|
Before you can generate your parser you will need to define a root rule. This will be the first rule run against the string provided to the parser
|
121
133
|
|
122
134
|
root = sentence
|
123
|
-
|
135
|
+
|
124
136
|
To generate the parser run the kpeg command with the kpeg file(s) as an argument. This will generate a ruby file with the same name as your grammar file.
|
125
137
|
|
126
138
|
kpeg example.kpeg
|
127
|
-
|
139
|
+
|
128
140
|
Include your generated parser file into an application that you want to use the parser in and run it. Create a new instance of the parser and pass in the string you want to evaluate. When parse is called on the parser instance it will return a true if the sting is matched, or false if it doesn't.
|
129
141
|
|
130
142
|
require "example.kpeg.rb"
|
131
|
-
|
143
|
+
|
132
144
|
parser = Example::Parser.new(string_to_evaluate)
|
133
145
|
parser.parse
|
134
146
|
|
@@ -140,6 +152,20 @@ Per vito, you can get the current line or current column in the following way
|
|
140
152
|
column = { current_column }
|
141
153
|
foo = line:line ... { # use line here }
|
142
154
|
|
155
|
+
## AST Generation
|
156
|
+
|
157
|
+
As of Kpeg 0.8 a parser can now generate an AST. To define an AST node use the following syntax
|
158
|
+
|
159
|
+
%% assign = ast Assignment(name, value)
|
160
|
+
|
161
|
+
Once you have a defined AST node, it can be used in your grammar like so
|
162
|
+
|
163
|
+
assignment = identifier:i space* = space* value:v ~assign(i,v)
|
164
|
+
|
165
|
+
This will create a new Assign node that you can add into your AST.
|
166
|
+
|
167
|
+
For a good example of usage check out [Talon](https://github.com/evanphx/talon)
|
168
|
+
|
143
169
|
## Examples
|
144
170
|
|
145
171
|
There are several examples available in the /examples directory. The upper parser has a readme with a step by step description of the grammar.
|
@@ -153,3 +179,5 @@ There are several examples available in the /examples directory. The upper parse
|
|
153
179
|
[Callisto](https://github.com/dwaite/Callisto)
|
154
180
|
|
155
181
|
[Doodle](https://github.com/vito/doodle)
|
182
|
+
|
183
|
+
[Kanbanpad](https://kanbanpad.com) (uses kpeg for parsing of the 'enter something' bar)
|
data/lib/kpeg/code_generator.rb
CHANGED
@@ -263,7 +263,11 @@ module KPeg
|
|
263
263
|
code << indentify("_tmp = _tmp ? nil : true\n", indent)
|
264
264
|
code << indentify("self.pos = #{ss}\n", indent)
|
265
265
|
when RuleReference
|
266
|
-
|
266
|
+
if op.arguments
|
267
|
+
code << indentify("_tmp = apply_with_args(:#{method_name op.rule_name}, #{op.arguments[1..-2]})\n", indent)
|
268
|
+
else
|
269
|
+
code << indentify("_tmp = apply(:#{method_name op.rule_name})\n", indent)
|
270
|
+
end
|
267
271
|
when InvokeRule
|
268
272
|
if op.arguments
|
269
273
|
code << indentify("_tmp = #{method_name op.rule_name}#{op.arguments}\n", indent)
|
data/lib/kpeg/compiled_parser.rb
CHANGED
@@ -32,8 +32,8 @@ module KPeg
|
|
32
32
|
end
|
33
33
|
|
34
34
|
attr_reader :string
|
35
|
-
attr_reader :
|
36
|
-
attr_accessor :pos
|
35
|
+
attr_reader :failing_rule_offset
|
36
|
+
attr_accessor :result, :pos
|
37
37
|
|
38
38
|
include Position
|
39
39
|
|
@@ -218,6 +218,7 @@ module KPeg
|
|
218
218
|
begin
|
219
219
|
if val = __send__(rule, *args)
|
220
220
|
other.pos = @pos
|
221
|
+
other.result = @result
|
221
222
|
else
|
222
223
|
other.set_failed_rule "#{self.class}##{rule}"
|
223
224
|
end
|
@@ -228,6 +229,43 @@ module KPeg
|
|
228
229
|
end
|
229
230
|
end
|
230
231
|
|
232
|
+
def apply_with_args(rule, *args)
|
233
|
+
memo_key = [rule, args]
|
234
|
+
if m = @memoizations[memo_key][@pos]
|
235
|
+
m.inc!
|
236
|
+
|
237
|
+
prev = @pos
|
238
|
+
@pos = m.pos
|
239
|
+
if m.ans.kind_of? LeftRecursive
|
240
|
+
m.ans.detected = true
|
241
|
+
return nil
|
242
|
+
end
|
243
|
+
|
244
|
+
@result = m.result
|
245
|
+
|
246
|
+
return m.ans
|
247
|
+
else
|
248
|
+
lr = LeftRecursive.new(false)
|
249
|
+
m = MemoEntry.new(lr, @pos)
|
250
|
+
@memoizations[memo_key][@pos] = m
|
251
|
+
start_pos = @pos
|
252
|
+
|
253
|
+
ans = __send__ rule, *args
|
254
|
+
|
255
|
+
m.move! ans, @pos, @result
|
256
|
+
|
257
|
+
# Don't bother trying to grow the left recursion
|
258
|
+
# if it's failing straight away (thus there is no seed)
|
259
|
+
if ans and lr.detected
|
260
|
+
return grow_lr(rule, args, start_pos, m)
|
261
|
+
else
|
262
|
+
return ans
|
263
|
+
end
|
264
|
+
|
265
|
+
return ans
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
231
269
|
def apply(rule)
|
232
270
|
if m = @memoizations[rule][@pos]
|
233
271
|
m.inc!
|
@@ -255,7 +293,7 @@ module KPeg
|
|
255
293
|
# Don't bother trying to grow the left recursion
|
256
294
|
# if it's failing straight away (thus there is no seed)
|
257
295
|
if ans and lr.detected
|
258
|
-
return grow_lr(rule, start_pos, m)
|
296
|
+
return grow_lr(rule, nil, start_pos, m)
|
259
297
|
else
|
260
298
|
return ans
|
261
299
|
end
|
@@ -264,12 +302,16 @@ module KPeg
|
|
264
302
|
end
|
265
303
|
end
|
266
304
|
|
267
|
-
def grow_lr(rule, start_pos, m)
|
305
|
+
def grow_lr(rule, args, start_pos, m)
|
268
306
|
while true
|
269
307
|
@pos = start_pos
|
270
308
|
@result = m.result
|
271
309
|
|
272
|
-
|
310
|
+
if args
|
311
|
+
ans = __send__ rule, *args
|
312
|
+
else
|
313
|
+
ans = __send__ rule
|
314
|
+
end
|
273
315
|
return nil unless ans
|
274
316
|
|
275
317
|
break if @pos <= m.pos
|
data/lib/kpeg/format_parser.rb
CHANGED
@@ -20,8 +20,8 @@ class KPeg::FormatParser
|
|
20
20
|
end
|
21
21
|
|
22
22
|
attr_reader :string
|
23
|
-
attr_reader :
|
24
|
-
attr_accessor :pos
|
23
|
+
attr_reader :failing_rule_offset
|
24
|
+
attr_accessor :result, :pos
|
25
25
|
|
26
26
|
# STANDALONE START
|
27
27
|
def current_column(target=pos)
|
@@ -234,6 +234,7 @@ class KPeg::FormatParser
|
|
234
234
|
begin
|
235
235
|
if val = __send__(rule, *args)
|
236
236
|
other.pos = @pos
|
237
|
+
other.result = @result
|
237
238
|
else
|
238
239
|
other.set_failed_rule "#{self.class}##{rule}"
|
239
240
|
end
|
@@ -244,6 +245,43 @@ class KPeg::FormatParser
|
|
244
245
|
end
|
245
246
|
end
|
246
247
|
|
248
|
+
def apply_with_args(rule, *args)
|
249
|
+
memo_key = [rule, args]
|
250
|
+
if m = @memoizations[memo_key][@pos]
|
251
|
+
m.inc!
|
252
|
+
|
253
|
+
prev = @pos
|
254
|
+
@pos = m.pos
|
255
|
+
if m.ans.kind_of? LeftRecursive
|
256
|
+
m.ans.detected = true
|
257
|
+
return nil
|
258
|
+
end
|
259
|
+
|
260
|
+
@result = m.result
|
261
|
+
|
262
|
+
return m.ans
|
263
|
+
else
|
264
|
+
lr = LeftRecursive.new(false)
|
265
|
+
m = MemoEntry.new(lr, @pos)
|
266
|
+
@memoizations[memo_key][@pos] = m
|
267
|
+
start_pos = @pos
|
268
|
+
|
269
|
+
ans = __send__ rule, *args
|
270
|
+
|
271
|
+
m.move! ans, @pos, @result
|
272
|
+
|
273
|
+
# Don't bother trying to grow the left recursion
|
274
|
+
# if it's failing straight away (thus there is no seed)
|
275
|
+
if ans and lr.detected
|
276
|
+
return grow_lr(rule, args, start_pos, m)
|
277
|
+
else
|
278
|
+
return ans
|
279
|
+
end
|
280
|
+
|
281
|
+
return ans
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
247
285
|
def apply(rule)
|
248
286
|
if m = @memoizations[rule][@pos]
|
249
287
|
m.inc!
|
@@ -271,7 +309,7 @@ class KPeg::FormatParser
|
|
271
309
|
# Don't bother trying to grow the left recursion
|
272
310
|
# if it's failing straight away (thus there is no seed)
|
273
311
|
if ans and lr.detected
|
274
|
-
return grow_lr(rule, start_pos, m)
|
312
|
+
return grow_lr(rule, nil, start_pos, m)
|
275
313
|
else
|
276
314
|
return ans
|
277
315
|
end
|
@@ -280,12 +318,16 @@ class KPeg::FormatParser
|
|
280
318
|
end
|
281
319
|
end
|
282
320
|
|
283
|
-
def grow_lr(rule, start_pos, m)
|
321
|
+
def grow_lr(rule, args, start_pos, m)
|
284
322
|
while true
|
285
323
|
@pos = start_pos
|
286
324
|
@result = m.result
|
287
325
|
|
288
|
-
|
326
|
+
if args
|
327
|
+
ans = __send__ rule, *args
|
328
|
+
else
|
329
|
+
ans = __send__ rule
|
330
|
+
end
|
289
331
|
return nil unless ans
|
290
332
|
|
291
333
|
break if @pos <= m.pos
|
@@ -536,7 +578,7 @@ class KPeg::FormatParser
|
|
536
578
|
return _tmp
|
537
579
|
end
|
538
580
|
|
539
|
-
# dbl_escapes = ("
|
581
|
+
# dbl_escapes = ("n" { "\n" } | "s" { " " } | "r" { "\r" } | "t" { "\t" } | "v" { "\v" } | "f" { "\f" } | "b" { "\b" } | "a" { "\a" } | "e" { "\e" } | "\\" { "\\" } | "\"" { "\"" } | num_escapes)
|
540
582
|
def _dbl_escapes
|
541
583
|
|
542
584
|
_save = self.pos
|
@@ -544,12 +586,12 @@ class KPeg::FormatParser
|
|
544
586
|
|
545
587
|
_save1 = self.pos
|
546
588
|
while true # sequence
|
547
|
-
_tmp = match_string("
|
589
|
+
_tmp = match_string("n")
|
548
590
|
unless _tmp
|
549
591
|
self.pos = _save1
|
550
592
|
break
|
551
593
|
end
|
552
|
-
@result = begin;
|
594
|
+
@result = begin; "\n" ; end
|
553
595
|
_tmp = true
|
554
596
|
unless _tmp
|
555
597
|
self.pos = _save1
|
@@ -562,12 +604,12 @@ class KPeg::FormatParser
|
|
562
604
|
|
563
605
|
_save2 = self.pos
|
564
606
|
while true # sequence
|
565
|
-
_tmp = match_string("
|
607
|
+
_tmp = match_string("s")
|
566
608
|
unless _tmp
|
567
609
|
self.pos = _save2
|
568
610
|
break
|
569
611
|
end
|
570
|
-
@result = begin; "
|
612
|
+
@result = begin; " " ; end
|
571
613
|
_tmp = true
|
572
614
|
unless _tmp
|
573
615
|
self.pos = _save2
|
@@ -580,12 +622,12 @@ class KPeg::FormatParser
|
|
580
622
|
|
581
623
|
_save3 = self.pos
|
582
624
|
while true # sequence
|
583
|
-
_tmp = match_string("
|
625
|
+
_tmp = match_string("r")
|
584
626
|
unless _tmp
|
585
627
|
self.pos = _save3
|
586
628
|
break
|
587
629
|
end
|
588
|
-
@result = begin; "\
|
630
|
+
@result = begin; "\r" ; end
|
589
631
|
_tmp = true
|
590
632
|
unless _tmp
|
591
633
|
self.pos = _save3
|
@@ -598,12 +640,12 @@ class KPeg::FormatParser
|
|
598
640
|
|
599
641
|
_save4 = self.pos
|
600
642
|
while true # sequence
|
601
|
-
_tmp = match_string("
|
643
|
+
_tmp = match_string("t")
|
602
644
|
unless _tmp
|
603
645
|
self.pos = _save4
|
604
646
|
break
|
605
647
|
end
|
606
|
-
@result = begin; "\
|
648
|
+
@result = begin; "\t" ; end
|
607
649
|
_tmp = true
|
608
650
|
unless _tmp
|
609
651
|
self.pos = _save4
|
@@ -616,12 +658,12 @@ class KPeg::FormatParser
|
|
616
658
|
|
617
659
|
_save5 = self.pos
|
618
660
|
while true # sequence
|
619
|
-
_tmp = match_string("
|
661
|
+
_tmp = match_string("v")
|
620
662
|
unless _tmp
|
621
663
|
self.pos = _save5
|
622
664
|
break
|
623
665
|
end
|
624
|
-
@result = begin; "
|
666
|
+
@result = begin; "\v" ; end
|
625
667
|
_tmp = true
|
626
668
|
unless _tmp
|
627
669
|
self.pos = _save5
|
@@ -629,6 +671,117 @@ class KPeg::FormatParser
|
|
629
671
|
break
|
630
672
|
end # end sequence
|
631
673
|
|
674
|
+
break if _tmp
|
675
|
+
self.pos = _save
|
676
|
+
|
677
|
+
_save6 = self.pos
|
678
|
+
while true # sequence
|
679
|
+
_tmp = match_string("f")
|
680
|
+
unless _tmp
|
681
|
+
self.pos = _save6
|
682
|
+
break
|
683
|
+
end
|
684
|
+
@result = begin; "\f" ; end
|
685
|
+
_tmp = true
|
686
|
+
unless _tmp
|
687
|
+
self.pos = _save6
|
688
|
+
end
|
689
|
+
break
|
690
|
+
end # end sequence
|
691
|
+
|
692
|
+
break if _tmp
|
693
|
+
self.pos = _save
|
694
|
+
|
695
|
+
_save7 = self.pos
|
696
|
+
while true # sequence
|
697
|
+
_tmp = match_string("b")
|
698
|
+
unless _tmp
|
699
|
+
self.pos = _save7
|
700
|
+
break
|
701
|
+
end
|
702
|
+
@result = begin; "\b" ; end
|
703
|
+
_tmp = true
|
704
|
+
unless _tmp
|
705
|
+
self.pos = _save7
|
706
|
+
end
|
707
|
+
break
|
708
|
+
end # end sequence
|
709
|
+
|
710
|
+
break if _tmp
|
711
|
+
self.pos = _save
|
712
|
+
|
713
|
+
_save8 = self.pos
|
714
|
+
while true # sequence
|
715
|
+
_tmp = match_string("a")
|
716
|
+
unless _tmp
|
717
|
+
self.pos = _save8
|
718
|
+
break
|
719
|
+
end
|
720
|
+
@result = begin; "\a" ; end
|
721
|
+
_tmp = true
|
722
|
+
unless _tmp
|
723
|
+
self.pos = _save8
|
724
|
+
end
|
725
|
+
break
|
726
|
+
end # end sequence
|
727
|
+
|
728
|
+
break if _tmp
|
729
|
+
self.pos = _save
|
730
|
+
|
731
|
+
_save9 = self.pos
|
732
|
+
while true # sequence
|
733
|
+
_tmp = match_string("e")
|
734
|
+
unless _tmp
|
735
|
+
self.pos = _save9
|
736
|
+
break
|
737
|
+
end
|
738
|
+
@result = begin; "\e" ; end
|
739
|
+
_tmp = true
|
740
|
+
unless _tmp
|
741
|
+
self.pos = _save9
|
742
|
+
end
|
743
|
+
break
|
744
|
+
end # end sequence
|
745
|
+
|
746
|
+
break if _tmp
|
747
|
+
self.pos = _save
|
748
|
+
|
749
|
+
_save10 = self.pos
|
750
|
+
while true # sequence
|
751
|
+
_tmp = match_string("\\")
|
752
|
+
unless _tmp
|
753
|
+
self.pos = _save10
|
754
|
+
break
|
755
|
+
end
|
756
|
+
@result = begin; "\\" ; end
|
757
|
+
_tmp = true
|
758
|
+
unless _tmp
|
759
|
+
self.pos = _save10
|
760
|
+
end
|
761
|
+
break
|
762
|
+
end # end sequence
|
763
|
+
|
764
|
+
break if _tmp
|
765
|
+
self.pos = _save
|
766
|
+
|
767
|
+
_save11 = self.pos
|
768
|
+
while true # sequence
|
769
|
+
_tmp = match_string("\"")
|
770
|
+
unless _tmp
|
771
|
+
self.pos = _save11
|
772
|
+
break
|
773
|
+
end
|
774
|
+
@result = begin; "\"" ; end
|
775
|
+
_tmp = true
|
776
|
+
unless _tmp
|
777
|
+
self.pos = _save11
|
778
|
+
end
|
779
|
+
break
|
780
|
+
end # end sequence
|
781
|
+
|
782
|
+
break if _tmp
|
783
|
+
self.pos = _save
|
784
|
+
_tmp = apply(:_num_escapes)
|
632
785
|
break if _tmp
|
633
786
|
self.pos = _save
|
634
787
|
break
|
@@ -638,6 +791,67 @@ class KPeg::FormatParser
|
|
638
791
|
return _tmp
|
639
792
|
end
|
640
793
|
|
794
|
+
# num_escapes = (< /[0-7]{3}/ > { [text.to_i(8)].pack("U") } | "x" < /[0-9a-fA-F]{2}/ > { [text.to_i(16)].pack("U") })
|
795
|
+
def _num_escapes
|
796
|
+
|
797
|
+
_save = self.pos
|
798
|
+
while true # choice
|
799
|
+
|
800
|
+
_save1 = self.pos
|
801
|
+
while true # sequence
|
802
|
+
_text_start = self.pos
|
803
|
+
_tmp = scan(/\A(?-mix:[0-7]{3})/)
|
804
|
+
if _tmp
|
805
|
+
text = get_text(_text_start)
|
806
|
+
end
|
807
|
+
unless _tmp
|
808
|
+
self.pos = _save1
|
809
|
+
break
|
810
|
+
end
|
811
|
+
@result = begin; [text.to_i(8)].pack("U") ; end
|
812
|
+
_tmp = true
|
813
|
+
unless _tmp
|
814
|
+
self.pos = _save1
|
815
|
+
end
|
816
|
+
break
|
817
|
+
end # end sequence
|
818
|
+
|
819
|
+
break if _tmp
|
820
|
+
self.pos = _save
|
821
|
+
|
822
|
+
_save2 = self.pos
|
823
|
+
while true # sequence
|
824
|
+
_tmp = match_string("x")
|
825
|
+
unless _tmp
|
826
|
+
self.pos = _save2
|
827
|
+
break
|
828
|
+
end
|
829
|
+
_text_start = self.pos
|
830
|
+
_tmp = scan(/\A(?-mix:[0-9a-fA-F]{2})/)
|
831
|
+
if _tmp
|
832
|
+
text = get_text(_text_start)
|
833
|
+
end
|
834
|
+
unless _tmp
|
835
|
+
self.pos = _save2
|
836
|
+
break
|
837
|
+
end
|
838
|
+
@result = begin; [text.to_i(16)].pack("U") ; end
|
839
|
+
_tmp = true
|
840
|
+
unless _tmp
|
841
|
+
self.pos = _save2
|
842
|
+
end
|
843
|
+
break
|
844
|
+
end # end sequence
|
845
|
+
|
846
|
+
break if _tmp
|
847
|
+
self.pos = _save
|
848
|
+
break
|
849
|
+
end # end choice
|
850
|
+
|
851
|
+
set_failed_rule :_num_escapes unless _tmp
|
852
|
+
return _tmp
|
853
|
+
end
|
854
|
+
|
641
855
|
# dbl_seq = < /[^\\"]+/ > { text }
|
642
856
|
def _dbl_seq
|
643
857
|
|
@@ -664,58 +878,52 @@ class KPeg::FormatParser
|
|
664
878
|
return _tmp
|
665
879
|
end
|
666
880
|
|
667
|
-
# dbl_not_quote = (dbl_escapes:s | dbl_seq:s)
|
881
|
+
# dbl_not_quote = ("\\" dbl_escapes:s | dbl_seq:s)*:ary { Array(ary) }
|
668
882
|
def _dbl_not_quote
|
669
883
|
|
670
884
|
_save = self.pos
|
671
885
|
while true # sequence
|
672
|
-
_save1 = self.pos
|
673
886
|
_ary = []
|
887
|
+
while true
|
674
888
|
|
675
|
-
|
676
|
-
|
677
|
-
_tmp = apply(:_dbl_escapes)
|
678
|
-
s = @result
|
679
|
-
break if _tmp
|
680
|
-
self.pos = _save2
|
681
|
-
_tmp = apply(:_dbl_seq)
|
682
|
-
s = @result
|
683
|
-
break if _tmp
|
684
|
-
self.pos = _save2
|
685
|
-
break
|
686
|
-
end # end choice
|
687
|
-
|
688
|
-
if _tmp
|
689
|
-
_ary << @result
|
690
|
-
while true
|
889
|
+
_save2 = self.pos
|
890
|
+
while true # choice
|
691
891
|
|
692
892
|
_save3 = self.pos
|
693
|
-
while true #
|
893
|
+
while true # sequence
|
894
|
+
_tmp = match_string("\\")
|
895
|
+
unless _tmp
|
896
|
+
self.pos = _save3
|
897
|
+
break
|
898
|
+
end
|
694
899
|
_tmp = apply(:_dbl_escapes)
|
695
900
|
s = @result
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
s = @result
|
700
|
-
break if _tmp
|
701
|
-
self.pos = _save3
|
901
|
+
unless _tmp
|
902
|
+
self.pos = _save3
|
903
|
+
end
|
702
904
|
break
|
703
|
-
end # end
|
905
|
+
end # end sequence
|
704
906
|
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
907
|
+
break if _tmp
|
908
|
+
self.pos = _save2
|
909
|
+
_tmp = apply(:_dbl_seq)
|
910
|
+
s = @result
|
911
|
+
break if _tmp
|
912
|
+
self.pos = _save2
|
913
|
+
break
|
914
|
+
end # end choice
|
915
|
+
|
916
|
+
_ary << @result if _tmp
|
917
|
+
break unless _tmp
|
712
918
|
end
|
919
|
+
_tmp = true
|
920
|
+
@result = _ary
|
713
921
|
ary = @result
|
714
922
|
unless _tmp
|
715
923
|
self.pos = _save
|
716
924
|
break
|
717
925
|
end
|
718
|
-
@result = begin; ary ; end
|
926
|
+
@result = begin; Array(ary) ; end
|
719
927
|
_tmp = true
|
720
928
|
unless _tmp
|
721
929
|
self.pos = _save
|
@@ -808,54 +1016,36 @@ class KPeg::FormatParser
|
|
808
1016
|
return _tmp
|
809
1017
|
end
|
810
1018
|
|
811
|
-
# sgl_not_quote = (sgl_escape_quote | sgl_seq)
|
1019
|
+
# sgl_not_quote = (sgl_escape_quote | sgl_seq)*:segs { Array(segs) }
|
812
1020
|
def _sgl_not_quote
|
813
1021
|
|
814
1022
|
_save = self.pos
|
815
1023
|
while true # sequence
|
816
|
-
_save1 = self.pos
|
817
1024
|
_ary = []
|
1025
|
+
while true
|
818
1026
|
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
if _tmp
|
831
|
-
_ary << @result
|
832
|
-
while true
|
833
|
-
|
834
|
-
_save3 = self.pos
|
835
|
-
while true # choice
|
836
|
-
_tmp = apply(:_sgl_escape_quote)
|
837
|
-
break if _tmp
|
838
|
-
self.pos = _save3
|
839
|
-
_tmp = apply(:_sgl_seq)
|
840
|
-
break if _tmp
|
841
|
-
self.pos = _save3
|
842
|
-
break
|
843
|
-
end # end choice
|
1027
|
+
_save2 = self.pos
|
1028
|
+
while true # choice
|
1029
|
+
_tmp = apply(:_sgl_escape_quote)
|
1030
|
+
break if _tmp
|
1031
|
+
self.pos = _save2
|
1032
|
+
_tmp = apply(:_sgl_seq)
|
1033
|
+
break if _tmp
|
1034
|
+
self.pos = _save2
|
1035
|
+
break
|
1036
|
+
end # end choice
|
844
1037
|
|
845
|
-
|
846
|
-
|
847
|
-
end
|
848
|
-
_tmp = true
|
849
|
-
@result = _ary
|
850
|
-
else
|
851
|
-
self.pos = _save1
|
1038
|
+
_ary << @result if _tmp
|
1039
|
+
break unless _tmp
|
852
1040
|
end
|
1041
|
+
_tmp = true
|
1042
|
+
@result = _ary
|
853
1043
|
segs = @result
|
854
1044
|
unless _tmp
|
855
1045
|
self.pos = _save
|
856
1046
|
break
|
857
1047
|
end
|
858
|
-
@result = begin; segs
|
1048
|
+
@result = begin; Array(segs) ; end
|
859
1049
|
_tmp = true
|
860
1050
|
unless _tmp
|
861
1051
|
self.pos = _save
|
@@ -867,7 +1057,7 @@ class KPeg::FormatParser
|
|
867
1057
|
return _tmp
|
868
1058
|
end
|
869
1059
|
|
870
|
-
# sgl_string = "'" sgl_not_quote:s "'" { @g.str(s) }
|
1060
|
+
# sgl_string = "'" sgl_not_quote:s "'" { @g.str(s.join) }
|
871
1061
|
def _sgl_string
|
872
1062
|
|
873
1063
|
_save = self.pos
|
@@ -888,7 +1078,7 @@ class KPeg::FormatParser
|
|
888
1078
|
self.pos = _save
|
889
1079
|
break
|
890
1080
|
end
|
891
|
-
@result = begin; @g.str(s) ; end
|
1081
|
+
@result = begin; @g.str(s.join) ; end
|
892
1082
|
_tmp = true
|
893
1083
|
unless _tmp
|
894
1084
|
self.pos = _save
|
@@ -1401,7 +1591,7 @@ class KPeg::FormatParser
|
|
1401
1591
|
return _tmp
|
1402
1592
|
end
|
1403
1593
|
|
1404
|
-
# value = (value:v ":" var:n { @g.t(v,n) } | value:v "?" { @g.maybe(v) } | value:v "+" { @g.many(v) } | value:v "*" { @g.kleene(v) } | value:v mult_range:r { @g.multiple(v, *r) } | "&" value:v { @g.andp(v) } | "!" value:v { @g.notp(v) } | "(" - expression:o - ")" { o } | "@<" - expression:o - ">" { @g.bounds(o) } | "<" - expression:o - ">" { @g.collect(o) } | curly_block | "~" method:m < nested_paren? > { @g.action("#{m}#{text}") } | "." { @g.dot } | "@" var:name !(- "=") { @g.invoke(name) } | "^" var:name < nested_paren? > { @g.foreign_invoke("parent", name, text) } | "%" var:gram "." var:name < nested_paren? > { @g.foreign_invoke(gram, name, text) } | var:name < nested_paren? > !(- "=") { text.empty? ?
|
1594
|
+
# value = (value:v ":" var:n { @g.t(v,n) } | value:v "?" { @g.maybe(v) } | value:v "+" { @g.many(v) } | value:v "*" { @g.kleene(v) } | value:v mult_range:r { @g.multiple(v, *r) } | "&" value:v { @g.andp(v) } | "!" value:v { @g.notp(v) } | "(" - expression:o - ")" { o } | "@<" - expression:o - ">" { @g.bounds(o) } | "<" - expression:o - ">" { @g.collect(o) } | curly_block | "~" method:m < nested_paren? > { @g.action("#{m}#{text}") } | "." { @g.dot } | "@" var:name < nested_paren? > !(- "=") { @g.invoke(name, text.empty? ? nil : text) } | "^" var:name < nested_paren? > { @g.foreign_invoke("parent", name, text) } | "%" var:gram "." var:name < nested_paren? > { @g.foreign_invoke(gram, name, text) } | var:name < nested_paren? > !(- "=") { @g.ref(name, nil, text.empty? ? nil : text) } | char_range | regexp | string)
|
1405
1595
|
def _value
|
1406
1596
|
|
1407
1597
|
_save = self.pos
|
@@ -1771,29 +1961,43 @@ class KPeg::FormatParser
|
|
1771
1961
|
self.pos = _save14
|
1772
1962
|
break
|
1773
1963
|
end
|
1964
|
+
_text_start = self.pos
|
1774
1965
|
_save15 = self.pos
|
1775
|
-
|
1966
|
+
_tmp = apply(:_nested_paren)
|
1967
|
+
unless _tmp
|
1968
|
+
_tmp = true
|
1969
|
+
self.pos = _save15
|
1970
|
+
end
|
1971
|
+
if _tmp
|
1972
|
+
text = get_text(_text_start)
|
1973
|
+
end
|
1974
|
+
unless _tmp
|
1975
|
+
self.pos = _save14
|
1976
|
+
break
|
1977
|
+
end
|
1776
1978
|
_save16 = self.pos
|
1979
|
+
|
1980
|
+
_save17 = self.pos
|
1777
1981
|
while true # sequence
|
1778
1982
|
_tmp = apply(:__hyphen_)
|
1779
1983
|
unless _tmp
|
1780
|
-
self.pos =
|
1984
|
+
self.pos = _save17
|
1781
1985
|
break
|
1782
1986
|
end
|
1783
1987
|
_tmp = match_string("=")
|
1784
1988
|
unless _tmp
|
1785
|
-
self.pos =
|
1989
|
+
self.pos = _save17
|
1786
1990
|
end
|
1787
1991
|
break
|
1788
1992
|
end # end sequence
|
1789
1993
|
|
1790
1994
|
_tmp = _tmp ? nil : true
|
1791
|
-
self.pos =
|
1995
|
+
self.pos = _save16
|
1792
1996
|
unless _tmp
|
1793
1997
|
self.pos = _save14
|
1794
1998
|
break
|
1795
1999
|
end
|
1796
|
-
@result = begin; @g.invoke(name) ; end
|
2000
|
+
@result = begin; @g.invoke(name, text.empty? ? nil : text) ; end
|
1797
2001
|
_tmp = true
|
1798
2002
|
unless _tmp
|
1799
2003
|
self.pos = _save14
|
@@ -1804,37 +2008,37 @@ class KPeg::FormatParser
|
|
1804
2008
|
break if _tmp
|
1805
2009
|
self.pos = _save
|
1806
2010
|
|
1807
|
-
|
2011
|
+
_save18 = self.pos
|
1808
2012
|
while true # sequence
|
1809
2013
|
_tmp = match_string("^")
|
1810
2014
|
unless _tmp
|
1811
|
-
self.pos =
|
2015
|
+
self.pos = _save18
|
1812
2016
|
break
|
1813
2017
|
end
|
1814
2018
|
_tmp = apply(:_var)
|
1815
2019
|
name = @result
|
1816
2020
|
unless _tmp
|
1817
|
-
self.pos =
|
2021
|
+
self.pos = _save18
|
1818
2022
|
break
|
1819
2023
|
end
|
1820
2024
|
_text_start = self.pos
|
1821
|
-
|
2025
|
+
_save19 = self.pos
|
1822
2026
|
_tmp = apply(:_nested_paren)
|
1823
2027
|
unless _tmp
|
1824
2028
|
_tmp = true
|
1825
|
-
self.pos =
|
2029
|
+
self.pos = _save19
|
1826
2030
|
end
|
1827
2031
|
if _tmp
|
1828
2032
|
text = get_text(_text_start)
|
1829
2033
|
end
|
1830
2034
|
unless _tmp
|
1831
|
-
self.pos =
|
2035
|
+
self.pos = _save18
|
1832
2036
|
break
|
1833
2037
|
end
|
1834
2038
|
@result = begin; @g.foreign_invoke("parent", name, text) ; end
|
1835
2039
|
_tmp = true
|
1836
2040
|
unless _tmp
|
1837
|
-
self.pos =
|
2041
|
+
self.pos = _save18
|
1838
2042
|
end
|
1839
2043
|
break
|
1840
2044
|
end # end sequence
|
@@ -1842,48 +2046,48 @@ class KPeg::FormatParser
|
|
1842
2046
|
break if _tmp
|
1843
2047
|
self.pos = _save
|
1844
2048
|
|
1845
|
-
|
2049
|
+
_save20 = self.pos
|
1846
2050
|
while true # sequence
|
1847
2051
|
_tmp = match_string("%")
|
1848
2052
|
unless _tmp
|
1849
|
-
self.pos =
|
2053
|
+
self.pos = _save20
|
1850
2054
|
break
|
1851
2055
|
end
|
1852
2056
|
_tmp = apply(:_var)
|
1853
2057
|
gram = @result
|
1854
2058
|
unless _tmp
|
1855
|
-
self.pos =
|
2059
|
+
self.pos = _save20
|
1856
2060
|
break
|
1857
2061
|
end
|
1858
2062
|
_tmp = match_string(".")
|
1859
2063
|
unless _tmp
|
1860
|
-
self.pos =
|
2064
|
+
self.pos = _save20
|
1861
2065
|
break
|
1862
2066
|
end
|
1863
2067
|
_tmp = apply(:_var)
|
1864
2068
|
name = @result
|
1865
2069
|
unless _tmp
|
1866
|
-
self.pos =
|
2070
|
+
self.pos = _save20
|
1867
2071
|
break
|
1868
2072
|
end
|
1869
2073
|
_text_start = self.pos
|
1870
|
-
|
2074
|
+
_save21 = self.pos
|
1871
2075
|
_tmp = apply(:_nested_paren)
|
1872
2076
|
unless _tmp
|
1873
2077
|
_tmp = true
|
1874
|
-
self.pos =
|
2078
|
+
self.pos = _save21
|
1875
2079
|
end
|
1876
2080
|
if _tmp
|
1877
2081
|
text = get_text(_text_start)
|
1878
2082
|
end
|
1879
2083
|
unless _tmp
|
1880
|
-
self.pos =
|
2084
|
+
self.pos = _save20
|
1881
2085
|
break
|
1882
2086
|
end
|
1883
2087
|
@result = begin; @g.foreign_invoke(gram, name, text) ; end
|
1884
2088
|
_tmp = true
|
1885
2089
|
unless _tmp
|
1886
|
-
self.pos =
|
2090
|
+
self.pos = _save20
|
1887
2091
|
end
|
1888
2092
|
break
|
1889
2093
|
end # end sequence
|
@@ -1891,54 +2095,54 @@ class KPeg::FormatParser
|
|
1891
2095
|
break if _tmp
|
1892
2096
|
self.pos = _save
|
1893
2097
|
|
1894
|
-
|
2098
|
+
_save22 = self.pos
|
1895
2099
|
while true # sequence
|
1896
2100
|
_tmp = apply(:_var)
|
1897
2101
|
name = @result
|
1898
2102
|
unless _tmp
|
1899
|
-
self.pos =
|
2103
|
+
self.pos = _save22
|
1900
2104
|
break
|
1901
2105
|
end
|
1902
2106
|
_text_start = self.pos
|
1903
|
-
|
2107
|
+
_save23 = self.pos
|
1904
2108
|
_tmp = apply(:_nested_paren)
|
1905
2109
|
unless _tmp
|
1906
2110
|
_tmp = true
|
1907
|
-
self.pos =
|
2111
|
+
self.pos = _save23
|
1908
2112
|
end
|
1909
2113
|
if _tmp
|
1910
2114
|
text = get_text(_text_start)
|
1911
2115
|
end
|
1912
2116
|
unless _tmp
|
1913
|
-
self.pos =
|
2117
|
+
self.pos = _save22
|
1914
2118
|
break
|
1915
2119
|
end
|
1916
|
-
_save23 = self.pos
|
1917
|
-
|
1918
2120
|
_save24 = self.pos
|
2121
|
+
|
2122
|
+
_save25 = self.pos
|
1919
2123
|
while true # sequence
|
1920
2124
|
_tmp = apply(:__hyphen_)
|
1921
2125
|
unless _tmp
|
1922
|
-
self.pos =
|
2126
|
+
self.pos = _save25
|
1923
2127
|
break
|
1924
2128
|
end
|
1925
2129
|
_tmp = match_string("=")
|
1926
2130
|
unless _tmp
|
1927
|
-
self.pos =
|
2131
|
+
self.pos = _save25
|
1928
2132
|
end
|
1929
2133
|
break
|
1930
2134
|
end # end sequence
|
1931
2135
|
|
1932
2136
|
_tmp = _tmp ? nil : true
|
1933
|
-
self.pos =
|
2137
|
+
self.pos = _save24
|
1934
2138
|
unless _tmp
|
1935
|
-
self.pos =
|
2139
|
+
self.pos = _save22
|
1936
2140
|
break
|
1937
2141
|
end
|
1938
|
-
@result = begin; text.empty? ?
|
2142
|
+
@result = begin; @g.ref(name, nil, text.empty? ? nil : text) ; end
|
1939
2143
|
_tmp = true
|
1940
2144
|
unless _tmp
|
1941
|
-
self.pos =
|
2145
|
+
self.pos = _save22
|
1942
2146
|
end
|
1943
2147
|
break
|
1944
2148
|
end # end sequence
|
@@ -2871,14 +3075,15 @@ class KPeg::FormatParser
|
|
2871
3075
|
Rules[:_kleene] = rule_info("kleene", "\"*\"")
|
2872
3076
|
Rules[:_var] = rule_info("var", "< (\"-\" | /[a-zA-Z][\\-_a-zA-Z0-9]*/) > { text }")
|
2873
3077
|
Rules[:_method] = rule_info("method", "< /[a-zA-Z_][a-zA-Z0-9_]*/ > { text }")
|
2874
|
-
Rules[:_dbl_escapes] = rule_info("dbl_escapes", "(\"
|
3078
|
+
Rules[:_dbl_escapes] = rule_info("dbl_escapes", "(\"n\" { \"\\n\" } | \"s\" { \" \" } | \"r\" { \"\\r\" } | \"t\" { \"\\t\" } | \"v\" { \"\\v\" } | \"f\" { \"\\f\" } | \"b\" { \"\\b\" } | \"a\" { \"\\a\" } | \"e\" { \"\\e\" } | \"\\\\\" { \"\\\\\" } | \"\\\"\" { \"\\\"\" } | num_escapes)")
|
3079
|
+
Rules[:_num_escapes] = rule_info("num_escapes", "(< /[0-7]{3}/ > { [text.to_i(8)].pack(\"U\") } | \"x\" < /[0-9a-fA-F]{2}/ > { [text.to_i(16)].pack(\"U\") })")
|
2875
3080
|
Rules[:_dbl_seq] = rule_info("dbl_seq", "< /[^\\\\\"]+/ > { text }")
|
2876
|
-
Rules[:_dbl_not_quote] = rule_info("dbl_not_quote", "(dbl_escapes:s | dbl_seq:s)
|
3081
|
+
Rules[:_dbl_not_quote] = rule_info("dbl_not_quote", "(\"\\\\\" dbl_escapes:s | dbl_seq:s)*:ary { Array(ary) }")
|
2877
3082
|
Rules[:_dbl_string] = rule_info("dbl_string", "\"\\\"\" dbl_not_quote:s \"\\\"\" { @g.str(s.join) }")
|
2878
3083
|
Rules[:_sgl_escape_quote] = rule_info("sgl_escape_quote", "\"\\\\'\" { \"'\" }")
|
2879
3084
|
Rules[:_sgl_seq] = rule_info("sgl_seq", "< /[^']/ > { text }")
|
2880
|
-
Rules[:_sgl_not_quote] = rule_info("sgl_not_quote", "(sgl_escape_quote | sgl_seq)
|
2881
|
-
Rules[:_sgl_string] = rule_info("sgl_string", "\"'\" sgl_not_quote:s \"'\" { @g.str(s) }")
|
3085
|
+
Rules[:_sgl_not_quote] = rule_info("sgl_not_quote", "(sgl_escape_quote | sgl_seq)*:segs { Array(segs) }")
|
3086
|
+
Rules[:_sgl_string] = rule_info("sgl_string", "\"'\" sgl_not_quote:s \"'\" { @g.str(s.join) }")
|
2882
3087
|
Rules[:_string] = rule_info("string", "(dbl_string | sgl_string)")
|
2883
3088
|
Rules[:_not_slash] = rule_info("not_slash", "< (\"\\\\/\" | /[^\\/]/)+ > { text }")
|
2884
3089
|
Rules[:_regexp_opts] = rule_info("regexp_opts", "< [a-z]* > { text }")
|
@@ -2891,7 +3096,7 @@ class KPeg::FormatParser
|
|
2891
3096
|
Rules[:_curly_block] = rule_info("curly_block", "curly")
|
2892
3097
|
Rules[:_curly] = rule_info("curly", "\"{\" < (/[^{}\"']+/ | string | curly)* > \"}\" { @g.action(text) }")
|
2893
3098
|
Rules[:_nested_paren] = rule_info("nested_paren", "\"(\" (/[^()\"']+/ | string | nested_paren)* \")\"")
|
2894
|
-
Rules[:_value] = rule_info("value", "(value:v \":\" var:n { @g.t(v,n) } | value:v \"?\" { @g.maybe(v) } | value:v \"+\" { @g.many(v) } | value:v \"*\" { @g.kleene(v) } | value:v mult_range:r { @g.multiple(v, *r) } | \"&\" value:v { @g.andp(v) } | \"!\" value:v { @g.notp(v) } | \"(\" - expression:o - \")\" { o } | \"@<\" - expression:o - \">\" { @g.bounds(o) } | \"<\" - expression:o - \">\" { @g.collect(o) } | curly_block | \"~\" method:m < nested_paren? > { @g.action(\"\#{m}\#{text}\") } | \".\" { @g.dot } | \"@\" var:name !(- \"=\") { @g.invoke(name) } | \"^\" var:name < nested_paren? > { @g.foreign_invoke(\"parent\", name, text) } | \"%\" var:gram \".\" var:name < nested_paren? > { @g.foreign_invoke(gram, name, text) } | var:name < nested_paren? > !(- \"=\") { text.empty? ?
|
3099
|
+
Rules[:_value] = rule_info("value", "(value:v \":\" var:n { @g.t(v,n) } | value:v \"?\" { @g.maybe(v) } | value:v \"+\" { @g.many(v) } | value:v \"*\" { @g.kleene(v) } | value:v mult_range:r { @g.multiple(v, *r) } | \"&\" value:v { @g.andp(v) } | \"!\" value:v { @g.notp(v) } | \"(\" - expression:o - \")\" { o } | \"@<\" - expression:o - \">\" { @g.bounds(o) } | \"<\" - expression:o - \">\" { @g.collect(o) } | curly_block | \"~\" method:m < nested_paren? > { @g.action(\"\#{m}\#{text}\") } | \".\" { @g.dot } | \"@\" var:name < nested_paren? > !(- \"=\") { @g.invoke(name, text.empty? ? nil : text) } | \"^\" var:name < nested_paren? > { @g.foreign_invoke(\"parent\", name, text) } | \"%\" var:gram \".\" var:name < nested_paren? > { @g.foreign_invoke(gram, name, text) } | var:name < nested_paren? > !(- \"=\") { @g.ref(name, nil, text.empty? ? nil : text) } | char_range | regexp | string)")
|
2895
3100
|
Rules[:_spaces] = rule_info("spaces", "(space | comment)+")
|
2896
3101
|
Rules[:_values] = rule_info("values", "(values:s spaces value:v { @g.seq(s, v) } | value:l spaces value:r { @g.seq(l, r) } | value)")
|
2897
3102
|
Rules[:_choose_cont] = rule_info("choose_cont", "- \"|\" - values:v { v }")
|
data/lib/kpeg/grammar.rb
CHANGED
@@ -396,13 +396,14 @@ module KPeg
|
|
396
396
|
end
|
397
397
|
|
398
398
|
class RuleReference < Operator
|
399
|
-
def initialize(name, grammar=nil)
|
399
|
+
def initialize(name, grammar=nil, args=nil)
|
400
400
|
super()
|
401
401
|
@rule_name = name
|
402
402
|
@grammar = grammar
|
403
|
+
@arguments = args
|
403
404
|
end
|
404
405
|
|
405
|
-
attr_reader :rule_name
|
406
|
+
attr_reader :rule_name, :arguments
|
406
407
|
|
407
408
|
def match(x)
|
408
409
|
if @grammar and @grammar != x.grammar
|
@@ -421,14 +422,19 @@ module KPeg
|
|
421
422
|
def ==(obj)
|
422
423
|
case obj
|
423
424
|
when RuleReference
|
424
|
-
@rule_name == obj.rule_name
|
425
|
+
@rule_name == obj.rule_name and @arguments == obj.arguments
|
425
426
|
else
|
426
427
|
super
|
427
428
|
end
|
428
429
|
end
|
429
430
|
|
430
431
|
def inspect
|
431
|
-
|
432
|
+
if @arguments
|
433
|
+
body = "#{@rule_name} #{@arguments}"
|
434
|
+
else
|
435
|
+
body = @rule_name
|
436
|
+
end
|
437
|
+
inspect_type "ref", body
|
432
438
|
end
|
433
439
|
end
|
434
440
|
|
@@ -807,14 +813,14 @@ module KPeg
|
|
807
813
|
NotPredicate.new Grammar.resolve(node)
|
808
814
|
end
|
809
815
|
|
810
|
-
def ref(name, other_grammar=nil)
|
811
|
-
RuleReference.new name.to_s, other_grammar
|
816
|
+
def ref(name, other_grammar=nil, args=nil)
|
817
|
+
RuleReference.new name.to_s, other_grammar, args
|
812
818
|
end
|
813
819
|
|
814
820
|
def invoke(name, args=nil)
|
815
821
|
InvokeRule.new name.to_s, args
|
816
822
|
end
|
817
|
-
|
823
|
+
|
818
824
|
# Invoke a rule defined on a foreign grammar
|
819
825
|
# == Parameters:
|
820
826
|
# gram::
|
@@ -132,10 +132,14 @@ module KPeg
|
|
132
132
|
render_op io, op.op
|
133
133
|
end
|
134
134
|
when RuleReference
|
135
|
-
io.print op.rule_name
|
136
|
-
when InvokeRule
|
137
135
|
if op.arguments
|
138
136
|
io.print "#{op.rule_name}#{op.arguments}"
|
137
|
+
else
|
138
|
+
io.print "#{op.rule_name}"
|
139
|
+
end
|
140
|
+
when InvokeRule
|
141
|
+
if op.arguments
|
142
|
+
io.print "@#{op.rule_name}#{op.arguments}"
|
139
143
|
else
|
140
144
|
io.print "@#{op.rule_name}"
|
141
145
|
end
|
data/lib/kpeg/version.rb
CHANGED
@@ -799,7 +799,7 @@ class Test < KPeg::CompiledParser
|
|
799
799
|
return _tmp
|
800
800
|
end
|
801
801
|
|
802
|
-
# root = greeting(1,2)
|
802
|
+
# root = @greeting(1,2)
|
803
803
|
def _root
|
804
804
|
_tmp = _greeting(1,2)
|
805
805
|
set_failed_rule :_root unless _tmp
|
@@ -808,7 +808,7 @@ class Test < KPeg::CompiledParser
|
|
808
808
|
|
809
809
|
Rules = {}
|
810
810
|
Rules[:_greeting] = rule_info("greeting", "\\\"hello\\\"")
|
811
|
-
Rules[:_root] = rule_info("root", "greeting(1,2)")
|
811
|
+
Rules[:_root] = rule_info("root", "@greeting(1,2)")
|
812
812
|
end
|
813
813
|
STR
|
814
814
|
|
data/test/test_kpeg_format.rb
CHANGED
@@ -27,6 +27,10 @@ class TestKPegFormat < Test::Unit::TestCase
|
|
27
27
|
assert_rule G.ref("b"), match("a=b"), "a"
|
28
28
|
end
|
29
29
|
|
30
|
+
def test_apply_with_arg
|
31
|
+
assert_rule G.ref("b", nil, "(x)"), match("a=b(x)"), "a"
|
32
|
+
end
|
33
|
+
|
30
34
|
def test_invoke
|
31
35
|
assert_rule G.invoke("b"), match("a=@b"), "a"
|
32
36
|
end
|
@@ -107,7 +111,7 @@ b(p) = x
|
|
107
111
|
|
108
112
|
|
109
113
|
def test_invoke_with_multiple_args
|
110
|
-
assert_rule G.invoke("b", "(1,2)"), match("a
|
114
|
+
assert_rule G.invoke("b", "(1,2)"), match("a=@b(1,2)"), "a"
|
111
115
|
end
|
112
116
|
|
113
117
|
def test_invoke_foreign_rule
|
@@ -140,7 +144,11 @@ b(p) = x
|
|
140
144
|
end
|
141
145
|
|
142
146
|
def test_string
|
147
|
+
assert_rule G.str(""), match('a=""')
|
143
148
|
assert_rule G.str("hello"), match('a="hello"')
|
149
|
+
assert_rule G.str("hello\ngoodbye"), match('a="hello\ngoodbye"')
|
150
|
+
assert_rule G.str("\n\s\r\t\v\f\b\a\r\\\"\012\x1b"),
|
151
|
+
match('a="\n\s\r\t\v\f\b\a\r\\\\\\"\012\x1b"')
|
144
152
|
assert_rule G.str("h\"ello"), match('a="h\"ello"')
|
145
153
|
end
|
146
154
|
|
@@ -453,7 +461,7 @@ fact = fact "*" num
|
|
453
461
|
def test_allow_ends_with_comment
|
454
462
|
path = File.expand_path("../inputs/comments.kpeg", __FILE__)
|
455
463
|
parser = KPeg::FormatParser.new File.read(path), true
|
456
|
-
|
464
|
+
assert_equal true, parser.parse
|
457
465
|
end
|
458
466
|
|
459
467
|
def test_roundtrip
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kpeg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 57
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 8
|
9
|
-
-
|
10
|
-
version: 0.8.
|
9
|
+
- 3
|
10
|
+
version: 0.8.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Evan Phoenix
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-05-05 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|