construction.rb revision 324c4644fee44b9898524c09511bd33c3f12e2df
1#!/usr/bin/ruby
2# encoding: utf-8
3
4require 'antlr3/test/functional'
5
6class TestASTConstructingParser < ANTLR3::Test::Functional
7
8  compile inline_grammar( <<-'END' )
9    grammar ASTBuilder;
10    options {
11      language = Ruby;
12      output = AST;
13    }
14    
15    tokens {
16        VARDEF;
17        FLOAT;
18        EXPR;
19        BLOCK;
20        VARIABLE;
21        FIELD;
22        CALL;
23        INDEX;
24        FIELDACCESS;
25    }
26    
27    @init {
28      @flag = false
29    }
30    
31    @members {
32      attr_accessor :flag
33      
34      def report_error(e)
35        # do nothing
36      end
37      
38    }
39    
40    
41    r1
42        : INT ('+'^ INT)*
43        ;
44    
45    r2
46        : 'assert'^ x=expression (':'! y=expression)? ';'!
47        ;
48    
49    r3
50        : 'if'^ expression s1=statement ('else'! s2=statement)?
51        ;
52    
53    r4
54        : 'while'^ expression statement
55        ;
56    
57    r5
58        : 'return'^ expression? ';'!
59        ;
60    
61    r6
62        : (INT|ID)+
63        ;
64    
65    r7
66        : INT -> 
67        ;
68    
69    r8
70        : 'var' ID ':' type -> ^('var' type ID) 
71        ;
72    
73    r9
74        : type ID ';' -> ^(VARDEF type ID) 
75        ;
76    
77    r10
78        : INT -> { ANTLR3::AST::CommonTree.new(ANTLR3::CommonToken.create(:type => FLOAT, :text => ($INT.text + ".0")))}
79        ;
80    
81    r11
82        : expression -> ^(EXPR expression)
83        | -> EXPR
84        ;
85    
86    r12
87        : ID (',' ID)* -> ID+
88        ;
89    
90    r13
91        : type ID (',' ID)* ';' -> ^(type ID+)
92        ;
93    
94    r14
95        :   expression? statement* type+
96            -> ^(EXPR expression? statement* type+)
97        ;
98    
99    r15
100        : INT -> INT INT
101        ;
102    
103    r16
104        : 'int' ID (',' ID)* -> ^('int' ID)+
105        ;
106    
107    r17
108        : 'for' '(' start=statement ';' expression ';' next=statement ')' statement
109            -> ^('for' $start expression $next statement)
110        ;
111    
112    r18
113        : t='for' -> ^(BLOCK)
114        ;
115    
116    r19
117        : t='for' -> ^(BLOCK[$t])
118        ;
119    
120    r20
121        : t='for' -> ^(BLOCK[$t,"FOR"])
122        ;
123    
124    r21
125        : t='for' -> BLOCK
126        ;
127    
128    r22
129        : t='for' -> BLOCK[$t]
130        ;
131    
132    r23
133        : t='for' -> BLOCK[$t,"FOR"]
134        ;
135    
136    r24
137        : r=statement expression -> ^($r expression)
138        ;
139    
140    r25
141        : r+=statement (',' r+=statement)+ expression -> ^($r expression)
142        ;
143    
144    r26
145        : r+=statement (',' r+=statement)+ -> ^(BLOCK $r+)
146        ;
147    
148    r27
149        : r=statement expression -> ^($r ^($r expression))
150        ;
151    
152    r28
153        : ('foo28a'|'foo28b') ->
154        ;
155    
156    r29
157        : (r+=statement)* -> ^(BLOCK $r+)
158        ;
159    
160    r30
161        : statement* -> ^(BLOCK statement?)
162        ;
163    
164    r31
165        : modifier type ID ('=' expression)? ';'
166            -> {@flag == 0}? ^(VARDEF ID modifier* type expression?)
167            -> {@flag == 1}? ^(VARIABLE ID modifier* type expression?)
168            ->                   ^(FIELD ID modifier* type expression?)
169        ;
170    
171    r32[which]
172      : ID INT -> {which==1}? ID
173               -> {which==2}? INT
174               -> // yield nothing as else-clause
175      ;
176    
177    r33
178        :   modifiers! statement
179        ;
180    
181    r34
182        :   modifiers! r34a[$modifiers.tree]
183        //|   modifiers! r33b[$modifiers.tree]
184        ;
185    
186    r34a[mod]
187        :   'class' ID ('extends' sup=type)?
188            ( 'implements' i+=type (',' i+=type)*)?
189            '{' statement* '}'
190            -> ^('class' ID {$mod} ^('extends' $sup)? ^('implements' $i+)? statement* )
191        ;
192    
193    r35
194        : '{' 'extends' (sup=type)? '}'
195            ->  ^('extends' $sup)?
196        ;
197    
198    r36
199        : 'if' '(' expression ')' s1=statement
200            ( 'else' s2=statement -> ^('if' ^(EXPR expression) $s1 $s2)
201            |                     -> ^('if' ^(EXPR expression) $s1)
202            )
203        ;
204    
205    r37
206        : (INT -> INT) ('+' i=INT -> ^('+' $r37 $i) )* 
207        ;
208    
209    r38
210        : INT ('+'^ INT)*
211        ;
212    
213    r39
214        : (primary->primary) // set return tree to just primary
215            ( '(' arg=expression ')'
216                -> ^(CALL $r39 $arg)
217            | '[' ie=expression ']'
218                -> ^(INDEX $r39 $ie)
219            | '.' p=primary
220                -> ^(FIELDACCESS $r39 $p)
221            )*
222        ;
223    
224    r40
225        : (INT -> INT) ( ('+' i+=INT)* -> ^('+' $r40 $i*) ) ';'
226        ;
227    
228    r41
229        : (INT -> INT) ( ('+' i=INT) -> ^($i $r41) )* ';'
230        ;
231    
232    r42
233        : ids+=ID (','! ids+=ID)*
234        ;
235    
236    r43 returns [res]
237        : ids+=ID! (','! ids+=ID!)* {$res = $ids.map { |id| id.text }}
238        ;
239    
240    r44
241        : ids+=ID^ (','! ids+=ID^)*
242        ;
243    
244    r45
245        : primary^
246        ;
247    
248    r46 returns [res]
249        : ids+=primary! (','! ids+=primary!)* {$res = $ids.map { |id| id.text }}
250        ;
251    
252    r47
253        : ids+=primary (','! ids+=primary)*
254        ;
255    
256    r48
257        : ids+=. (','! ids+=.)*
258        ;
259    
260    r49
261        : .^ ID
262        ;
263    
264    r50
265        : ID 
266            -> ^({ANTLR3::AST::CommonTree.new(ANTLR3::CommonToken.create(:type => FLOAT, :text => "1.0"))} ID)
267        ;
268    
269    /** templates tested:
270        tokenLabelPropertyRef_tree
271    */
272    r51 returns [res]
273        : ID t=ID ID
274            { $res = $t.tree }
275        ;
276    
277    /** templates tested:
278        rulePropertyRef_tree
279    */
280    r52 returns [res]
281    @after {
282        $res = $tree
283    }
284        : ID
285        ;
286    
287    /** templates tested:
288        ruleLabelPropertyRef_tree
289    */
290    r53 returns [res]
291        : t=primary
292            { $res = $t.tree }
293        ;
294    
295    /** templates tested:
296        ruleSetPropertyRef_tree
297    */
298    r54 returns [res]
299    @after {
300        $tree = $t.tree;
301    }
302        : ID t=expression ID
303        ;
304    
305    /** backtracking */
306    r55
307    options { backtrack=true; k=1; }
308        : (modifier+ INT)=> modifier+ expression
309        | modifier+ statement
310        ;
311    
312    
313    /** templates tested:
314        rewriteTokenRef with len(args)>0
315    */
316    r56
317        : t=ID* -> ID[$t,'foo']
318        ;
319    
320    /** templates tested:
321        rewriteTokenRefRoot with len(args)>0
322    */
323    r57
324        : t=ID* -> ^(ID[$t,'foo'])
325        ;
326    
327    /** templates tested:
328        ???
329    */
330    r58
331        : ({CommonTree.new(CommonToken.create(:type => FLOAT, :text => "2.0"))})^
332        ;
333    
334    /** templates tested:
335        rewriteTokenListLabelRefRoot
336    */
337    r59
338        : (t+=ID)+ statement -> ^($t statement)+
339        ;
340    
341    primary
342        : ID
343        ;
344    
345    expression
346        : r1
347        ;
348    
349    statement
350        : 'fooze'
351        | 'fooze2'
352        ;
353    
354    modifiers
355        : modifier+
356        ;
357    
358    modifier
359        : 'public'
360        | 'private'
361        ;
362    
363    type
364        : 'int'
365        | 'bool'
366        ;
367    
368    ID : 'a'..'z' + ;
369    INT : '0'..'9' +;
370    WS: (' ' | '\n' | '\t')+ {$channel = HIDDEN;};
371  END
372  
373  def self.ast_test( opts, &special_test )
374    input = opts[ :input ]
375    rule  = opts[ :rule ]
376    expected_tree = opts[ :ast ]
377    flag = opts[ :flag ]
378    args = opts[ :arguments ] || []
379    message = opts[ :message ] || rule.to_s #"should parse %p with rule %s and make tree %s" % [input, rule, expected_tree]
380    
381    example( message ) do
382      lexer = ASTBuilder::Lexer.new( input )
383      parser = ASTBuilder::Parser.new( lexer )
384      parser.flag = flag unless flag.nil?
385      result = parser.send( rule, *args )
386      if special_test then instance_exec( result, &special_test )
387      elsif expected_tree then
388        result.tree.inspect.should == expected_tree
389      else result.tree.should be_nil
390      end
391    end
392  end
393  
394  ast_test :input => "1 + 2", :rule => :r1, :ast => "(+ 1 2)"
395  
396  ast_test :input => "assert 2+3", :rule => :r2, :ast => "(assert (+ 2 3))"
397  
398  ast_test :input => "assert 2+3 : 5", :rule => :r2, :ast => "(assert (+ 2 3) 5)"
399  
400  ast_test :input => "if 1 fooze", :rule => :r3, :ast => "(if 1 fooze)"
401  
402  ast_test :input => "if 1 fooze else fooze", :rule => :r3, :ast => "(if 1 fooze fooze)"
403  
404  ast_test :input => "while 2 fooze", :rule => :r4, :ast => "(while 2 fooze)"
405  
406  ast_test :input => "return;", :rule => :r5, :ast => "return"
407  
408  ast_test :input => "return 2+3;", :rule => :r5, :ast => "(return (+ 2 3))"
409  
410  ast_test :input => "3", :rule => :r6, :ast => "3"
411  
412  ast_test :input => "3 a", :rule => :r6, :ast => "3 a"
413  
414  ast_test :input => "3", :rule => :r7, :ast => nil
415  
416  ast_test :input => "var foo:bool", :rule => :r8, :ast => "(var bool foo)"
417  
418  ast_test :input => "int foo;", :rule => :r9, :ast => "(VARDEF int foo)"
419  
420  ast_test :input => "10", :rule => :r10, :ast => "10.0"
421  
422  ast_test :input => "1+2", :rule => :r11, :ast => "(EXPR (+ 1 2))"
423  
424  ast_test :input => "", :rule => :r11, :ast => "EXPR"
425  
426  ast_test :input => "foo", :rule => :r12, :ast => "foo"
427  
428  ast_test :input => "foo, bar, gnurz", :rule => :r12, :ast => "foo bar gnurz"
429  
430  ast_test :input => "int foo;", :rule => :r13, :ast => "(int foo)"
431  
432  ast_test :input => "bool foo, bar, gnurz;", :rule => :r13, :ast => "(bool foo bar gnurz)"
433  
434  ast_test :input => "1+2 int", :rule => :r14, :ast => "(EXPR (+ 1 2) int)"
435  
436  ast_test :input => "1+2 int bool", :rule => :r14, :ast => "(EXPR (+ 1 2) int bool)"
437  
438  ast_test :input => "int bool", :rule => :r14, :ast => "(EXPR int bool)"
439  
440  ast_test :input => "fooze fooze int bool", :rule => :r14, :ast => "(EXPR fooze fooze int bool)"
441  
442  ast_test :input => "7+9 fooze fooze int bool", :rule => :r14, :ast => "(EXPR (+ 7 9) fooze fooze int bool)"
443  
444  ast_test :input => "7", :rule => :r15, :ast => "7 7"
445  
446  ast_test :input => "int foo", :rule => :r16, :ast => "(int foo)"
447  
448  ast_test :input => "int foo, bar, gnurz", :rule => :r16, :ast => "(int foo) (int bar) (int gnurz)"
449  
450  ast_test :input => "for ( fooze ; 1 + 2 ; fooze ) fooze", :rule => :r17, :ast => "(for fooze (+ 1 2) fooze fooze)"
451  
452  ast_test :input => "for", :rule => :r18, :ast => "BLOCK"
453  
454  ast_test :input => "for", :rule => :r19, :ast => "for"
455  
456  ast_test :input => "for", :rule => :r20, :ast => "FOR"
457  
458  ast_test :input => "for", :rule => :r21, :ast => "BLOCK"
459  
460  ast_test :input => "for", :rule => :r22, :ast => "for"
461  
462  ast_test :input => "for", :rule => :r23, :ast => "FOR"
463  
464  ast_test :input => "fooze 1 + 2", :rule => :r24, :ast => "(fooze (+ 1 2))"
465  
466  ast_test :input => "fooze, fooze2 1 + 2", :rule => :r25, :ast => "(fooze (+ 1 2))"
467  
468  ast_test :input => "fooze, fooze2", :rule => :r26, :ast => "(BLOCK fooze fooze2)"
469  
470  ast_test :input => "fooze 1 + 2", :rule => :r27, :ast => "(fooze (fooze (+ 1 2)))"
471  
472  ast_test :input => "foo28a", :rule => :r28, :ast => nil
473  
474  ast_test :input => "public int gnurz = 1 + 2;", :rule => :r31, :ast => "(VARDEF gnurz public int (+ 1 2))", :flag => 0
475  
476  ast_test :input => "public int gnurz = 1 + 2;", :rule => :r31, :ast => "(VARIABLE gnurz public int (+ 1 2))", :flag => 1
477  
478  ast_test :input => "public int gnurz = 1 + 2;", :rule => :r31, :ast => "(FIELD gnurz public int (+ 1 2))", :flag => 2
479  
480  ast_test :input => 'gnurz 32', :rule => :r32, :arguments => [ 1 ], :flag => 2, :ast => 'gnurz'
481  
482  ast_test :input => 'gnurz 32', :rule => :r32, :arguments => [ 2 ], :flag => 2, :ast => '32'
483  
484  ast_test :input => 'gnurz', :rule => :r32, :arguments => [ 3 ], :flag => 2, :ast => nil
485  
486  ast_test :input => "public private fooze", :rule => :r33, :ast => "fooze"
487  
488  ast_test :input => "public class gnurz { fooze fooze2 }", :rule => :r34, :ast => "(class gnurz public fooze fooze2)"
489  
490  ast_test :input => "public class gnurz extends bool implements int, bool { fooze fooze2 }", :rule => :r34, :ast => "(class gnurz public (extends bool) (implements int bool) fooze fooze2)"
491  
492  ast_test :input => "if ( 1 + 2 ) fooze", :rule => :r36, :ast => "(if (EXPR (+ 1 2)) fooze)"
493  
494  ast_test :input => "1 + 2 + 3", :rule => :r37, :ast => "(+ (+ 1 2) 3)"
495  
496  ast_test :input => "1 + 2 + 3", :rule => :r38, :ast => "(+ (+ 1 2) 3)"
497  
498  ast_test :input => "gnurz[1]", :rule => :r39, :ast => "(INDEX gnurz 1)"
499  
500  ast_test :input => "gnurz(2)", :rule => :r39, :ast => "(CALL gnurz 2)"
501  
502  ast_test :input => "gnurz.gnarz", :rule => :r39, :ast => "(FIELDACCESS gnurz gnarz)"
503  
504  ast_test :input => "gnurz.gnarz.gnorz", :rule => :r39, :ast => "(FIELDACCESS (FIELDACCESS gnurz gnarz) gnorz)"
505  
506  ast_test :input => "1 + 2 + 3;", :rule => :r40, :ast => "(+ 1 2 3)"
507  
508  ast_test :input => "1 + 2 + 3;", :rule => :r41, :ast => "(3 (2 1))"
509  
510  ast_test :input => "gnurz, gnarz, gnorz", :rule => :r42, :ast => "gnurz gnarz gnorz"
511  
512  ast_test :input => "gnurz, gnarz, gnorz", :rule => :r43 do |result|
513    result.tree.should be_nil
514    result.res.should == %w(gnurz gnarz gnorz)
515  end
516  
517  ast_test :input => 'gnurz, gnarz, gnorz', :rule => :r44, :ast => '(gnorz (gnarz gnurz))'
518  
519  ast_test :input => 'gnurz', :rule => :r45, :ast => 'gnurz'
520  
521  ast_test :input => 'gnurz, gnarz, gnorz', :rule => :r46 do |result|
522    result.tree.should be_nil
523    result.res.should == %w(gnurz gnarz gnorz)
524  end
525  
526  ast_test :input => 'gnurz, gnarz, gnorz', :rule => :r47, :ast => 'gnurz gnarz gnorz'
527  
528  ast_test :input => 'gnurz, gnarz, gnorz', :rule => :r48, :ast => 'gnurz gnarz gnorz'
529  
530  ast_test :input => 'gnurz gnorz', :rule => :r49, :ast => '(gnurz gnorz)'
531  
532  ast_test :input => 'gnurz', :rule => :r50, :ast => '(1.0 gnurz)'
533  
534  ast_test :input => 'gnurza gnurzb gnurzc', :rule => :r51 do |result|
535    result.res.inspect.should == 'gnurzb'
536  end
537  
538  ast_test :input => 'gnurz', :rule => :r52, :ast => 'gnurz'
539  
540  ast_test :input => 'gnurz', :rule => :r53, :ast => 'gnurz'
541  
542  ast_test :input => 'gnurza 1 + 2 gnurzb', :rule => :r54, :ast => '(+ 1 2)'
543  
544  ast_test :input => 'public private 1 + 2', :rule => :r55, :ast => 'public private (+ 1 2)'
545  
546  ast_test :input => 'public fooze', :rule => :r55, :ast => 'public fooze'
547  
548  ast_test :input => 'a b c d', :rule => :r56, :ast => 'foo'
549  
550  ast_test :input => 'a b c d', :rule => :r57, :ast => 'foo'
551  
552  ast_test :input => 'a b c fooze', :rule => :r59, :ast => '(a fooze) (b fooze) (c fooze)'
553
554end
555