| #!/usr/bin/ruby |
| # encoding: utf-8 |
| |
| require 'antlr3/test/functional' |
| |
| class TestASTViaRewriteRules < ANTLR3::Test::Functional |
| |
| def parse( grammar, rule, input, expect_errors = false ) |
| @grammar = inline_grammar( grammar ) |
| compile_and_load @grammar |
| grammar_module = self.class.const_get( @grammar.name ) |
| |
| grammar_module::Lexer.send( :include, ANTLR3::Test::CollectErrors ) |
| grammar_module::Lexer.send( :include, ANTLR3::Test::CaptureOutput ) |
| grammar_module::Parser.send( :include, ANTLR3::Test::CollectErrors ) |
| grammar_module::Parser.send( :include, ANTLR3::Test::CaptureOutput ) |
| |
| lexer = grammar_module::Lexer.new( input ) |
| parser = grammar_module::Parser.new( lexer ) |
| |
| r = parser.send( rule ) |
| parser.reported_errors.should be_empty unless expect_errors |
| result = '' |
| |
| unless r.nil? |
| result += r.result if r.respond_to?( :result ) |
| result += r.tree.inspect if r.tree |
| end |
| return( expect_errors ? [ result, parser.reported_errors ] : result ) |
| end |
| |
| def tree_parse( grammar, tree_grammar, rule, tree_rule, input ) |
| @grammar = inline_grammar( grammar ) |
| @tree_grammar = inline_grammar( tree_grammar ) |
| compile_and_load @grammar |
| compile_and_load @tree_grammar |
| |
| grammar_module = self.class.const_get( @grammar.name ) |
| tree_grammar_module = self.class.const_get( @tree_grammar.name ) |
| |
| grammar_module::Lexer.send( :include, ANTLR3::Test::CollectErrors ) |
| grammar_module::Lexer.send( :include, ANTLR3::Test::CaptureOutput ) |
| grammar_module::Parser.send( :include, ANTLR3::Test::CollectErrors ) |
| grammar_module::Parser.send( :include, ANTLR3::Test::CaptureOutput ) |
| tree_grammar_module::TreeParser.send( :include, ANTLR3::Test::CollectErrors ) |
| tree_grammar_module::TreeParser.send( :include, ANTLR3::Test::CaptureOutput ) |
| |
| lexer = grammar_module::Lexer.new( input ) |
| parser = grammar.module::Parser.new( lexer ) |
| r = parser.send( rule ) |
| nodes = ANTLR3::CommonTreeNodeStream( r.tree ) |
| nodes.token_stream = parser.input |
| walker = tree_grammar_module::TreeParser.new( nodes ) |
| r = walker.send( tree_rule ) |
| |
| return( r ? r.tree.inspect : '' ) |
| end |
| |
| example "delete" do |
| result = parse( <<-'END', :a, 'abc 34' ) |
| grammar Delete; |
| options {language=Ruby;output=AST;} |
| a : ID INT -> ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| END |
| result.should == '' |
| end |
| |
| |
| example "single token" do |
| result = parse( <<-'END', :a, 'abc' ) |
| grammar SingleToken; |
| options {language=Ruby;output=AST;} |
| a : ID -> ID; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'abc' |
| end |
| |
| |
| example "single token to new node" do |
| result = parse( <<-'END', :a, 'abc' ) |
| grammar SingleTokenToNewNode; |
| options {language=Ruby;output=AST;} |
| a : ID -> ID["x"]; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'x' |
| end |
| |
| |
| example "single token to new node root" do |
| result = parse( <<-'END', :a, 'abc' ) |
| grammar SingleTokenToNewNodeRoot; |
| options {language=Ruby;output=AST;} |
| a : ID -> ^(ID["x"] INT); |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(x INT)' |
| end |
| |
| |
| example "single token to new node2" do |
| result = parse( <<-'END', :a, 'abc' ) |
| grammar SingleTokenToNewNode2; |
| options {language=Ruby;output=AST;} |
| a : ID -> ID[ ]; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| END |
| result.should == 'ID' |
| end |
| |
| |
| example "single char literal" do |
| result = parse( <<-'END', :a, 'c' ) |
| grammar SingleCharLiteral; |
| options {language=Ruby;output=AST;} |
| a : 'c' -> 'c'; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'c' |
| end |
| |
| |
| example "single string literal" do |
| result = parse( <<-'END', :a, 'ick' ) |
| grammar SingleStringLiteral; |
| options {language=Ruby;output=AST;} |
| a : 'ick' -> 'ick'; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'ick' |
| end |
| |
| |
| example "single rule" do |
| result = parse( <<-'END', :a, 'abc' ) |
| grammar SingleRule; |
| options {language=Ruby;output=AST;} |
| a : b -> b; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'abc' |
| end |
| |
| |
| example "reorder tokens" do |
| result = parse( <<-'END', :a, 'abc 34' ) |
| grammar ReorderTokens; |
| options {language=Ruby;output=AST;} |
| a : ID INT -> INT ID; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '34 abc' |
| end |
| |
| |
| example "reorder token and rule" do |
| result = parse( <<-'END', :a, 'abc 34' ) |
| grammar ReorderTokenAndRule; |
| options {language=Ruby;output=AST;} |
| a : b INT -> INT b; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '34 abc' |
| end |
| |
| |
| example "token tree" do |
| result = parse( <<-'END', :a, 'abc 34' ) |
| grammar TokenTree; |
| options {language=Ruby;output=AST;} |
| a : ID INT -> ^(INT ID); |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(34 abc)' |
| end |
| |
| |
| example "token tree after other stuff" do |
| result = parse( <<-'END', :a, 'void abc 34' ) |
| grammar TokenTreeAfterOtherStuff; |
| options {language=Ruby;output=AST;} |
| a : 'void' ID INT -> 'void' ^(INT ID); |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'void (34 abc)' |
| end |
| |
| |
| example "nested token tree with outer loop" do |
| result = parse( <<-'END', :a, 'a 1 b 2' ) |
| grammar NestedTokenTreeWithOuterLoop; |
| options {language=Ruby;output=AST;} |
| tokens {DUH;} |
| a : ID INT ID INT -> ^( DUH ID ^( DUH INT) )+ ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(DUH a (DUH 1)) (DUH b (DUH 2))' |
| end |
| |
| |
| example "optional single token" do |
| result = parse( <<-'END', :a, 'abc' ) |
| grammar OptionalSingleToken; |
| options {language=Ruby;output=AST;} |
| a : ID -> ID? ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'abc' |
| end |
| |
| |
| example "closure single token" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar ClosureSingleToken; |
| options {language=Ruby;output=AST;} |
| a : ID ID -> ID* ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b' |
| end |
| |
| |
| example "positive closure single token" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar PositiveClosureSingleToken; |
| options {language=Ruby;output=AST;} |
| a : ID ID -> ID+ ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b' |
| end |
| |
| |
| example "optional single rule" do |
| result = parse( <<-'END', :a, 'abc' ) |
| grammar OptionalSingleRule; |
| options {language=Ruby;output=AST;} |
| a : b -> b?; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'abc' |
| end |
| |
| |
| example "closure single rule" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar ClosureSingleRule; |
| options {language=Ruby;output=AST;} |
| a : b b -> b*; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b' |
| end |
| |
| |
| example "closure of label" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar ClosureOfLabel; |
| options {language=Ruby;output=AST;} |
| a : x+=b x+=b -> $x*; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b' |
| end |
| |
| |
| example "optional label no list label" do |
| result = parse( <<-'END', :a, 'a' ) |
| grammar OptionalLabelNoListLabel; |
| options {language=Ruby;output=AST;} |
| a : (x=ID)? -> $x?; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a' |
| end |
| |
| |
| example "positive closure single rule" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar PositiveClosureSingleRule; |
| options {language=Ruby;output=AST;} |
| a : b b -> b+; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b' |
| end |
| |
| |
| example "single predicate t" do |
| result = parse( <<-'END', :a, 'abc' ) |
| grammar SinglePredicateT; |
| options {language=Ruby;output=AST;} |
| a : ID -> {true}? ID -> ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'abc' |
| end |
| |
| |
| example "single predicate f" do |
| result = parse( <<-'END', :a, 'abc' ) |
| grammar SinglePredicateF; |
| options {language=Ruby;output=AST;} |
| a : ID -> {false}? ID -> ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '' |
| end |
| |
| |
| example "multiple predicate" do |
| result = parse( <<-'END', :a, 'a 2' ) |
| grammar MultiplePredicate; |
| options {language=Ruby;output=AST;} |
| a : ID INT -> {false}? ID |
| -> {true}? INT |
| -> |
| ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '2' |
| end |
| |
| |
| example "multiple predicate trees" do |
| result = parse( <<-'END', :a, 'a 2' ) |
| grammar MultiplePredicateTrees; |
| options {language=Ruby;output=AST;} |
| a : ID INT -> {false}? ^(ID INT) |
| -> {true}? ^(INT ID) |
| -> ID |
| ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(2 a)' |
| end |
| |
| |
| example "simple tree" do |
| result = parse( <<-'END', :a, '-34' ) |
| grammar SimpleTree; |
| options {language=Ruby;output=AST;} |
| a : op INT -> ^(op INT); |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(- 34)' |
| end |
| |
| |
| example "simple tree2" do |
| result = parse( <<-'END', :a, '+ 34' ) |
| grammar SimpleTree2; |
| options {language=Ruby;output=AST;} |
| a : op INT -> ^(INT op); |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(34 +)' |
| end |
| |
| |
| example "nested trees" do |
| result = parse( <<-'END', :a, 'var a:int; b:float;' ) |
| grammar NestedTrees; |
| options {language=Ruby;output=AST;} |
| a : 'var' (ID ':' type ';')+ -> ^('var' ^(':' ID type)+) ; |
| type : 'int' | 'float' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(var (: a int) (: b float))' |
| end |
| |
| |
| example "imaginary token copy" do |
| result = parse( <<-'END', :a, 'a,b,c' ) |
| grammar ImaginaryTokenCopy; |
| options {language=Ruby;output=AST;} |
| tokens {VAR;} |
| a : ID (',' ID)*-> ^(VAR ID)+ ; |
| type : 'int' | 'float' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(VAR a) (VAR b) (VAR c)' |
| end |
| |
| |
| example "token unreferenced on left but defined" do |
| result = parse( <<-'END', :a, 'a' ) |
| grammar TokenUnreferencedOnLeftButDefined; |
| options {language=Ruby;output=AST;} |
| tokens {VAR;} |
| a : b -> ID ; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'ID' |
| end |
| |
| |
| example "imaginary token copy set text" do |
| result = parse( <<-'END', :a, 'a,b,c' ) |
| grammar ImaginaryTokenCopySetText; |
| options {language=Ruby;output=AST;} |
| tokens {VAR;} |
| a : ID (',' ID)*-> ^(VAR["var"] ID)+ ; |
| type : 'int' | 'float' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(var a) (var b) (var c)' |
| end |
| |
| |
| example "imaginary token no copy from token" do |
| result = parse( <<-'END', :a, '{a b c}' ) |
| grammar ImaginaryTokenNoCopyFromToken; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ; |
| type : 'int' | 'float' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '({ a b c)' |
| end |
| |
| |
| example "imaginary token no copy from token set text" do |
| result = parse( <<-'END', :a, '{a b c}' ) |
| grammar ImaginaryTokenNoCopyFromTokenSetText; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : lc='{' ID+ '}' -> ^(BLOCK[$lc,"block"] ID+) ; |
| type : 'int' | 'float' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(block a b c)' |
| end |
| |
| |
| example "mixed rewrite and auto ast" do |
| result = parse( <<-'END', :a, 'a 1 2' ) |
| grammar MixedRewriteAndAutoAST; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : b b^ ; // 2nd b matches only an INT; can make it root |
| b : ID INT -> INT ID |
| | INT |
| ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| END |
| result.should == '(2 1 a)' |
| end |
| |
| |
| example "subrule with rewrite" do |
| result = parse( <<-'END', :a, 'a 1 2 3' ) |
| grammar SubruleWithRewrite; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : b b ; |
| b : (ID INT -> INT ID | INT INT -> INT+ ) |
| ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '1 a 2 3' |
| end |
| |
| |
| example "subrule with rewrite2" do |
| result = parse( <<-'END', :a, 'int a; int b=3;' ) |
| grammar SubruleWithRewrite2; |
| options {language=Ruby;output=AST;} |
| tokens {TYPE;} |
| a : b b ; |
| b : 'int' |
| ( ID -> ^(TYPE 'int' ID) |
| | ID '=' INT -> ^(TYPE 'int' ID INT) |
| ) |
| ';' |
| ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(TYPE int a) (TYPE int b 3)' |
| end |
| |
| |
| example "nested rewrite shuts off auto ast" do |
| result = parse( <<-'END', :a, 'a b c d; 42' ) |
| grammar NestedRewriteShutsOffAutoAST; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : b b ; |
| b : ID ( ID (last=ID -> $last)+ ) ';' // get last ID |
| | INT // should still get auto AST construction |
| ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'd 42' |
| end |
| |
| |
| example "rewrite actions" do |
| result = parse( <<-'END', :a, '3' ) |
| grammar RewriteActions; |
| options {language=Ruby;output=AST;} |
| a : atom -> ^({ @adaptor.create( INT, "9" ) } atom) ; |
| atom : INT ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(9 3)' |
| end |
| |
| |
| example "rewrite actions2" do |
| result = parse( <<-'END', :a, '3' ) |
| grammar RewriteActions2; |
| options {language=Ruby;output=AST;} |
| a : atom -> { @adaptor.create( INT, "9" ) } atom ; |
| atom : INT ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') { $channel = HIDDEN } ; |
| |
| END |
| result.should == '9 3' |
| end |
| |
| |
| example "ref to old value" do |
| result = parse( <<-'END', :a, '3+4+5' ) |
| grammar RefToOldValue; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : (atom -> atom) (op='+' r=atom -> ^($op $a $r) )* ; |
| atom : INT ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(+ (+ 3 4) 5)' |
| end |
| |
| |
| example "copy semantics for rules" do |
| result = parse( <<-'END', :a, '3' ) |
| grammar CopySemanticsForRules; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : atom -> ^(atom atom) ; // NOT CYCLE! (dup atom) |
| atom : INT ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(3 3)' |
| end |
| |
| |
| example "copy semantics for rules2" do |
| result = parse( <<-'END', :a, 'int a,b,c;' ) |
| grammar CopySemanticsForRules2; |
| options {language=Ruby;output=AST;} |
| a : type ID (',' ID)* ';' -> ^(type ID)+ ; |
| type : 'int' ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(int a) (int b) (int c)' |
| end |
| |
| |
| example "copy semantics for rules3" do |
| result = parse( <<-'END', :a, 'public int a,b,c;' ) |
| grammar CopySemanticsForRules3; |
| options {language=Ruby;output=AST;} |
| a : modifier? type ID (',' ID)* ';' -> ^(type modifier? ID)+ ; |
| type : 'int' ; |
| modifier : 'public' ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(int public a) (int public b) (int public c)' |
| end |
| |
| |
| example "copy semantics for rules3 double" do |
| result = parse( <<-'END', :a, 'public int a,b,c;' ) |
| grammar CopySemanticsForRules3Double; |
| options {language=Ruby;output=AST;} |
| a : modifier? type ID (',' ID)* ';' -> ^(type modifier? ID)+ ^(type modifier? ID)+ ; |
| type : 'int' ; |
| modifier : 'public' ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(int public a) (int public b) (int public c) (int public a) (int public b) (int public c)' |
| end |
| |
| |
| example "copy semantics for rules4" do |
| result = parse( <<-'END', :a, 'public int a,b,c;' ) |
| grammar CopySemanticsForRules4; |
| options {language=Ruby;output=AST;} |
| tokens {MOD;} |
| a : modifier? type ID (',' ID)* ';' -> ^(type ^(MOD modifier)? ID)+ ; |
| type : 'int' ; |
| modifier : 'public' ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(int (MOD public) a) (int (MOD public) b) (int (MOD public) c)' |
| end |
| |
| |
| example "copy semantics lists" do |
| result = parse( <<-'END', :a, 'a,b,c;' ) |
| grammar CopySemanticsLists; |
| options {language=Ruby;output=AST;} |
| tokens {MOD;} |
| a : ID (',' ID)* ';' -> ID+ ID+ ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b c a b c' |
| end |
| |
| |
| example "copy rule label" do |
| result = parse( <<-'END', :a, 'a' ) |
| grammar CopyRuleLabel; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : x=b -> $x $x; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a a' |
| end |
| |
| |
| example "copy rule label2" do |
| result = parse( <<-'END', :a, 'a' ) |
| grammar CopyRuleLabel2; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : x=b -> ^($x $x); |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(a a)' |
| end |
| |
| |
| example "queueing of tokens" do |
| result = parse( <<-'END', :a, 'int a,b,c;' ) |
| grammar QueueingOfTokens; |
| options {language=Ruby;output=AST;} |
| a : 'int' ID (',' ID)* ';' -> ^('int' ID+) ; |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(int a b c)' |
| end |
| |
| |
| example "copy of tokens" do |
| result = parse( <<-'END', :a, 'int a;' ) |
| grammar CopyOfTokens; |
| options {language=Ruby;output=AST;} |
| a : 'int' ID ';' -> 'int' ID 'int' ID ; |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'int a int a' |
| end |
| |
| |
| example "token copy in loop" do |
| result = parse( <<-'END', :a, 'int a,b,c;' ) |
| grammar TokenCopyInLoop; |
| options {language=Ruby;output=AST;} |
| a : 'int' ID (',' ID)* ';' -> ^('int' ID)+ ; |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(int a) (int b) (int c)' |
| end |
| |
| |
| example "token copy in loop against two others" do |
| result = parse( <<-'END', :a, 'int a:1,b:2,c:3;' ) |
| grammar TokenCopyInLoopAgainstTwoOthers; |
| options {language=Ruby;output=AST;} |
| a : 'int' ID ':' INT (',' ID ':' INT)* ';' -> ^('int' ID INT)+ ; |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(int a 1) (int b 2) (int c 3)' |
| end |
| |
| |
| example "list refd one at a time" do |
| result = parse( <<-'END', :a, 'a b c' ) |
| grammar ListRefdOneAtATime; |
| options {language=Ruby;output=AST;} |
| a : ID+ -> ID ID ID ; // works if 3 input IDs |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b c' |
| end |
| |
| |
| example "split list with labels" do |
| result = parse( <<-'END', :a, 'a b c' ) |
| grammar SplitListWithLabels; |
| options {language=Ruby;output=AST;} |
| tokens {VAR;} |
| a : first=ID others+=ID* -> $first VAR $others+ ; |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a VAR b c' |
| end |
| |
| |
| example "complicated melange" do |
| result = parse( <<-'END', :a, 'a a b b b c c c d' ) |
| grammar ComplicatedMelange; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : A A b=B B b=B c+=C C c+=C D {s=$D.text} -> A+ B+ C+ D ; |
| type : 'int' | 'float' ; |
| A : 'a' ; |
| B : 'b' ; |
| C : 'c' ; |
| D : 'd' ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a a b b b c c c d' |
| end |
| |
| |
| example "rule label" do |
| result = parse( <<-'END', :a, 'a' ) |
| grammar RuleLabel; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : x=b -> $x; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a' |
| end |
| |
| |
| example "ambiguous rule" do |
| result = parse( <<-'END', :a, 'abc 34' ) |
| grammar AmbiguousRule; |
| options {language=Ruby;output=AST;} |
| a : ID a -> a | INT ; |
| ID : 'a'..'z'+ ; |
| INT: '0'..'9'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '34' |
| end |
| |
| |
| example "rule list label" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar RuleListLabel; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : x+=b x+=b -> $x+; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b' |
| end |
| |
| |
| example "rule list label2" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar RuleListLabel2; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : x+=b x+=b -> $x $x*; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b' |
| end |
| |
| |
| example "optional" do |
| result = parse( <<-'END', :a, 'a' ) |
| grammar Optional; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : x=b (y=b)? -> $x $y?; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a' |
| end |
| |
| |
| example "optional2" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar Optional2; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : x=ID (y=b)? -> $x $y?; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b' |
| end |
| |
| |
| example "optional3" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar Optional3; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : x=ID (y=b)? -> ($x $y)?; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a b' |
| end |
| |
| |
| example "optional4" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar Optional4; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : x+=ID (y=b)? -> ($x $y)?; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| END |
| result.should == 'a b' |
| end |
| |
| |
| example "optional5" do |
| result = parse( <<-'END', :a, 'a' ) |
| grammar Optional5; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : ID -> ID? ; // match an ID to optional ID |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == 'a' |
| end |
| |
| |
| example "arbitrary expr type" do |
| result = parse( <<-'END', :a, 'a b' ) |
| grammar ArbitraryExprType; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : x+=b x+=b -> {ANTLR3::CommonTree.new(nil)}; |
| b : ID ; |
| ID : 'a'..'z'+ ; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '' |
| end |
| |
| |
| example "set" do |
| result = parse( <<-'END', :a, '2 a 34 de' ) |
| grammar SetT; |
| options {language=Ruby;output=AST;} |
| a: (INT|ID)+ -> INT+ ID+ ; |
| INT: '0'..'9'+; |
| ID : 'a'..'z'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '2 34 a de' |
| end |
| |
| |
| example "set2" do |
| result = parse( <<-'END', :a, '2' ) |
| grammar Set2; |
| options {language=Ruby;output=AST;} |
| a: (INT|ID) -> INT? ID? ; |
| INT: '0'..'9'+; |
| ID : 'a'..'z'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '2' |
| end |
| |
| |
| example "set with label" do |
| warn( 'test SetWithLabel officially broken' ) |
| #result = parse(<<-'END', :a, '2') |
| # grammar SetWithLabel; |
| # options {language=Ruby;output=AST;} |
| # a : x=(INT|ID) -> $x ; |
| # INT: '0'..'9'+; |
| # ID : 'a'..'z'+; |
| # WS : (' '|'\n') {$channel=HIDDEN;} ; |
| # |
| #END |
| #result.should == '2' |
| end |
| |
| |
| example "rewrite action" do |
| result = parse( <<-'END', :r, '25' ) |
| grammar RewriteAction; |
| options {language=Ruby;output=AST;} |
| tokens { FLOAT; } |
| r |
| : INT -> { ANTLR3::CommonTree.new( create_token( FLOAT, nil, "#{$INT.text}.0" ) ) } |
| ; |
| INT : '0'..'9'+; |
| WS: (' ' | '\n' | '\t')+ {$channel = HIDDEN;}; |
| |
| END |
| result.should == '25.0' |
| end |
| |
| |
| example "optional subrule without real elements" do |
| result = parse( <<-'END', :modulo, 'modulo abc (x y #)' ) |
| grammar OptionalSubruleWithoutRealElements; |
| options {language=Ruby;output=AST;} |
| tokens {PARMS;} |
| |
| modulo |
| : 'modulo' ID ('(' parms+ ')')? -> ^('modulo' ID ^(PARMS parms+)?) |
| ; |
| parms : '#'|ID; |
| ID : ('a'..'z' | 'A'..'Z')+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '(modulo abc (PARMS x y #))' |
| end |
| |
| |
| example "wildcard" do |
| result = parse( <<-'END', :a, 'abc 34' ) |
| grammar Wildcard; |
| options {language=Ruby;output=AST;} |
| a : ID c=. -> $c; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| result.should == '34' |
| end |
| |
| |
| example "extra token in simple decl" do |
| result, errors = parse( <<-'END', :decl, 'int 34 x=1;', true ) |
| grammar ExtraTokenInSimpleDecl; |
| options {language=Ruby;output=AST;} |
| tokens {EXPR;} |
| decl : type ID '=' INT ';' -> ^(EXPR type ID INT) ; |
| type : 'int' | 'float' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| errors.should == [ 'line 1:4 extraneous input "34" expecting ID' ] |
| result.should == '(EXPR int x 1)' |
| end |
| |
| |
| example "missing id in simple decl" do |
| result, errors = parse( <<-'END', :decl, 'int =1;', true ) |
| grammar MissingIDInSimpleDecl; |
| options {language=Ruby;output=AST;} |
| tokens {EXPR;} |
| decl : type ID '=' INT ';' -> ^(EXPR type ID INT) ; |
| type : 'int' | 'float' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| errors.should == [ 'line 1:4 missing ID at "="' ] |
| result.should == '(EXPR int <missing ID> 1)' |
| end |
| |
| |
| example "missing set in simple decl" do |
| result, errors = parse( <<-'END', :decl, 'x=1;', true ) |
| grammar MissingSetInSimpleDecl; |
| options {language=Ruby;output=AST;} |
| tokens {EXPR;} |
| decl : type ID '=' INT ';' -> ^(EXPR type ID INT) ; |
| type : 'int' | 'float' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| errors.should == [ 'line 1:0 mismatched input "x" expecting set nil' ] |
| result.should == '(EXPR <error: x> x 1)' |
| end |
| |
| |
| example "missing token gives error node" do |
| result, errors = parse( <<-'END', :a, 'abc', true ) |
| grammar MissingTokenGivesErrorNode; |
| options {language=Ruby;output=AST;} |
| a : ID INT -> ID INT ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| errors.should == [ "line 0:-1 missing INT at \"<EOF>\"" ] |
| result.should == 'abc <missing INT>' |
| #end |
| end |
| |
| |
| example "extra token gives error node" do |
| result, errors = parse( <<-'END', :a, 'abc ick 34', true ) |
| grammar ExtraTokenGivesErrorNode; |
| options {language=Ruby;output=AST;} |
| a : b c -> b c; |
| b : ID -> ID ; |
| c : INT -> INT ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| errors.should == [ 'line 1:4 extraneous input "ick" expecting INT' ] |
| result.should == 'abc 34' |
| end |
| |
| |
| example "missing first token gives error node" do |
| result, errors = parse( <<-'END', :a, '34', true ) |
| grammar MissingFirstTokenGivesErrorNode; |
| options {language=Ruby;output=AST;} |
| a : ID INT -> ID INT ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| errors.should == [ 'line 1:0 missing ID at "34"' ] |
| result.should == '<missing ID> 34' |
| end |
| |
| |
| example "missing first token gives error node2" do |
| result, errors = parse( <<-'END', :a, '34', true ) |
| grammar MissingFirstTokenGivesErrorNode2; |
| options {language=Ruby;output=AST;} |
| a : b c -> b c; |
| b : ID -> ID ; |
| c : INT -> INT ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| errors.should == [ 'line 1:0 missing ID at "34"' ] |
| result.should == '<missing ID> 34' |
| end |
| |
| |
| example "no viable alt gives error node" do |
| result, errors = parse( <<-'END', :a, '*', true ) |
| grammar NoViableAltGivesErrorNode; |
| options {language=Ruby;output=AST;} |
| a : b -> b | c -> c; |
| b : ID -> ID ; |
| c : INT -> INT ; |
| ID : 'a'..'z'+ ; |
| S : '*' ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| |
| END |
| errors.should == [ 'line 1:0 no viable alternative at input "*"' ] |
| result.should == '<unexpected: 0 S["*"] @ line 1 col 0 (0..0), resync = *>' |
| end |
| |
| |
| example "cardinality" do |
| lambda do |
| parse( <<-'END', :a, "a b 3 4 5" ) |
| grammar Cardinality; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : ID ID INT INT INT -> (ID INT)+; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| END |
| end.should raise_error( ANTLR3::Error::RewriteCardinalityError ) |
| end |
| |
| example "cardinality2" do |
| lambda do |
| parse( <<-'END', :a, "a b" ) |
| grammar Cardinality2; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : ID+ -> ID ID ID ; // only 2 input IDs |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| END |
| end.should raise_error( ANTLR3::Error::RewriteCardinalityError ) |
| end |
| |
| example "cardinality3" do |
| lambda do |
| parse( <<-'END', :a, "3" ) |
| grammar Cardinality3; |
| options {language=Ruby;output=AST;} |
| tokens {BLOCK;} |
| a : ID? INT -> ID INT ; |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| END |
| end.should raise_error( ANTLR3::Error::RewriteEmptyStream ) |
| end |
| |
| example "loop cardinality" do |
| lambda do |
| parse( <<-'END', :a, "3" ) |
| grammar LoopCardinality; |
| options {language=Ruby;output=AST;} |
| a : ID? INT -> ID+ INT ; |
| op : '+'|'-' ; |
| ID : 'a'..'z'+ ; |
| INT : '0'..'9'+; |
| WS : (' '|'\n') {$channel=HIDDEN;} ; |
| END |
| end.should raise_error( ANTLR3::Error::RewriteEarlyExit ) |
| end |
| |
| |
| |
| end |