Home | History | Annotate | Download | only in template-output
      1 #!/usr/bin/ruby
      2 # encoding: utf-8
      3 
      4 require 'antlr3/test/functional'
      5 
      6 class TestTemplateOutput < ANTLR3::Test::Functional
      7   
      8   def parse( grammar, input, options = nil )
      9     @grammar = inline_grammar( grammar )
     10     compile_and_load( @grammar )
     11     grammar_module = self.class.const_get( @grammar.name )
     12     
     13     parser_options = {}
     14     if options
     15       rule = options.fetch( :rule ) { grammar_module::Parser.default_rule }
     16       group = options[ :templates ] and parser_options[ :templates ] = group
     17     else
     18       rule = grammar_module::Parser.default_rule
     19     end
     20     
     21     @lexer  = grammar_module::Lexer.new( input )
     22     @parser = grammar_module::Parser.new( @lexer, parser_options )
     23     
     24     out = @parser.send( rule ).template
     25     return( out ? out.to_s : out )
     26   end
     27   
     28   def parse_templates( source )
     29     ANTLR3::Template::Group.parse( source.fixed_indent( 0 ) )
     30   end
     31   
     32   
     33   example 'inline templates' do
     34     text = parse( <<-'END', "abc 34" )
     35       grammar InlineTemplates;
     36       options {
     37         language = Ruby;
     38         output = template;
     39       }
     40       
     41       a : ID INT
     42         -> template(id={$ID.text}, int={$INT.text})
     43            "id=<%= @id %>, int=<%= @int %>"
     44       ;
     45       
     46       ID : 'a'..'z'+;
     47       INT : '0'..'9'+;
     48       WS : (' '|'\n') {$channel=HIDDEN;} ;
     49     END
     50     
     51     text.should == "id=abc, int=34"
     52   end
     53   
     54   example 'external template' do
     55     templates = ANTLR3::Template::Group.new do
     56       define_template( :expr, <<-'END'.strip )
     57         [<%= @args.join( @op.to_s ) %>]
     58       END
     59     end
     60     
     61     text = parse( <<-'END', 'a + b', :templates => templates )
     62       grammar ExternalTemplate;
     63       options {
     64         language = Ruby;
     65         output = template;
     66       }
     67       
     68       a : r+=arg OP r+=arg
     69         -> expr( op={$OP.text}, args={$r} )
     70       ;
     71       arg: ID -> template(t={$ID.text}) "<%= @t %>";
     72       
     73       ID : 'a'..'z'+;
     74       OP: '+';
     75       WS : (' '|'\n') {$channel=HIDDEN;} ;
     76     END
     77     
     78     text.should == '[a+b]'
     79   end
     80 
     81   example "empty template" do
     82     text = parse( <<-'END', 'abc 34' )
     83       grammar EmptyTemplate;
     84       options {
     85         language=Ruby;
     86         output=template;
     87       }
     88       a : ID INT
     89         -> 
     90       ;
     91       
     92       ID : 'a'..'z'+;
     93       INT : '0'..'9'+;
     94       WS : (' '|'\n') {$channel=HIDDEN;} ;
     95       
     96     END
     97     text.should be_nil
     98   end
     99   
    100   example "list" do
    101     text = parse( <<-'END', "abc def ghi" )
    102       grammar List;
    103       options {
    104         language=Ruby;
    105         output=template;
    106       }
    107       a: (r+=b)* EOF
    108         -> template(r={$r}) "<%= @r.join(',') %>"
    109       ;
    110       
    111       b: ID
    112         -> template(t={$ID.text}) "<%= @t %>"
    113       ;
    114       
    115       ID : 'a'..'z'+;
    116       WS : (' '|'\n') {$channel=HIDDEN;} ;
    117     END
    118     text.should == 'abc,def,ghi'
    119   end
    120   
    121   example 'action' do
    122     text = parse( <<-'END', "abc" )
    123       grammar Action;
    124       options {
    125         language=Ruby;
    126         output=template;
    127       }
    128       a: ID
    129         -> { create_template( "hello" ) }
    130       ;
    131       
    132       ID : 'a'..'z'+;
    133       WS : (' '|'\n') {$channel=HIDDEN;} ;
    134     END
    135     
    136     text.should == 'hello'
    137   end
    138   
    139   example "template expression in action" do
    140     text = parse( <<-'END', 'abc' )
    141       grammar TemplateExpressionInAction;
    142       options {
    143         language=Ruby;
    144         output=template;
    145       }
    146       a: ID
    147         { $st = %{"hello"} }
    148       ;
    149       
    150       ID : 'a'..'z'+;
    151       WS : (' '|'\n') {$channel=HIDDEN;} ;
    152     END
    153     text.should == 'hello'
    154   end
    155   
    156   #example "template expression in action2" do
    157   #  text = parse( <<-'END', 'abc' )
    158   #    grammar TemplateExpressionInAction2;
    159   #    options {
    160   #      language=Ruby;
    161   #      output=template;
    162   #    }
    163   #    a: ID
    164   #      {
    165   #        res = %{"hello <%= @foo %>"}
    166   #        %res.foo = "world";
    167   #      }
    168   #      -> { res }
    169   #    ;
    170   #    
    171   #    ID : 'a'..'z'+;
    172   #    WS : (' '|'\n') {$channel=HIDDEN;} ;
    173   #  END
    174   #  
    175   #  text.should == 'hello world'
    176   #end
    177   
    178   example "indirect template constructor" do
    179     templates = ANTLR3::Template::Group.new do
    180       define_template( :expr, <<-'END'.strip )
    181         [<%= @args.join( @op.to_s ) %>]
    182       END
    183     end
    184     
    185     text = parse( <<-'END', 'abc', :templates => templates )
    186       grammar IndirectTemplateConstructor;
    187       options {
    188         language=Ruby;
    189         output=template;
    190       }
    191       
    192       a: ID
    193         {
    194           $st = %({"expr"})(args={[1, 2, 3]}, op={"+"})
    195         }
    196       ;
    197       
    198       ID : 'a'..'z'+;
    199       WS : (' '|'\n') {$channel=HIDDEN;} ;
    200     END
    201     
    202     text.should == '[1+2+3]'
    203   end
    204   
    205   example "predicates" do
    206     text = parse( <<-'END', 'b 34' )
    207       grammar Predicates;
    208       options {
    209         language=Ruby;
    210         output=template;
    211       }
    212       a : ID INT
    213         -> {$ID.text=='a'}? template(int={$INT.text})
    214                             "A: <%= @int %>"
    215         -> {$ID.text=='b'}? template(int={$INT.text})
    216                             "B: <%= @int %>"
    217         ->                  template(int={$INT.text})
    218                             "C: <%= @int %>"
    219       ;
    220       
    221       ID : 'a'..'z'+;
    222       INT : '0'..'9'+;
    223       WS : (' '|'\n') {$channel=HIDDEN;} ;
    224     END
    225     
    226     text.should == 'B: 34'
    227   end
    228   
    229   example "backtracking mode" do
    230     text = parse( <<-'END', 'abc 34' )
    231       grammar BacktrackingMode;
    232       options {
    233         language=Ruby;
    234         output=template;
    235         backtrack=true;
    236       }
    237       a : (ID INT)=> ID INT
    238         -> template(id={$ID.text}, int={$INT.text})
    239            "id=<%= @id %>, int=<%= @int %>"
    240       ;
    241       
    242       ID : 'a'..'z'+;
    243       INT : '0'..'9'+;
    244       WS : (' '|'\n') {$channel=HIDDEN;} ;
    245     END
    246     
    247     text.should == "id=abc, int=34"
    248   end
    249   
    250   example "rewrite" do
    251     input = <<-'END'.here_indent!
    252     | if ( foo ) {
    253     |   b = /* bla */ 2;
    254     |   return 1 /* foo */;
    255     | }
    256     | 
    257     | /* gnurz */
    258     | return 12;
    259     END
    260     expected = <<-'END'.here_indent!
    261     | if ( foo ) {
    262     |   b = /* bla */ 2;
    263     |   return boom(1) /* foo */;
    264     | }
    265     | 
    266     | /* gnurz */
    267     | return boom(12);
    268     END
    269     
    270     parse( <<-'END', input )
    271       grammar Rewrite;
    272       options {
    273         language=Ruby;
    274         output=template;
    275         rewrite=true;
    276       }
    277       
    278       prog: stat+;
    279       
    280       stat
    281           : 'if' '(' expr ')' stat
    282           | 'return' return_expr ';'
    283           | '{' stat* '}'
    284           | ID '=' expr ';'
    285           ;
    286       
    287       return_expr
    288           : expr
    289             -> template(t={$text}) <<boom(<%= @t %>)>>
    290           ;
    291           
    292       expr
    293           : ID
    294           | INT
    295           ;
    296           
    297       ID:  'a'..'z'+;
    298       INT: '0'..'9'+;
    299       WS: (' '|'\n')+ {$channel=HIDDEN;} ;
    300       COMMENT: '/*' (options {greedy=false;} : .)* '*/' {$channel = HIDDEN;} ;
    301     END
    302     
    303     @parser.input.render.should == expected
    304   end
    305   
    306   example "tree rewrite" do
    307     input = <<-'END'.here_indent!
    308     | if ( foo ) {
    309     |   b = /* bla */ 2;
    310     |   return 1 /* foo */;
    311     | }
    312     | 
    313     | /* gnurz */
    314     | return 12;
    315     END
    316     expected = <<-'END'.here_indent!
    317     | if ( foo ) {
    318     |   b = /* bla */ 2;
    319     |   return boom(1) /* foo */;
    320     | }
    321     | 
    322     | /* gnurz */
    323     | return boom(12);
    324     END
    325     
    326     compile_and_load( inline_grammar( <<-'END' ) )
    327       grammar TreeRewrite;
    328       options {
    329         language=Ruby;
    330         output=AST;
    331       }
    332       
    333       tokens {
    334         BLOCK;
    335         ASSIGN;
    336       }
    337       
    338       prog: stat+;
    339       
    340       stat
    341           : IF '(' e=expr ')' s=stat
    342             -> ^(IF $e $s)
    343           | RETURN expr ';'
    344             -> ^(RETURN expr)
    345           | '{' stat* '}'
    346             -> ^(BLOCK stat*)
    347           | ID '=' expr ';'
    348             -> ^(ASSIGN ID expr)
    349           ;
    350           
    351       expr
    352           : ID
    353           | INT
    354           ;
    355       
    356       IF: 'if';
    357       RETURN: 'return';
    358       ID:  'a'..'z'+;
    359       INT: '0'..'9'+;
    360       WS: (' '|'\n')+ {$channel=HIDDEN;} ;
    361       COMMENT: '/*' (options {greedy=false;} : .)* '*/' {$channel = HIDDEN;} ;
    362     END
    363     
    364     compile_and_load( inline_grammar( <<-'END' ) )
    365       tree grammar TreeRewriteTG;
    366       options {
    367         language=Ruby;
    368         tokenVocab=TreeRewrite;
    369         ASTLabelType=CommonTree;
    370         output=template;
    371         rewrite=true;
    372       }
    373       
    374       prog: stat+;
    375       
    376       stat
    377           : ^(IF expr stat)
    378           | ^(RETURN return_expr)                
    379           | ^(BLOCK stat*)                
    380           | ^(ASSIGN ID expr)
    381           ;
    382       
    383       return_expr
    384           : expr
    385             -> template(t={$text}) <<boom(<%= @t %>)>>
    386           ;
    387       
    388       expr
    389           : ID
    390           | INT
    391           ;
    392     END
    393     
    394     lexer = TreeRewrite::Lexer.new( input )
    395     tokens = ANTLR3::TokenRewriteStream.new( lexer )
    396     parser = TreeRewrite::Parser.new( tokens )
    397     tree = parser.prog.tree
    398     nodes = ANTLR3::AST::CommonTreeNodeStream.new( tree )
    399     nodes.token_stream = tokens
    400     tree_parser = TreeRewriteTG::TreeParser.new( nodes )
    401     tree_parser.prog
    402     tokens.render.should == expected
    403   end
    404 end
    405