@@ -1,5 +1,8 @@ | |||||
import re | import re | ||||
import sre_parse | import sre_parse | ||||
import sys | |||||
Py36 = (sys.version_info[:2] >= (3, 6)) | |||||
class GrammarError(Exception): | class GrammarError(Exception): | ||||
pass | pass | ||||
@@ -54,7 +57,7 @@ class Pattern(object): | |||||
self.flags = flags | self.flags = flags | ||||
def __repr__(self): | def __repr__(self): | ||||
return repr(self._get_flags() + self.value) | |||||
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): | ||||
@@ -62,15 +65,24 @@ class Pattern(object): | |||||
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 | ||||
def _get_flags(self): | |||||
if self.flags: | |||||
assert len(self.flags) == 1 | |||||
return '(?%s)' % self.flags | |||||
return '' | |||||
if Py36: | |||||
# Python 3.6 changed syntax for flags in regular expression | |||||
def _get_flags(self, value): | |||||
if self.flags: | |||||
assert len(self.flags) == 1 | |||||
return ('(?%s:%s)' % (self.flags[0], value)) | |||||
return value | |||||
else: | |||||
def _get_flags(self, value): | |||||
if self.flags: | |||||
assert len(self.flags) == 1 | |||||
return ('(?%s)' % self.flags) + value | |||||
return value | |||||
class PatternStr(Pattern): | class PatternStr(Pattern): | ||||
def to_regexp(self): | def to_regexp(self): | ||||
return self._get_flags() + re.escape(self.value) | |||||
return self._get_flags(re.escape(self.value)) | |||||
@property | @property | ||||
def min_width(self): | def min_width(self): | ||||
@@ -79,7 +91,7 @@ class PatternStr(Pattern): | |||||
class PatternRE(Pattern): | class PatternRE(Pattern): | ||||
def to_regexp(self): | def to_regexp(self): | ||||
return self._get_flags() + self.value | |||||
return self._get_flags(self.value) | |||||
@property | @property | ||||
def min_width(self): | def min_width(self): | ||||
@@ -30,12 +30,12 @@ def _read(n, *args): | |||||
class TestParsers(unittest.TestCase): | class TestParsers(unittest.TestCase): | ||||
def test_same_ast(self): | def test_same_ast(self): | ||||
"Tests that Earley and LALR parsers produce equal trees" | "Tests that Earley and LALR parsers produce equal trees" | ||||
g = Lark("""start: "(" name_list ("," "*" NAME)? ")" | |||||
g = Lark(r"""start: "(" name_list ("," "*" NAME)? ")" | |||||
name_list: NAME | name_list "," NAME | name_list: NAME | name_list "," NAME | ||||
NAME: /\w+/ """, parser='lalr') | NAME: /\w+/ """, parser='lalr') | ||||
l = g.parse('(a,b,c,*x)') | l = g.parse('(a,b,c,*x)') | ||||
g = Lark("""start: "(" name_list ("," "*" NAME)? ")" | |||||
g = Lark(r"""start: "(" name_list ("," "*" NAME)? ")" | |||||
name_list: NAME | name_list "," NAME | name_list: NAME | name_list "," NAME | ||||
NAME: /\w/+ """) | NAME: /\w/+ """) | ||||
l2 = g.parse('(a,b,c,*x)') | l2 = g.parse('(a,b,c,*x)') | ||||
@@ -507,7 +507,7 @@ def _make_parser_test(LEXER, PARSER): | |||||
g.parse("a" * (sys.getrecursionlimit() // 4)) | g.parse("a" * (sys.getrecursionlimit() // 4)) | ||||
def test_token_collision(self): | def test_token_collision(self): | ||||
g = _Lark("""start: "Hello" NAME | |||||
g = _Lark(r"""start: "Hello" NAME | |||||
NAME: /\w/+ | NAME: /\w/+ | ||||
%ignore " " | %ignore " " | ||||
""") | """) | ||||
@@ -517,7 +517,7 @@ def _make_parser_test(LEXER, PARSER): | |||||
self.assertSequenceEqual(x.children, ['HelloWorld']) | self.assertSequenceEqual(x.children, ['HelloWorld']) | ||||
def test_token_collision_WS(self): | def test_token_collision_WS(self): | ||||
g = _Lark("""start: "Hello" NAME | |||||
g = _Lark(r"""start: "Hello" NAME | |||||
NAME: /\w/+ | NAME: /\w/+ | ||||
%import common.WS | %import common.WS | ||||
%ignore WS | %ignore WS | ||||