Commit 6919c326 authored by di68kap's avatar di68kap

- DHParser: parse.py: bugfix: Fehlermeldungen fehlten in History-Log

parent bf11f707
...@@ -372,8 +372,8 @@ def log_ST(syntax_tree, log_file_name): ...@@ -372,8 +372,8 @@ def log_ST(syntax_tree, log_file_name):
""" """
if is_logging(): if is_logging():
path = os.path.join(log_dir(), log_file_name) path = os.path.join(log_dir(), log_file_name)
if os.path.exists(path): # if os.path.exists(path):
print('WARNING: Log-file "%s" already exists and will be overwritten!' % path) # print('WARNING: Log-file "%s" already exists and will be overwritten!' % path)
with open(path, "w", encoding="utf-8") as f: with open(path, "w", encoding="utf-8") as f:
f.write(syntax_tree.as_sxpr()) f.write(syntax_tree.as_sxpr())
...@@ -401,7 +401,7 @@ def log_parsing_history(grammar, log_file_name: str = '', html: bool = True) -> ...@@ -401,7 +401,7 @@ def log_parsing_history(grammar, log_file_name: str = '', html: bool = True) ->
path = os.path.join(log_dir(), log_name + "_parser.log" + htm) path = os.path.join(log_dir(), log_name + "_parser.log" + htm)
if os.path.exists(path): if os.path.exists(path):
os.remove(path) os.remove(path)
print('WARNING: Log-file "%s" already existed and was deleted.' % path) # print('WARNING: Log-file "%s" already existed and was deleted.' % path)
if history: if history:
with open(path, "w", encoding="utf-8") as f: with open(path, "w", encoding="utf-8") as f:
if html: if html:
......
...@@ -106,9 +106,10 @@ class ParserError(Exception): ...@@ -106,9 +106,10 @@ class ParserError(Exception):
different kind of error like `UnknownParserError`, is when a `Series`- different kind of error like `UnknownParserError`, is when a `Series`-
detects a missing mandatory element. detects a missing mandatory element.
""" """
def __init__(self, node: Node, rest: StringView, first_throw: bool): def __init__(self, node: Node, rest: StringView, error: Optional[Error], first_throw: bool):
self.node = node # type: Node self.node = node # type: Node
self.rest = rest # type: StringView self.rest = rest # type: StringView
self.error = error # type: Optional[Error]
self.first_throw = first_throw # type: bool self.first_throw = first_throw # type: bool
def __str__(self): def __str__(self):
...@@ -263,6 +264,15 @@ class Parser: ...@@ -263,6 +264,15 @@ class Parser:
the business intelligence that is common to all parsers. The actual parsing is the business intelligence that is common to all parsers. The actual parsing is
done in the overridden method `_parse()`. done in the overridden method `_parse()`.
""" """
def get_error_node_id(error_node: Node, root_node: RootNode) -> int:
if error_node:
error_node_id = id(error_node)
while error_node_id not in grammar.tree__.error_nodes and error_node.children:
error_node = error_node.result[-1]
error_node_id = id(error_node)
else:
error_node_id = 0
grammar = self._grammar grammar = self._grammar
location = grammar.document_length__ - len(text) location = grammar.document_length__ - len(text)
...@@ -291,15 +301,16 @@ class Parser: ...@@ -291,15 +301,16 @@ class Parser:
(':RegExp', ':Token', ':DropToken') (':RegExp', ':Token', ':DropToken')
else self.tag_name) else self.tag_name)
grammar.moving_forward__ = True grammar.moving_forward__ = True
error = None
try: try:
# PARSER CALL: run _parse() method # PARSER CALL: run _parse() method
node, rest = self._parse(text) node, rest = self._parse(text)
except ParserError as error: except ParserError as pe:
# does this play well with variable setting? add rollback clause here? tests needed... # does this play well with variable setting? add rollback clause here? tests needed...
gap = len(text) - len(error.rest) gap = len(text) - len(pe.rest)
rules = grammar.resume_rules__.get(self.pname, []) rules = grammar.resume_rules__.get(self.pname, [])
rest = error.rest[len(error.node):] rest = pe.rest[len(pe.node):]
i = reentry_point(rest, rules) i = reentry_point(rest, rules)
if i >= 0 or self == grammar.start_parser__: if i >= 0 or self == grammar.start_parser__:
# apply reentry-rule or catch error at root-parser # apply reentry-rule or catch error at root-parser
...@@ -307,26 +318,28 @@ class Parser: ...@@ -307,26 +318,28 @@ class Parser:
i = 1 i = 1
nd = Node(ZOMBIE_TAG, rest[:i]).with_pos(location) nd = Node(ZOMBIE_TAG, rest[:i]).with_pos(location)
rest = rest[i:] rest = rest[i:]
assert error.node.children or (not error.node.result) assert pe.node.children or (not pe.node.result)
if error.first_throw: if pe.first_throw:
node = error.node node = pe.node
node.result = node.children + (nd,) node.result = node.children + (nd,)
else: else:
# TODO: ggf. Fehlermeldung, die sagt, wo es weitergeht anfügen # TODO: ggf. Fehlermeldung, die sagt, wo es weitergeht, anfügen;
# dürfte allerdings erst an den nächsten(!) Knoten angehängt werden (wie?) # dürfte allerdings erst an den nächsten(!) Knoten angehängt werden (wie?)
node = Node(self.tag_name, node = Node(self.tag_name,
(Node(ZOMBIE_TAG, text[:gap]).with_pos(location), (Node(ZOMBIE_TAG, text[:gap]).with_pos(location),
error.node, nd)) pe.node, nd))
elif error.first_throw: elif pe.first_throw:
raise ParserError(error.node, error.rest, first_throw=False) raise ParserError(pe.node, pe.rest, pe.error, first_throw=False)
else: else:
result = (Node(ZOMBIE_TAG, text[:gap]).with_pos(location), error.node) if gap \ result = (Node(ZOMBIE_TAG, text[:gap]).with_pos(location), pe.node) if gap \
else error.node # type: ResultType else pe.node # type: ResultType
if grammar.tree__.errors[-1].code == Error.MANDATORY_CONTINUATION_AT_EOF: # EXPERIMENTAL!! if grammar.tree__.errors[-1].code == Error.MANDATORY_CONTINUATION_AT_EOF: # EXPERIMENTAL!!
node = error.node node = pe.node
else: else:
raise ParserError(Node(self.tag_name, result).with_pos(location), raise ParserError(Node(self.tag_name, result).with_pos(location),
text, first_throw=False) text, pe.error, first_throw=False)
error = pe.error # needed for history tracking
if left_recursion_depth__: if left_recursion_depth__:
self.recursion_counter[location] -= 1 self.recursion_counter[location] -= 1
...@@ -343,6 +356,7 @@ class Parser: ...@@ -343,6 +356,7 @@ class Parser:
"Refactor grammar to avoid slow parsing.", "Refactor grammar to avoid slow parsing.",
node.pos if node else location, node.pos if node else location,
Error.LEFT_RECURSION_WARNING)) Error.LEFT_RECURSION_WARNING))
error_id = id(node)
grammar.last_recursion_location__ = location grammar.last_recursion_location__ = location
# don't overwrite any positive match (i.e. node not None) in the cache # don't overwrite any positive match (i.e. node not None) in the cache
# and don't add empty entries for parsers returning from left recursive calls! # and don't add empty entries for parsers returning from left recursive calls!
...@@ -372,13 +386,13 @@ class Parser: ...@@ -372,13 +386,13 @@ class Parser:
record = HistoryRecord(grammar.call_stack__, node, text, record = HistoryRecord(grammar.call_stack__, node, text,
grammar.line_col__(text)) grammar.line_col__(text))
grammar.history__.append(record) grammar.history__.append(record)
elif node: elif error:
nid = id(node) # type: int # error_nid = id(node) # type: int
if nid in grammar.tree__.error_nodes: # if error_nid in grammar.tree__.error_nodes:
record = HistoryRecord(grammar.call_stack__, node, text, record = HistoryRecord(grammar.call_stack__, node, text,
grammar.line_col__(text), grammar.line_col__(text),
grammar.tree__.error_nodes[nid]) [error])
grammar.history__.append(record) grammar.history__.append(record)
grammar.moving_forward__ = False grammar.moving_forward__ = False
grammar.call_stack__.pop() grammar.call_stack__.pop()
...@@ -1763,7 +1777,7 @@ class Series(NaryParser): ...@@ -1763,7 +1777,7 @@ class Series(NaryParser):
ret_node = self._return_values(results) # type: Node ret_node = self._return_values(results) # type: Node
if error: if error:
raise ParserError(ret_node.with_pos(self.grammar.document_length__ - len(text)), raise ParserError(ret_node.with_pos(self.grammar.document_length__ - len(text)),
text, first_throw=True) text, error, first_throw=True)
return ret_node, text_ return ret_node, text_
def __repr__(self): def __repr__(self):
...@@ -1980,7 +1994,7 @@ class AllOf(NaryParser): ...@@ -1980,7 +1994,7 @@ class AllOf(NaryParser):
nd = self._return_values(results) # type: Node nd = self._return_values(results) # type: Node
if error: if error:
raise ParserError(nd.with_pos(self.grammar.document_length__ - len(text)), raise ParserError(nd.with_pos(self.grammar.document_length__ - len(text)),
text, first_throw=True) text, error, first_throw=True)
return nd, text_ return nd, text_
def __repr__(self): def __repr__(self):
......
...@@ -22,9 +22,11 @@ import os ...@@ -22,9 +22,11 @@ import os
import sys import sys
scriptdir = os.path.dirname(os.path.abspath(__file__)) scriptdir = os.path.dirname(os.path.abspath(__file__))
i = scriptdir.find('DHParser') i, k = scriptdir.find('DHParser-submodule'), len('DHParser-submodule')
if i < 0:
i, k = scriptdir.find('DHParser'), len('DHParser')
if i >= 0: if i >= 0:
dhparserdir = scriptdir[:i + 8] dhparserdir = scriptdir[:i + k]
sys.path.append(dhparserdir) sys.path.append(dhparserdir)
else: else:
dhparserdir = '' dhparserdir = ''
......
...@@ -552,8 +552,8 @@ class LanguageServer(Server): ...@@ -552,8 +552,8 @@ class LanguageServer(Server):
def rpc_initialize(self, **kwargs): def rpc_initialize(self, **kwargs):
if self._server_initialized: if self._server_initialized:
return {"jsonrpc": "2.0", return {"jsonrpc": "2.0",
"error": {"code": -322002, "error": {"code": -322002,
"message": "Server has already been initialized."}, "message": "Server has already been initialized."},
"id": 0} "id": 0}
else: else:
result = self.initialize(**kwargs) result = self.initialize(**kwargs)
...@@ -566,8 +566,8 @@ class LanguageServer(Server): ...@@ -566,8 +566,8 @@ class LanguageServer(Server):
pass # clients must not reply to notifations! pass # clients must not reply to notifations!
# print('double notification!') # print('double notification!')
# return {"jsonrpc": "2.0", # return {"jsonrpc": "2.0",
# "error": {"code": -322002, # "error": {"code": -322002,
# "message": "Initialize Notification already received!"}, # "message": "Initialize Notification already received!"},
# "id": 0} # "id": 0}
else: else:
self._client_initialized = True self._client_initialized = True
......
...@@ -178,7 +178,7 @@ class Node: # (collections.abc.Sized): Base class omitted for cython-compatibil ...@@ -178,7 +178,7 @@ class Node: # (collections.abc.Sized): Base class omitted for cython-compatibil
S-Expression-output. S-Expression-output.
""" """
__slots__ = '_result', 'children', '_pos', 'tag_name', '_xml_attr', '_id' __slots__ = '_result', 'children', '_pos', 'tag_name', '_xml_attr'
def __init__(self, tag_name: str, result: ResultType, leafhint: bool = False) -> None: def __init__(self, tag_name: str, result: ResultType, leafhint: bool = False) -> None:
""" """
......
...@@ -39,7 +39,7 @@ from DHParser.stringview import StringView ...@@ -39,7 +39,7 @@ from DHParser.stringview import StringView
class TestParserError: class TestParserError:
def test_parser_error_str(self): def test_parser_error_str(self):
pe = ParserError(Node('TAG', 'test').with_pos(0), StringView('Beispiel'), True) pe = ParserError(Node('TAG', 'test').with_pos(0), StringView('Beispiel'), None, True)
assert str(pe).find('Beispiel') >= 0 and str(pe).find('TAG') >= 0 assert str(pe).find('Beispiel') >= 0 and str(pe).find('TAG') >= 0
...@@ -779,7 +779,7 @@ class TestReentryAfterError: ...@@ -779,7 +779,7 @@ class TestReentryAfterError:
class TestConfiguredErrorMessages: class TestConfiguredErrorMessages:
def test_(self): def test_configured_error_message(self):
lang = """ lang = """
document = series | /.*/ document = series | /.*/
@series_error = "a badly configured error message {5}" @series_error = "a badly configured error message {5}"
......
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