abnf-parser 0.8.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/lib/abnf/compiler.rb +28 -0
- data/lib/abnf/compiler/ast.rb +67 -0
- data/lib/abnf/compiler/controls.rb +4 -0
- data/lib/abnf/compiler/controls/ast.rb +28 -0
- data/lib/abnf/compiler/controls/grammar.rb +32 -0
- data/lib/abnf/compiler/controls/rules.rb +44 -0
- data/lib/abnf/compiler/controls/text_stream.rb +15 -0
- data/lib/abnf/compiler/errors.rb +7 -0
- data/lib/abnf/compiler/grammar.rb +17 -0
- data/lib/abnf/compiler/grammar/alternative.rb +27 -0
- data/lib/abnf/compiler/grammar/char_val.rb +15 -0
- data/lib/abnf/compiler/grammar/compiler.rb +55 -0
- data/lib/abnf/compiler/grammar/concatenation.rb +21 -0
- data/lib/abnf/compiler/grammar/element.rb +57 -0
- data/lib/abnf/compiler/grammar/num_val.rb +72 -0
- data/lib/abnf/compiler/grammar/prose_val.rb +15 -0
- data/lib/abnf/compiler/grammar/repetition.rb +58 -0
- data/lib/abnf/compiler/grammar/rule.rb +31 -0
- data/lib/abnf/compiler/grammar/rulename.rb +15 -0
- data/lib/abnf/compiler/rule.rb +10 -0
- data/lib/abnf/compiler/rule/alternative.rb +43 -0
- data/lib/abnf/compiler/rule/concatenation.rb +29 -0
- data/lib/abnf/compiler/rule/none.rb +17 -0
- data/lib/abnf/compiler/rule/optional.rb +24 -0
- data/lib/abnf/compiler/rule/reference.rb +19 -0
- data/lib/abnf/compiler/rule/repetition.rb +41 -0
- data/lib/abnf/compiler/rule/terminal_value.rb +32 -0
- data/lib/abnf/compiler/rule/value_range.rb +33 -0
- data/lib/abnf/compiler/rule_list.rb +25 -0
- data/lib/abnf/compiler/rule_list/entry.rb +21 -0
- data/lib/abnf/compiler/text_stream.rb +67 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f9345bd72e56a26df453cb85fe51c3dac095f90c
|
4
|
+
data.tar.gz: 9caae3be175e985e45e9be3fa75d7293e28d13fe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fce4984fcd8c8f28cbfa5b1cadb1721fcb43f08b9c5754c5d2aa42c1b2a335f33b1efd18c6d58ad785bccf4bb4fe3113929c09afa6c9ac04bd2dce5e59799f60
|
7
|
+
data.tar.gz: e8ddbfa79408449743b00d809006dd897544ee10bd966d26bc09d186cc55624f269f01bf28721d10b541644b08062cf53e4405242f951bed9748c77e6d34c721
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'abnf/compiler/ast'
|
2
|
+
require 'abnf/compiler/errors'
|
3
|
+
require 'abnf/compiler/text_stream'
|
4
|
+
|
5
|
+
require 'abnf/compiler/grammar'
|
6
|
+
require 'abnf/compiler/grammar/compiler'
|
7
|
+
require 'abnf/compiler/grammar/alternative'
|
8
|
+
require 'abnf/compiler/grammar/char_val'
|
9
|
+
require 'abnf/compiler/grammar/concatenation'
|
10
|
+
require 'abnf/compiler/grammar/element'
|
11
|
+
require 'abnf/compiler/grammar/num_val'
|
12
|
+
require 'abnf/compiler/grammar/prose_val'
|
13
|
+
require 'abnf/compiler/grammar/repetition'
|
14
|
+
require 'abnf/compiler/grammar/rule'
|
15
|
+
require 'abnf/compiler/grammar/rulename'
|
16
|
+
|
17
|
+
require 'abnf/compiler/rule'
|
18
|
+
require 'abnf/compiler/rule/alternative'
|
19
|
+
require 'abnf/compiler/rule/concatenation'
|
20
|
+
require 'abnf/compiler/rule/none'
|
21
|
+
require 'abnf/compiler/rule/optional'
|
22
|
+
require 'abnf/compiler/rule/reference'
|
23
|
+
require 'abnf/compiler/rule/repetition'
|
24
|
+
require 'abnf/compiler/rule/terminal_value'
|
25
|
+
require 'abnf/compiler/rule/value_range'
|
26
|
+
|
27
|
+
require 'abnf/compiler/rule_list'
|
28
|
+
require 'abnf/compiler/rule_list/entry'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module AST
|
4
|
+
def self.leaf *arguments
|
5
|
+
Leaf.new *arguments
|
6
|
+
end
|
7
|
+
|
8
|
+
class Leaf
|
9
|
+
attr_reader :text
|
10
|
+
|
11
|
+
def initialize text
|
12
|
+
@text = text
|
13
|
+
end
|
14
|
+
|
15
|
+
def == other_node
|
16
|
+
other_node.respond_to? :text and text == other_node.text
|
17
|
+
end
|
18
|
+
|
19
|
+
def inner_text
|
20
|
+
text
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.repetition *arguments
|
25
|
+
Repetition.new *arguments
|
26
|
+
end
|
27
|
+
|
28
|
+
class Repetition
|
29
|
+
attr_reader :nodes
|
30
|
+
|
31
|
+
def initialize *nodes
|
32
|
+
@nodes = nodes
|
33
|
+
end
|
34
|
+
|
35
|
+
def == other_node
|
36
|
+
other_node.respond_to? :nodes and nodes == other_node.nodes
|
37
|
+
end
|
38
|
+
|
39
|
+
def inner_text
|
40
|
+
strings = nodes.map &:inner_text
|
41
|
+
strings.join
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.sequence *arguments
|
46
|
+
Sequence.new *arguments
|
47
|
+
end
|
48
|
+
|
49
|
+
class Sequence
|
50
|
+
attr_reader :nodes
|
51
|
+
|
52
|
+
def initialize *nodes
|
53
|
+
@nodes = nodes
|
54
|
+
end
|
55
|
+
|
56
|
+
def == other_node
|
57
|
+
other_node.respond_to? :nodes and nodes == other_node.nodes
|
58
|
+
end
|
59
|
+
|
60
|
+
def inner_text
|
61
|
+
strings = nodes.map &:inner_text
|
62
|
+
strings.join
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Controls
|
4
|
+
module AST
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def leaf text = nil
|
8
|
+
text ||= 'some-string'
|
9
|
+
Compiler::AST.leaf text
|
10
|
+
end
|
11
|
+
|
12
|
+
def repetition
|
13
|
+
Compiler::AST.repetition(
|
14
|
+
leaf('some-string'),
|
15
|
+
leaf('other-string'),
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def sequence
|
20
|
+
Compiler::AST.sequence(
|
21
|
+
leaf('some-string'),
|
22
|
+
leaf('other-string'),
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Controls
|
4
|
+
module Grammar
|
5
|
+
class Example
|
6
|
+
attr_reader :abnf
|
7
|
+
attr_reader :type
|
8
|
+
|
9
|
+
def initialize abnf, type
|
10
|
+
@abnf = abnf
|
11
|
+
@type = type
|
12
|
+
end
|
13
|
+
|
14
|
+
def rule
|
15
|
+
@rule ||= type.compile abnf
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Alternative = Example.new '1*%x30-39 / *%x30-39 "*" *%x30-39', Compiler::Grammar::Alternative
|
20
|
+
CharVal = Example.new '"some-string"', Compiler::Grammar::CharVal
|
21
|
+
Concatenation = Example.new '"some-string" " " "some-string"', Compiler::Grammar::Concatenation
|
22
|
+
Group = Example.new '( "foo" / "bar" )', Compiler::Grammar::Element
|
23
|
+
NumVal = Example.new '%x41.42.43', Compiler::Grammar::NumVal
|
24
|
+
Option = Example.new '[ "some-string" ]', Compiler::Grammar::Element
|
25
|
+
Repetition = Example.new '1*2"some-element"', Compiler::Grammar::Repetition
|
26
|
+
Rulename = Example.new 'some-rule', Compiler::Grammar::Rulename
|
27
|
+
Rule = Example.new "some-rule = \"some-string\"\r\n", Compiler::Grammar::Rule
|
28
|
+
ProseVal = Example.new '<Some Prose>', Compiler::Grammar::ProseVal
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Controls
|
4
|
+
module Rules
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def alternative
|
8
|
+
Compiler::Rule::Alternative.new terminal_value, value_range
|
9
|
+
end
|
10
|
+
|
11
|
+
def concatenation
|
12
|
+
Compiler::Rule::Concatenation.new terminal_value, reference
|
13
|
+
end
|
14
|
+
|
15
|
+
def optional
|
16
|
+
Compiler::Rule::Optional.new terminal_value
|
17
|
+
end
|
18
|
+
|
19
|
+
def reference
|
20
|
+
Compiler::Rule::Reference.new 'some-rule'
|
21
|
+
end
|
22
|
+
|
23
|
+
def repetition range = nil
|
24
|
+
range ||= (1..2)
|
25
|
+
element = Rules.terminal_value
|
26
|
+
|
27
|
+
Compiler::Rule::Repetition.new range, element
|
28
|
+
end
|
29
|
+
|
30
|
+
def space
|
31
|
+
Compiler::Rule::TerminalValue.new ' '
|
32
|
+
end
|
33
|
+
|
34
|
+
def terminal_value case_sensitive = false
|
35
|
+
Compiler::Rule::TerminalValue.new 'some-string', case_sensitive
|
36
|
+
end
|
37
|
+
|
38
|
+
def value_range
|
39
|
+
Compiler::Rule::ValueRange.new 'A', 'Z'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Alternative
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
DELIMITER = %r{/}
|
8
|
+
|
9
|
+
def call
|
10
|
+
concatenations = []
|
11
|
+
|
12
|
+
begin
|
13
|
+
concatenation = Concatenation.compile stream
|
14
|
+
break unless concatenation
|
15
|
+
concatenations << concatenation
|
16
|
+
end while match? stream
|
17
|
+
|
18
|
+
ABNF::Compiler::Rule::Alternative.new *concatenations
|
19
|
+
end
|
20
|
+
|
21
|
+
def match? stream
|
22
|
+
stream.match C_WSP and stream.match DELIMITER and stream.match C_WSP
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
module Compiler
|
5
|
+
def self.included cls
|
6
|
+
cls.extend BuildMethod
|
7
|
+
cls.extend CompileMethod
|
8
|
+
cls.extend PatternMethod
|
9
|
+
end
|
10
|
+
|
11
|
+
module CompileMethod
|
12
|
+
def compile? stream
|
13
|
+
if compile stream then true else false end
|
14
|
+
end
|
15
|
+
|
16
|
+
def compile stream
|
17
|
+
stream = ABNF::Compiler::TextStream(stream)
|
18
|
+
pattern = self.pattern
|
19
|
+
match_data = stream.match pattern
|
20
|
+
|
21
|
+
return unless match_data
|
22
|
+
|
23
|
+
instance = build stream, match_data
|
24
|
+
instance.()
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module BuildMethod
|
29
|
+
def build stream, match_data
|
30
|
+
instance = new stream, match_data
|
31
|
+
instance
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module PatternMethod
|
36
|
+
def pattern
|
37
|
+
if const_defined? :PATTERN
|
38
|
+
const_get :PATTERN
|
39
|
+
else
|
40
|
+
@null_pattern ||= %r{}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_reader :match_data
|
46
|
+
attr_reader :stream
|
47
|
+
|
48
|
+
def initialize stream, match_data = nil
|
49
|
+
@match_data = match_data
|
50
|
+
@stream = stream
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Concatenation
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
def call
|
8
|
+
repetitions = []
|
9
|
+
|
10
|
+
begin
|
11
|
+
repetition = Repetition.compile stream
|
12
|
+
break unless repetition
|
13
|
+
repetitions << repetition
|
14
|
+
end while stream.match C_WSP
|
15
|
+
|
16
|
+
ABNF::Compiler::Rule::Concatenation.new *repetitions
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Element
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
GROUP_START = %r{\(}
|
8
|
+
GROUP_STOP = %r{\)}
|
9
|
+
OPTION_START = %r{\[}
|
10
|
+
OPTION_STOP = %r{\]}
|
11
|
+
|
12
|
+
def call
|
13
|
+
if stream.next_character == '['.freeze
|
14
|
+
option
|
15
|
+
elsif stream.next_character == '('.freeze
|
16
|
+
group
|
17
|
+
else
|
18
|
+
terminal
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def group
|
23
|
+
stream.match GROUP_START
|
24
|
+
stream.match C_WSP
|
25
|
+
|
26
|
+
alternative = Alternative.compile stream
|
27
|
+
|
28
|
+
stream.match C_WSP
|
29
|
+
stream.match GROUP_STOP
|
30
|
+
|
31
|
+
alternative
|
32
|
+
end
|
33
|
+
|
34
|
+
def option
|
35
|
+
stream.match OPTION_START
|
36
|
+
stream.match C_WSP
|
37
|
+
|
38
|
+
alternative = Alternative.compile stream
|
39
|
+
option = ABNF::Compiler::Rule::Optional.new alternative
|
40
|
+
|
41
|
+
stream.match C_WSP
|
42
|
+
stream.match OPTION_STOP
|
43
|
+
|
44
|
+
option
|
45
|
+
end
|
46
|
+
|
47
|
+
def terminal
|
48
|
+
[Rulename, CharVal, NumVal, ProseVal].each do |type|
|
49
|
+
output = type.compile stream
|
50
|
+
return output if output
|
51
|
+
end
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class NumVal
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
PATTERN = %r{\A%
|
8
|
+
(?:
|
9
|
+
(?<base_code>x)(?<first_character>[[:xdigit:]]+)
|
10
|
+
(?:(?:-(?<range_end>[[:xdigit:]]+))|(?<sequence>(?:\.[[:xdigit:]]+)+))?
|
11
|
+
|
|
12
|
+
(?<base_code>d)(?<first_character>[[:digit:]]+)
|
13
|
+
(?:(?:-(?<range_end>[[:digit:]]+))|(?<sequence>(?:\.[[:digit:]]+)+))?
|
14
|
+
|
|
15
|
+
(?<base_code>b)(?<first_character>[01]+)
|
16
|
+
(?:(?:-(?<range_end>[01]+))|(?<sequence>(?:\.[01]+)+))?
|
17
|
+
)
|
18
|
+
}nx
|
19
|
+
|
20
|
+
def base
|
21
|
+
base_code = match_data['base_code'.freeze]
|
22
|
+
|
23
|
+
{
|
24
|
+
'b'.freeze => 2,
|
25
|
+
'd'.freeze => 10,
|
26
|
+
'x'.freeze => 16,
|
27
|
+
}[base_code]
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_string
|
31
|
+
*characters = sequence.to_s.split '.'
|
32
|
+
|
33
|
+
[first_character, *characters].reduce String.new do |string, character|
|
34
|
+
octet = convert_hex_character character
|
35
|
+
string << octet
|
36
|
+
string
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def call
|
41
|
+
if range_end
|
42
|
+
first_octet = convert_hex_character first_character
|
43
|
+
last_octet = convert_hex_character range_end
|
44
|
+
return ABNF::Compiler::Rule::ValueRange.new first_octet, last_octet
|
45
|
+
end
|
46
|
+
|
47
|
+
ABNF::Compiler::Rule::TerminalValue.new build_string, true
|
48
|
+
end
|
49
|
+
|
50
|
+
def convert_hex_character hex
|
51
|
+
character = hex.to_i base
|
52
|
+
octet = character.chr
|
53
|
+
octet
|
54
|
+
end
|
55
|
+
|
56
|
+
def first_character
|
57
|
+
match_data['first_character'.freeze]
|
58
|
+
end
|
59
|
+
|
60
|
+
def range_end
|
61
|
+
match_data['range_end'.freeze]
|
62
|
+
end
|
63
|
+
|
64
|
+
def sequence
|
65
|
+
sequence = match_data['sequence'.freeze]
|
66
|
+
sequence.slice! 0, 1 if sequence
|
67
|
+
sequence
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Repetition
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
PATTERN = %r{\A
|
8
|
+
(?:
|
9
|
+
(?<range>(?<minimum>[[:digit:]]*)\*(?<maximum>[[:digit:]]*))
|
10
|
+
|
|
11
|
+
(?<fixed_number>[[:digit:]]+)
|
12
|
+
)?
|
13
|
+
}nx
|
14
|
+
|
15
|
+
def call
|
16
|
+
element = Element.compile stream
|
17
|
+
return unless element
|
18
|
+
|
19
|
+
if no_repeat?
|
20
|
+
min = 1
|
21
|
+
max = 1
|
22
|
+
elsif fixed_number
|
23
|
+
min = fixed_number.to_i
|
24
|
+
max = min
|
25
|
+
else
|
26
|
+
min = minimum.to_i
|
27
|
+
max = if maximum.empty? then Float::INFINITY else maximum.to_i end
|
28
|
+
end
|
29
|
+
|
30
|
+
return element if min == 1 and max == 1
|
31
|
+
return if min > max
|
32
|
+
|
33
|
+
ABNF::Compiler::Rule::Repetition.new min..max, element
|
34
|
+
end
|
35
|
+
|
36
|
+
def fixed_number
|
37
|
+
match_data['fixed_number'.freeze]
|
38
|
+
end
|
39
|
+
|
40
|
+
def maximum
|
41
|
+
match_data['maximum'.freeze]
|
42
|
+
end
|
43
|
+
|
44
|
+
def minimum
|
45
|
+
match_data['minimum'.freeze]
|
46
|
+
end
|
47
|
+
|
48
|
+
def no_repeat?
|
49
|
+
not fixed_number and not range?
|
50
|
+
end
|
51
|
+
|
52
|
+
def range?
|
53
|
+
match_data['range'.freeze]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Rule
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
DELIMITER = %r{=/?}n
|
8
|
+
|
9
|
+
def call
|
10
|
+
reference = Rulename.compile stream
|
11
|
+
return unless reference
|
12
|
+
|
13
|
+
rulename = reference.rulename
|
14
|
+
stream.match C_WSP
|
15
|
+
alternative_form = extract_delimiter
|
16
|
+
stream.match C_WSP
|
17
|
+
alternative = Alternative.compile stream
|
18
|
+
stream.match C_NL
|
19
|
+
|
20
|
+
RuleList::Entry.new rulename, alternative, alternative_form
|
21
|
+
end
|
22
|
+
|
23
|
+
def extract_delimiter
|
24
|
+
match_data = stream.match DELIMITER
|
25
|
+
return unless match_data
|
26
|
+
match_data.to_s == '=/'.freeze
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Rulename
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
PATTERN = %r{\A(?<string>[[:alpha:]][-[:alpha:][:digit:]]*)}n
|
8
|
+
|
9
|
+
def call
|
10
|
+
ABNF::Compiler::Rule::Reference.new match_data['string']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class Alternative
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :rules
|
8
|
+
|
9
|
+
def initialize *rules
|
10
|
+
@rules = rules
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_match stream
|
14
|
+
matches = []
|
15
|
+
|
16
|
+
rules.each do |rule|
|
17
|
+
stream.branch do
|
18
|
+
node = rule.parse stream
|
19
|
+
matches.<< Match.new node, stream.position if node
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
matches.sort!
|
25
|
+
matches.pop
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse stream
|
29
|
+
match = find_match stream
|
30
|
+
return unless match
|
31
|
+
stream.seek match.stream_position
|
32
|
+
match.node
|
33
|
+
end
|
34
|
+
|
35
|
+
Match = Struct.new :node, :stream_position do
|
36
|
+
def <=> match
|
37
|
+
stream_position <=> match.stream_position
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class Concatenation
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :rules
|
8
|
+
|
9
|
+
def initialize *rules
|
10
|
+
@rules = rules
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse stream
|
14
|
+
nodes = []
|
15
|
+
|
16
|
+
stream.branch do
|
17
|
+
rules.all? do |rule|
|
18
|
+
node = rule.parse stream
|
19
|
+
nodes << node if node
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
return unless nodes.size == rules.size
|
24
|
+
AST.sequence *nodes
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class None
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
def self.instance
|
8
|
+
@instance ||= new
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse *;
|
12
|
+
raise ParsingError, 'Prose in ABNF source material must be overridden'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class Optional
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :rule
|
8
|
+
|
9
|
+
def initialize rule
|
10
|
+
@rule = rule
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse stream
|
14
|
+
node = nil
|
15
|
+
stream.branch do
|
16
|
+
node = rule.parse stream
|
17
|
+
end
|
18
|
+
node ||= AST.leaf ''
|
19
|
+
node
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class Reference
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :rulename
|
8
|
+
|
9
|
+
def initialize rulename
|
10
|
+
@rulename = rulename
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse *;
|
14
|
+
raise ParsingError, "Rule not found: #{rulename.inspect}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class Repetition
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :element
|
8
|
+
attr_reader :range
|
9
|
+
|
10
|
+
def initialize range, element
|
11
|
+
@element = element
|
12
|
+
@range = range
|
13
|
+
end
|
14
|
+
|
15
|
+
def maximum
|
16
|
+
range.last
|
17
|
+
end
|
18
|
+
|
19
|
+
def minimum
|
20
|
+
range.first
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse stream
|
24
|
+
matches = false
|
25
|
+
nodes = []
|
26
|
+
|
27
|
+
stream.branch do
|
28
|
+
until nodes.size == maximum
|
29
|
+
node = element.parse stream
|
30
|
+
break unless node
|
31
|
+
nodes << node
|
32
|
+
end
|
33
|
+
matches = true if nodes.size >= minimum
|
34
|
+
end
|
35
|
+
|
36
|
+
AST.repetition *nodes if matches
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class TerminalValue
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :case_sensitive
|
8
|
+
attr_reader :string
|
9
|
+
|
10
|
+
def initialize string, case_sensitive = false
|
11
|
+
@string = string
|
12
|
+
@case_sensitive = case_sensitive
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse stream
|
16
|
+
match_data = stream.match regexp
|
17
|
+
return unless match_data
|
18
|
+
AST.leaf match_data.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def regexp
|
22
|
+
@regexp ||=
|
23
|
+
begin
|
24
|
+
escaped_string = Regexp.escape string
|
25
|
+
case_insensitive = !case_sensitive
|
26
|
+
Regexp.new escaped_string, case_insensitive, 'n'.freeze
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class ValueRange
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :start_character
|
8
|
+
attr_reader :end_character
|
9
|
+
|
10
|
+
def initialize start_character, end_character
|
11
|
+
@start_character = start_character
|
12
|
+
@end_character = end_character
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse stream
|
16
|
+
match_data = stream.match regexp
|
17
|
+
return unless match_data
|
18
|
+
AST.leaf match_data.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def regexp
|
22
|
+
@regexp ||=
|
23
|
+
begin
|
24
|
+
start_char = Regexp.escape start_character
|
25
|
+
end_char = Regexp.escape end_character
|
26
|
+
|
27
|
+
Regexp.new "[#{start_char}-#{end_char}]", false, 'n'.freeze
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
class RuleList
|
4
|
+
attr_reader :rules
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@rules = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def compile abnf
|
11
|
+
stream = Compiler::TextStream(abnf)
|
12
|
+
|
13
|
+
until stream.eof?
|
14
|
+
stream.match Grammar::C_WSP
|
15
|
+
stream.match Grammar::C_NL
|
16
|
+
|
17
|
+
rule = Grammar::Rule.compile stream
|
18
|
+
next unless rule
|
19
|
+
|
20
|
+
rules[rule.name] = rule
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
class RuleList
|
4
|
+
class Entry
|
5
|
+
attr_reader :alternative_form
|
6
|
+
attr_reader :name
|
7
|
+
attr_reader :rule
|
8
|
+
|
9
|
+
def initialize name, rule, alternative_form
|
10
|
+
@alternative_form = alternative_form
|
11
|
+
@name = name
|
12
|
+
@rule = rule
|
13
|
+
end
|
14
|
+
|
15
|
+
def alternative_form?
|
16
|
+
alternative_form
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
class TextStream
|
4
|
+
attr_reader :stack
|
5
|
+
attr_reader :text
|
6
|
+
|
7
|
+
def initialize text
|
8
|
+
@text = text
|
9
|
+
@stack = [0]
|
10
|
+
end
|
11
|
+
|
12
|
+
def == other_stream
|
13
|
+
return unless other_stream.is_a? self.class
|
14
|
+
text == other_stream.text and stack == other_stream.stack
|
15
|
+
end
|
16
|
+
|
17
|
+
def branch &block
|
18
|
+
next_position = position
|
19
|
+
|
20
|
+
stack << position
|
21
|
+
if block.()
|
22
|
+
next_position = position
|
23
|
+
end
|
24
|
+
stack.pop
|
25
|
+
|
26
|
+
self.position = next_position
|
27
|
+
end
|
28
|
+
|
29
|
+
def eof?
|
30
|
+
position == text.size
|
31
|
+
end
|
32
|
+
|
33
|
+
def match regexp
|
34
|
+
match_data = regexp.match rest
|
35
|
+
return unless match_data
|
36
|
+
return unless match_data.pre_match.empty?
|
37
|
+
self.position += match_data.to_s.size
|
38
|
+
match_data
|
39
|
+
end
|
40
|
+
|
41
|
+
def next_character
|
42
|
+
text[position]
|
43
|
+
end
|
44
|
+
|
45
|
+
def position= new_position
|
46
|
+
stack[-1] = new_position
|
47
|
+
end
|
48
|
+
alias_method :seek, :position=
|
49
|
+
|
50
|
+
def position
|
51
|
+
stack[-1]
|
52
|
+
end
|
53
|
+
|
54
|
+
def rest
|
55
|
+
text[position..-1]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.TextStream string_or_stream
|
60
|
+
case string_or_stream
|
61
|
+
when String then TextStream.new string_or_stream
|
62
|
+
when TextStream then string_or_stream
|
63
|
+
else raise TypeError, "Invalid value for TextStream(): #{string_or_stream.inspect}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: abnf-parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nathan Ladd
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-11-13 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: abnf-parser allows you to compile ABNF into rule lists that can be used
|
14
|
+
to parse text.
|
15
|
+
email: nathanladd+github@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/abnf/compiler.rb
|
21
|
+
- lib/abnf/compiler/ast.rb
|
22
|
+
- lib/abnf/compiler/controls.rb
|
23
|
+
- lib/abnf/compiler/controls/ast.rb
|
24
|
+
- lib/abnf/compiler/controls/grammar.rb
|
25
|
+
- lib/abnf/compiler/controls/rules.rb
|
26
|
+
- lib/abnf/compiler/controls/text_stream.rb
|
27
|
+
- lib/abnf/compiler/errors.rb
|
28
|
+
- lib/abnf/compiler/grammar.rb
|
29
|
+
- lib/abnf/compiler/grammar/alternative.rb
|
30
|
+
- lib/abnf/compiler/grammar/char_val.rb
|
31
|
+
- lib/abnf/compiler/grammar/compiler.rb
|
32
|
+
- lib/abnf/compiler/grammar/concatenation.rb
|
33
|
+
- lib/abnf/compiler/grammar/element.rb
|
34
|
+
- lib/abnf/compiler/grammar/num_val.rb
|
35
|
+
- lib/abnf/compiler/grammar/prose_val.rb
|
36
|
+
- lib/abnf/compiler/grammar/repetition.rb
|
37
|
+
- lib/abnf/compiler/grammar/rule.rb
|
38
|
+
- lib/abnf/compiler/grammar/rulename.rb
|
39
|
+
- lib/abnf/compiler/rule.rb
|
40
|
+
- lib/abnf/compiler/rule/alternative.rb
|
41
|
+
- lib/abnf/compiler/rule/concatenation.rb
|
42
|
+
- lib/abnf/compiler/rule/none.rb
|
43
|
+
- lib/abnf/compiler/rule/optional.rb
|
44
|
+
- lib/abnf/compiler/rule/reference.rb
|
45
|
+
- lib/abnf/compiler/rule/repetition.rb
|
46
|
+
- lib/abnf/compiler/rule/terminal_value.rb
|
47
|
+
- lib/abnf/compiler/rule/value_range.rb
|
48
|
+
- lib/abnf/compiler/rule_list.rb
|
49
|
+
- lib/abnf/compiler/rule_list/entry.rb
|
50
|
+
- lib/abnf/compiler/text_stream.rb
|
51
|
+
homepage: https://github.com/ntl/abnf-parser
|
52
|
+
licenses:
|
53
|
+
- MIT
|
54
|
+
metadata: {}
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 2.4.5.1
|
72
|
+
signing_key:
|
73
|
+
specification_version: 4
|
74
|
+
summary: ABNF Compiler & Parsing Library
|
75
|
+
test_files: []
|