Commit 791b86d6 authored by eckhart's avatar eckhart
Browse files

test/test_ebnf.py: new test case: customized comments and whitespace in resume regexes

parent de5c1825
DHParser Version 0.9.1
......................
- added support for tag-less parsers: i.e. parser that are assigned to a
symbol with leading underscore will be treated as anonymous parsers
- resuming after an error does not jump in to commentaries, any more (bugfix!)
DHParser Version 0.9.0 (20.10.2019)
......
......@@ -736,6 +736,7 @@ class EBNFCompiler(Compiler):
string search or a regular expression from the nodes content. Returns
an empty string in case the node is neither regexp nor literal.
"""
# self.directives.whitespace, self.directives.comment
if nd.tag_name == 'regexp':
return unrepr("re.compile(r'%s')" % self._extract_regex(nd))
elif nd.tag_name == 'literal':
......
......@@ -375,19 +375,29 @@ class Parser:
rest = pe.rest[len(pe.node):]
i = reentry_point(rest, rules, grammar.comment_rx__)
if i >= 0 or self == grammar.start_parser__:
assert pe.node.children or (not pe.node.result)
# apply reentry-rule or catch error at root-parser
if i < 0:
i = 1
nd = Node(ZOMBIE_TAG, rest[:i]).with_pos(location)
nd.attr['err'] = pe.error.message
try:
zombie = pe.node[ZOMBIE_TAG]
except KeyError:
zombie = None
if zombie and not zombie.result:
zombie.result = rest[:i]
tail = tuple()
else:
nd = Node(ZOMBIE_TAG, rest[:i]).with_pos(location)
nd.attr['err'] = pe.error.message
tail = (nd,)
rest = rest[i:]
assert pe.node.children or (not pe.node.result)
if pe.first_throw:
node = pe.node
node.result = node.children + (nd,)
node.result = node.children + tail
else:
node = Node(self.tag_name,
(Node(ZOMBIE_TAG, text[:gap]).with_pos(location), pe.node, nd))
node = Node(
self.tag_name,
(Node(ZOMBIE_TAG, text[:gap]).with_pos(location), pe.node) + tail)
elif pe.first_throw:
raise ParserError(pe.node, pe.rest, pe.error, first_throw=False)
elif grammar.tree__.errors[-1].code == Error.MANDATORY_CONTINUATION_AT_EOF:
......@@ -399,7 +409,6 @@ class Parser:
text, pe.error, first_throw=False)
error = pe.error # needed for history tracking
if left_recursion_depth__:
self.recursion_counter[location] -= 1
# don't clear recursion_locations__ !!!
......@@ -1098,9 +1107,6 @@ class Grammar:
h = HistoryRecord([], None, StringView(''), (0, 0))
if h.status == h.MATCH and (h.node.pos + len(h.node) == len(self.document__)):
# TODO: this case still needs unit-tests and support in testing.py
for j in self.history__:
print(j)
print(h); print()
error_msg = "Parser stopped before end, but matched with lookahead."
error_code = Error.PARSER_LOOKAHEAD_MATCH_ONLY
max_parser_dropouts = -1 # no further retries!
......
......@@ -573,7 +573,8 @@ class Node: # (collections.abc.Sized): Base class omitted for cython-compatibil
for child in self.children:
if mf(child):
return child
raise KeyError(str(key))
raise IndexError('index out of range') if isinstance(key, int) \
else KeyError(str(key))
raise ValueError('Leaf-nodes have no children that can be indexed!')
def __contains__(self, what: CriteriaType) -> bool:
......
......@@ -42,4 +42,4 @@ Fail-test "F1"
% comment
### Messages:
Error (1040): Parser stopped before end! trying to recover but stopping history recording at this point.
\ No newline at end of file
1:1: Error (1040): Parser stopped before end! Terminating parser.
\ No newline at end of file
......@@ -63,7 +63,7 @@ class jsonGrammar(Grammar):
r"""Parser for a json source file.
"""
_element = Forward()
source_hash__ = "0a609252bf6179c3e939bc132665e70a"
source_hash__ = "31833295329c0325d087229c3d932092"
static_analysis_pending__ = [True]
parser_initialization__ = ["upon instantiation"]
resume_rules__ = {}
......
......@@ -639,6 +639,21 @@ class TestCustomizedResumeParsing:
# because of resuming, there should be only on error message
assert len(cst.errors_sorted) == 1
def test_resume_with_customized_whitespace(self):
grammar_specification = r"""
@whitespace = /\s*/
@comment = /(?:\/\*(?:.|\n)*?\*\/)/ # c-style comments
document = ~ { word }
@ word_resume = /\s+(?=.)|$/
word = !EOF §/\w+/ ~
EOF = !/./
"""
doc1 = """word no*word /* comment */ word"""
grammar = grammar_provider(grammar_specification)()
st = grammar(doc1)
# TODO: provide test case
# print(st.as_sxpr())
class TestInSeriesResume:
def setup(self):
......
......@@ -858,7 +858,6 @@ class TestReentryAfterError:
# test regex-defined resume rule
grammar = grammar_provider(lang)()
print(grammar.resume_rules__)
mini_suite(grammar)
......
......@@ -160,9 +160,6 @@ class TestTokenParsing:
def test_parse_tokenized(self):
cst = self.grammar(self.tokenized)
# for e in cst.errors(self.tokenized):
# print(e.visualize(self.tokenized) + str(e))
# print()
assert not cst.error_flag
def test_source_mapping_1(self):
......@@ -206,7 +203,6 @@ class TestTokenParsing:
result, messages, syntaxtree = compile_source(orig_src, prepr, self.grammar,
lambda i: i, lambda i: i)
for err in messages:
print(err)
if self.code[err.orig_pos] == "#":
break
else:
......
Supports Markdown
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