1#!/usr/bin/ruby
2# encoding: utf-8
3
4require 'antlr3/test/functional'
5
6class TestParser001 < ANTLR3::Test::Functional
7  inline_grammar( <<-'END' )
8    grammar Identifiers;
9    options { language = Ruby; }
10
11    @parser::init {
12      @identifiers = []
13      @reported_errors = []
14    }
15
16    @parser::members {
17      attr_reader :reported_errors, :identifiers
18
19      def found_identifier(name)
20          @identifiers << name
21      end
22
23      def emit_error_message(msg)
24        @reported_errors << msg
25      end
26    }
27
28    document:
29            t=IDENTIFIER {found_identifier($t.text)}
30            ;
31
32    IDENTIFIER: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
33  END
34
35  example "parsing 'blah_de_blah'" do
36    # to build a parser, this is the standard chain of calls to prepare the input
37    input = ANTLR3::StringStream.new( 'blah_de_blah', :file => 'blah.txt' )
38    lexer  = Identifiers::Lexer.new( input )
39    tokens = ANTLR3::CommonTokenStream.new( lexer )
40    parser = Identifiers::Parser.new( tokens )
41
42    parser.document
43
44    parser.reported_errors.should be_empty
45    parser.identifiers.should == %w(blah_de_blah)
46  end
47
48  example "error from empty input" do
49    # if you don't need to use a customized stream, lexers and parsers will
50    # automatically wrap input in the standard stream classes
51    lexer = Identifiers::Lexer.new( '' )
52    parser = Identifiers::Parser.new( lexer )
53    parser.document
54
55    parser.reported_errors.should have( 1 ).thing
56  end
57
58  example 'automatic input wrapping' do
59    # if the parser is able to figure out what lexer class
60    # to use (typically when it comes from a combined grammar),
61    # and you don't need to do any special token processing
62    # before making a parser, this is an extra shortcut for
63    # parser construction
64    parser = Identifiers::Parser.new( 'blah_de_blah', :file => 'blah.txt' )
65
66    parser.document
67
68    parser.reported_errors.should be_empty
69    parser.identifiers.should == %w(blah_de_blah)
70  end
71end
72
73class TestParser002 < ANTLR3::Test::Functional
74  inline_grammar( <<-'END' )
75    grammar SimpleLanguage;
76    options {
77      language = Ruby;
78    }
79
80    @parser::init {
81      @events = []
82      @reported_errors = []
83    }
84
85    @parser::members {
86      attr_reader :reported_errors, :events
87
88      def emit_error_message(msg)
89        @reported_errors << msg
90      end
91    }
92
93    document:
94            ( declaration
95            | call
96            )*
97            EOF
98        ;
99
100    declaration:
101            'var' t=IDENTIFIER ';'
102            {@events << ['decl', $t.text]}
103        ;
104
105    call:
106            t=IDENTIFIER '(' ')' ';'
107            {@events << ['call', $t.text]}
108        ;
109
110    IDENTIFIER: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
111    WS:  (' '|'\r'|'\t'|'\n') {$channel=HIDDEN;};
112  END
113
114
115  example "parsing decls and calls" do
116    lexer  = SimpleLanguage::Lexer.new( "var foobar; gnarz(); var blupp; flupp ( ) ;" )
117    parser = SimpleLanguage::Parser.new( lexer )
118
119    parser.document
120
121    parser.reported_errors.should be_empty
122    parser.events.should == [
123      %w(decl foobar),
124      %w(call gnarz),
125      %w(decl blupp),
126      %w(call flupp)
127    ]
128  end
129
130  example "bad declaration" do
131    lexer  = SimpleLanguage::Lexer.new( 'var; foo()' )
132    parser = SimpleLanguage::Parser.new( lexer )
133
134    parser.document
135
136    parser.reported_errors.should have( 1 ).thing
137    parser.events.should be_empty
138  end
139
140  example "error recovery via token insertion" do
141    lexer  = SimpleLanguage::Lexer.new( 'gnarz(; flupp();' )
142    parser = SimpleLanguage::Parser.new( lexer )
143
144    parser.document
145
146    parser.reported_errors.should have( 1 ).thing
147    parser.events.should == [
148      %w(call gnarz),
149      %w(call flupp)
150    ]
151  end
152
153end
154
155class TestParser003 < ANTLR3::Test::Functional
156  inline_grammar( <<-'END' )
157    grammar MoreComplicated;
158
159    options { language = Ruby; }
160
161    @init {
162      @reported_errors = []
163    }
164
165    @members {
166      attr_reader :reported_errors
167
168      def emit_error_message(msg)
169        @reported_errors << msg
170      end
171    }
172
173    program
174        :   declaration+
175        ;
176
177    declaration
178        :   variable
179        |   functionHeader ';'
180        |   functionHeader block
181        ;
182
183    variable
184        :   type declarator ';'
185        ;
186
187    declarator
188        :   ID
189        ;
190
191    functionHeader
192        :   type ID '(' ( formalParameter ( ',' formalParameter )* )? ')'
193        ;
194
195    formalParameter
196        :   type declarator
197        ;
198
199    type
200        :   'int'
201        |   'char'
202        |   'void'
203        |   ID
204        ;
205
206    block
207        :   '{'
208                variable*
209                stat*
210            '}'
211        ;
212
213    stat: forStat
214        | expr ';'
215        | block
216        | assignStat ';'
217        | ';'
218        ;
219
220    forStat
221        :   'for' '(' assignStat ';' expr ';' assignStat ')' block
222        ;
223
224    assignStat
225        :   ID '=' expr
226        ;
227
228    expr:   condExpr
229        ;
230
231    condExpr
232        :   aexpr ( ('==' | '<') aexpr )?
233        ;
234
235    aexpr
236        :   atom ( '+' atom )*
237        ;
238
239    atom
240        : ID
241        | INT
242        | '(' expr ')'
243        ;
244
245    ID  :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
246        ;
247
248    INT :	('0'..'9')+
249        ;
250
251    WS  :   (   ' '
252            |   '\t'
253            |   '\r'
254            |   '\n'
255            )+
256            {$channel=HIDDEN}
257        ;
258  END
259
260  example "parsing 'int foo;'" do
261    lexer = MoreComplicated::Lexer.new "int foo;"
262    parser = MoreComplicated::Parser.new lexer
263    parser.program
264    parser.reported_errors.should be_empty
265  end
266
267
268  example "catching badly formed input" do
269    lexer = MoreComplicated::Lexer.new "int foo() { 1+2 }"
270    parser = MoreComplicated::Parser.new lexer
271    parser.program
272    parser.reported_errors.should have( 1 ).thing
273  end
274
275  example "two instances of badly formed input" do
276    lexer = MoreComplicated::Lexer.new "int foo() { 1+; 1+2 }"
277    parser = MoreComplicated::Parser.new lexer
278    parser.program
279    parser.reported_errors.should have( 2 ).things
280  end
281
282end
283