@@ -52,29 +52,29 @@ class ParserConf: | |||||
class Pattern(object): | class Pattern(object): | ||||
def __init__(self, value, flags=None): | |||||
def __init__(self, value, flags=()): | |||||
self.value = value | self.value = value | ||||
self.flags = flags | |||||
self.flags = frozenset(flags) | |||||
def __repr__(self): | def __repr__(self): | ||||
return repr(self.to_regexp()) | return repr(self.to_regexp()) | ||||
# Pattern Hashing assumes all subclasses have a different priority! | # Pattern Hashing assumes all subclasses have a different priority! | ||||
def __hash__(self): | def __hash__(self): | ||||
return hash((type(self), self.value)) | |||||
return hash((type(self), self.value, self.flags)) | |||||
def __eq__(self, other): | def __eq__(self, other): | ||||
return type(self) == type(other) and self.value == other.value | |||||
return type(self) == type(other) and self.value == other.value and self.flags == other.flags | |||||
if Py36: | if Py36: | ||||
# Python 3.6 changed syntax for flags in regular expression | # Python 3.6 changed syntax for flags in regular expression | ||||
def _get_flags(self, value): | def _get_flags(self, value): | ||||
for f in self.flags or (): | |||||
for f in self.flags: | |||||
value = ('(?%s:%s)' % (f, value)) | value = ('(?%s:%s)' % (f, value)) | ||||
return value | return value | ||||
else: | else: | ||||
def _get_flags(self, value): | def _get_flags(self, value): | ||||
for f in self.flags or (): | |||||
for f in self.flags: | |||||
value = ('(?%s)' % f) + value | value = ('(?%s)' % f) + value | ||||
return value | return value | ||||
@@ -332,7 +332,7 @@ def _literal_to_pattern(literal): | |||||
s = s.replace('\\\\', '\\') | s = s.replace('\\\\', '\\') | ||||
return { 'STRING': PatternStr, | return { 'STRING': PatternStr, | ||||
'REGEXP': PatternRE }[literal.type](s, flags or None) | |||||
'REGEXP': PatternRE }[literal.type](s, flags) | |||||
class PrepareLiterals(InlineTransformer): | class PrepareLiterals(InlineTransformer): | ||||
@@ -368,7 +368,7 @@ class TokenTreeToPattern(Transformer): | |||||
def expansions(self, exps): | def expansions(self, exps): | ||||
if len(exps) == 1: | if len(exps) == 1: | ||||
return exps[0] | return exps[0] | ||||
assert all(i.flags is None for i in exps) | |||||
assert all(not i.flags for i in exps) | |||||
return PatternRE('(?:%s)' % ('|'.join(i.to_regexp() for i in exps))) | return PatternRE('(?:%s)' % ('|'.join(i.to_regexp() for i in exps))) | ||||
def expr(self, args): | def expr(self, args): | ||||
@@ -750,13 +750,13 @@ def _make_parser_test(LEXER, PARSER): | |||||
tree = l.parse('aA') | tree = l.parse('aA') | ||||
self.assertEqual(tree.children, ['a', 'A']) | self.assertEqual(tree.children, ['a', 'A']) | ||||
g = """!start: "a"i "a" | |||||
""" | |||||
self.assertRaises(GrammarError, _Lark, g) | |||||
# g = """!start: "a"i "a" | |||||
# """ | |||||
# self.assertRaises(GrammarError, _Lark, g) | |||||
g = """!start: /a/i /a/ | |||||
""" | |||||
self.assertRaises(GrammarError, _Lark, g) | |||||
# g = """!start: /a/i /a/ | |||||
# """ | |||||
# self.assertRaises(GrammarError, _Lark, g) | |||||
g = """start: NAME "," "a" | g = """start: NAME "," "a" | ||||
NAME: /[a-z_]/i /[a-z0-9_]/i* | NAME: /[a-z_]/i /[a-z0-9_]/i* | ||||