treetop 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/treetop.rb +6 -0
- data/lib/treetop/api.rb +3 -0
- data/lib/treetop/api/load_grammar.rb +16 -0
- data/lib/treetop/api/malformed_grammar_exception.rb +9 -0
- data/lib/treetop/grammar.rb +7 -0
- data/lib/treetop/grammar/grammar.rb +48 -0
- data/lib/treetop/grammar/grammar_builder.rb +35 -0
- data/lib/treetop/grammar/parsing_expression_builder.rb +5 -0
- data/lib/treetop/grammar/parsing_expression_builder_helper.rb +121 -0
- data/lib/treetop/grammar/parsing_expressions.rb +18 -0
- data/lib/treetop/grammar/parsing_expressions/and_predicate.rb +17 -0
- data/lib/treetop/grammar/parsing_expressions/anything_symbol.rb +20 -0
- data/lib/treetop/grammar/parsing_expressions/character_class.rb +24 -0
- data/lib/treetop/grammar/parsing_expressions/node_instantiating_parsing_expression.rb +14 -0
- data/lib/treetop/grammar/parsing_expressions/node_propagating_parsing_expression.rb +4 -0
- data/lib/treetop/grammar/parsing_expressions/nonterminal_symbol.rb +42 -0
- data/lib/treetop/grammar/parsing_expressions/not_predicate.rb +18 -0
- data/lib/treetop/grammar/parsing_expressions/one_or_more.rb +12 -0
- data/lib/treetop/grammar/parsing_expressions/optional.rb +14 -0
- data/lib/treetop/grammar/parsing_expressions/ordered_choice.rb +27 -0
- data/lib/treetop/grammar/parsing_expressions/parsing_expression.rb +36 -0
- data/lib/treetop/grammar/parsing_expressions/predicate.rb +25 -0
- data/lib/treetop/grammar/parsing_expressions/repeating_parsing_expression.rb +29 -0
- data/lib/treetop/grammar/parsing_expressions/sequence.rb +41 -0
- data/lib/treetop/grammar/parsing_expressions/terminal_parsing_expression.rb +11 -0
- data/lib/treetop/grammar/parsing_expressions/terminal_symbol.rb +31 -0
- data/lib/treetop/grammar/parsing_expressions/zero_or_more.rb +11 -0
- data/lib/treetop/grammar/parsing_rule.rb +10 -0
- data/lib/treetop/metagrammar.rb +2 -0
- data/lib/treetop/metagrammar/metagrammar.rb +14 -0
- data/lib/treetop/metagrammar/metagrammar.treetop +320 -0
- data/lib/treetop/parser.rb +11 -0
- data/lib/treetop/parser/node_cache.rb +25 -0
- data/lib/treetop/parser/parse_cache.rb +17 -0
- data/lib/treetop/parser/parse_failure.rb +22 -0
- data/lib/treetop/parser/parse_result.rb +26 -0
- data/lib/treetop/parser/parser.rb +24 -0
- data/lib/treetop/parser/sequence_syntax_node.rb +14 -0
- data/lib/treetop/parser/syntax_node.rb +31 -0
- data/lib/treetop/parser/terminal_parse_failure.rb +18 -0
- data/lib/treetop/parser/terminal_syntax_node.rb +7 -0
- data/lib/treetop/protometagrammar.rb +16 -0
- data/lib/treetop/protometagrammar/anything_symbol_expression_builder.rb +13 -0
- data/lib/treetop/protometagrammar/block_expression_builder.rb +17 -0
- data/lib/treetop/protometagrammar/character_class_expression_builder.rb +25 -0
- data/lib/treetop/protometagrammar/grammar_expression_builder.rb +38 -0
- data/lib/treetop/protometagrammar/nonterminal_symbol_expression_builder.rb +45 -0
- data/lib/treetop/protometagrammar/ordered_choice_expression_builder.rb +21 -0
- data/lib/treetop/protometagrammar/parsing_rule_expression_builder.rb +23 -0
- data/lib/treetop/protometagrammar/parsing_rule_sequence_expression_builder.rb +14 -0
- data/lib/treetop/protometagrammar/prefix_expression_builder.rb +25 -0
- data/lib/treetop/protometagrammar/primary_expression_builder.rb +71 -0
- data/lib/treetop/protometagrammar/protometagrammar.rb +25 -0
- data/lib/treetop/protometagrammar/sequence_expression_builder.rb +37 -0
- data/lib/treetop/protometagrammar/suffix_expression_builder.rb +33 -0
- data/lib/treetop/protometagrammar/terminal_symbol_expression_builder.rb +52 -0
- data/lib/treetop/protometagrammar/trailing_block_expression_builder.rb +30 -0
- data/lib/treetop/ruby_extension.rb +11 -0
- metadata +110 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/parser/parser"
|
3
|
+
require "#{dir}/parser/parse_result"
|
4
|
+
require "#{dir}/parser/syntax_node"
|
5
|
+
require "#{dir}/parser/terminal_syntax_node"
|
6
|
+
require "#{dir}/parser/sequence_syntax_node"
|
7
|
+
require "#{dir}/parser/parse_failure"
|
8
|
+
require "#{dir}/parser/node_cache"
|
9
|
+
require "#{dir}/parser/parse_cache"
|
10
|
+
require "#{dir}/parser/parse_failure"
|
11
|
+
require "#{dir}/parser/terminal_parse_failure"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Treetop
|
2
|
+
class NodeCache
|
3
|
+
attr_reader :parse_results
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@parse_results = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def empty?
|
10
|
+
parse_results.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def store(parse_result)
|
14
|
+
if parse_result.failure?
|
15
|
+
parse_results[parse_result.index] = parse_result
|
16
|
+
else
|
17
|
+
parse_results[parse_result.interval.begin] = parse_result
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](start_index)
|
22
|
+
parse_results[start_index]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Treetop
|
2
|
+
class ParseCache
|
3
|
+
attr_reader :node_caches
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@node_caches = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](parsing_expression)
|
10
|
+
node_caches[parsing_expression] ||= NodeCache.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def empty?
|
14
|
+
node_caches.empty?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Treetop
|
2
|
+
class ParseFailure < ParseResult
|
3
|
+
attr_reader :index
|
4
|
+
|
5
|
+
def initialize(index, nested_failures = [])
|
6
|
+
super(nested_failures)
|
7
|
+
@index = index
|
8
|
+
end
|
9
|
+
|
10
|
+
def success?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
def failure?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def interval
|
19
|
+
@interval ||= (index...index)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Treetop
|
2
|
+
class ParseResult
|
3
|
+
attr_reader :nested_failures
|
4
|
+
|
5
|
+
def initialize(nested_failures = [])
|
6
|
+
@nested_failures = select_failures_at_maximum_index(nested_failures)
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
def select_failures_at_maximum_index(failures)
|
11
|
+
maximum_index = 0
|
12
|
+
failures_at_maximum_index = []
|
13
|
+
|
14
|
+
failures.each do |failure|
|
15
|
+
if failure.index > maximum_index
|
16
|
+
failures_at_maximum_index = [failure]
|
17
|
+
maximum_index = failure.index
|
18
|
+
elsif failure.index == maximum_index
|
19
|
+
failures_at_maximum_index << failure
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
return failures_at_maximum_index
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Treetop
|
2
|
+
class Parser
|
3
|
+
attr_reader :grammar, :parse_cache
|
4
|
+
|
5
|
+
def initialize(grammar)
|
6
|
+
@grammar = grammar
|
7
|
+
@parse_cache = ParseCache.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse(input)
|
11
|
+
@parse_cache = ParseCache.new
|
12
|
+
result = grammar.root.parse_at(input, 0, self)
|
13
|
+
if result.success? and result.interval.end == input.size
|
14
|
+
return result
|
15
|
+
else
|
16
|
+
return ParseFailure.new(result.interval.end, result.nested_failures)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def node_cache_for(parsing_expression)
|
21
|
+
parse_cache[parsing_expression]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Treetop
|
2
|
+
class SequenceSyntaxNode < SyntaxNode
|
3
|
+
attr_reader :elements
|
4
|
+
|
5
|
+
def initialize(input, interval, elements, nested_failures = [])
|
6
|
+
super(input, interval, nested_failures)
|
7
|
+
@elements = elements
|
8
|
+
end
|
9
|
+
|
10
|
+
def empty?
|
11
|
+
elements.empty?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Treetop
|
2
|
+
class SyntaxNode < ParseResult
|
3
|
+
attr_reader :input, :interval
|
4
|
+
|
5
|
+
def initialize(input, interval, nested_failures = [])
|
6
|
+
super(nested_failures)
|
7
|
+
@input = input
|
8
|
+
@interval = interval
|
9
|
+
end
|
10
|
+
|
11
|
+
def update_nested_failures(failures)
|
12
|
+
@nested_failures = select_failures_at_maximum_index(nested_failures + failures)
|
13
|
+
end
|
14
|
+
|
15
|
+
def text_value
|
16
|
+
input[interval]
|
17
|
+
end
|
18
|
+
|
19
|
+
def success?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def failure?
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
def epsilon?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Treetop
|
2
|
+
class TerminalParseFailure < ParseFailure
|
3
|
+
attr_reader :expression
|
4
|
+
|
5
|
+
def initialize(index, expression)
|
6
|
+
super(index)
|
7
|
+
@expression = expression
|
8
|
+
end
|
9
|
+
|
10
|
+
def nested_failures
|
11
|
+
[self]
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"String matching #{expression} expected at position #{index}."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
dir = File.dirname(__FILE__)
|
2
|
+
require "#{dir}/protometagrammar/protometagrammar"
|
3
|
+
require "#{dir}/protometagrammar/grammar_expression_builder"
|
4
|
+
require "#{dir}/protometagrammar/parsing_rule_sequence_expression_builder"
|
5
|
+
require "#{dir}/protometagrammar/parsing_rule_expression_builder"
|
6
|
+
require "#{dir}/protometagrammar/primary_expression_builder"
|
7
|
+
require "#{dir}/protometagrammar/nonterminal_symbol_expression_builder"
|
8
|
+
require "#{dir}/protometagrammar/terminal_symbol_expression_builder"
|
9
|
+
require "#{dir}/protometagrammar/character_class_expression_builder"
|
10
|
+
require "#{dir}/protometagrammar/anything_symbol_expression_builder"
|
11
|
+
require "#{dir}/protometagrammar/sequence_expression_builder"
|
12
|
+
require "#{dir}/protometagrammar/suffix_expression_builder"
|
13
|
+
require "#{dir}/protometagrammar/prefix_expression_builder"
|
14
|
+
require "#{dir}/protometagrammar/ordered_choice_expression_builder"
|
15
|
+
require "#{dir}/protometagrammar/block_expression_builder"
|
16
|
+
require "#{dir}/protometagrammar/trailing_block_expression_builder"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Treetop
|
2
|
+
class Protometagrammar
|
3
|
+
class BlockExpressionBuilder < ParsingExpressionBuilder
|
4
|
+
def build
|
5
|
+
seq('{', zero_or_more(choice(:block, anything_but_a_brace)), '}') do
|
6
|
+
def value
|
7
|
+
elements[1].text_value
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def anything_but_a_brace
|
13
|
+
seq(notp(choice('{', '}')), any)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Treetop
|
2
|
+
class Protometagrammar
|
3
|
+
class CharacterClassExpressionBuilder < ParsingExpressionBuilder
|
4
|
+
def build
|
5
|
+
character_class
|
6
|
+
end
|
7
|
+
|
8
|
+
def character_class
|
9
|
+
seq('[', one_or_more(char_class_char), ']') do
|
10
|
+
def value(grammar = nil)
|
11
|
+
CharacterClass.new(characters)
|
12
|
+
end
|
13
|
+
|
14
|
+
def characters
|
15
|
+
elements[1].text_value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def char_class_char
|
21
|
+
seq(notp(']'), choice(escaped(']'), any))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Treetop
|
2
|
+
class Protometagrammar
|
3
|
+
class GrammarExpressionBuilder < ParsingExpressionBuilder
|
4
|
+
def build
|
5
|
+
seq('grammar', :space, grammar_name, :parsing_rule_sequence, optional(:space), 'end') do
|
6
|
+
def value
|
7
|
+
grammar = Grammar.new(grammar_name)
|
8
|
+
parsing_rules(grammar).each do |parsing_rule|
|
9
|
+
grammar.add_parsing_rule(parsing_rule)
|
10
|
+
end
|
11
|
+
return grammar
|
12
|
+
end
|
13
|
+
|
14
|
+
def grammar_name
|
15
|
+
name_string = elements[2].text_value.chop
|
16
|
+
|
17
|
+
if name_string.empty?
|
18
|
+
nil
|
19
|
+
else
|
20
|
+
name_string.to_sym
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def parsing_rules(grammar)
|
25
|
+
elements[3].value(grammar)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def grammar_name
|
31
|
+
optional(
|
32
|
+
seq(char_class('A-Z'),
|
33
|
+
zero_or_more(char_class('a-z0-9_')),
|
34
|
+
:space))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Treetop
|
2
|
+
class Protometagrammar
|
3
|
+
class NonterminalSymbolExpressionBuilder < ParsingExpressionBuilder
|
4
|
+
def build
|
5
|
+
seq(notp(naked_keyword), nonterminal_symbol) do
|
6
|
+
def value(grammar)
|
7
|
+
nonterminal_symbol.value(grammar)
|
8
|
+
end
|
9
|
+
|
10
|
+
def nonterminal_symbol
|
11
|
+
elements[1]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def naked_keyword
|
17
|
+
seq(:keyword, notp(alphanumeric_char))
|
18
|
+
end
|
19
|
+
|
20
|
+
def nonterminal_symbol
|
21
|
+
seq(alpha_char, zero_or_more(alphanumeric_char)) do
|
22
|
+
def value(grammar)
|
23
|
+
grammar.nonterminal_symbol(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def name
|
27
|
+
text_value.to_sym
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def alpha_char
|
33
|
+
char_class('A-Za-z_')
|
34
|
+
end
|
35
|
+
|
36
|
+
def numeric_char
|
37
|
+
char_class('0-9')
|
38
|
+
end
|
39
|
+
|
40
|
+
def alphanumeric_char
|
41
|
+
choice(alpha_char, numeric_char)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Treetop
|
2
|
+
class Protometagrammar
|
3
|
+
class OrderedChoiceExpressionBuilder < ParsingExpressionBuilder
|
4
|
+
def build
|
5
|
+
choice(ordered_choice, :sequence)
|
6
|
+
end
|
7
|
+
|
8
|
+
def ordered_choice
|
9
|
+
two_or_more_delimited(:sequence, seq(optional(:space), "/", optional(:space))) do
|
10
|
+
def value(grammar)
|
11
|
+
OrderedChoice.new(element_values(grammar))
|
12
|
+
end
|
13
|
+
|
14
|
+
def element_values(grammar)
|
15
|
+
elements.collect { |element| element.value(grammar) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Treetop
|
2
|
+
class Protometagrammar
|
3
|
+
class ParsingRuleExpressionBuilder < ParsingExpressionBuilder
|
4
|
+
def build
|
5
|
+
seq('rule', :space, :nonterminal_symbol, :space, :ordered_choice, :space, 'end') do
|
6
|
+
def value(grammar)
|
7
|
+
ParsingRule.new(nonterminal_symbol.value(grammar),
|
8
|
+
parsing_expression.value(grammar))
|
9
|
+
end
|
10
|
+
|
11
|
+
def nonterminal_symbol
|
12
|
+
elements[2]
|
13
|
+
end
|
14
|
+
|
15
|
+
def parsing_expression
|
16
|
+
elements[4]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Treetop
|
2
|
+
class Protometagrammar
|
3
|
+
class ParsingRuleSequenceExpressionBuilder < ParsingExpressionBuilder
|
4
|
+
def build
|
5
|
+
zero_or_more_delimited(:parsing_rule, :space) do
|
6
|
+
def value(grammar)
|
7
|
+
elements.collect {|element| element.value(grammar) }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Treetop
|
2
|
+
class Protometagrammar
|
3
|
+
class PrefixExpressionBuilder < ParsingExpressionBuilder
|
4
|
+
def build
|
5
|
+
choice(and_predicate, not_predicate)
|
6
|
+
end
|
7
|
+
|
8
|
+
def and_predicate
|
9
|
+
exp('&') do
|
10
|
+
def value(parsing_expression)
|
11
|
+
parsing_expression.and_predicate
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def not_predicate
|
17
|
+
exp('!') do
|
18
|
+
def value(parsing_expression)
|
19
|
+
parsing_expression.not_predicate
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|