You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
689 lines
24 KiB
689 lines
24 KiB
#!/usr/bin/ruby
|
|
# encoding: utf-8
|
|
|
|
require 'antlr3'
|
|
require 'fileutils'
|
|
require 'antlr3/test/functional'
|
|
#require 'antlr3/test/diff'
|
|
|
|
class ANTLRDebugger < Thread
|
|
self.abort_on_exception = true
|
|
attr_accessor :events, :success, :port
|
|
include Timeout
|
|
|
|
def initialize( port )
|
|
@events = []
|
|
@success = false
|
|
@port = port
|
|
|
|
super do
|
|
timeout( 2 ) do
|
|
begin
|
|
@socket = TCPSocket.open( 'localhost', @port )
|
|
#Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
|
#@socket.connect( Socket.pack_sockaddr_in(@port, '127.0.0.1') )
|
|
rescue Errno::ECONNREFUSED => error
|
|
if $VERBOSE
|
|
$stderr.printf(
|
|
"%s:%s received connection refuse error: %p\n",
|
|
__FILE__, __LINE__, error
|
|
)
|
|
$stderr.puts( "sleeping for 0.1 seconds before retrying" )
|
|
end
|
|
sleep( 0.01 )
|
|
retry
|
|
end
|
|
end
|
|
|
|
@socket.readline.strip.should == 'ANTLR 2'
|
|
@socket.readline.strip.start_with?( 'grammar "' ).should == true
|
|
ack
|
|
loop do
|
|
event = @socket.readline.strip
|
|
@events << event.split( "\t" )
|
|
ack
|
|
break if event == 'terminate'
|
|
end
|
|
|
|
@socket.close
|
|
@success = true
|
|
end
|
|
|
|
end
|
|
|
|
def ack
|
|
@socket.write( "ACK\n" )
|
|
@socket.flush
|
|
end
|
|
|
|
end # ANTLRDebugger
|
|
|
|
class TestDebugGrammars < ANTLR3::Test::Functional
|
|
compile_options :debug => true
|
|
|
|
#include ANTLR3::Test::Diff
|
|
|
|
def parse( grammar, rule, input, options = {} )
|
|
@grammar = inline_grammar( grammar )
|
|
@grammar.compile( self.class.compile_options )
|
|
@grammar_path = File.expand_path( @grammar.path )
|
|
for output_file in @grammar.target_files
|
|
self.class.import( output_file )
|
|
end
|
|
grammar_module = self.class.const_get( @grammar.name )
|
|
listener = options[ :listener ] or debugger = ANTLRDebugger.new( port = 49100 )
|
|
|
|
begin
|
|
lexer = grammar_module::Lexer.new( input )
|
|
tokens = ANTLR3::CommonTokenStream.new( lexer )
|
|
options[ :debug_listener ] = listener
|
|
parser = grammar_module::Parser.new( tokens, options )
|
|
parser.send( rule )
|
|
ensure
|
|
if listener.nil?
|
|
debugger.join
|
|
return( debugger )
|
|
end
|
|
end
|
|
end
|
|
|
|
example 'basic debug-mode parser using a RecordEventListener' do
|
|
grammar = %q<
|
|
grammar BasicParser; // line 1
|
|
options {language=Ruby;} // line 2
|
|
a : ID EOF; // line 3
|
|
ID : 'a'..'z'+ ; // line 4
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
listener = ANTLR3::Debug::RecordEventListener.new
|
|
parse( grammar, :a, 'a', :listener => listener )
|
|
lt_events, found = listener.events.partition { |event| event.start_with?( "(look): " ) }
|
|
lt_events.should_not be_empty
|
|
|
|
expected = [ "(enter_rule): rule=a",
|
|
"(location): line=3 position=1",
|
|
"(enter_alternative): number=1",
|
|
"(location): line=3 position=5",
|
|
"(location): line=3 position=8",
|
|
"(location): line=3 position=11",
|
|
"(exit_rule): rule=a" ]
|
|
found.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser using a socket proxy to transmit events' do
|
|
grammar = %q<
|
|
grammar SocketProxy; // line 1
|
|
options {language=Ruby;} // line 2
|
|
a : ID EOF; // line 3
|
|
ID : 'a'..'z'+ ; // line 4
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
debugger = parse( grammar, :a, 'a' )
|
|
debugger.success.should be_true
|
|
expected = [
|
|
[ 'enter_rule', @grammar_path, 'a' ],
|
|
[ 'location', '3', '1' ],
|
|
[ 'enter_alternative', '1' ],
|
|
[ 'location', '3', '5' ],
|
|
[ 'look', '1', '0', '4', 'default', '1', '0', '"a"' ],
|
|
[ 'look', '1', '0', '4', 'default', '1', '0', '"a"' ],
|
|
[ 'consume_token', '0', '4', 'default', '1', '0', '"a"' ],
|
|
[ 'location', '3', '8' ],
|
|
[ 'look', '1', '-1', '-1', 'default', '0', '-1', 'nil' ],
|
|
[ 'look', '1', '-1', '-1', 'default', '0', '-1', 'nil' ],
|
|
[ 'consume_token', '-1', '-1', 'default', '0', '-1', 'nil' ],
|
|
[ 'location', '3', '11' ],
|
|
[ 'exit_rule', @grammar_path, 'a' ],
|
|
[ 'terminate' ]
|
|
]
|
|
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser events triggered by recognition errors' do
|
|
grammar = %q<
|
|
grammar RecognitionError;
|
|
options { language=Ruby; }
|
|
a : ID EOF;
|
|
ID : 'a'..'z'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
debugger = parse( grammar, :a, "a b" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "5" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_hidden_token", "1", "5", "hidden", "1", "1", '" "' ],
|
|
[ "location", "3", "8" ],
|
|
[ "look", "1", "2", "4", "default", "1", "2", "\"b\"" ],
|
|
[ "look", "1", "2", "4", "default", "1", "2", "\"b\"" ],
|
|
[ "look", "2", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "look", "1", "2", "4", "default", "1", "2", "\"b\"" ],
|
|
[ "begin_resync" ],
|
|
[ "consume_token", "2", "4", "default", "1", "2", "\"b\"" ],
|
|
[ "end_resync" ],
|
|
[ "recognition_exception", "ANTLR3::Error::UnwantedToken", "2", "1", "2" ],
|
|
[ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "location", "3", "11" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser events triggered by semantic predicate evaluation' do
|
|
grammar = %q<
|
|
grammar SemPred;
|
|
options { language=Ruby; }
|
|
a : {true}? ID EOF;
|
|
ID : 'a'..'z'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
|
|
debugger = parse( grammar, :a, "a" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "5" ],
|
|
[ "semantic_predicate", "true", '"true"' ],
|
|
[ "location", "3", "13" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "location", "3", "16" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "location", "3", "19" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser events triggered by recognizing a (...)+ block' do
|
|
grammar = %q<
|
|
grammar PositiveClosureBlock;
|
|
options { language=Ruby; }
|
|
a : ID ( ID | INT )+ EOF;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
|
|
debugger = parse( grammar, :a, "a 1 b c 3" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "5" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_hidden_token", "1", "6", "hidden", "1", "1", '" "' ],
|
|
[ "location", "3", "8" ],
|
|
[ "enter_subrule", "1" ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "8" ],
|
|
[ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
|
|
[ "consume_token", "2", "5", "default", "1", "2", "\"1\"" ],
|
|
[ "consume_hidden_token", "3", "6", "hidden", "1", "3", '" "' ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "8" ],
|
|
[ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ],
|
|
[ "consume_token", "4", "4", "default", "1", "4", "\"b\"" ],
|
|
[ "consume_hidden_token", "5", "6", "hidden", "1", "5", '" "' ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "8" ],
|
|
[ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ],
|
|
[ "consume_token", "6", "4", "default", "1", "6", "\"c\"" ],
|
|
[ "consume_hidden_token", "7", "6", "hidden", "1", "7", '" "' ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "8" ],
|
|
[ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ],
|
|
[ "consume_token", "8", "5", "default", "1", "8", "\"3\"" ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "exit_subrule", "1" ],
|
|
[ "location", "3", "22" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "location", "3", "25" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser events triggered by recognizing a (...)* block' do
|
|
grammar = %q<
|
|
grammar ClosureBlock;
|
|
options { language=Ruby; }
|
|
a : ID ( ID | INT )* EOF;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
|
|
debugger = parse( grammar, :a, "a 1 b c 3" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "5" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_hidden_token", "1", "6", "hidden", "1", "1", '" "' ],
|
|
[ "location", "3", "8" ],
|
|
[ "enter_subrule", "1" ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "8" ],
|
|
[ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
|
|
[ "consume_token", "2", "5", "default", "1", "2", "\"1\"" ],
|
|
[ "consume_hidden_token", "3", "6", "hidden", "1", "3", '" "' ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "8" ],
|
|
[ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ],
|
|
[ "consume_token", "4", "4", "default", "1", "4", "\"b\"" ],
|
|
[ "consume_hidden_token", "5", "6", "hidden", "1", "5", '" "' ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "8" ],
|
|
[ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ],
|
|
[ "consume_token", "6", "4", "default", "1", "6", "\"c\"" ],
|
|
[ "consume_hidden_token", "7", "6", "hidden", "1", "7", '" "' ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "8" ],
|
|
[ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ],
|
|
[ "consume_token", "8", "5", "default", "1", "8", "\"3\"" ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "exit_subrule", "1" ],
|
|
[ "location", "3", "22" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "location", "3", "25" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser events triggered by a mismatched set error' do
|
|
grammar = %q<
|
|
grammar MismatchedSetError;
|
|
options { language=Ruby; }
|
|
a : ID ( ID | INT ) EOF;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
|
|
debugger = parse( grammar, :a, "a" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "5" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "location", "3", "8" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "recognition_exception", "ANTLR3::Error::MismatchedSet", "1", "0", "-1" ],
|
|
[ "recognition_exception", "ANTLR3::Error::MismatchedSet", "1", "0", "-1" ],
|
|
[ "begin_resync" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "end_resync" ],
|
|
[ "location", "3", "24" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser block-location events for subrules' do
|
|
grammar = %q<
|
|
grammar Block;
|
|
options { language=Ruby; }
|
|
a : ID ( b | c ) EOF;
|
|
b : ID;
|
|
c : INT;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
|
|
debugger = parse( grammar, :a, "a 1" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "5" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_hidden_token", "1", "6", "hidden", "1", "1", '" "' ],
|
|
[ "location", "3", "8" ],
|
|
[ "enter_subrule", "1" ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "2" ],
|
|
[ "location", "3", "14" ],
|
|
[ "enter_rule", @grammar_path, "c" ],
|
|
[ "location", "5", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "5", "5" ],
|
|
[ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
|
|
[ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ],
|
|
[ "consume_token", "2", "5", "default", "1", "2", "\"1\"" ],
|
|
[ "location", "5", "8" ],
|
|
[ "exit_rule", @grammar_path, "c" ],
|
|
[ "exit_subrule", "1" ],
|
|
[ "location", "3", "18" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "location", "3", "21" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser events triggered by a no viable alternative error' do
|
|
grammar = %q<
|
|
grammar NoViableAlt;
|
|
options { language=Ruby; }
|
|
a : ID ( b | c ) EOF;
|
|
b : ID;
|
|
c : INT;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
BANG : '!' ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
|
|
debugger = parse( grammar, :a, "a !" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "5" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_hidden_token", "1", "7", "hidden", "1", "1", '" "' ],
|
|
[ "location", "3", "8" ],
|
|
[ "enter_subrule", "1" ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "2", "6", "default", "1", "2", "\"!\"" ],
|
|
[ "look", "1", "2", "6", "default", "1", "2", "\"!\"" ],
|
|
[ "recognition_exception", "ANTLR3::Error::NoViableAlternative", "2", "1", "2" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "exit_subrule", "1" ],
|
|
[ "recognition_exception", "ANTLR3::Error::NoViableAlternative", "2", "1", "2" ],
|
|
[ "begin_resync" ],
|
|
[ "look", "1", "2", "6", "default", "1", "2", "\"!\"" ],
|
|
[ "consume_token", "2", "6", "default", "1", "2", "\"!\"" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "end_resync" ],
|
|
[ "location", "3", "21" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser block-location events triggered by rules' do
|
|
grammar = %q<
|
|
grammar RuleBlock;
|
|
options { language=Ruby; }
|
|
a : b | c;
|
|
b : ID;
|
|
c : INT;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
|
|
debugger = parse( grammar, :a, "1" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_decision", "1" ],
|
|
[ "look", "1", "0", "5", "default", "1", "0", "\"1\"" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "2" ],
|
|
[ "location", "3", "9" ],
|
|
[ "enter_rule", @grammar_path, "c" ],
|
|
[ "location", "5", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "5", "5" ],
|
|
[ "look", "1", "0", "5", "default", "1", "0", "\"1\"" ],
|
|
[ "look", "1", "0", "5", "default", "1", "0", "\"1\"" ],
|
|
[ "consume_token", "0", "5", "default", "1", "0", "\"1\"" ],
|
|
[ "location", "5", "8" ],
|
|
[ "exit_rule", @grammar_path, "c" ],
|
|
[ "location", "3", "10" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser block-location events triggered by single-alternative rules' do
|
|
grammar = %q<
|
|
grammar RuleBlockSingleAlt;
|
|
options { language=Ruby; }
|
|
a : b;
|
|
b : ID;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
|
|
debugger = parse( grammar, :a, "a" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "5" ],
|
|
[ "enter_rule", @grammar_path, "b" ],
|
|
[ "location", "4", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "4", "5" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "location", "4", "7" ],
|
|
[ "exit_rule", @grammar_path, "b" ],
|
|
[ "location", "3", "6" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser block-location events triggered by single-alternative subrules' do
|
|
grammar = %q<
|
|
grammar BlockSingleAlt;
|
|
options { language=Ruby; }
|
|
a : ( b );
|
|
b : ID;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
|
|
debugger = parse( grammar, :a, "a" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "5" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "7" ],
|
|
[ "enter_rule", @grammar_path, "b" ],
|
|
[ "location", "4", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "4", "5" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "location", "4", "7" ],
|
|
[ "exit_rule", @grammar_path, "b" ],
|
|
[ "location", "3", "10" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode parser block-location events triggered by invoking a cyclic DFA for prediction' do
|
|
grammar = %q<
|
|
grammar DFA;
|
|
options { language=Ruby; }
|
|
a : ( b | c ) EOF;
|
|
b : ID* INT;
|
|
c : ID+ BANG;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
BANG : '!';
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
>
|
|
|
|
debugger = parse( grammar, :a, "a!" )
|
|
debugger.success.should be_true
|
|
|
|
expected = [
|
|
[ "enter_rule", @grammar_path, "a" ],
|
|
[ "location", "3", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "3", "5" ],
|
|
[ "enter_subrule", "1" ],
|
|
[ "enter_decision", "1" ],
|
|
[ "mark", "0" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ],
|
|
[ "consume_token", "1", "6", "default", "1", "1", "\"!\"" ],
|
|
[ "rewind", "0" ],
|
|
[ "exit_decision", "1" ],
|
|
[ "enter_alternative", "2" ],
|
|
[ "location", "3", "11" ],
|
|
[ "enter_rule", @grammar_path, "c" ],
|
|
[ "location", "5", "1" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "5", "5" ],
|
|
[ "enter_subrule", "3" ],
|
|
[ "enter_decision", "3" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "exit_decision", "3" ],
|
|
[ "enter_alternative", "1" ],
|
|
[ "location", "5", "5" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ],
|
|
[ "enter_decision", "3" ],
|
|
[ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ],
|
|
[ "exit_decision", "3" ],
|
|
[ "exit_subrule", "3" ],
|
|
[ "location", "5", "9" ],
|
|
[ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ],
|
|
[ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ],
|
|
[ "consume_token", "1", "6", "default", "1", "1", "\"!\"" ],
|
|
[ "location", "5", "13" ],
|
|
[ "exit_rule", @grammar_path, "c" ],
|
|
[ "exit_subrule", "1" ],
|
|
[ "location", "3", "15" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ],
|
|
[ "location", "3", "18" ],
|
|
[ "exit_rule", @grammar_path, "a" ],
|
|
[ "terminate" ]
|
|
]
|
|
debugger.events.should == expected
|
|
end
|
|
|
|
example 'debug-mode AST-building parser events' do
|
|
grammar = %q/
|
|
grammar BasicAST;
|
|
options {
|
|
language=Ruby;
|
|
output=AST;
|
|
}
|
|
a : ( b | c ) EOF!;
|
|
b : ID* INT -> ^(INT ID*);
|
|
c : ID+ BANG -> ^(BANG ID+);
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
BANG : '!';
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
/
|
|
listener = ANTLR3::Debug::RecordEventListener.new
|
|
parse( grammar, :a, "a!", :listener => listener )
|
|
end
|
|
|
|
end
|