| #!/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}) <<boom(<%= @t %>)>> |
| ; |
| |
| 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}) <<boom(<%= @t %>)>> |
| ; |
| |
| 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 |