#!/usr/bin/ruby # encoding: utf-8 require 'antlr3/test/functional' class TestTemplateOutput < ANTLR3::Test::Functional def parse( grammar, input, options = nil ) @grammar = inline_grammar( grammar ) compile_and_load( @grammar ) grammar_module = self.class.const_get( @grammar.name ) parser_options = {} if options rule = options.fetch( :rule ) { grammar_module::Parser.default_rule } group = options[ :templates ] and parser_options[ :templates ] = group else rule = grammar_module::Parser.default_rule end @lexer = grammar_module::Lexer.new( input ) @parser = grammar_module::Parser.new( @lexer, parser_options ) out = @parser.send( rule ).template return( out ? out.to_s : out ) end def parse_templates( source ) ANTLR3::Template::Group.parse( source.fixed_indent( 0 ) ) end example 'inline templates' do text = parse( <<-'END', "abc 34" ) grammar InlineTemplates; options { language = Ruby; output = template; } a : ID INT -> template(id={$ID.text}, int={$INT.text}) "id=<%= @id %>, int=<%= @int %>" ; ID : 'a'..'z'+; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END text.should == "id=abc, int=34" end example 'external template' do templates = ANTLR3::Template::Group.new do define_template( :expr, <<-'END'.strip ) [<%= @args.join( @op.to_s ) %>] END end text = parse( <<-'END', 'a + b', :templates => templates ) grammar ExternalTemplate; options { language = Ruby; output = template; } a : r+=arg OP r+=arg -> expr( op={$OP.text}, args={$r} ) ; arg: ID -> template(t={$ID.text}) "<%= @t %>"; ID : 'a'..'z'+; OP: '+'; WS : (' '|'\n') {$channel=HIDDEN;} ; END text.should == '[a+b]' end example "empty template" do text = parse( <<-'END', 'abc 34' ) grammar EmptyTemplate; options { language=Ruby; output=template; } a : ID INT -> ; ID : 'a'..'z'+; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END text.should be_nil end example "list" do text = parse( <<-'END', "abc def ghi" ) grammar List; options { language=Ruby; output=template; } a: (r+=b)* EOF -> template(r={$r}) "<%= @r.join(',') %>" ; b: ID -> template(t={$ID.text}) "<%= @t %>" ; ID : 'a'..'z'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END text.should == 'abc,def,ghi' end example 'action' do text = parse( <<-'END', "abc" ) grammar Action; options { language=Ruby; output=template; } a: ID -> { create_template( "hello" ) } ; ID : 'a'..'z'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END text.should == 'hello' end example "template expression in action" do text = parse( <<-'END', 'abc' ) grammar TemplateExpressionInAction; options { language=Ruby; output=template; } a: ID { $st = %{"hello"} } ; ID : 'a'..'z'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END text.should == 'hello' end #example "template expression in action2" do # text = parse( <<-'END', 'abc' ) # grammar TemplateExpressionInAction2; # options { # language=Ruby; # output=template; # } # a: ID # { # res = %{"hello <%= @foo %>"} # %res.foo = "world"; # } # -> { res } # ; # # ID : 'a'..'z'+; # WS : (' '|'\n') {$channel=HIDDEN;} ; # END # # text.should == 'hello world' #end example "indirect template constructor" do templates = ANTLR3::Template::Group.new do define_template( :expr, <<-'END'.strip ) [<%= @args.join( @op.to_s ) %>] END end text = parse( <<-'END', 'abc', :templates => templates ) grammar IndirectTemplateConstructor; options { language=Ruby; output=template; } a: ID { $st = %({"expr"})(args={[1, 2, 3]}, op={"+"}) } ; ID : 'a'..'z'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END text.should == '[1+2+3]' end example "predicates" do text = parse( <<-'END', 'b 34' ) grammar Predicates; options { language=Ruby; output=template; } a : ID INT -> {$ID.text=='a'}? template(int={$INT.text}) "A: <%= @int %>" -> {$ID.text=='b'}? template(int={$INT.text}) "B: <%= @int %>" -> template(int={$INT.text}) "C: <%= @int %>" ; ID : 'a'..'z'+; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END text.should == 'B: 34' end example "backtracking mode" do text = parse( <<-'END', 'abc 34' ) grammar BacktrackingMode; options { language=Ruby; output=template; backtrack=true; } a : (ID INT)=> ID INT -> template(id={$ID.text}, int={$INT.text}) "id=<%= @id %>, int=<%= @int %>" ; ID : 'a'..'z'+; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END text.should == "id=abc, int=34" end example "rewrite" do input = <<-'END'.here_indent! | if ( foo ) { | b = /* bla */ 2; | return 1 /* foo */; | } | | /* gnurz */ | return 12; END expected = <<-'END'.here_indent! | if ( foo ) { | b = /* bla */ 2; | return boom(1) /* foo */; | } | | /* gnurz */ | return boom(12); END parse( <<-'END', input ) grammar Rewrite; options { language=Ruby; output=template; rewrite=true; } prog: stat+; stat : 'if' '(' expr ')' stat | 'return' return_expr ';' | '{' stat* '}' | ID '=' expr ';' ; return_expr : expr -> template(t={$text}) <)>> ; expr : ID | INT ; ID: 'a'..'z'+; INT: '0'..'9'+; WS: (' '|'\n')+ {$channel=HIDDEN;} ; COMMENT: '/*' (options {greedy=false;} : .)* '*/' {$channel = HIDDEN;} ; END @parser.input.render.should == expected end example "tree rewrite" do input = <<-'END'.here_indent! | if ( foo ) { | b = /* bla */ 2; | return 1 /* foo */; | } | | /* gnurz */ | return 12; END expected = <<-'END'.here_indent! | if ( foo ) { | b = /* bla */ 2; | return boom(1) /* foo */; | } | | /* gnurz */ | return boom(12); END compile_and_load( inline_grammar( <<-'END' ) ) grammar TreeRewrite; options { language=Ruby; output=AST; } tokens { BLOCK; ASSIGN; } prog: stat+; stat : IF '(' e=expr ')' s=stat -> ^(IF $e $s) | RETURN expr ';' -> ^(RETURN expr) | '{' stat* '}' -> ^(BLOCK stat*) | ID '=' expr ';' -> ^(ASSIGN ID expr) ; expr : ID | INT ; IF: 'if'; RETURN: 'return'; ID: 'a'..'z'+; INT: '0'..'9'+; WS: (' '|'\n')+ {$channel=HIDDEN;} ; COMMENT: '/*' (options {greedy=false;} : .)* '*/' {$channel = HIDDEN;} ; END compile_and_load( inline_grammar( <<-'END' ) ) tree grammar TreeRewriteTG; options { language=Ruby; tokenVocab=TreeRewrite; ASTLabelType=CommonTree; output=template; rewrite=true; } prog: stat+; stat : ^(IF expr stat) | ^(RETURN return_expr) | ^(BLOCK stat*) | ^(ASSIGN ID expr) ; return_expr : expr -> template(t={$text}) <)>> ; expr : ID | INT ; END lexer = TreeRewrite::Lexer.new( input ) tokens = ANTLR3::TokenRewriteStream.new( lexer ) parser = TreeRewrite::Parser.new( tokens ) tree = parser.prog.tree nodes = ANTLR3::AST::CommonTreeNodeStream.new( tree ) nodes.token_stream = tokens tree_parser = TreeRewriteTG::TreeParser.new( nodes ) tree_parser.prog tokens.render.should == expected end end