public
Fork of nathansobo/treetop
Description: A Ruby-based parsing DSL based on parsing expression grammars.
Homepage: http://treetop.rubyforge.org
Clone URL: git://github.com/juretta/treetop.git
Propagations are returned from choice expressions.

The compiled parser will always discard a propagation returned as the 
result of the entire parse unless the return_propagations option is set to 
true. SyntaxNodes add propagations to their dependencies but add the 
propagated result to their elements.
Nathan Sobo (author)
Wed Mar 05 21:49:51 -0800 2008
commit  877a6e7f7c8142b272e1de8042784df480b52da2
tree    1de4a349678900ec916c511cd06f7abe00232091
parent  3f2a1080557e763642d56a95de0a637a63b0fffd
...
7
8
9
10
 
11
12
13
...
18
19
20
 
21
22
 
23
24
25
...
7
8
9
 
10
11
12
13
...
18
19
20
21
22
23
24
25
26
27
0
@@ -7,7 +7,7 @@ module Treetop
0
         use_vars :result, :start_index
0
         builder.assign "failed_alternatives", "[]"
0
         compile_alternatives(alternatives)
0
- builder << "failed_alternatives.each { |alt| alt.dependent_results.push(#{result_var}) }"
0
+ builder << "#{result_var}.dependencies.concat(failed_alternatives)"
0
         end_comment(self)
0
       end
0
       
0
@@ -18,8 +18,10 @@ module Treetop
0
           assign_result subexpression_result_var
0
           extend_result_with_declared_module
0
           extend_result_with_inline_module
0
+ assign_result "Propagation.new(#{result_var})"
0
         end
0
         builder.else_ do
0
+ builder.accumulate "failed_alternatives", subexpression_result_var
0
           if alternatives.size == 1
0
             reset_index
0
             assign_failure start_index_var
...
5
6
7
8
 
9
10
 
11
12
13
...
66
67
68
69
 
 
 
 
 
 
70
71
72
...
5
6
7
 
8
9
10
11
12
13
14
...
67
68
69
 
70
71
72
73
74
75
76
77
78
0
@@ -5,9 +5,10 @@ module Treetop
0
       
0
       attr_reader :input, :index, :terminal_failures, :max_terminal_failure_first_index, :max_terminal_failure_last_index
0
       attr_writer :root
0
- attr_accessor :consume_all_input, :return_parse_failure
0
+ attr_accessor :consume_all_input, :return_parse_failure, :return_propagations
0
       alias :consume_all_input? :consume_all_input
0
       alias :return_parse_failure? :return_parse_failure
0
+ alias :return_propagations? :return_propagations
0
       
0
       def initialize
0
         self.consume_all_input = true
0
@@ -66,7 +67,12 @@ module Treetop
0
           end
0
         end
0
         return nil if (consume_all_input? && index != input.size)
0
- result
0
+
0
+ if return_propagations?
0
+ result
0
+ else
0
+ result.element
0
+ end
0
       end
0
 
0
       def prepare_to_parse(input)
...
8
9
10
 
 
 
 
11
12
13
14
...
8
9
10
11
12
13
14
15
16
17
18
0
@@ -8,6 +8,10 @@ module Treetop
0
         @element = element
0
         @dependencies = [element]
0
       end
0
+
0
+ def resume_index
0
+ element.resume_index
0
+ end
0
     end
0
   end
0
 end
0
\ No newline at end of file
...
20
21
22
23
24
 
25
26
27
...
31
32
33
34
 
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 
51
52
53
54
55
 
 
 
56
57
58
59
60
61
62
63
64
65
66
67
68
 
 
 
 
 
 
 
69
70
 
71
 
 
 
 
 
 
72
73
74
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
77
78
 
 
 
 
 
 
 
 
 
 
 
 
 
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
96
97
...
109
110
111
112
 
113
114
115
...
124
125
126
127
 
128
129
130
...
20
21
22
 
 
23
24
25
26
...
30
31
32
 
33
34
35
36
37
 
38
39
40
41
 
42
43
44
45
 
 
46
47
48
 
 
 
49
50
51
52
53
54
 
 
 
 
 
 
 
 
 
 
55
56
57
58
59
60
61
62
 
63
64
65
66
67
68
69
70
71
 
 
 
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
 
92
93
94
95
96
97
98
99
100
101
102
103
104
105
 
 
 
 
 
 
 
106
 
 
 
 
 
 
 
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
...
139
140
141
 
142
143
144
145
...
154
155
156
 
157
158
159
160
0
@@ -20,8 +20,7 @@ module ChoiceSpec
0
     
0
     
0
     it "upon parsing a string matching the first alternative, returns a Propagation with the result of the first alternative as its result" do
0
- pending
0
- result = parse('foo')
0
+ result = parse('foo', :return_propagations => true)
0
       result.should be_an_instance_of(Runtime::Propagation)
0
       result.element.should be_terminal
0
       result.element.text_value.should == 'foo'
0
@@ -31,67 +30,98 @@ module ChoiceSpec
0
       attr_reader :result
0
 
0
       before do
0
- @result = parse('bar')
0
+ @result = parse('bar', :return_propagations => true)
0
       end
0
 
0
       describe "the result" do
0
         it "is an instance Propagation" do
0
- pending
0
           result.should be_an_instance_of(Runtime::Propagation)
0
         end
0
 
0
         it "has the result of the second alternative as its #element" do
0
- pending
0
           result.element.should be_terminal
0
           result.element.text_value.should == 'bar'
0
         end
0
 
0
- it "has the failing result of the first alternative and the successful result of the second alternative as its dependencies" do
0
- pending
0
+ it "has the successful result of the second alternative and the failing result of the first alternative as its dependencies" do
0
           dependencies = result.dependencies
0
           dependencies.size.should == 2
0
- dependencies[0].should be_an_instance_of(Runtime::TerminalParseFailure)
0
- dependencies[0].expected_string.should == 'foo'
0
- dependencies[1].should == result.element
0
+ dependencies[0].should == result.element
0
+ dependencies[1].should be_an_instance_of(Runtime::TerminalParseFailure)
0
+ dependencies[1].expected_string.should == 'foo'
0
         end
0
       end
0
       
0
- it "records the failure of the first terminal"
0
- end
0
-
0
- it "upon parsing a string matching the second alternative, records the failure of the first terminal" do
0
- result = parse('bar')
0
- terminal_failures = parser.terminal_failures
0
- terminal_failures.size.should == 1
0
- failure = terminal_failures[0]
0
- failure.expected_string.should == 'foo'
0
- failure.index.should == 0
0
+ it "records the failure of the first terminal" do
0
+ terminal_failures = parser.terminal_failures
0
+ terminal_failures.size.should == 1
0
+ failure = terminal_failures[0]
0
+ failure.expected_string.should == 'foo'
0
+ failure.index.should == 0
0
+ end
0
     end
0
-
0
+
0
     describe "upon parsing a string matching the third alternative" do
0
+ attr_reader :result
0
+
0
+ before do
0
+ @result = parse("baz", :return_propagations => true)
0
+ end
0
+
0
       describe "the result" do
0
- it "is an instance Propagation"
0
- it "has the result of the third alternative as its #result"
0
- it "has the failing results of the first and second alternatives and the successful result of the third alternative as its dependencies"
0
+ it "is an instance Propagation" do
0
+ result.should be_an_instance_of(Runtime::Propagation)
0
+ end
0
+
0
+ it "has the result of the third alternative as its #element" do
0
+ result.element.should be_terminal
0
+ result.element.text_value.should == 'baz'
0
+ end
0
+
0
+ it "has the successful result of the third alternative and the failing results of the first and second alternatives as its dependencies" do
0
+ dependencies = result.dependencies
0
+ dependencies.size.should == 3
0
+ dependencies[0].should == result.element
0
+ dependencies[1].should be_an_instance_of(Runtime::TerminalParseFailure)
0
+ dependencies[1].expected_string.should == 'foo'
0
+ dependencies[2].should be_an_instance_of(Runtime::TerminalParseFailure)
0
+ dependencies[2].expected_string.should == 'bar'
0
+ end
0
       end
0
       
0
- it "records the failure of the first terminal and second terminals"
0
+ it "records the failure of the first terminal and second terminals" do
0
+ terminal_failures = parser.terminal_failures
0
+
0
+ terminal_failures.size.should == 2
0
+
0
+ failure_1 = terminal_failures[0]
0
+ failure_1.expected_string == 'foo'
0
+ failure_1.index.should == 0
0
+
0
+ failure_2 = terminal_failures[1]
0
+ failure_2.expected_string == 'bar'
0
+ failure_2.index.should == 0
0
+ end
0
     end
0
-
0
- it "upon parsing a string matching the third alternative, records the failure of the first two terminals" do
0
- result = parse('baz')
0
-
0
- terminal_failures = parser.terminal_failures
0
-
0
- terminal_failures.size.should == 2
0
 
0
- failure_1 = terminal_failures[0]
0
- failure_1.expected_string == 'foo'
0
- failure_1.index.should == 0
0
-
0
- failure_2 = terminal_failures[1]
0
- failure_2.expected_string == 'bar'
0
- failure_2.index.should == 0
0
+ describe "the result of parsing non-matching input" do
0
+ attr_reader :result
0
+ before do
0
+ @result = parse('cat', :return_parse_failure => true)
0
+ end
0
+
0
+ it "is a ParseFailure that depends on the failure of all 3 alternatives" do
0
+ result.should be_an_instance_of(Runtime::ParseFailure)
0
+ dependencies = result.dependencies
0
+
0
+ dependencies.size.should == 3
0
+ dependencies[0].should be_an_instance_of(Runtime::TerminalParseFailure)
0
+ dependencies[0].expected_string.should == 'foo'
0
+ dependencies[1].should be_an_instance_of(Runtime::TerminalParseFailure)
0
+ dependencies[1].expected_string.should == 'bar'
0
+ dependencies[2].should be_an_instance_of(Runtime::TerminalParseFailure)
0
+ dependencies[2].expected_string.should == 'baz'
0
+ end
0
     end
0
   end
0
 
0
@@ -109,7 +139,7 @@ module ChoiceSpec
0
 
0
     it "extends a match of any of its subexpressions with a module created from the block" do
0
       ['a', 'b', 'c'].each do |letter|
0
- parse(letter).should respond_to(:a_method)
0
+ parse(letter).element.should respond_to(:a_method)
0
       end
0
     end
0
   end
0
@@ -124,7 +154,7 @@ module ChoiceSpec
0
 
0
     it "extends a match of any of its subexpressions with a module created from the block" do
0
       ['a', 'b', 'c'].each do |letter|
0
- parse(letter).should respond_to(:a_method)
0
+ parse(letter).element.should respond_to(:a_method)
0
       end
0
     end
0
   end
...
65
66
67
 
 
 
 
 
 
 
 
 
 
 
 
68
69
70
...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
0
@@ -65,6 +65,18 @@ module CompiledParserSpec
0
       parser.failure_line.should == 1
0
       parser.failure_column.should == 1
0
     end
0
+
0
+ it "returns the element of the returned Propagation as the result of the parse" do
0
+ result = parse('a')
0
+ result.should be_an_instance_of(Runtime::SyntaxNode)
0
+ result.text_value.should == 'a'
0
+ end
0
+
0
+ it "returns a Propagation as the result of the parse if the :return_propagations is true" do
0
+ result = parse('a', :return_propagations => true)
0
+ result.should be_an_instance_of(Runtime::Propagation)
0
+ result.element.text_value.should == 'a'
0
+ end
0
   end
0
 
0
   describe Runtime::CompiledParser, "#terminal_failures" do
...
18
19
20
 
 
 
 
21
22
23
...
18
19
20
21
22
23
24
25
26
27
0
@@ -18,5 +18,9 @@ module PropagationSpec
0
     it "returns the propagated SyntaxNode as its only dependency" do
0
       propagation.dependencies.should == [propagated_syntax_node]
0
     end
0
+
0
+ it "proxies #resume_index to its element" do
0
+ propagation.resume_index.should == propagated_syntax_node.resume_index
0
+ end
0
   end
0
 end
0
\ No newline at end of file
...
72
73
74
 
 
75
76
77
...
72
73
74
75
76
77
78
79
0
@@ -72,6 +72,8 @@ module Treetop
0
       @parser = parser_class_under_test.new
0
       parser.consume_all_input = options[:consume_all_input] if options.has_key?(:consume_all_input)
0
       parser.return_parse_failure = options[:return_parse_failure] if options.has_key?(:return_parse_failure)
0
+ parser.return_propagations = options[:return_propagations] if options.has_key?(:return_propagations)
0
+
0
       result = parser.parse(input, options)
0
       yield result if block_given?
0
       result

Comments

    No one has commented yet.