#!/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