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.
1006 lines
29 KiB
1006 lines
29 KiB
import unittest
|
|
import textwrap
|
|
import antlr3
|
|
import antlr3.tree
|
|
import testbase
|
|
import sys
|
|
|
|
class TestAutoAST(testbase.ANTLRTest):
|
|
def parserClass(self, base):
|
|
class TParser(base):
|
|
def __init__(self, *args, **kwargs):
|
|
base.__init__(self, *args, **kwargs)
|
|
|
|
self._errors = []
|
|
self._output = ""
|
|
|
|
|
|
def capture(self, t):
|
|
self._output += t
|
|
|
|
|
|
def traceIn(self, ruleName, ruleIndex):
|
|
self.traces.append('>'+ruleName)
|
|
|
|
|
|
def traceOut(self, ruleName, ruleIndex):
|
|
self.traces.append('<'+ruleName)
|
|
|
|
|
|
def emitErrorMessage(self, msg):
|
|
self._errors.append(msg)
|
|
|
|
|
|
return TParser
|
|
|
|
|
|
def lexerClass(self, base):
|
|
class TLexer(base):
|
|
def __init__(self, *args, **kwargs):
|
|
base.__init__(self, *args, **kwargs)
|
|
|
|
self._output = ""
|
|
|
|
|
|
def capture(self, t):
|
|
self._output += t
|
|
|
|
|
|
def traceIn(self, ruleName, ruleIndex):
|
|
self.traces.append('>'+ruleName)
|
|
|
|
|
|
def traceOut(self, ruleName, ruleIndex):
|
|
self.traces.append('<'+ruleName)
|
|
|
|
|
|
def recover(self, input, re):
|
|
# no error recovery yet, just crash!
|
|
raise
|
|
|
|
return TLexer
|
|
|
|
|
|
def execParser(self, grammar, grammarEntry, input, expectErrors=False):
|
|
lexerCls, parserCls = self.compileInlineGrammar(grammar)
|
|
|
|
cStream = antlr3.StringStream(input)
|
|
lexer = lexerCls(cStream)
|
|
tStream = antlr3.CommonTokenStream(lexer)
|
|
parser = parserCls(tStream)
|
|
r = getattr(parser, grammarEntry)()
|
|
|
|
if not expectErrors:
|
|
self.assertEquals(len(parser._errors), 0, parser._errors)
|
|
|
|
result = ""
|
|
|
|
if r is not None:
|
|
if hasattr(r, 'result'):
|
|
result += r.result
|
|
|
|
if r.tree is not None:
|
|
result += r.tree.toStringTree()
|
|
|
|
if not expectErrors:
|
|
return result
|
|
|
|
else:
|
|
return result, parser._errors
|
|
|
|
|
|
def execTreeParser(self, grammar, grammarEntry, treeGrammar, treeEntry, input):
|
|
lexerCls, parserCls = self.compileInlineGrammar(grammar)
|
|
walkerCls = self.compileInlineGrammar(treeGrammar)
|
|
|
|
cStream = antlr3.StringStream(input)
|
|
lexer = lexerCls(cStream)
|
|
tStream = antlr3.CommonTokenStream(lexer)
|
|
parser = parserCls(tStream)
|
|
r = getattr(parser, grammarEntry)()
|
|
nodes = antlr3.tree.CommonTreeNodeStream(r.tree)
|
|
nodes.setTokenStream(tStream)
|
|
walker = walkerCls(nodes)
|
|
r = getattr(walker, treeEntry)()
|
|
|
|
if r is not None:
|
|
return r.tree.toStringTree()
|
|
|
|
return ""
|
|
|
|
|
|
def testTokenList(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
a : ID INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;};
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "abc 34")
|
|
self.assertEquals("abc 34", found);
|
|
|
|
|
|
def testTokenListInSingleAltBlock(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
a : (ID INT) ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar,"a", "abc 34")
|
|
self.assertEquals("abc 34", found)
|
|
|
|
|
|
def testSimpleRootAtOuterLevel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
a : ID^ INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "abc 34")
|
|
self.assertEquals("(abc 34)", found)
|
|
|
|
|
|
def testSimpleRootAtOuterLevelReverse(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : INT ID^ ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "34 abc")
|
|
self.assertEquals("(abc 34)", found)
|
|
|
|
|
|
def testBang(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ID INT! ID! INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "abc 34 dag 4532")
|
|
self.assertEquals("abc 4532", found)
|
|
|
|
|
|
def testOptionalThenRoot(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ( ID INT )? ID^ ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a 1 b")
|
|
self.assertEquals("(b a 1)", found)
|
|
|
|
|
|
def testLabeledStringRoot(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : v='void'^ ID ';' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "void foo;")
|
|
self.assertEquals("(void foo ;)", found)
|
|
|
|
|
|
def testWildcard(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : v='void'^ . ';' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "void foo;")
|
|
self.assertEquals("(void foo ;)", found)
|
|
|
|
|
|
def testWildcardRoot(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : v='void' .^ ';' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "void foo;")
|
|
self.assertEquals("(foo void ;)", found)
|
|
|
|
|
|
def testWildcardRootWithLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : v='void' x=.^ ';' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "void foo;")
|
|
self.assertEquals("(foo void ;)", found)
|
|
|
|
|
|
def testWildcardRootWithListLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : v='void' x=.^ ';' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "void foo;")
|
|
self.assertEquals("(foo void ;)", found)
|
|
|
|
|
|
def testWildcardBangWithListLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : v='void' x=.! ';' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "void foo;")
|
|
self.assertEquals("void ;", found)
|
|
|
|
|
|
def testRootRoot(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ID^ INT^ ID ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a 34 c")
|
|
self.assertEquals("(34 a c)", found)
|
|
|
|
|
|
def testRootRoot2(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ID INT^ ID^ ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a 34 c")
|
|
self.assertEquals("(c (34 a))", found)
|
|
|
|
|
|
def testRootThenRootInLoop(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ID^ (INT '*'^ ID)+ ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a 34 * b 9 * c")
|
|
self.assertEquals("(* (* (a 34) b 9) c)", found)
|
|
|
|
|
|
def testNestedSubrule(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : 'void' (({pass}ID|INT) ID | 'null' ) ';' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "void a b;")
|
|
self.assertEquals("void a b ;", found)
|
|
|
|
|
|
def testInvokeRule(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : type ID ;
|
|
type : {pass}'int' | 'float' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "int a")
|
|
self.assertEquals("int a", found)
|
|
|
|
|
|
def testInvokeRuleAsRoot(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : type^ ID ;
|
|
type : {pass}'int' | 'float' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "int a")
|
|
self.assertEquals("(int a)", found)
|
|
|
|
|
|
def testInvokeRuleAsRootWithLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : x=type^ ID ;
|
|
type : {pass}'int' | 'float' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "int a")
|
|
self.assertEquals("(int a)", found)
|
|
|
|
|
|
def testInvokeRuleAsRootWithListLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : x+=type^ ID ;
|
|
type : {pass}'int' | 'float' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "int a")
|
|
self.assertEquals("(int a)", found)
|
|
|
|
|
|
def testRuleRootInLoop(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ID ('+'^ ID)* ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a+b+c+d")
|
|
self.assertEquals("(+ (+ (+ a b) c) d)", found)
|
|
|
|
|
|
def testRuleInvocationRuleRootInLoop(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ID (op^ ID)* ;
|
|
op : {pass}'+' | '-' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a+b+c-d")
|
|
self.assertEquals("(- (+ (+ a b) c) d)", found)
|
|
|
|
|
|
def testTailRecursion(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
s : a ;
|
|
a : atom ('exp'^ a)? ;
|
|
atom : INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "s", "3 exp 4 exp 5")
|
|
self.assertEquals("(exp 3 (exp 4 5))", found)
|
|
|
|
|
|
def testSet(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ID|INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "abc")
|
|
self.assertEquals("abc", found)
|
|
|
|
|
|
def testSetRoot(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ('+' | '-')^ ID ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "+abc")
|
|
self.assertEquals("(+ abc)", found)
|
|
|
|
|
|
@testbase.broken(
|
|
"FAILS until antlr.g rebuilt in v3", testbase.GrammarCompileError)
|
|
def testSetRootWithLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : x=('+' | '-')^ ID ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "+abc")
|
|
self.assertEquals("(+ abc)", found)
|
|
|
|
|
|
def testSetAsRuleRootInLoop(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ID (('+'|'-')^ ID)* ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a+b-c")
|
|
self.assertEquals("(- (+ a b) c)", found)
|
|
|
|
|
|
def testNotSet(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ~ID '+' INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "34+2")
|
|
self.assertEquals("34 + 2", found)
|
|
|
|
|
|
def testNotSetWithLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : x=~ID '+' INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "34+2")
|
|
self.assertEquals("34 + 2", found)
|
|
|
|
|
|
def testNotSetWithListLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : x=~ID '+' INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "34+2")
|
|
self.assertEquals("34 + 2", found)
|
|
|
|
|
|
def testNotSetRoot(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ~'+'^ INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "34 55")
|
|
self.assertEquals("(34 55)", found)
|
|
|
|
|
|
def testNotSetRootWithLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ~'+'^ INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "34 55")
|
|
self.assertEquals("(34 55)", found)
|
|
|
|
|
|
def testNotSetRootWithListLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : ~'+'^ INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "34 55")
|
|
self.assertEquals("(34 55)", found)
|
|
|
|
|
|
def testNotSetRuleRootInLoop(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : INT (~INT^ INT)* ;
|
|
blort : '+' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "3+4+5")
|
|
self.assertEquals("(+ (+ 3 4) 5)", found)
|
|
|
|
|
|
@testbase.broken("FIXME: What happened to the semicolon?", AssertionError)
|
|
def testTokenLabelReuse(self):
|
|
# check for compilation problem due to multiple defines
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a returns [result] : id=ID id=ID {$result = "2nd id="+$id.text+";";} ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a b")
|
|
self.assertEquals("2nd id=b;a b", found)
|
|
|
|
|
|
def testTokenLabelReuse2(self):
|
|
# check for compilation problem due to multiple defines
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a returns [result]: id=ID id=ID^ {$result = "2nd id="+$id.text+',';} ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a b")
|
|
self.assertEquals("2nd id=b,(b a)", found)
|
|
|
|
|
|
def testTokenListLabelReuse(self):
|
|
# check for compilation problem due to multiple defines
|
|
# make sure ids has both ID tokens
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a returns [result] : ids+=ID ids+=ID {$result = "id list=["+",".join([t.text for t in $ids])+'],';} ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a b")
|
|
expecting = "id list=[a,b],a b"
|
|
self.assertEquals(expecting, found)
|
|
|
|
|
|
def testTokenListLabelReuse2(self):
|
|
# check for compilation problem due to multiple defines
|
|
# make sure ids has both ID tokens
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a returns [result] : ids+=ID^ ids+=ID {$result = "id list=["+",".join([t.text for t in $ids])+'],';} ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a b")
|
|
expecting = "id list=[a,b],(a b)"
|
|
self.assertEquals(expecting, found)
|
|
|
|
|
|
def testTokenListLabelRuleRoot(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : id+=ID^ ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a")
|
|
self.assertEquals("a", found)
|
|
|
|
|
|
def testTokenListLabelBang(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : id+=ID! ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a")
|
|
self.assertEquals("", found)
|
|
|
|
|
|
def testRuleListLabel(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a returns [result]: x+=b x+=b {
|
|
t=$x[1]
|
|
$result = "2nd x="+t.toStringTree()+',';
|
|
};
|
|
b : ID;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a b")
|
|
self.assertEquals("2nd x=b,a b", found)
|
|
|
|
|
|
def testRuleListLabelRuleRoot(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a returns [result] : ( x+=b^ )+ {
|
|
$result = "x="+$x[1].toStringTree()+',';
|
|
} ;
|
|
b : ID;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a b")
|
|
self.assertEquals("x=(b a),(b a)", found)
|
|
|
|
|
|
def testRuleListLabelBang(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a returns [result] : x+=b! x+=b {
|
|
$result = "1st x="+$x[0].toStringTree()+',';
|
|
} ;
|
|
b : ID;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a b")
|
|
self.assertEquals("1st x=a,b", found)
|
|
|
|
|
|
def testComplicatedMelange(self):
|
|
# check for compilation problem
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options {language=Python;output=AST;}
|
|
a : A b=B b=B c+=C c+=C D {s = $D.text} ;
|
|
A : 'a' ;
|
|
B : 'b' ;
|
|
C : 'c' ;
|
|
D : 'd' ;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "a b b c c d")
|
|
self.assertEquals("a b b c c d", found)
|
|
|
|
|
|
def testReturnValueWithAST(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
a returns [result] : ID b { $result = str($b.i) + '\n';} ;
|
|
b returns [i] : INT {$i=int($INT.text);} ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found = self.execParser(grammar, "a", "abc 34")
|
|
self.assertEquals("34\nabc 34", found)
|
|
|
|
|
|
def testSetLoop(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar T;
|
|
options { language=Python;output=AST; }
|
|
r : (INT|ID)+ ;
|
|
ID : 'a'..'z' + ;
|
|
INT : '0'..'9' +;
|
|
WS: (' ' | '\n' | '\\t')+ {$channel = HIDDEN;};
|
|
''')
|
|
|
|
found = self.execParser(grammar, "r", "abc 34 d")
|
|
self.assertEquals("abc 34 d", found)
|
|
|
|
|
|
def testExtraTokenInSimpleDecl(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
decl : type^ ID '='! INT ';'! ;
|
|
type : 'int' | 'float' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found, errors = self.execParser(grammar, "decl", "int 34 x=1;",
|
|
expectErrors=True)
|
|
self.assertEquals(["line 1:4 extraneous input u'34' expecting ID"],
|
|
errors)
|
|
self.assertEquals("(int x 1)", found) # tree gets correct x and 1 tokens
|
|
|
|
|
|
def testMissingIDInSimpleDecl(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
tokens {EXPR;}
|
|
decl : type^ ID '='! INT ';'! ;
|
|
type : 'int' | 'float' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found, errors = self.execParser(grammar, "decl", "int =1;",
|
|
expectErrors=True)
|
|
self.assertEquals(["line 1:4 missing ID at u'='"], errors)
|
|
self.assertEquals("(int <missing ID> 1)", found) # tree gets invented ID token
|
|
|
|
|
|
def testMissingSetInSimpleDecl(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
tokens {EXPR;}
|
|
decl : type^ ID '='! INT ';'! ;
|
|
type : 'int' | 'float' ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found, errors = self.execParser(grammar, "decl", "x=1;",
|
|
expectErrors=True)
|
|
self.assertEquals(["line 1:0 mismatched input u'x' expecting set None"], errors)
|
|
self.assertEquals("(<error: x> x 1)", found) # tree gets invented ID token
|
|
|
|
|
|
def testMissingTokenGivesErrorNode(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
a : ID INT ; // follow is EOF
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found, errors = self.execParser(grammar, "a", "abc", expectErrors=True)
|
|
self.assertEquals(["line 1:3 missing INT at '<EOF>'"], errors)
|
|
self.assertEquals("abc <missing INT>", found)
|
|
|
|
|
|
def testMissingTokenGivesErrorNodeInInvokedRule(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
a : b ;
|
|
b : ID INT ; // follow should see EOF
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found, errors = self.execParser(grammar, "a", "abc", expectErrors=True)
|
|
self.assertEquals(["line 1:3 mismatched input '<EOF>' expecting INT"], errors)
|
|
self.assertEquals("<mismatched token: <EOF>, resync=abc>", found)
|
|
|
|
|
|
def testExtraTokenGivesErrorNode(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
a : b c ;
|
|
b : ID ;
|
|
c : INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found, errors = self.execParser(grammar, "a", "abc ick 34",
|
|
expectErrors=True)
|
|
self.assertEquals(["line 1:4 extraneous input u'ick' expecting INT"],
|
|
errors)
|
|
self.assertEquals("abc 34", found)
|
|
|
|
|
|
def testMissingFirstTokenGivesErrorNode(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
a : ID INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found, errors = self.execParser(grammar, "a", "34", expectErrors=True)
|
|
self.assertEquals(["line 1:0 missing ID at u'34'"], errors)
|
|
self.assertEquals("<missing ID> 34", found)
|
|
|
|
|
|
def testMissingFirstTokenGivesErrorNode2(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
a : b c ;
|
|
b : ID ;
|
|
c : INT ;
|
|
ID : 'a'..'z'+ ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found, errors = self.execParser(grammar, "a", "34", expectErrors=True)
|
|
|
|
# finds an error at the first token, 34, and re-syncs.
|
|
# re-synchronizing does not consume a token because 34 follows
|
|
# ref to rule b (start of c). It then matches 34 in c.
|
|
self.assertEquals(["line 1:0 missing ID at u'34'"], errors)
|
|
self.assertEquals("<missing ID> 34", found)
|
|
|
|
|
|
def testNoViableAltGivesErrorNode(self):
|
|
grammar = textwrap.dedent(
|
|
r'''
|
|
grammar foo;
|
|
options {language=Python;output=AST;}
|
|
a : b | c ;
|
|
b : ID ;
|
|
c : INT ;
|
|
ID : 'a'..'z'+ ;
|
|
S : '*' ;
|
|
INT : '0'..'9'+;
|
|
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
|
''')
|
|
|
|
found, errors = self.execParser(grammar, "a", "*", expectErrors=True)
|
|
self.assertEquals(["line 1:0 no viable alternative at input u'*'"],
|
|
errors)
|
|
self.assertEquals("<unexpected: [@0,0:0=u'*',<6>,1:0], resync=*>",
|
|
found)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|