Home | History | Annotate | Download | only in debugging
      1 #!/usr/bin/ruby
      2 # encoding: utf-8
      3 
      4 require 'antlr3'
      5 require 'fileutils'
      6 require 'antlr3/test/functional'
      7 #require 'antlr3/test/diff'
      8 
      9 class ANTLRDebugger < Thread
     10   self.abort_on_exception = true
     11   attr_accessor :events, :success, :port
     12   include Timeout
     13   
     14   def initialize( port )
     15     @events = []
     16     @success = false
     17     @port = port
     18     
     19     super do
     20       timeout( 2 ) do
     21         begin
     22           @socket = TCPSocket.open( 'localhost', @port )
     23           #Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
     24           #@socket.connect( Socket.pack_sockaddr_in(@port, '127.0.0.1') )
     25         rescue Errno::ECONNREFUSED => error
     26           if $VERBOSE
     27             $stderr.printf( 
     28                 "%s:%s received connection refuse error: %p\n",
     29                 __FILE__, __LINE__, error
     30               )
     31             $stderr.puts( "sleeping for 0.1 seconds before retrying" )
     32           end
     33           sleep( 0.01 )
     34           retry
     35         end
     36       end
     37       
     38       @socket.readline.strip.should == 'ANTLR 2'
     39       @socket.readline.strip.start_with?( 'grammar "' ).should == true
     40       ack
     41       loop do
     42         event = @socket.readline.strip
     43         @events << event.split( "\t" )
     44         ack
     45         break if event == 'terminate'
     46       end
     47       
     48       @socket.close
     49       @success = true
     50     end
     51     
     52   end
     53   
     54   def ack
     55     @socket.write( "ACK\n" )
     56     @socket.flush
     57   end
     58 
     59 end # ANTLRDebugger
     60 
     61 class TestDebugGrammars < ANTLR3::Test::Functional
     62   compile_options :debug => true
     63   
     64   #include ANTLR3::Test::Diff
     65   
     66   def parse( grammar, rule, input, options = {} )
     67     @grammar = inline_grammar( grammar )
     68     @grammar.compile( self.class.compile_options )
     69     @grammar_path = File.expand_path( @grammar.path )
     70     for output_file in @grammar.target_files
     71       self.class.import( output_file )
     72     end
     73     grammar_module = self.class.const_get( @grammar.name )
     74     listener = options[ :listener ] or debugger = ANTLRDebugger.new( port = 49100 )
     75     
     76     begin
     77       lexer = grammar_module::Lexer.new( input )
     78       tokens = ANTLR3::CommonTokenStream.new( lexer )
     79       options[ :debug_listener ] = listener
     80       parser = grammar_module::Parser.new( tokens, options )
     81       parser.send( rule )
     82     ensure
     83       if listener.nil?
     84         debugger.join
     85         return( debugger )
     86       end
     87     end
     88   end
     89   
     90   example 'basic debug-mode parser using a RecordEventListener' do
     91     grammar = %q<
     92       grammar BasicParser;                      // line 1
     93       options {language=Ruby;}                  // line 2
     94       a : ID EOF;                               // line 3
     95       ID : 'a'..'z'+ ;                          // line 4
     96       WS : (' '|'\n') {$channel=HIDDEN;} ;
     97     >
     98     listener = ANTLR3::Debug::RecordEventListener.new
     99     parse( grammar, :a, 'a', :listener => listener )
    100     lt_events, found = listener.events.partition { |event| event.start_with?( "(look): " ) }
    101     lt_events.should_not be_empty
    102     
    103     expected = [ "(enter_rule): rule=a",
    104                 "(location): line=3 position=1",
    105                 "(enter_alternative): number=1",
    106                 "(location): line=3 position=5",
    107                 "(location): line=3 position=8",
    108                 "(location): line=3 position=11",
    109                 "(exit_rule): rule=a" ]
    110     found.should == expected
    111   end
    112   
    113   example 'debug-mode parser using a socket proxy to transmit events' do
    114     grammar = %q<
    115       grammar SocketProxy;                   // line 1
    116       options {language=Ruby;}               // line 2
    117       a : ID EOF;                           // line 3
    118       ID : 'a'..'z'+ ;                       // line 4
    119       WS : (' '|'\n') {$channel=HIDDEN;} ;
    120     >
    121     debugger = parse( grammar, :a, 'a' )
    122     debugger.success.should be_true
    123     expected = [ 
    124       [ 'enter_rule', @grammar_path, 'a' ],
    125       [ 'location', '3', '1' ],
    126       [ 'enter_alternative', '1' ],
    127       [ 'location', '3', '5' ],
    128       [ 'look', '1', '0', '4', 'default', '1', '0', '"a"' ],
    129       [ 'look', '1', '0', '4', 'default', '1', '0', '"a"' ],
    130       [ 'consume_token', '0', '4', 'default', '1', '0', '"a"' ],
    131       [ 'location', '3', '8' ],
    132       [ 'look', '1', '-1', '-1', 'default', '0', '-1', 'nil' ],
    133       [ 'look', '1', '-1', '-1', 'default', '0', '-1', 'nil' ],
    134       [ 'consume_token', '-1', '-1', 'default', '0', '-1', 'nil' ],
    135       [ 'location', '3', '11' ],
    136       [ 'exit_rule', @grammar_path, 'a' ],
    137       [ 'terminate' ]
    138     ]
    139     
    140     debugger.events.should == expected
    141   end
    142   
    143   example 'debug-mode parser events triggered by recognition errors' do
    144     grammar = %q<
    145       grammar RecognitionError;
    146       options { language=Ruby; }
    147       a : ID EOF;
    148       ID : 'a'..'z'+ ;
    149       WS : (' '|'\n') {$channel=HIDDEN;} ;
    150     >
    151     debugger = parse( grammar, :a, "a b" )
    152     debugger.success.should be_true
    153     
    154     expected = [ 
    155       [ "enter_rule", @grammar_path, "a" ],
    156       [ "location", "3", "1" ],
    157       [ "enter_alternative", "1" ],
    158       [ "location", "3", "5" ],
    159       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    160       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    161       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    162       [ "consume_hidden_token", "1", "5", "hidden", "1", "1", '" "' ],
    163       [ "location", "3", "8" ],
    164       [ "look", "1", "2", "4", "default", "1", "2", "\"b\"" ],
    165       [ "look", "1", "2", "4", "default", "1", "2", "\"b\"" ],
    166       [ "look", "2", "-1", "-1", "default", "0", "-1", "nil" ],
    167       [ "look", "1", "2", "4", "default", "1", "2", "\"b\"" ],
    168       [ "begin_resync" ],
    169       [ "consume_token", "2", "4", "default", "1", "2", "\"b\"" ],
    170       [ "end_resync" ],
    171       [ "recognition_exception", "ANTLR3::Error::UnwantedToken", "2", "1", "2" ],
    172       [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
    173       [ "location", "3", "11" ],
    174       [ "exit_rule", @grammar_path, "a" ],
    175       [ "terminate" ]
    176     ]
    177     debugger.events.should == expected
    178   end
    179   
    180   example 'debug-mode parser events triggered by semantic predicate evaluation' do
    181     grammar = %q<
    182       grammar SemPred;
    183       options { language=Ruby; }
    184       a : {true}? ID EOF;
    185       ID : 'a'..'z'+ ;
    186       WS : (' '|'\n') {$channel=HIDDEN;} ;
    187     >
    188     
    189     debugger = parse( grammar, :a, "a" )
    190     debugger.success.should be_true
    191     
    192     expected = [ 
    193       [ "enter_rule", @grammar_path, "a" ],
    194       [ "location", "3", "1" ],
    195       [ "enter_alternative", "1" ],
    196       [ "location", "3", "5" ],
    197       [ "semantic_predicate", "true", '"true"' ],
    198       [ "location", "3", "13" ],
    199       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    200       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    201       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    202       [ "location", "3", "16" ],
    203       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    204       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    205       [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
    206       [ "location", "3", "19" ],
    207       [ "exit_rule", @grammar_path, "a" ],
    208       [ "terminate" ]
    209     ]
    210     debugger.events.should == expected
    211   end
    212   
    213   example 'debug-mode parser events triggered by recognizing a (...)+ block' do
    214     grammar = %q<
    215       grammar PositiveClosureBlock;
    216       options { language=Ruby; }
    217       a : ID ( ID | INT )+ EOF;
    218       ID : 'a'..'z'+ ;
    219       INT : '0'..'9'+ ;
    220       WS : (' '|'\n') {$channel=HIDDEN;} ;
    221     >
    222     
    223     debugger = parse( grammar, :a, "a 1 b c 3" )
    224     debugger.success.should be_true
    225     
    226     expected = [ 
    227       [ "enter_rule", @grammar_path, "a" ],
    228       [ "location", "3", "1" ],
    229       [ "enter_alternative", "1" ],
    230       [ "location", "3", "5" ],
    231       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    232       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    233       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    234       [ "consume_hidden_token", "1", "6", "hidden", "1", "1", '" "' ],
    235       [ "location", "3", "8" ],
    236       [ "enter_subrule", "1" ],
    237       [ "enter_decision", "1" ],
    238       [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
    239       [ "exit_decision", "1" ],
    240       [ "enter_alternative", "1" ],
    241       [ "location", "3", "8" ],
    242       [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
    243       [ "consume_token", "2", "5", "default", "1", "2", "\"1\"" ],
    244       [ "consume_hidden_token", "3", "6", "hidden", "1", "3", '" "' ],
    245       [ "enter_decision", "1" ],
    246       [ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ],
    247       [ "exit_decision", "1" ],
    248       [ "enter_alternative", "1" ],
    249       [ "location", "3", "8" ],
    250       [ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ],
    251       [ "consume_token", "4", "4", "default", "1", "4", "\"b\"" ],
    252       [ "consume_hidden_token", "5", "6", "hidden", "1", "5", '" "' ],
    253       [ "enter_decision", "1" ],
    254       [ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ],
    255       [ "exit_decision", "1" ],
    256       [ "enter_alternative", "1" ],
    257       [ "location", "3", "8" ],
    258       [ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ],
    259       [ "consume_token", "6", "4", "default", "1", "6", "\"c\"" ],
    260       [ "consume_hidden_token", "7", "6", "hidden", "1", "7", '" "' ],
    261       [ "enter_decision", "1" ],
    262       [ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ],
    263       [ "exit_decision", "1" ],
    264       [ "enter_alternative", "1" ],
    265       [ "location", "3", "8" ],
    266       [ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ],
    267       [ "consume_token", "8", "5", "default", "1", "8", "\"3\"" ],
    268       [ "enter_decision", "1" ],
    269       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    270       [ "exit_decision", "1" ],
    271       [ "exit_subrule", "1" ],
    272       [ "location", "3", "22" ],
    273       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    274       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    275       [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
    276       [ "location", "3", "25" ],
    277       [ "exit_rule", @grammar_path, "a" ],
    278       [ "terminate" ]
    279     ]
    280     
    281     debugger.events.should == expected
    282   end
    283   
    284   example 'debug-mode parser events triggered by recognizing a (...)* block' do
    285     grammar = %q<
    286       grammar ClosureBlock;
    287       options { language=Ruby; }
    288       a : ID ( ID | INT )* EOF;
    289       ID : 'a'..'z'+ ;
    290       INT : '0'..'9'+ ;
    291       WS : (' '|'\n') {$channel=HIDDEN;} ;
    292     >
    293     
    294     debugger = parse( grammar, :a, "a 1 b c 3" )
    295     debugger.success.should be_true
    296     
    297     expected = [ 
    298       [ "enter_rule", @grammar_path, "a" ],
    299       [ "location", "3", "1" ],
    300       [ "enter_alternative", "1" ],
    301       [ "location", "3", "5" ],
    302       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    303       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    304       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    305       [ "consume_hidden_token", "1", "6", "hidden", "1", "1", '" "' ],
    306       [ "location", "3", "8" ],
    307       [ "enter_subrule", "1" ],
    308       [ "enter_decision", "1" ],
    309       [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
    310       [ "exit_decision", "1" ],
    311       [ "enter_alternative", "1" ],
    312       [ "location", "3", "8" ],
    313       [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
    314       [ "consume_token", "2", "5", "default", "1", "2", "\"1\"" ],
    315       [ "consume_hidden_token", "3", "6", "hidden", "1", "3", '" "' ],
    316       [ "enter_decision", "1" ],
    317       [ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ],
    318       [ "exit_decision", "1" ],
    319       [ "enter_alternative", "1" ],
    320       [ "location", "3", "8" ],
    321       [ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ],
    322       [ "consume_token", "4", "4", "default", "1", "4", "\"b\"" ],
    323       [ "consume_hidden_token", "5", "6", "hidden", "1", "5", '" "' ],
    324       [ "enter_decision", "1" ],
    325       [ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ],
    326       [ "exit_decision", "1" ],
    327       [ "enter_alternative", "1" ],
    328       [ "location", "3", "8" ],
    329       [ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ],
    330       [ "consume_token", "6", "4", "default", "1", "6", "\"c\"" ],
    331       [ "consume_hidden_token", "7", "6", "hidden", "1", "7", '" "' ],
    332       [ "enter_decision", "1" ],
    333       [ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ],
    334       [ "exit_decision", "1" ],
    335       [ "enter_alternative", "1" ],
    336       [ "location", "3", "8" ],
    337       [ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ],
    338       [ "consume_token", "8", "5", "default", "1", "8", "\"3\"" ],
    339       [ "enter_decision", "1" ],
    340       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    341       [ "exit_decision", "1" ],
    342       [ "exit_subrule", "1" ],
    343       [ "location", "3", "22" ],
    344       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    345       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    346       [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
    347       [ "location", "3", "25" ],
    348       [ "exit_rule", @grammar_path, "a" ],
    349       [ "terminate" ]
    350     ]
    351     debugger.events.should == expected
    352   end
    353   
    354   example 'debug-mode parser events triggered by a mismatched set error' do
    355     grammar = %q<
    356       grammar MismatchedSetError;
    357       options { language=Ruby; }
    358       a : ID ( ID | INT ) EOF;
    359       ID : 'a'..'z'+ ;
    360       INT : '0'..'9'+ ;
    361       WS : (' '|'\n') {$channel=HIDDEN;} ;
    362     >
    363     
    364     debugger = parse( grammar, :a, "a" )
    365     debugger.success.should be_true
    366     
    367     expected = [ 
    368       [ "enter_rule", @grammar_path, "a" ],
    369       [ "location", "3", "1" ],
    370       [ "enter_alternative", "1" ],
    371       [ "location", "3", "5" ],
    372       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    373       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    374       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    375       [ "location", "3", "8" ],
    376       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    377       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    378       [ "recognition_exception", "ANTLR3::Error::MismatchedSet", "1", "0", "-1" ],
    379       [ "recognition_exception", "ANTLR3::Error::MismatchedSet", "1", "0", "-1" ],
    380       [ "begin_resync" ],
    381       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    382       [ "end_resync" ],
    383       [ "location", "3", "24" ],
    384       [ "exit_rule", @grammar_path, "a" ],
    385       [ "terminate" ]
    386     ]
    387     
    388     debugger.events.should == expected
    389   end
    390   
    391   example 'debug-mode parser block-location events for subrules' do
    392     grammar = %q<
    393       grammar Block;
    394       options { language=Ruby; }
    395       a : ID ( b | c ) EOF;
    396       b : ID;
    397       c : INT;
    398       ID : 'a'..'z'+ ;
    399       INT : '0'..'9'+ ;
    400       WS : (' '|'\n') {$channel=HIDDEN;} ;
    401     >
    402     
    403     debugger = parse( grammar, :a, "a 1" )
    404     debugger.success.should be_true
    405     
    406     expected = [ 
    407       [ "enter_rule", @grammar_path, "a" ],
    408       [ "location", "3", "1" ],
    409       [ "enter_alternative", "1" ],
    410       [ "location", "3", "5" ],
    411       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    412       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    413       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    414       [ "consume_hidden_token", "1", "6", "hidden", "1", "1", '" "' ],
    415       [ "location", "3", "8" ],
    416       [ "enter_subrule", "1" ],
    417       [ "enter_decision", "1" ],
    418       [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
    419       [ "exit_decision", "1" ],
    420       [ "enter_alternative", "2" ],
    421       [ "location", "3", "14" ],
    422       [ "enter_rule", @grammar_path, "c" ],
    423       [ "location", "5", "1" ],
    424       [ "enter_alternative", "1" ],
    425       [ "location", "5", "5" ],
    426       [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
    427       [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
    428       [ "consume_token", "2", "5", "default", "1", "2", "\"1\"" ],
    429       [ "location", "5", "8" ],
    430       [ "exit_rule", @grammar_path, "c" ],
    431       [ "exit_subrule", "1" ],
    432       [ "location", "3", "18" ],
    433       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    434       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    435       [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
    436       [ "location", "3", "21" ],
    437       [ "exit_rule", @grammar_path, "a" ],
    438       [ "terminate" ]
    439     ]
    440     debugger.events.should == expected
    441   end
    442   
    443   example 'debug-mode parser events triggered by a no viable alternative error' do
    444     grammar = %q<
    445       grammar NoViableAlt;
    446       options { language=Ruby; }
    447       a : ID ( b | c ) EOF;
    448       b : ID;
    449       c : INT;
    450       ID : 'a'..'z'+ ;
    451       INT : '0'..'9'+ ;
    452       BANG : '!' ;
    453       WS : (' '|'\n') {$channel=HIDDEN;} ;
    454     >
    455     
    456     debugger = parse( grammar, :a, "a !" )
    457     debugger.success.should be_true
    458     
    459     expected = [ 
    460       [ "enter_rule", @grammar_path, "a" ],
    461       [ "location", "3", "1" ],
    462       [ "enter_alternative", "1" ],
    463       [ "location", "3", "5" ],
    464       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    465       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    466       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    467       [ "consume_hidden_token", "1", "7", "hidden", "1", "1", '" "' ],
    468       [ "location", "3", "8" ],
    469       [ "enter_subrule", "1" ],
    470       [ "enter_decision", "1" ],
    471       [ "look", "1", "2", "6", "default", "1", "2", "\"!\"" ],
    472       [ "look", "1", "2", "6", "default", "1", "2", "\"!\"" ],
    473       [ "recognition_exception", "ANTLR3::Error::NoViableAlternative", "2", "1", "2" ],
    474       [ "exit_decision", "1" ],
    475       [ "exit_subrule", "1" ],
    476       [ "recognition_exception", "ANTLR3::Error::NoViableAlternative", "2", "1", "2" ],
    477       [ "begin_resync" ],
    478       [ "look", "1", "2", "6", "default", "1", "2", "\"!\"" ],
    479       [ "consume_token", "2", "6", "default", "1", "2", "\"!\"" ],
    480       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    481       [ "end_resync" ],
    482       [ "location", "3", "21" ],
    483       [ "exit_rule", @grammar_path, "a" ],
    484       [ "terminate" ]
    485     ]
    486     debugger.events.should == expected
    487   end
    488   
    489   example 'debug-mode parser block-location events triggered by rules' do
    490     grammar = %q<
    491       grammar RuleBlock;
    492       options { language=Ruby; }
    493       a : b | c;
    494       b : ID;
    495       c : INT;
    496       ID : 'a'..'z'+ ;
    497       INT : '0'..'9'+ ;
    498       WS : (' '|'\n') {$channel=HIDDEN;} ;
    499     >
    500     
    501     debugger = parse( grammar, :a, "1" )
    502     debugger.success.should be_true
    503     
    504     expected = [ 
    505       [ "enter_rule", @grammar_path, "a" ],
    506       [ "location", "3", "1" ],
    507       [ "enter_decision", "1" ],
    508       [ "look", "1", "0", "5", "default", "1", "0", "\"1\"" ],
    509       [ "exit_decision", "1" ],
    510       [ "enter_alternative", "2" ],
    511       [ "location", "3", "9" ],
    512       [ "enter_rule", @grammar_path, "c" ],
    513       [ "location", "5", "1" ],
    514       [ "enter_alternative", "1" ],
    515       [ "location", "5", "5" ],
    516       [ "look", "1", "0", "5", "default", "1", "0", "\"1\"" ],
    517       [ "look", "1", "0", "5", "default", "1", "0", "\"1\"" ],
    518       [ "consume_token", "0", "5", "default", "1", "0", "\"1\"" ],
    519       [ "location", "5", "8" ],
    520       [ "exit_rule", @grammar_path, "c" ],
    521       [ "location", "3", "10" ],
    522       [ "exit_rule", @grammar_path, "a" ],
    523       [ "terminate" ]
    524     ]
    525     
    526     debugger.events.should == expected
    527   end
    528   
    529   example 'debug-mode parser block-location events triggered by single-alternative rules' do
    530     grammar = %q<
    531       grammar RuleBlockSingleAlt;
    532       options { language=Ruby; }
    533       a : b;
    534       b : ID;
    535       ID : 'a'..'z'+ ;
    536       INT : '0'..'9'+ ;
    537       WS : (' '|'\n') {$channel=HIDDEN;} ;
    538     >
    539     
    540     debugger = parse( grammar, :a, "a" )
    541     debugger.success.should be_true
    542     
    543     expected = [ 
    544       [ "enter_rule", @grammar_path, "a" ],
    545       [ "location", "3", "1" ],
    546       [ "enter_alternative", "1" ],
    547       [ "location", "3", "5" ],
    548       [ "enter_rule", @grammar_path, "b" ],
    549       [ "location", "4", "1" ],
    550       [ "enter_alternative", "1" ],
    551       [ "location", "4", "5" ],
    552       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    553       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    554       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    555       [ "location", "4", "7" ],
    556       [ "exit_rule", @grammar_path, "b" ],
    557       [ "location", "3", "6" ],
    558       [ "exit_rule", @grammar_path, "a" ],
    559       [ "terminate" ]
    560     ]
    561     
    562     debugger.events.should == expected
    563   end
    564   
    565   example 'debug-mode parser block-location events triggered by single-alternative subrules' do
    566     grammar = %q<
    567       grammar BlockSingleAlt;
    568       options { language=Ruby; }
    569       a : ( b );
    570       b : ID;
    571       ID : 'a'..'z'+ ;
    572       INT : '0'..'9'+ ;
    573       WS : (' '|'\n') {$channel=HIDDEN;} ;
    574     >
    575     
    576     debugger = parse( grammar, :a, "a" )
    577     debugger.success.should be_true
    578     
    579     expected = [ 
    580       [ "enter_rule", @grammar_path, "a" ],
    581       [ "location", "3", "1" ],
    582       [ "enter_alternative", "1" ],
    583       [ "location", "3", "5" ],
    584       [ "enter_alternative", "1" ],
    585       [ "location", "3", "7" ],
    586       [ "enter_rule", @grammar_path, "b" ],
    587       [ "location", "4", "1" ],
    588       [ "enter_alternative", "1" ],
    589       [ "location", "4", "5" ],
    590       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    591       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    592       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    593       [ "location", "4", "7" ],
    594       [ "exit_rule", @grammar_path, "b" ],
    595       [ "location", "3", "10" ],
    596       [ "exit_rule", @grammar_path, "a" ],
    597       [ "terminate" ]
    598     ]
    599     debugger.events.should == expected
    600   end
    601   
    602   example 'debug-mode parser block-location events triggered by invoking a cyclic DFA for prediction' do
    603     grammar = %q<
    604       grammar DFA;
    605       options { language=Ruby; }
    606       a : ( b | c ) EOF;
    607       b : ID* INT;
    608       c : ID+ BANG;
    609       ID : 'a'..'z'+ ;
    610       INT : '0'..'9'+ ;
    611       BANG : '!';
    612       WS : (' '|'\n') {$channel=HIDDEN;} ;
    613     >
    614     
    615     debugger = parse( grammar, :a, "a!" )
    616     debugger.success.should be_true
    617     
    618     expected = [ 
    619       [ "enter_rule", @grammar_path, "a" ],
    620       [ "location", "3", "1" ],
    621       [ "enter_alternative", "1" ],
    622       [ "location", "3", "5" ],
    623       [ "enter_subrule", "1" ],
    624       [ "enter_decision", "1" ],
    625       [ "mark", "0" ],
    626       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    627       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    628       [ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ],
    629       [ "consume_token", "1", "6", "default", "1", "1", "\"!\"" ],
    630       [ "rewind", "0" ],
    631       [ "exit_decision", "1" ],
    632       [ "enter_alternative", "2" ],
    633       [ "location", "3", "11" ],
    634       [ "enter_rule", @grammar_path, "c" ],
    635       [ "location", "5", "1" ],
    636       [ "enter_alternative", "1" ],
    637       [ "location", "5", "5" ],
    638       [ "enter_subrule", "3" ],
    639       [ "enter_decision", "3" ],
    640       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    641       [ "exit_decision", "3" ],
    642       [ "enter_alternative", "1" ],
    643       [ "location", "5", "5" ],
    644       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    645       [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
    646       [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
    647       [ "enter_decision", "3" ],
    648       [ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ],
    649       [ "exit_decision", "3" ],
    650       [ "exit_subrule", "3" ],
    651       [ "location", "5", "9" ],
    652       [ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ],
    653       [ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ],
    654       [ "consume_token", "1", "6", "default", "1", "1", "\"!\"" ],
    655       [ "location", "5", "13" ],
    656       [ "exit_rule", @grammar_path, "c" ],
    657       [ "exit_subrule", "1" ],
    658       [ "location", "3", "15" ],
    659       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    660       [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
    661       [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
    662       [ "location", "3", "18" ],
    663       [ "exit_rule", @grammar_path, "a" ],
    664       [ "terminate" ]
    665     ]
    666     debugger.events.should == expected
    667   end
    668   
    669   example 'debug-mode AST-building parser events' do
    670     grammar = %q/
    671       grammar BasicAST;
    672       options {
    673         language=Ruby;
    674         output=AST;
    675       }
    676       a : ( b | c ) EOF!;
    677       b : ID* INT -> ^(INT ID*);
    678       c : ID+ BANG -> ^(BANG ID+);
    679       ID : 'a'..'z'+ ;
    680       INT : '0'..'9'+ ;
    681       BANG : '!';
    682       WS : (' '|'\n') {$channel=HIDDEN;} ;
    683     /
    684     listener = ANTLR3::Debug::RecordEventListener.new
    685     parse( grammar, :a, "a!", :listener => listener )
    686   end
    687 
    688 end
    689