#!/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 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 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 \"\"" ] result.should == 'abc ' #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 == ' 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 == ' 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 == '' 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