#!/usr/bin/ruby # encoding: utf-8 require 'antlr3/test/functional' class TestHeterogeneousNodeTypes < ANTLR3::Test::Functional inline_grammar( <<-'END' ) grammar VToken; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : ID ; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar TokenWithQualifiedType; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : ID ; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar TokenWithLabel; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : x=ID ; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar TokenWithListLabel; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : x+=ID ; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar TokenRoot; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : ID^ ; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar TokenRootWithListLabel; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : x+=ID^ ; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar FromString; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : 'begin' ; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar StringRoot; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : 'begin'^ ; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar RewriteToken; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : ID -> ID ; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar RewriteTokenWithArgs; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def initialize(*args) case args.length when 4 ttype, @x, @y, @z = args token = ANTLR3::CommonToken.new(ttype, nil, '') when 3 ttype, token, @x = args @y = @z = 0 else raise ArgumentError, "invalid number of arguments: #{args.length} for 3-4" end super(token) end def to_s (@token.text.to_s rescue '') << ";\%d\%d\%d" \% [@x, @y, @z] end end } a : ID -> ID[42,19,30] ID[$ID,99]; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar RewriteTokenRoot; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : ID INT -> ^(ID INT) ; ID : 'a'..'z'+ ; INT : '0'..'9'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar RewriteString; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : 'begin' -> 'begin' ; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar RewriteStringRoot; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : 'begin' INT -> ^('begin' INT) ; ID : 'a'..'z'+ ; INT : '0'..'9'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar RewriteRuleResults; options { language=Ruby; output=AST; } tokens {LIST;} @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end class W < ANTLR3::CommonTree def initialize(tok, text) tok.text = text super(tok) end def to_s return @token.text + "" end end } a : id (',' id)* -> ^(LIST["LIST"] id+); id : ID -> ID; ID : 'a'..'z'+ ; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar CopySemanticsWithHetero; options { language=Ruby; output=AST; } @members { class V < ANTLR3::CommonTree def dup_node return V.new(self) end def to_s return @token.text + "" end end } a : type ID (',' ID)* ';' -> ^(type ID)+; type : 'int' ; ID : 'a'..'z'+ ; INT : '0'..'9'+; WS : (' '|'\\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) grammar TreeParserRewriteFlatList; options { language=Ruby; output=AST; } a : ID INT; ID : 'a'..'z'+ ; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) tree grammar TreeParserRewriteFlatListWalker; options { language=Ruby; output=AST; ASTLabelType=CommonTree; tokenVocab=TreeParserRewriteFlatList; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end class W < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : ID INT -> INT ID ; END inline_grammar( <<-'END' ) grammar TreeParserRewriteTree; options { language=Ruby; output=AST; } a : ID INT; ID : 'a'..'z'+ ; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) tree grammar TreeParserRewriteTreeWalker; options { language=Ruby; output=AST; ASTLabelType=CommonTree; tokenVocab=TreeParserRewriteTree; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end class W < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : ID INT -> ^(INT ID) ; END inline_grammar( <<-'END' ) grammar TreeParserRewriteImaginary; options { language=Ruby; output=AST; } a : ID ; ID : 'a'..'z'+ ; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) tree grammar TreeParserRewriteImaginaryWalker; options { language=Ruby; output=AST; ASTLabelType=CommonTree; tokenVocab=TreeParserRewriteImaginary; } tokens { ROOT; } @members { class V < ANTLR3::CommonTree def to_s return @token.name + "" end end } a : ID -> ROOT ID ; END inline_grammar( <<-'END' ) grammar TreeParserRewriteImaginaryWithArgs; options { language=Ruby; output=AST; } a : ID ; ID : 'a'..'z'+ ; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) tree grammar TreeParserRewriteImaginaryWithArgsWalker; options { language=Ruby; output=AST; ASTLabelType=CommonTree; tokenVocab=TreeParserRewriteImaginaryWithArgs; } tokens { ROOT; } @members { class V < ANTLR3::CommonTree def initialize(token_type, x) super(token_type) @x = x end def to_s return @token.name + ";#@x" end end } a : ID -> ROOT[42] ID ; END inline_grammar( <<-'END' ) grammar TreeParserRewriteImaginaryRoot; options { language=Ruby; output=AST; } a : ID ; ID : 'a'..'z'+ ; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) tree grammar TreeParserRewriteImaginaryRootWalker; options { language=Ruby; output=AST; ASTLabelType=CommonTree; tokenVocab=TreeParserRewriteImaginaryRoot; } tokens { ROOT; } @members { class V < ANTLR3::CommonTree def to_s return @token.name + "" end end } a : ID -> ^(ROOT ID) ; END inline_grammar( <<-'END' ) grammar TreeParserRewriteImaginaryFromReal; options { language=Ruby; output=AST; } a : ID ; ID : 'a'..'z'+ ; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) tree grammar TreeParserRewriteImaginaryFromRealWalker; options { language=Ruby; output=AST; ASTLabelType=CommonTree; tokenVocab=TreeParserRewriteImaginaryFromReal; } tokens { ROOT; } @members { class V < ANTLR3::CommonTree def initialize(token, tree = nil) if tree.nil? then super(token) else super(tree) @token = TokenData::Token.from_token(@token) @token.type = token.type end end def to_s return @token.name + "@" + @token.line.to_s end end } a : ID -> ROOT[$ID] ; END inline_grammar( <<-'END' ) grammar TreeParserAutoHeteroAST; options { language=Ruby; output=AST; } a : ID ';' ; ID : 'a'..'z'+ ; INT : '0'..'9'+; WS : (' '|'\n') {$channel=HIDDEN;} ; END inline_grammar( <<-'END' ) tree grammar TreeParserAutoHeteroASTWalker; options { language=Ruby; output=AST; ASTLabelType=CommonTree; tokenVocab=TreeParserAutoHeteroAST; } tokens { ROOT; } @members { class V < ANTLR3::CommonTree def to_s return @token.text + "" end end } a : ID ';'; END def parse( grammar_name, grammar_rule, input ) grammar_module = self.class.const_get( grammar_name.to_s ) lexer = grammar_module::Lexer.new( input ) tokens = ANTLR3::CommonTokenStream.new( lexer ) parser = grammar_module::Parser.new( tokens ) r = parser.send( grammar_rule ) return( r.tree.inspect rescue '' ) end def tree_parse( grammar_name, grammar_rule, tree_grammar_rule, input ) grammar_module = self.class.const_get( grammar_name.to_s ) tree_grammar_module = self.class.const_get( grammar_name.to_s + 'Walker' ) lexer = grammar_module::Lexer.new( input ) tokens = ANTLR3::CommonTokenStream.new( lexer ) parser = grammar_module::Parser.new( tokens ) r = parser.send( grammar_rule ) nodes = ANTLR3::CommonTreeNodeStream.new( r.tree ) nodes.token_stream = tokens tree_parser = tree_grammar_module::TreeParser.new( nodes ) r = tree_parser.send( tree_grammar_rule ) return( r.tree.inspect rescue '' ) end example "v token" do result = parse( :VToken, :a, 'a' ) result.should == 'a' end example "token with qualified type" do result = parse( :TokenWithQualifiedType, :a, 'a' ) result.should == 'a' end example "token with label" do result = parse( :TokenWithLabel, :a, 'a' ) result.should == 'a' end example "token with list label" do result = parse( :TokenWithListLabel, :a, 'a' ) result.should == 'a' end example "token root" do result = parse( :TokenRoot, :a, 'a' ) result.should == 'a' end example "token root with list label" do result = parse( :TokenRootWithListLabel, :a, 'a' ) result.should == 'a' end example "string" do result = parse( :FromString, :a, 'begin' ) result.should == 'begin' end example "string root" do result = parse( :StringRoot, :a, 'begin' ) result.should == 'begin' end example "rewrite token" do result = parse( :RewriteToken, :a, 'a' ) result.should == 'a' end example "rewrite token with args" do result = parse( :RewriteTokenWithArgs, :a, 'a' ) result.should == ';421930 a;9900' end example "rewrite token root" do result = parse( :RewriteTokenRoot, :a, 'a 2' ) result.should == '(a 2)' end example "rewrite string" do result = parse( :RewriteString, :a, 'begin' ) result.should == 'begin' end example "rewrite string root" do result = parse( :RewriteStringRoot, :a, 'begin 2' ) result.should == '(begin 2)' end example "rewrite rule results" do result = parse( :RewriteRuleResults, :a, 'a,b,c' ) result.should == '(LIST a b c)' end example "copy semantics with hetero" do result = parse( :CopySemanticsWithHetero, :a, 'int a, b, c;' ) result.should == '(int a) (int b) (int c)' end example "tree parser rewrite flat list" do result = tree_parse( :TreeParserRewriteFlatList, :a, :a, 'abc 34' ) result.should == '34 abc' end example "tree parser rewrite tree" do result = tree_parse( :TreeParserRewriteTree, :a, :a, 'abc 34' ) result.should == '(34 abc)' end example "tree parser rewrite imaginary" do result = tree_parse( :TreeParserRewriteImaginary, :a, :a, 'abc' ) result.should == 'ROOT abc' end example "tree parser rewrite imaginary with args" do result = tree_parse( :TreeParserRewriteImaginaryWithArgs, :a, :a, 'abc' ) result.should == 'ROOT;42 abc' end example "tree parser rewrite imaginary root" do result = tree_parse( :TreeParserRewriteImaginaryRoot, :a, :a, 'abc' ) result.should == '(ROOT abc)' end example "tree parser rewrite imaginary from real" do result = tree_parse( :TreeParserRewriteImaginaryFromReal, :a, :a, 'abc' ) result.should == 'ROOT@1' end example "tree parser auto hetero ast" do result = tree_parse( :TreeParserAutoHeteroAST, :a, :a, 'abc;' ) result.should == 'abc ;' end end