Commit d84004ae authored by Eckhart Arnold's avatar Eckhart Arnold
Browse files

Lookbehind operator

parent 0c9c4171
...@@ -1240,13 +1240,15 @@ def iter_right_branch(node) -> Iterator[Node]: ...@@ -1240,13 +1240,15 @@ def iter_right_branch(node) -> Iterator[Node]:
class Lookbehind(FlowOperator): class Lookbehind(FlowOperator):
"""EXPERIMENTAL AND NEVER TESTED!!!""" """EXPERIMENTAL AND NEVER TESTED!!!"""
def __init__(self, parser: Parser, name: str = '') -> None: def __init__(self, parser: Parser, name: str = '') -> None:
assert parser.name or isinstance(parser, RegExp)
super(Lookbehind, self).__init__(parser, name) super(Lookbehind, self).__init__(parser, name)
print("WARNING: Lookbehind Operator is experimental!") print("WARNING: Lookbehind Operator is experimental!")
def __call__(self, text: str) -> Tuple[Node, str]: def __call__(self, text: str) -> Tuple[Node, str]:
if isinstance(self.grammar.last_node__, Lookahead): node = self.grammar.last_node__
return Node(self, '').add_error('Lookbehind right after Lookahead ' # if isinstance(node.parser, Lookahead):
'does not make sense!'), text # return Node(self, '').add_error('Lookbehind right after Lookahead '
# 'does not make sense!'), text
if self.sign(self.condition()): if self.sign(self.condition()):
return Node(self, ''), text return Node(self, ''), text
else: else:
...@@ -1259,13 +1261,13 @@ class Lookbehind(FlowOperator): ...@@ -1259,13 +1261,13 @@ class Lookbehind(FlowOperator):
return bool_value return bool_value
def condition(self): def condition(self):
node = None node = self.grammar.last_node__
for node in iter_right_branch(self.grammar.last_node__): if node and isinstance(self.parser, RegExp) and self.parser.regexp.match(str(node)):
if node.parser.name == self.parser.name:
return True
if node and isinstance(self.parser, RegExp) and \
self.parser.regexp.match(str(node)): # Is there really a use case for this?
return True return True
elif self.parser.name:
for node in iter_right_branch(self.grammar.last_node__):
if node.parser.name == self.parser.name:
return True
return False return False
......
...@@ -53,7 +53,7 @@ Index = "\printindex" [PARSEP] ...@@ -53,7 +53,7 @@ Index = "\printindex" [PARSEP]
#### block environments #### #### block environments ####
# TODO: ambiguity between generic bock envieronments and generic inline environments # TODO: ambiguity between generic block envieronments and generic inline environments
block_environment = known_environment | generic_environment block_environment = known_environment | generic_environment
known_environment = itemize | enumerate | figure | table | quotation known_environment = itemize | enumerate | figure | table | quotation
......
...@@ -25,7 +25,8 @@ from functools import partial ...@@ -25,7 +25,8 @@ from functools import partial
sys.path.extend(['../', './']) sys.path.extend(['../', './'])
from DHParser.toolkit import is_logging, logging, compile_python_object from DHParser.toolkit import is_logging, logging, compile_python_object
from DHParser.parser import compile_source, Retrieve, Grammar, Forward, Token, ZeroOrMore, RE from DHParser.parser import compile_source, Retrieve, Grammar, Forward, Token, ZeroOrMore, RE, \
RegExp, Lookbehind, Lookahead, NegativeLookahead, OneOrMore
from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, get_ebnf_compiler from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, get_ebnf_compiler
from DHParser.dsl import grammar_provider, DHPARSER_IMPORTS from DHParser.dsl import grammar_provider, DHPARSER_IMPORTS
...@@ -97,6 +98,28 @@ class TestInfiLoopsAndRecursion: ...@@ -97,6 +98,28 @@ class TestInfiLoopsAndRecursion:
# print(syntax_tree.collect_errors()) # print(syntax_tree.collect_errors())
class TestFlowControl:
def test_lookbehind(self):
ws = RegExp('\s*')
end = RegExp("END")
doc_end = Lookbehind(RegExp('.*\n$')) + end
word = RegExp('\w+')
sequence = OneOrMore(NegativeLookahead(end) + word + ws)
document = ws + sequence + doc_end + ws
parser = Grammar(document)
t1 = """
All work and no play
makes Jack a dull boy
END
"""
cst = parser(t1)
assert not cst.error_flag, cst.as_sxpr()
t2 = "All word and not play makes Jack a dull boy END\n"
cst = parser(t2)
assert cst.error_flag, cst.as_sxpr()
class TestRegex: class TestRegex:
def test_multilineRegex(self): def test_multilineRegex(self):
mlregex = r""" mlregex = r"""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment