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.
788 lines
28 KiB
788 lines
28 KiB
import unittest
|
|
import textwrap
|
|
import antlr3
|
|
import antlr3.tree
|
|
import antlr3.debug
|
|
import testbase
|
|
import sys
|
|
import threading
|
|
import socket
|
|
import errno
|
|
import time
|
|
|
|
class Debugger(threading.Thread):
|
|
def __init__(self, port):
|
|
super().__init__()
|
|
self.events = []
|
|
self.success = False
|
|
self.port = port
|
|
|
|
def run(self):
|
|
# create listening socket
|
|
s = None
|
|
tstart = time.time()
|
|
while time.time() - tstart < 10:
|
|
try:
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s.connect(('127.0.0.1', self.port))
|
|
break
|
|
except socket.error as exc:
|
|
if s:
|
|
s.close()
|
|
if exc.args[0] != errno.ECONNREFUSED:
|
|
raise
|
|
time.sleep(0.1)
|
|
|
|
if s is None:
|
|
self.events.append(['nosocket'])
|
|
return
|
|
|
|
s.setblocking(1)
|
|
s.settimeout(10.0)
|
|
|
|
output = s.makefile('w', 1)
|
|
input = s.makefile('r', 1)
|
|
|
|
try:
|
|
# handshake
|
|
l = input.readline().strip()
|
|
assert l == 'ANTLR 2'
|
|
l = input.readline().strip()
|
|
assert l.startswith('grammar "'), l
|
|
|
|
output.write('ACK\n')
|
|
output.flush()
|
|
|
|
while True:
|
|
event = input.readline().strip()
|
|
self.events.append(event.split('\t'))
|
|
|
|
output.write('ACK\n')
|
|
output.flush()
|
|
|
|
if event == 'terminate':
|
|
self.success = True
|
|
break
|
|
|
|
except socket.timeout:
|
|
self.events.append(['timeout'])
|
|
except socket.error as exc:
|
|
self.events.append(['socketerror', exc.args])
|
|
finally:
|
|
output.close()
|
|
input.close()
|
|
s.close()
|
|
|
|
|
|
class T(testbase.ANTLRTest):
|
|
def execParser(self, grammar, grammarEntry, input, listener,
|
|
parser_args={}):
|
|
if listener is None:
|
|
port = 49100
|
|
debugger = Debugger(port)
|
|
debugger.start()
|
|
# TODO(pink): install alarm, so it doesn't hang forever in case of a bug
|
|
|
|
else:
|
|
port = None
|
|
|
|
try:
|
|
lexerCls, parserCls = self.compileInlineGrammar(
|
|
grammar, options='-debug')
|
|
|
|
cStream = antlr3.StringStream(input)
|
|
lexer = lexerCls(cStream)
|
|
tStream = antlr3.CommonTokenStream(lexer)
|
|
parser = parserCls(tStream, dbg=listener, port=port, **parser_args)
|
|
getattr(parser, grammarEntry)()
|
|
|
|
finally:
|
|
if listener is None:
|
|
debugger.join()
|
|
return debugger
|
|
|
|
def testBasicParser(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : ID EOF;
|
|
ID : 'a'..'z'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
listener = antlr3.debug.RecordDebugEventListener()
|
|
|
|
self.execParser(
|
|
grammar, 'a',
|
|
input="a",
|
|
listener=listener)
|
|
|
|
# We only check that some LT events are present. How many is subject
|
|
# to change (at the time of writing there are two, which is one too
|
|
# many).
|
|
lt_events = [event for event in listener.events
|
|
if event.startswith("LT ")]
|
|
self.assertNotEqual(lt_events, [])
|
|
|
|
# For the rest, filter out LT events to get a reliable test.
|
|
expected = ["enterRule a",
|
|
"location 6:1",
|
|
"location 6:5",
|
|
"location 6:8",
|
|
"location 6:11",
|
|
"exitRule a"]
|
|
found = [event for event in listener.events
|
|
if not event.startswith("LT ")]
|
|
self.assertListEqual(found, expected)
|
|
|
|
def testSocketProxy(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : ID EOF;
|
|
ID : 'a'..'z'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '4', '0', '1', '0', '"a'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
|
|
['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
|
|
['consumeToken', '-1', '-1', '0', '1', '1', '"<EOF>'],
|
|
['location', '6', '11'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
def testRecognitionException(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : ID EOF;
|
|
ID : 'a'..'z'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a b",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeHiddenToken', '1', '5', '99', '1', '1', '"'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '2', '4', '0', '1', '2', '"b'],
|
|
['LT', '1', '2', '4', '0', '1', '2', '"b'],
|
|
['LT', '2', '-1', '-1', '0', '1', '3', '"<EOF>'],
|
|
['LT', '1', '2', '4', '0', '1', '2', '"b'],
|
|
['LT', '1', '2', '4', '0', '1', '2', '"b'],
|
|
['beginResync'],
|
|
['consumeToken', '2', '4', '0', '1', '2', '"b'],
|
|
['endResync'],
|
|
['exception', 'UnwantedTokenException', '2', '1', '2'],
|
|
['LT', '1', '-1', '-1', '0', '1', '3', '"<EOF>'],
|
|
['consumeToken', '-1', '-1', '0', '1', '3', '"<EOF>'],
|
|
['location', '6', '11'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testSemPred(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : {True}? ID EOF;
|
|
ID : 'a'..'z'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['semanticPredicate', '1', 'True'],
|
|
['location', '6', '13'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '4', '0', '1', '0', '"a'],
|
|
['location', '6', '16'],
|
|
['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
|
|
['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
|
|
['consumeToken', '-1', '-1', '0', '1', '1', '"<EOF>'],
|
|
['location', '6', '19'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testPositiveClosureBlock(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : ID ( ID | INT )+ EOF;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a 1 b c 3",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeHiddenToken', '1', '6', '99', '1', '1', '"'],
|
|
['location', '6', '8'],
|
|
['enterSubRule', '1'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '2', '5', '0', '1', '2', '"1'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '2', '5', '0', '1', '2', '"1'],
|
|
['consumeToken', '2', '5', '0', '1', '2', '"1'],
|
|
['consumeHiddenToken', '3', '6', '99', '1', '3', '"'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '4', '4', '0', '1', '4', '"b'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '4', '4', '0', '1', '4', '"b'],
|
|
['consumeToken', '4', '4', '0', '1', '4', '"b'],
|
|
['consumeHiddenToken', '5', '6', '99', '1', '5', '"'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '6', '4', '0', '1', '6', '"c'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '6', '4', '0', '1', '6', '"c'],
|
|
['consumeToken', '6', '4', '0', '1', '6', '"c'],
|
|
['consumeHiddenToken', '7', '6', '99', '1', '7', '"'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '8', '5', '0', '1', '8', '"3'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '8', '5', '0', '1', '8', '"3'],
|
|
['consumeToken', '8', '5', '0', '1', '8', '"3'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
|
|
['exitDecision', '1'],
|
|
['exitSubRule', '1'],
|
|
['location', '6', '22'],
|
|
['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
|
|
['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
|
|
['consumeToken', '-1', '-1', '0', '1', '9', '"<EOF>'],
|
|
['location', '6', '25'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testClosureBlock(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : ID ( ID | INT )* EOF;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a 1 b c 3",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeHiddenToken', '1', '6', '99', '1', '1', '"'],
|
|
['location', '6', '8'],
|
|
['enterSubRule', '1'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '2', '5', '0', '1', '2', '"1'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '2', '5', '0', '1', '2', '"1'],
|
|
['consumeToken', '2', '5', '0', '1', '2', '"1'],
|
|
['consumeHiddenToken', '3', '6', '99', '1', '3', '"'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '4', '4', '0', '1', '4', '"b'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '4', '4', '0', '1', '4', '"b'],
|
|
['consumeToken', '4', '4', '0', '1', '4', '"b'],
|
|
['consumeHiddenToken', '5', '6', '99', '1', '5', '"'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '6', '4', '0', '1', '6', '"c'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '6', '4', '0', '1', '6', '"c'],
|
|
['consumeToken', '6', '4', '0', '1', '6', '"c'],
|
|
['consumeHiddenToken', '7', '6', '99', '1', '7', '"'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '8', '5', '0', '1', '8', '"3'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '8', '5', '0', '1', '8', '"3'],
|
|
['consumeToken', '8', '5', '0', '1', '8', '"3'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
|
|
['exitDecision', '1'],
|
|
['exitSubRule', '1'],
|
|
['location', '6', '22'],
|
|
['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
|
|
['LT', '1', '-1', '-1', '0', '1', '9', '"<EOF>'],
|
|
['consumeToken', '-1', '-1', '0', '1', '9', '"<EOF>'],
|
|
['location', '6', '25'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testMismatchedSetException(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : ID ( ID | INT ) EOF;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '4', '0', '1', '0', '"a'],
|
|
['location', '6', '8'],
|
|
['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
|
|
['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
|
|
['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
|
|
['exception', 'MismatchedSetException', '1', '1', '1'],
|
|
['exception', 'MismatchedSetException', '1', '1', '1'],
|
|
['beginResync'],
|
|
['LT', '1', '-1', '-1', '0', '1', '1', '"<EOF>'],
|
|
['endResync'],
|
|
['location', '6', '24'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testBlock(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : ID ( b | c ) EOF;
|
|
b : ID;
|
|
c : INT;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a 1",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeHiddenToken', '1', '6', '99', '1', '1', '"'],
|
|
['location', '6', '8'],
|
|
['enterSubRule', '1'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '2', '5', '0', '1', '2', '"1'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '2'],
|
|
['location', '6', '14'],
|
|
['enterRule', 'T.g', 'c'],
|
|
['location', '8', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '8', '5'],
|
|
['LT', '1', '2', '5', '0', '1', '2', '"1'],
|
|
['LT', '1', '2', '5', '0', '1', '2', '"1'],
|
|
['consumeToken', '2', '5', '0', '1', '2', '"1'],
|
|
['location', '8', '8'],
|
|
['exitRule', 'T.g', 'c'],
|
|
['exitSubRule', '1'],
|
|
['location', '6', '18'],
|
|
['LT', '1', '-1', '-1', '0', '1', '3', '"<EOF>'],
|
|
['LT', '1', '-1', '-1', '0', '1', '3', '"<EOF>'],
|
|
['consumeToken', '-1', '-1', '0', '1', '3', '"<EOF>'],
|
|
['location', '6', '21'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testNoViableAlt(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : ID ( b | c ) EOF;
|
|
b : ID;
|
|
c : INT;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
BANG : '!' ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a !",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['LT', '1', '0', '5', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '5', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '5', '0', '1', '0', '"a'],
|
|
['consumeHiddenToken', '1', '7', '99', '1', '1', '"'],
|
|
['location', '6', '8'],
|
|
['enterSubRule', '1'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '2', '4', '0', '1', '2', '"!'],
|
|
['LT', '1', '2', '4', '0', '1', '2', '"!'],
|
|
['LT', '1', '2', '4', '0', '1', '2', '"!'],
|
|
['exception', 'NoViableAltException', '2', '1', '2'],
|
|
['exitDecision', '1'],
|
|
['exitSubRule', '1'],
|
|
['exception', 'NoViableAltException', '2', '1', '2'],
|
|
['beginResync'],
|
|
['LT', '1', '2', '4', '0', '1', '2', '"!'],
|
|
['consumeToken', '2', '4', '0', '1', '2', '"!'],
|
|
['LT', '1', '-1', '-1', '0', '1', '3', '"<EOF>'],
|
|
['endResync'],
|
|
['location', '6', '21'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testRuleBlock(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : b | c;
|
|
b : ID;
|
|
c : INT;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="1",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterDecision', '1', '0'],
|
|
['LT', '1', '0', '5', '0', '1', '0', '"1'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '2'],
|
|
['location', '6', '9'],
|
|
['enterRule', 'T.g', 'c'],
|
|
['location', '8', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '8', '5'],
|
|
['LT', '1', '0', '5', '0', '1', '0', '"1'],
|
|
['LT', '1', '0', '5', '0', '1', '0', '"1'],
|
|
['consumeToken', '0', '5', '0', '1', '0', '"1'],
|
|
['location', '8', '8'],
|
|
['exitRule', 'T.g', 'c'],
|
|
['location', '6', '10'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testRuleBlockSingleAlt(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : b;
|
|
b : ID;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['enterRule', 'T.g', 'b'],
|
|
['location', '7', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '7', '5'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '4', '0', '1', '0', '"a'],
|
|
['location', '7', '7'],
|
|
['exitRule', 'T.g', 'b'],
|
|
['location', '6', '6'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testBlockSingleAlt(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : ( b );
|
|
b : ID;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '7'],
|
|
['enterRule', 'T.g', 'b'],
|
|
['location', '7', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '7', '5'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '4', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '4', '0', '1', '0', '"a'],
|
|
['location', '7', '7'],
|
|
['exitRule', 'T.g', 'b'],
|
|
['location', '6', '10'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testDFA(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
}
|
|
a : ( b | c ) EOF;
|
|
b : ID* INT;
|
|
c : ID+ BANG;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+ ;
|
|
BANG : '!';
|
|
WS : (' '|'\n') {$channel=HIDDEN} ;
|
|
''')
|
|
|
|
debugger = self.execParser(
|
|
grammar, 'a',
|
|
input="a!",
|
|
listener=None)
|
|
|
|
self.assertTrue(debugger.success)
|
|
expected = [['enterRule', 'T.g', 'a'],
|
|
['location', '6', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '6', '5'],
|
|
['enterSubRule', '1'],
|
|
['enterDecision', '1', '0'],
|
|
['mark', '0'],
|
|
['LT', '1', '0', '5', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '5', '0', '1', '0', '"a'],
|
|
['LT', '1', '1', '4', '0', '1', '1', '"!'],
|
|
['consumeToken', '1', '4', '0', '1', '1', '"!'],
|
|
['rewind', '0'],
|
|
['exitDecision', '1'],
|
|
['enterAlt', '2'],
|
|
['location', '6', '11'],
|
|
['enterRule', 'T.g', 'c'],
|
|
['location', '8', '1'],
|
|
['enterAlt', '1'],
|
|
['location', '8', '5'],
|
|
['enterSubRule', '3'],
|
|
['enterDecision', '3', '0'],
|
|
['LT', '1', '0', '5', '0', '1', '0', '"a'],
|
|
['exitDecision', '3'],
|
|
['enterAlt', '1'],
|
|
['location', '8', '5'],
|
|
['LT', '1', '0', '5', '0', '1', '0', '"a'],
|
|
['LT', '1', '0', '5', '0', '1', '0', '"a'],
|
|
['consumeToken', '0', '5', '0', '1', '0', '"a'],
|
|
['enterDecision', '3', '0'],
|
|
['LT', '1', '1', '4', '0', '1', '1', '"!'],
|
|
['exitDecision', '3'],
|
|
['exitSubRule', '3'],
|
|
['location', '8', '9'],
|
|
['LT', '1', '1', '4', '0', '1', '1', '"!'],
|
|
['LT', '1', '1', '4', '0', '1', '1', '"!'],
|
|
['consumeToken', '1', '4', '0', '1', '1', '"!'],
|
|
['location', '8', '13'],
|
|
['exitRule', 'T.g', 'c'],
|
|
['exitSubRule', '1'],
|
|
['location', '6', '15'],
|
|
['LT', '1', '-1', '-1', '0', '1', '2', '"<EOF>'],
|
|
['LT', '1', '-1', '-1', '0', '1', '2', '"<EOF>'],
|
|
['consumeToken', '-1', '-1', '0', '1', '2', '"<EOF>'],
|
|
['location', '6', '18'],
|
|
['exitRule', 'T.g', 'a'],
|
|
['terminate']]
|
|
|
|
self.assertListEqual(debugger.events, expected)
|
|
|
|
|
|
def testBasicAST(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {
|
|
language=Python3;
|
|
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.RecordDebugEventListener()
|
|
|
|
self.execParser(
|
|
grammar, 'a',
|
|
input="a!",
|
|
listener=listener)
|
|
|
|
# don't check output for now (too dynamic), I'm satisfied if it
|
|
# doesn't crash
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|