abnf-parser 0.8.1 → 0.9.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 +4 -4
- data/lib/abnf/parser.rb +23 -25
- data/lib/abnf/parser/common.rb +63 -0
- data/lib/abnf/parser/compiler.rb +73 -33
- data/lib/abnf/parser/compiler/alternation.rb +54 -0
- data/lib/abnf/parser/compiler/concatenation.rb +55 -0
- data/lib/abnf/parser/compiler/element.rb +87 -0
- data/lib/abnf/parser/compiler/group.rb +19 -0
- data/lib/abnf/parser/compiler/option.rb +19 -0
- data/lib/abnf/parser/compiler/repetition.rb +50 -0
- data/lib/abnf/parser/compiler/rule_builder.rb +32 -0
- data/lib/abnf/parser/compiler/rule_list.rb +67 -0
- data/lib/abnf/parser/compiler/token.rb +34 -0
- data/lib/abnf/parser/compiler/tokenizer.rb +95 -0
- data/lib/abnf/parser/controls.rb +5 -3
- data/lib/abnf/parser/controls/abnf.rb +237 -0
- data/lib/abnf/parser/controls/compiler/tokens.rb +97 -0
- data/lib/abnf/parser/controls/nodes.rb +113 -0
- data/lib/abnf/parser/controls/rule_lists.rb +63 -0
- data/lib/abnf/parser/controls/rule_lists/multiples_of_three.rb +146 -0
- data/lib/abnf/parser/controls/rules.rb +40 -17
- data/lib/abnf/parser/{errors.rb → error.rb} +0 -2
- data/lib/abnf/parser/node.rb +138 -0
- data/lib/abnf/parser/rule_list.rb +50 -11
- data/lib/abnf/parser/rules/alternation.rb +38 -0
- data/lib/abnf/parser/rules/concatenation.rb +36 -0
- data/lib/abnf/parser/rules/prose_val.rb +18 -0
- data/lib/abnf/parser/rules/reference.rb +22 -0
- data/lib/abnf/parser/rules/regexp_pattern.rb +35 -0
- data/lib/abnf/parser/rules/repetition.rb +46 -0
- data/lib/abnf/parser/rules/terminal.rb +63 -0
- metadata +31 -31
- data/lib/abnf/parser/ast.rb +0 -67
- data/lib/abnf/parser/controls/ast.rb +0 -28
- data/lib/abnf/parser/controls/grammar.rb +0 -32
- data/lib/abnf/parser/controls/text_stream.rb +0 -15
- data/lib/abnf/parser/grammar.rb +0 -17
- data/lib/abnf/parser/grammar/alternative.rb +0 -27
- data/lib/abnf/parser/grammar/char_val.rb +0 -15
- data/lib/abnf/parser/grammar/concatenation.rb +0 -21
- data/lib/abnf/parser/grammar/element.rb +0 -57
- data/lib/abnf/parser/grammar/num_val.rb +0 -72
- data/lib/abnf/parser/grammar/prose_val.rb +0 -15
- data/lib/abnf/parser/grammar/repetition.rb +0 -58
- data/lib/abnf/parser/grammar/rule.rb +0 -31
- data/lib/abnf/parser/grammar/rulename.rb +0 -15
- data/lib/abnf/parser/rule.rb +0 -10
- data/lib/abnf/parser/rule/alternative.rb +0 -43
- data/lib/abnf/parser/rule/concatenation.rb +0 -29
- data/lib/abnf/parser/rule/none.rb +0 -17
- data/lib/abnf/parser/rule/optional.rb +0 -24
- data/lib/abnf/parser/rule/reference.rb +0 -19
- data/lib/abnf/parser/rule/repetition.rb +0 -41
- data/lib/abnf/parser/rule/terminal_value.rb +0 -32
- data/lib/abnf/parser/rule/value_range.rb +0 -33
- data/lib/abnf/parser/rule_list/entry.rb +0 -21
- data/lib/abnf/parser/text_stream.rb +0 -67
@@ -0,0 +1,138 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Parser
|
3
|
+
module Node
|
4
|
+
def self.alternation node, abnf
|
5
|
+
Alternation.new node, abnf
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.concatenation children=nil, abnf
|
9
|
+
children ||= Array(children)
|
10
|
+
Sequence.new children, abnf
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.repetition children=nil, abnf
|
14
|
+
children ||= Array(children)
|
15
|
+
Sequence.new children, abnf
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.pattern_match match_data, abnf
|
19
|
+
PatternMatch.new match_data, abnf
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.terminal text, abnf
|
23
|
+
Single.new text, abnf
|
24
|
+
end
|
25
|
+
|
26
|
+
def == other_node
|
27
|
+
return false unless other_node.is_a? Node
|
28
|
+
self.text == other_node.text and self.abnf == other_node.abnf
|
29
|
+
end
|
30
|
+
|
31
|
+
def octets
|
32
|
+
text.bytesize
|
33
|
+
end
|
34
|
+
|
35
|
+
class Alternation
|
36
|
+
include Node
|
37
|
+
|
38
|
+
attr_reader :abnf
|
39
|
+
attr_reader :match
|
40
|
+
|
41
|
+
def initialize match, abnf
|
42
|
+
@abnf = abnf
|
43
|
+
@match = match
|
44
|
+
end
|
45
|
+
|
46
|
+
def text
|
47
|
+
match.text
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Sequence
|
52
|
+
include Enumerable
|
53
|
+
include Node
|
54
|
+
|
55
|
+
attr_reader :abnf
|
56
|
+
attr_reader :children
|
57
|
+
|
58
|
+
def initialize children, abnf
|
59
|
+
@abnf = abnf
|
60
|
+
@children = children
|
61
|
+
end
|
62
|
+
|
63
|
+
def [] index
|
64
|
+
children[index]
|
65
|
+
end
|
66
|
+
|
67
|
+
def add child
|
68
|
+
children << child
|
69
|
+
end
|
70
|
+
alias_method :<<, :add
|
71
|
+
|
72
|
+
def child_count
|
73
|
+
children.size
|
74
|
+
end
|
75
|
+
|
76
|
+
def each &block
|
77
|
+
children.each &block
|
78
|
+
end
|
79
|
+
|
80
|
+
def text
|
81
|
+
@text ||= to_a.join
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_a
|
85
|
+
map do |child|
|
86
|
+
if child.respond_to? :to_a
|
87
|
+
child.to_a
|
88
|
+
else
|
89
|
+
child.text
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class Single
|
96
|
+
include Node
|
97
|
+
|
98
|
+
attr_reader :abnf
|
99
|
+
attr_reader :text
|
100
|
+
|
101
|
+
def initialize text, abnf
|
102
|
+
@text = text
|
103
|
+
@abnf = abnf
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class PatternMatch
|
108
|
+
include Node
|
109
|
+
|
110
|
+
attr_reader :abnf
|
111
|
+
attr_reader :match_data
|
112
|
+
|
113
|
+
def initialize match_data, abnf
|
114
|
+
@match_data = match_data
|
115
|
+
@abnf = abnf
|
116
|
+
end
|
117
|
+
|
118
|
+
def pattern
|
119
|
+
match_data.regexp
|
120
|
+
end
|
121
|
+
|
122
|
+
def text
|
123
|
+
match_data.to_s
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_h
|
127
|
+
hash = {}
|
128
|
+
|
129
|
+
match_data.names.each do |name|
|
130
|
+
hash[name] = match_data[name]
|
131
|
+
end
|
132
|
+
|
133
|
+
hash
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -1,24 +1,63 @@
|
|
1
1
|
module ABNF
|
2
2
|
module Parser
|
3
3
|
class RuleList
|
4
|
-
|
4
|
+
def == other_rule_list
|
5
|
+
return false unless other_rule_list.is_a? self.class
|
5
6
|
|
6
|
-
|
7
|
-
@rules = {}
|
7
|
+
rules == other_rule_list.rules
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
10
|
+
def [] rule_name
|
11
|
+
rules[rule_name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def []= rule_name, rule
|
15
|
+
rules[rule_name] = rule
|
16
|
+
end
|
17
|
+
|
18
|
+
def apply rule_name, io
|
19
|
+
rule = fetch rule_name
|
20
|
+
|
21
|
+
call_method = rule.method :call
|
12
22
|
|
13
|
-
|
14
|
-
stream.match Grammar::C_WSP
|
15
|
-
stream.match Grammar::C_NL
|
23
|
+
io = StringIO.new io if io.is_a? String
|
16
24
|
|
17
|
-
|
18
|
-
|
25
|
+
rules[rule_name].(io, self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def fetch rule_name
|
29
|
+
rule = rules[rule_name]
|
19
30
|
|
20
|
-
|
31
|
+
unless rule
|
32
|
+
raise Error.new "Rule not found: #{rule_name.inspect}"
|
21
33
|
end
|
34
|
+
|
35
|
+
rule
|
36
|
+
end
|
37
|
+
|
38
|
+
def names
|
39
|
+
rules.keys
|
40
|
+
end
|
41
|
+
|
42
|
+
def replace rule_name, regexp, max_octets
|
43
|
+
existing_rule = fetch rule_name
|
44
|
+
abnf = existing_rule
|
45
|
+
|
46
|
+
rule = Rules::RegexpPattern.new regexp, abnf, max_octets
|
47
|
+
rules[rule_name] = rule
|
48
|
+
end
|
49
|
+
|
50
|
+
def rules
|
51
|
+
@rules ||= {}
|
52
|
+
end
|
53
|
+
|
54
|
+
def update additional_rules
|
55
|
+
rules.update additional_rules
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.common
|
59
|
+
abnf = Common.to_s
|
60
|
+
Compiler.(abnf)
|
22
61
|
end
|
23
62
|
end
|
24
63
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Parser
|
3
|
+
module Rules
|
4
|
+
class Alternation
|
5
|
+
attr_reader :abnf
|
6
|
+
attr_reader :alternatives
|
7
|
+
|
8
|
+
def initialize alternatives, abnf
|
9
|
+
@abnf = abnf
|
10
|
+
@alternatives = alternatives
|
11
|
+
end
|
12
|
+
|
13
|
+
def == other_rule
|
14
|
+
return unless other_rule.is_a? self.class
|
15
|
+
alternatives == other_rule.alternatives
|
16
|
+
end
|
17
|
+
|
18
|
+
def call io, rule_list=nil
|
19
|
+
best_match = nil
|
20
|
+
|
21
|
+
alternatives.each do |alternative|
|
22
|
+
node = alternative.(io, rule_list) or next
|
23
|
+
|
24
|
+
io.seek -node.octets, IO::SEEK_CUR
|
25
|
+
|
26
|
+
best_match ||= node
|
27
|
+
best_match = node if node.octets > best_match.octets
|
28
|
+
end
|
29
|
+
|
30
|
+
return unless best_match
|
31
|
+
|
32
|
+
io.seek best_match.octets, IO::SEEK_CUR
|
33
|
+
best_match
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Parser
|
3
|
+
module Rules
|
4
|
+
class Concatenation
|
5
|
+
attr_reader :abnf
|
6
|
+
attr_reader :rules
|
7
|
+
|
8
|
+
def initialize rules, abnf
|
9
|
+
@abnf = abnf
|
10
|
+
@rules = rules
|
11
|
+
end
|
12
|
+
|
13
|
+
def == other_rule
|
14
|
+
return false unless other_rule.is_a? self.class
|
15
|
+
self.rules == other_rule.rules
|
16
|
+
end
|
17
|
+
|
18
|
+
def call io, rule_list=nil
|
19
|
+
node = Node.concatenation abnf
|
20
|
+
|
21
|
+
match = rules.all? do |rule|
|
22
|
+
child = rule.(io, rule_list) or break
|
23
|
+
node << child
|
24
|
+
end
|
25
|
+
|
26
|
+
if match
|
27
|
+
node
|
28
|
+
else
|
29
|
+
io.seek -node.octets, IO::SEEK_CUR
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Parser
|
3
|
+
module Rules
|
4
|
+
class ProseVal
|
5
|
+
attr_reader :abnf
|
6
|
+
|
7
|
+
def initialize abnf
|
8
|
+
@abnf = abnf
|
9
|
+
end
|
10
|
+
|
11
|
+
def call io, _=nil
|
12
|
+
error = ABNF::Parser::Error.new "Cannot parse prose #{abnf.inspect}"
|
13
|
+
raise error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Parser
|
3
|
+
module Rules
|
4
|
+
class Reference
|
5
|
+
attr_reader :rule_name
|
6
|
+
|
7
|
+
def initialize rule_name
|
8
|
+
@rule_name = rule_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def abnf
|
12
|
+
rule_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def call io, rule_list
|
16
|
+
rule = rule_list.fetch rule_name
|
17
|
+
rule.(io, rule_list)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Parser
|
3
|
+
module Rules
|
4
|
+
class RegexpPattern
|
5
|
+
attr_reader :abnf
|
6
|
+
attr_reader :max_octets
|
7
|
+
attr_reader :regexp
|
8
|
+
|
9
|
+
def initialize regexp, abnf, max_octets
|
10
|
+
@abnf = abnf
|
11
|
+
@max_octets = max_octets
|
12
|
+
@regexp = regexp
|
13
|
+
end
|
14
|
+
|
15
|
+
def bounded_regexp
|
16
|
+
@bounded_regexp ||= %r{\A#{regexp}}
|
17
|
+
end
|
18
|
+
|
19
|
+
def call io, _=nil
|
20
|
+
string = io.read max_octets
|
21
|
+
return unless string
|
22
|
+
io.seek -string.bytesize, IO::SEEK_CUR
|
23
|
+
|
24
|
+
match_data = bounded_regexp.match string
|
25
|
+
|
26
|
+
if match_data
|
27
|
+
node = Node.pattern_match match_data, abnf
|
28
|
+
io.seek node.octets, IO::SEEK_CUR
|
29
|
+
node
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Parser
|
3
|
+
module Rules
|
4
|
+
class Repetition
|
5
|
+
attr_reader :abnf
|
6
|
+
attr_reader :rule
|
7
|
+
attr_reader :range
|
8
|
+
|
9
|
+
def initialize rule, range, abnf
|
10
|
+
@abnf = abnf
|
11
|
+
@rule = rule
|
12
|
+
@range = range
|
13
|
+
end
|
14
|
+
|
15
|
+
def == other_rule
|
16
|
+
return false unless other_rule.is_a? self.class
|
17
|
+
rule == other_rule.rule and range == other_rule.range
|
18
|
+
end
|
19
|
+
|
20
|
+
def call io, rule_list=nil
|
21
|
+
node = Node.repetition abnf
|
22
|
+
|
23
|
+
(0...maximum).each do
|
24
|
+
child = rule.(io, rule_list) or break
|
25
|
+
node << child
|
26
|
+
end
|
27
|
+
|
28
|
+
if node.child_count >= minimum
|
29
|
+
node
|
30
|
+
else
|
31
|
+
io.seek -node.octets, IO::SEEK_CUR
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def maximum
|
37
|
+
range.last
|
38
|
+
end
|
39
|
+
|
40
|
+
def minimum
|
41
|
+
range.first
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Parser
|
3
|
+
module Rules
|
4
|
+
class Terminal
|
5
|
+
attr_reader :abnf
|
6
|
+
attr_reader :pattern
|
7
|
+
|
8
|
+
def initialize pattern, abnf
|
9
|
+
@abnf = abnf
|
10
|
+
@pattern = pattern
|
11
|
+
fail if self.class == Terminal
|
12
|
+
end
|
13
|
+
|
14
|
+
def == other_rule
|
15
|
+
return false unless other_rule.is_a? self.class
|
16
|
+
pattern == other_rule.pattern
|
17
|
+
end
|
18
|
+
|
19
|
+
def call io, _=nil
|
20
|
+
potential_match = io.read octets
|
21
|
+
return unless potential_match
|
22
|
+
|
23
|
+
matches = match? potential_match
|
24
|
+
|
25
|
+
if matches
|
26
|
+
Node.terminal potential_match, abnf
|
27
|
+
else
|
28
|
+
io.seek -potential_match.bytesize, IO::SEEK_CUR
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class String < Terminal
|
34
|
+
def match? potential_match
|
35
|
+
pattern == potential_match
|
36
|
+
end
|
37
|
+
|
38
|
+
def octets
|
39
|
+
pattern.bytesize
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.string *arguments
|
44
|
+
String.new *arguments
|
45
|
+
end
|
46
|
+
|
47
|
+
class CharacterRange < Terminal
|
48
|
+
def match? potential_match
|
49
|
+
pattern.include? potential_match
|
50
|
+
end
|
51
|
+
|
52
|
+
def octets
|
53
|
+
1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.character_range *arguments
|
58
|
+
CharacterRange.new *arguments
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|