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.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/lib/abnf/compiler.rb +28 -0
  3. data/lib/abnf/compiler/ast.rb +67 -0
  4. data/lib/abnf/compiler/controls.rb +4 -0
  5. data/lib/abnf/compiler/controls/ast.rb +28 -0
  6. data/lib/abnf/compiler/controls/grammar.rb +32 -0
  7. data/lib/abnf/compiler/controls/rules.rb +44 -0
  8. data/lib/abnf/compiler/controls/text_stream.rb +15 -0
  9. data/lib/abnf/compiler/errors.rb +7 -0
  10. data/lib/abnf/compiler/grammar.rb +17 -0
  11. data/lib/abnf/compiler/grammar/alternative.rb +27 -0
  12. data/lib/abnf/compiler/grammar/char_val.rb +15 -0
  13. data/lib/abnf/compiler/grammar/compiler.rb +55 -0
  14. data/lib/abnf/compiler/grammar/concatenation.rb +21 -0
  15. data/lib/abnf/compiler/grammar/element.rb +57 -0
  16. data/lib/abnf/compiler/grammar/num_val.rb +72 -0
  17. data/lib/abnf/compiler/grammar/prose_val.rb +15 -0
  18. data/lib/abnf/compiler/grammar/repetition.rb +58 -0
  19. data/lib/abnf/compiler/grammar/rule.rb +31 -0
  20. data/lib/abnf/compiler/grammar/rulename.rb +15 -0
  21. data/lib/abnf/compiler/rule.rb +10 -0
  22. data/lib/abnf/compiler/rule/alternative.rb +43 -0
  23. data/lib/abnf/compiler/rule/concatenation.rb +29 -0
  24. data/lib/abnf/compiler/rule/none.rb +17 -0
  25. data/lib/abnf/compiler/rule/optional.rb +24 -0
  26. data/lib/abnf/compiler/rule/reference.rb +19 -0
  27. data/lib/abnf/compiler/rule/repetition.rb +41 -0
  28. data/lib/abnf/compiler/rule/terminal_value.rb +32 -0
  29. data/lib/abnf/compiler/rule/value_range.rb +33 -0
  30. data/lib/abnf/compiler/rule_list.rb +25 -0
  31. data/lib/abnf/compiler/rule_list/entry.rb +21 -0
  32. data/lib/abnf/compiler/text_stream.rb +67 -0
  33. metadata +75 -0
@@ -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,4 @@
1
+ require 'abnf/compiler/controls/ast'
2
+ require 'abnf/compiler/controls/grammar'
3
+ require 'abnf/compiler/controls/rules'
4
+ require 'abnf/compiler/controls/text_stream'
@@ -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,15 @@
1
+ module ABNF
2
+ module Compiler
3
+ module Controls
4
+ module TextStream
5
+ def self.example
6
+ Compiler::TextStream.new 'some-text'
7
+ end
8
+
9
+ def self.rule
10
+ Compiler::TextStream.new 'some-rule = "some-string"'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module ABNF
2
+ module Compiler
3
+ Error = Class.new StandardError
4
+ ParsingError = Class.new Error
5
+ CompileError = Class.new Error
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ module ABNF
2
+ module Compiler
3
+ module Grammar
4
+ C_NL = %r{;[\t -~]*\r\n|\r\n}n
5
+
6
+ C_WSP = %r{\A
7
+ (?:
8
+ [[:blank:]]
9
+ |
10
+ #{C_NL}[[:blank:]]
11
+ )*
12
+ }xn
13
+
14
+ CRLF = %r{\r\n}
15
+ end
16
+ end
17
+ 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,15 @@
1
+ module ABNF
2
+ module Compiler
3
+ module Grammar
4
+ class CharVal
5
+ include Compiler
6
+
7
+ PATTERN = %r{\A"(?<string>[\x20-\x21\x23-\x7E]*)"}
8
+
9
+ def call
10
+ ABNF::Compiler::Rule::TerminalValue.new match_data['string']
11
+ end
12
+ end
13
+ end
14
+ end
15
+ 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,15 @@
1
+ module ABNF
2
+ module Compiler
3
+ module Grammar
4
+ class ProseVal
5
+ include Compiler
6
+
7
+ PATTERN = %r{\A<[\x20-\x3D\x3F-\x7E]*>\z}n
8
+
9
+ def call
10
+ ABNF::Compiler::Rule::None.instance
11
+ end
12
+ end
13
+ end
14
+ end
15
+ 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,10 @@
1
+ module ABNF
2
+ module Compiler
3
+ module Rule
4
+ def parse? text
5
+ stream = Compiler::TextStream(text)
6
+ if parse stream then true else false end
7
+ end
8
+ end
9
+ end
10
+ 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: []