1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver#!/usr/bin/ruby
2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver# encoding: utf-8
3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverrequire 'antlr3/test/functional'
5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass TestAutoAST < ANTLR3::Test::Functional
7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def parse( grammar, rule, input, expect_errors = false )
9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @grammar = inline_grammar( grammar )
10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    compile_and_load @grammar
11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar_module = self.class.const_get( @grammar.name )
12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar_module::Lexer.send( :include, ANTLR3::Test::CollectErrors )
14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar_module::Lexer.send( :include, ANTLR3::Test::CaptureOutput )
15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar_module::Parser.send( :include, ANTLR3::Test::CollectErrors )
16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar_module::Parser.send( :include, ANTLR3::Test::CaptureOutput )
17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    lexer  = grammar_module::Lexer.new( input )
19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    parser = grammar_module::Parser.new( lexer )
20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    r = parser.send( rule )
22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    parser.reported_errors.should be_empty unless expect_errors
23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = ''
24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    unless r.nil?
26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      result += r.result if r.respond_to?( :result )
27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      result += r.tree.inspect if r.tree
28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return( expect_errors ? [ result, parser.reported_errors ] : result )
30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
31324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def tree_parse( grammar, tree_grammar, rule, tree_rule, input )
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @grammar = inline_grammar( grammar )
34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @tree_grammar = inline_grammar( tree_grammar )
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    compile_and_load @grammar
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    compile_and_load @tree_grammar
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar_module = self.class.const_get( @grammar.name )
39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    tree_grammar_module = self.class.const_get( @tree_grammar.name )
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar_module::Lexer.send( :include, ANTLR3::Test::CollectErrors )
42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar_module::Lexer.send( :include, ANTLR3::Test::CaptureOutput )
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar_module::Parser.send( :include, ANTLR3::Test::CollectErrors )
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar_module::Parser.send( :include, ANTLR3::Test::CaptureOutput )
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    tree_grammar_module::TreeParser.send( :include, ANTLR3::Test::CollectErrors )
46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    tree_grammar_module::TreeParser.send( :include, ANTLR3::Test::CaptureOutput )
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    lexer  = grammar_module::Lexer.new( input )
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    parser = grammar.module::Parser.new( lexer )
50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    r = parser.send( rule )
51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    nodes = ANTLR3::CommonTreeNodeStream( r.tree )
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    nodes.token_stream = parser.input
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    walker = tree_grammar_module::TreeParser.new( nodes )
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    r = walker.send( tree_rule )
55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return( r ? r.tree.inspect : '' )
57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example 'flat token list' do
61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'abc 34' )
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar TokenList;
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID INT ;
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;};
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'abc 34'
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example 'token list in a single-alternative subrule' do
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'abc 34' )
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar TokenListInSingleAltBlock;
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : (ID INT) ;
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'abc 34'
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "simple root at the outer level via the `^' operator" do
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'abc 34' )
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar SimpleRootAtOuterLevel;
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID^ INT ;
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(abc 34)'
94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "outer-level root changing token order from the `^' operator" do
97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, '34 abc' )
98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar SimpleRootAtOuterLevelReverse;
99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : INT ID^ ;
101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(abc 34)'
106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "leaving out tokens using the `!' operator" do
109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'abc 34 dag 4532' )
110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar Bang;
111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID INT! ID! INT ;
113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'abc 4532'
119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "tokens in `(...)?' optional subrule" do
122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a 1 b' )
123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar OptionalThenRoot;
124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ( ID INT )? ID^ ;
126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(b a 1)'
131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "labeled literal-string root token" do
134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'void foo;' )
135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar LabeledStringRoot;
136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : v='void'^ ID ';' ;
138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(void foo ;)'
143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example 'rule with token wildcard' do
146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'void foo;' )
147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar Wildcard;
148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : v='void'^ . ';' ;
150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(void foo ;)'
155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "token wildcard as root via the `^' operator" do
158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'void foo;' )
159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar WildcardRoot;
160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : v='void' .^ ';' ;
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(foo void ;)'
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "labeled token wildcard as root via the `^' operator" do
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'void foo;' )
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar WildcardRootWithLabel;
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : v='void' x=.^ ';' ;
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(foo void ;)'
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "token wildcard as root (with list label)" do
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'void foo;' )
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar WildcardRootWithListLabel;
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : v='void' x=.^ ';' ;
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(foo void ;)'
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "trashed token wildcard" do
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'void foo;' )
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar WildcardBangWithListLabel;
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : v='void' x=.! ';' ;
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'void ;'
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "multiple occurences of the `^' operator in a list of tokens" do
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a 34 c' )
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar RootRoot;
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID^ INT^ ID ;
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(34 a c)'
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "another case of multiple occurences of the `^' operator" do
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a 34 c' )
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar RootRoot2;
224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID INT^ ID^ ;
226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(c (34 a))'
232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "root-hoist using `^' from within a (...)+ block" do
235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a 34 * b 9 * c' )
236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar RootThenRootInLoop;
237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID^ (INT '*'^ ID)+ ;
239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID  : 'a'..'z'+ ;
240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(* (* (a 34) b 9) c)'
245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "nested subrules without any AST ops resulting in a flat list" do
248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'void a b;' )
249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar NestedSubrule;
250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : 'void' (({
252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      #do nothing
253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      } ID|INT) ID | 'null' ) ';' ;
254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'void a b ;'
260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "invoking another rule without any AST ops, resulting in a flat list" do
263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'int a' )
264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar InvokeRule;
265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a  : type ID ;
267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      type : {
268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # do nothing
269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      }'int' | 'float' ;
270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'int a'
276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "hoisting the results of another rule as root using the `^' operator" do
279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'int a' )
280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar InvokeRuleAsRoot;
281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a  : type^ ID ;
283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      type : {
284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # do nothing
285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      }'int' | 'float' ;
286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(int a)'
292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "hoisting another rule's true as root using the `^' operator (with a label)" do
295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'int a' )
296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar InvokeRuleAsRootWithLabel;
297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a  : x=type^ ID ;
299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      type : {
300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # do nothing
301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      }'int' | 'float' ;
302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(int a)'
308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "hoisting another rule's result tree as root using the `^' operator (with a list += label)" do
311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'int a' )
312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar InvokeRuleAsRootWithListLabel;
313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a  : x+=type^ ID ;
315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      type : {
316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # do nothing
317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      }'int' | 'float' ;
318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(int a)'
324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "root-hoist via `^' within a (...)* loop resulting in a deeply-nested tree" do
327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a+b+c+d' )
328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar RuleRootInLoop;
329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID ('+'^ ID)* ;
331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(+ (+ (+ a b) c) d)'
337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "hoisting another rule's result tree as root from within a (...)* loop resulting in a deeply nested tree" do
340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a+b+c-d' )
341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar RuleInvocationRuleRootInLoop;
342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID (op^ ID)* ;
344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      op : {
345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # do nothing
346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      }'+' | '-' ;
347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(- (+ (+ a b) c) d)'
353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "using tail recursion to build deeply-nested expression trees" do
356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :s, '3 exp 4 exp 5' )
357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar TailRecursion;
358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      s : a ;
360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : atom ('exp'^ a)? ;
361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      atom : INT ;
362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(exp 3 (exp 4 5))'
368324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
369324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
370324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "simple token node from a token type set" do
371324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'abc' )
372324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar TokenSet;
373324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby; output=AST;}
374324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID|INT ;
375324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
376324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
377324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
378324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
379324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'abc'
380324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
381324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
382324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "hoisting a token-type set token as root with `^'" do
383324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, '+abc' )
384324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar SetRoot;
385324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
386324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ('+' | '-')^ ID ;
387324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
388324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
389324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
390324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
391324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
392324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(+ abc)'
393324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
394324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
395324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "hoisting a token-type set token as root with `^' (with a label)" do
396324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, '+abc' )
397324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar SetRootWithLabel;
398324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
399324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : (x=('+' | '-'))^ ID ;
400324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
401324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
402324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
403324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
404324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
405324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '+ abc'
406324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
407324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
408324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "hoisting a token-type set token as root from within a (...)* loop" do
409324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a+b-c' )
410324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar SetAsRuleRootInLoop;
411324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
412324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID (('+'|'-')^ ID)* ;
413324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
414324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
415324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
416324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
417324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
418324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(- (+ a b) c)'
419324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
420324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
421324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "an `~' inverted token-type set element" do
422324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, '34+2' )
423324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar NotSet;
424324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
425324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ~ID '+' INT ;
426324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
427324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
428324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
429324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
430324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
431324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '34 + 2'
432324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
433324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
434324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "a `~' inverted token-type set in a rule (with a label)" do
435324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, '34+2' )
436324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar NotSetWithLabel;
437324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
438324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : x=~ID '+' INT ;
439324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
440324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
441324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
442324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
443324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
444324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '34 + 2'
445324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
446324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
447324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "a `~' inverted token-type set element in a rule (with a list += label)" do
448324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, '34+2' )
449324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar NotSetWithListLabel;
450324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
451324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : x=~ID '+' INT ;
452324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
453324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
454324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
455324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
456324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
457324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '34 + 2'
458324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
459324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
460324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "a `~' inverted token-type set element hoisted to root via `^'" do
461324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, '34 55' )
462324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar NotSetRoot;
463324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
464324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ~'+'^ INT ;
465324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
466324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
467324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
468324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
469324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
470324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(34 55)'
471324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
472324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
473324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "hoisting a `~' inverted token-type set to root using `^' (with label)" do
474324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, '34 55' )
475324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar NotSetRootWithLabel;
476324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
477324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a   : x=~'+'^ INT ;
478324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID  : 'a'..'z'+ ;
479324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
480324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS  : (' '|'\n') {$channel=HIDDEN;} ;
481324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
482324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(34 55)'
483324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
484324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
485324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "hoisting a `~' inverted token-type set to root using `^' (with list += label)" do
486324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, '34 55' )
487324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar NotSetRootWithListLabel;
488324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
489324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : x+=~'+'^ INT ;
490324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
491324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
492324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
493324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
494324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(34 55)'
495324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
496324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
497324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "hoisting a `~' inverted token-type set to root from within a (...)* loop" do
498324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, '3+4+5' )
499324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar NotSetRuleRootInLoop;
500324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
501324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : INT (~INT^ INT)* ;
502324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      blort : '+' ;
503324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
504324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
505324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
506324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
507324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
508324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(+ (+ 3 4) 5)'
509324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
510324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
511324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "multiple tokens with the same label in a rule" do
512324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a b' )
513324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar TokenLabelReuse;
514324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
515324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a returns [result] : id=ID id=ID {
516324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        $result = "2nd id=\%s," \% $id.text
517324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      } ;
518324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
519324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
520324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
521324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
522324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
523324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '2nd id=b,a b'
524324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
525324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
526324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "multiple tokens with the same label in a rule (with a `^' root hoist)" do
527324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a b' )
528324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar TokenLabelReuse2;
529324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
530324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a returns [result]: id=ID id=ID^ {$result = "2nd id=#{$id.text},"} ;
531324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
532324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
533324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
534324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
535324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
536324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '2nd id=b,(b a)'
537324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
538324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
539324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "extra token in a simple declaration" do
540324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result, errors = parse( <<-'END', :decl, 'int 34 x=1;', true )
541324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar ExtraTokenInSimpleDecl;
542324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
543324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      decl : type^ ID '='! INT ';'! ;
544324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      type : 'int' | 'float' ;
545324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
546324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
547324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
548324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
549324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
550324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    errors.should == [ "line 1:4 extraneous input \"34\" expecting ID" ]
551324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(int x 1)'
552324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
553324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
554324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "missing ID in a simple declaration" do
555324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result, errors = parse( <<-'END', :decl, 'int =1;', true )
556324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar MissingIDInSimpleDecl;
557324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
558324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      tokens {EXPR;}
559324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      decl : type^ ID '='! INT ';'! ;
560324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      type : 'int' | 'float' ;
561324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
562324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
563324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
564324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
565324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    errors.should == [ "line 1:4 missing ID at \"=\"" ]
566324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(int <missing ID> 1)'
567324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
568324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
569324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "missing token of a token-type set in a simple declaration" do
570324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result, errors = parse( <<-'END', :decl, 'x=1;', true )
571324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar MissingSetInSimpleDecl;
572324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
573324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      tokens {EXPR;}
574324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      decl : type^ ID '='! INT ';'! ;
575324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      type : 'int' | 'float' ;
576324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
577324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
578324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
579324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
580324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
581324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    errors.should == [ "line 1:0 mismatched input \"x\" expecting set nil" ]
582324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '(<error: x> x 1)'
583324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
584324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
585324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "missing INT token simulated with a `<missing INT>' error node" do
586324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result, errors = parse( <<-'END', :a, 'abc', true )
587324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar MissingTokenGivesErrorNode;
588324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
589324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID INT ; // follow is EOF
590324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
591324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
592324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
593324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
594324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
595324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    errors.should == [ "line 0:-1 missing INT at \"<EOF>\"" ]
596324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'abc <missing INT>'
597324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
598324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
599324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "missing token from invoked rule results in error node with a resync attribute" do
600324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result, errors = parse( <<-'END', :a, 'abc', true )
601324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar MissingTokenGivesErrorNodeInInvokedRule;
602324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
603324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : b ;
604324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      b : ID INT ; // follow should see EOF
605324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
606324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
607324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
608324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
609324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
610324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    errors.should == [ "line 0:-1 mismatched input \"<EOF>\" expecting INT" ]
611324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '<mismatched token: <EOF>, resync = abc>'
612324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
613324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
614324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "extraneous ID token displays error and is ignored in AST output" do
615324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result, errors = parse( <<-'END', :a, 'abc ick 34', true )
616324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar ExtraTokenGivesErrorNode;
617324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
618324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : b c ;
619324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      b : ID ;
620324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      c : INT ;
621324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
622324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
623324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
624324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
625324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
626324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    errors.should == [ "line 1:4 extraneous input \"ick\" expecting INT" ]
627324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'abc 34'
628324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
629324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
630324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "missing ID token simulated with a `<missing ID>' error node" do
631324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result, errors = parse( <<-'END', :a, '34', true )
632324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar MissingFirstTokenGivesErrorNode;
633324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
634324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : ID INT ;
635324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
636324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
637324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
638324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
639324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
640324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    errors.should == [ "line 1:0 missing ID at \"34\"" ]
641324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '<missing ID> 34'
642324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
643324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
644324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "another case where a missing ID token is simulated with a `<missing ID>' error node" do
645324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result, errors = parse( <<-'END', :a, '34', true )
646324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar MissingFirstTokenGivesErrorNode2;
647324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
648324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : b c ;
649324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      b : ID ;
650324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      c : INT ;
651324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
652324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
653324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
654324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
655324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
656324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    errors.should == [ "line 1:0 missing ID at \"34\"" ]
657324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '<missing ID> 34'
658324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
659324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
660324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "no viable alternative for rule is represented as a single `<unexpected: ...>' error node" do
661324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result, errors = parse( <<-'END', :a, '*', true )
662324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar NoViableAltGivesErrorNode;
663324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
664324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : b | c ;
665324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      b : ID ;
666324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      c : INT ;
667324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
668324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      S : '*' ;
669324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
670324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
671324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
672324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    errors.should == [ "line 1:0 no viable alternative at input \"*\"" ]
673324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == "<unexpected: 0 S[\"*\"] @ line 1 col 0 (0..0), resync = *>"
674324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
675324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
676324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "token with a `+=' list label hoisted to root with `^'" do
677324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a' )
678324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar TokenListLabelRuleRoot;
679324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
680324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : id+=ID^ ;
681324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
682324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
683324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
684324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
685324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
686324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'a'
687324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
688324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
689324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "token with a list `+=' label trashed with `!'" do
690324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a' )
691324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar TokenListLabelBang;
692324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
693324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : id+=ID! ;
694324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
695324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
696324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
697324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
698324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
699324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == ''
700324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
701324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
702324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "using list `+=' labels to collect trees of invoked rules" do
703324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a b' )
704324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar RuleListLabel;
705324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
706324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a returns [result]: x+=b x+=b {
707324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      t = $x[1]
708324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      $result = "2nd x=#{t.inspect},"
709324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      };
710324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      b : ID;
711324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
712324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
713324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
714324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
715324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
716324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '2nd x=b,a b'
717324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
718324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
719324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "using a list `+=' label to collect the trees of invoked rules within a (...)+ block" do
720324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a b' )
721324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar RuleListLabelRuleRoot;
722324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
723324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a returns [result] : ( x+=b^ )+ {
724324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      $result = "x=\%s," \% $x[1].inspect
725324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      } ;
726324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      b : ID;
727324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
728324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
729324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
730324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
731324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
732324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'x=(b a),(b a)'
733324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
734324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
735324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "trashing the tree of an invoked rule with `!' while collecting the tree with a list `+=' label" do
736324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a b' )
737324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar RuleListLabelBang;
738324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
739324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a returns [result] : x+=b! x+=b {
740324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      $result = "1st x=#{$x[0].inspect},"
741324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      } ;
742324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      b : ID;
743324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
744324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
745324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
746324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
747324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
748324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == '1st x=a,b'
749324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
750324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
751324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "a whole bunch of different elements" do
752324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'a b b c c d' )
753324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar ComplicatedMelange;
754324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
755324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a : A b=B b=B c+=C c+=C D {s = $D.text} ;
756324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      A : 'a' ;
757324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      B : 'b' ;
758324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      C : 'c' ;
759324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      D : 'd' ;
760324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
761324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
762324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'a b b c c d'
763324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
764324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
765324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "rule return values in addition to AST output" do
766324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :a, 'abc 34' )
767324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar ReturnValueWithAST;
768324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options {language=Ruby;output=AST;}
769324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      a returns [result] : ID b { $result = $b.i.to_s + "\n" } ;
770324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      b returns [i] : INT {$i=$INT.text.to_i};
771324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z'+ ;
772324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9'+;
773324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS : (' '|'\n') {$channel=HIDDEN;} ;
774324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
775324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
776324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == "34\nabc 34"
777324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
778324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
779324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  example "a (...)+ loop containing a token-type set" do
780324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result = parse( <<-'END', :r, 'abc 34 d' )
781324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammar SetLoop;
782324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      options { language=Ruby;output=AST; }
783324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      r : (INT|ID)+ ; 
784324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      ID : 'a'..'z' + ;
785324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      INT : '0'..'9' +;
786324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      WS: (' ' | '\n' | '\t')+ {$channel = HIDDEN;};
787324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
788324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    END
789324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    result.should == 'abc 34 d'
790324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
791324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
792324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend
793