1#!/usr/bin/ruby
2# encoding: utf-8
3
4require 'antlr3/test/functional'
5
6class TestScopes1 < ANTLR3::Test::Functional
7
8  inline_grammar( <<-'END' )
9    grammar SimpleScope;
10
11    options {
12        language = Ruby;
13    }
14
15    prog
16    scope {
17    name
18    }
19        :   ID {$prog::name=$ID.text;}
20        ;
21
22    ID  :   ('a'..'z')+
23        ;
24
25    WS  :   (' '|'\n'|'\r')+ {$channel=HIDDEN}
26        ;
27  END
28
29  example "parsing 'foobar'" do
30    lexer = SimpleScope::Lexer.new( 'foobar' )
31    parser = SimpleScope::Parser.new lexer
32    parser.prog
33  end
34end
35
36class TestScopes2 < ANTLR3::Test::Functional
37  inline_grammar( <<-'END' )
38    grammar LotsaScopes;
39
40    options {
41        language = Ruby;
42    }
43
44    /* global scopes */
45
46    scope aScope {
47      names;
48    }
49
50    @members {
51      def emit_error_message(msg)
52        # do nothing
53      end
54
55      def report_error(error)
56        raise error
57      end
58    }
59
60    a
61    scope aScope;
62        :   {$aScope::names = []} ID*
63        ;
64
65
66    /* rule scopes, from the book, final beta, p.147 */
67
68    b[v]
69    scope {x}
70        : {$b::x = v;} b2
71        ;
72
73    b2
74        : b3
75        ;
76
77    b3
78        : {$b::x}?=> ID // only visible, if b was called with True
79        | NUM
80        ;
81
82
83    /* rule scopes, from the book, final beta, p.148 */
84
85    c returns [res]
86    scope {
87        symbols
88    }
89    @init {
90        $c::symbols = Set.new;
91    }
92        : '{' c1* c2+ '}'
93            { $res = $c::symbols; }
94        ;
95
96    c1
97        : 'int' ID {$c::symbols.add($ID.text)} ';'
98        ;
99
100    c2
101        : ID '=' NUM ';'
102            {
103                $c::symbols.include?($ID.text) or raise RuntimeError, $ID.text
104             }
105        ;
106
107    /* recursive rule scopes, from the book, final beta, p.150 */
108
109    d returns [res]
110    scope {
111        symbols
112    }
113    @init {
114        $d::symbols = Set.new
115    }
116        : '{' d1* d2* '}'
117            { $res = $d::symbols; }
118        ;
119
120    d1
121        : 'int' ID {$d::symbols.add($ID.text)} ';'
122        ;
123
124    d2
125        : ID '=' NUM ';'
126            {
127              catch(:found) do
128                level = ($d.length - 1).downto(0) do |s|
129                  $d[s].symbols.include?($ID.text) and throw(:found)
130                end
131                raise $ID.text
132              end
133            }
134        | d
135        ;
136
137    /* recursive rule scopes, access bottom-most scope */
138
139    e returns [res]
140    scope {
141        a
142    }
143    @after {
144        $res = $e::a;
145    }
146        : NUM { $e[0]::a = Integer($NUM.text); }
147        | '{' e '}'
148        ;
149
150
151    /* recursive rule scopes, access with negative index */
152
153    f returns [res]
154    scope {
155        a
156    }
157    @after {
158        $res = $f::a;
159    }
160        : NUM { $f[-2]::a = Integer($NUM.text); }
161        | '{' f '}'
162        ;
163
164
165    /* tokens */
166
167    ID  :   ('a'..'z')+
168        ;
169
170    NUM :   ('0'..'9')+
171        ;
172
173    WS  :   (' '|'\n'|'\r')+ {$channel=HIDDEN}
174        ;
175  END
176
177  example "parsing 'foobar' with rule a" do
178    lexer = LotsaScopes::Lexer.new( "foobar" )
179    parser = LotsaScopes::Parser.new lexer
180    parser.a
181  end
182
183  example "failing to parse 'foobar' with rule b[false]" do
184    lexer = LotsaScopes::Lexer.new( "foobar" )
185    parser = LotsaScopes::Parser.new lexer
186    proc { parser.b( false ) }.should raise_error( ANTLR3::RecognitionError )
187  end
188
189  example "parsing 'foobar' with rule b[true]" do
190    lexer = LotsaScopes::Lexer.new( "foobar" )
191    parser = LotsaScopes::Parser.new lexer
192    parser.b( true )
193  end
194
195  example "parsing a decl block with rule c" do
196    lexer = LotsaScopes::Lexer.new( <<-END.here_indent! )
197    | {
198    |     int i;
199    |     int j;
200    |     i = 0;
201    | }
202    END
203    parser = LotsaScopes::Parser.new lexer
204
205    symbols = parser.c
206    symbols.should have( 2 ).things
207    symbols.should include 'i'
208    symbols.should include 'j'
209  end
210
211  example "failing to parse undeclared symbols with rule c" do
212    lexer = LotsaScopes::Lexer.new( <<-END.here_indent! )
213    | {
214    |     int i;
215    |     int j;
216    |     i = 0;
217    |     x = 4;
218    | }
219    END
220    parser = LotsaScopes::Parser.new lexer
221
222    proc { parser.c }.should raise_error RuntimeError, 'x'
223  end
224
225  example "parsing nested declaration blocks" do
226    lexer = LotsaScopes::Lexer.new( <<-END.here_indent! )
227    | {
228    |     int i;
229    |     int j;
230    |     i = 0;
231    |     {
232    |        int i;
233    |        int x;
234    |        x = 5;
235    |     }
236    | }
237    END
238    parser = LotsaScopes::Parser.new lexer
239
240    symbols = parser.d
241    symbols.should have( 2 ).things
242    symbols.should include 'i'
243    symbols.should include 'j'
244  end
245
246  example "parsing a deeply nested set of blocks with rule e" do
247    lexer = LotsaScopes::Lexer.new( <<-END.here_indent! )
248    | { { { { 12 } } } }
249    END
250
251    parser = LotsaScopes::Parser.new lexer
252    parser.e.should == 12
253  end
254
255  example "parsing a deeply nested set of blocks with rule f" do
256    lexer = LotsaScopes::Lexer.new( <<-END.here_indent! )
257    | { { { { 12 } } } }
258    END
259
260    parser = LotsaScopes::Parser.new lexer
261    parser.f.should == nil
262  end
263
264  example "parsing a 2-level nested set of blocks with rule f" do
265    lexer = LotsaScopes::Lexer.new( <<-END.here_indent! )
266    | { { 12 } }
267    END
268    parser = LotsaScopes::Parser.new lexer
269
270    parser.f.should == nil
271  end
272
273end
274