Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

Commit 447927f6 authored by di68kap's avatar di68kap
Browse files

- errors in user configured error messages are now caught and properly reported

parent 333f4a9a
......@@ -83,6 +83,7 @@ class Error:
PARSER_LOOKAHEAD_MATCH_ONLY = ErrorCode(1003)
PARSER_STOPPED_BEFORE_END = ErrorCode(1004)
CAPTURE_STACK_NOT_EMPTY = ErrorCode(1005)
MALFORMED_ERROR_STRING = ErrorCode(1006)
def __init__(self, message: str, pos, code: ErrorCode = ERROR,
orig_pos: int = -1, line: int = -1, column: int = -1) -> None:
......
......@@ -1424,8 +1424,14 @@ class Series(NaryOperator):
for search, message in self.err_msgs:
rxs = not isinstance(search, str)
if rxs and text_.match(search) or not rxs and text_.startswith(search):
msg = message.format(parser.repr, found)
break
try:
msg = message.format(parser.repr, found)
break
except (ValueError, KeyError, IndexError) as e:
error = Error("Malformed error format string '{}' lead to '{}'"
.format(message, str(e)),
location, Error.MALFORMED_ERROR_STRING)
self.grammar.tree__.add_error(node, error)
else:
msg = '%s expected, "%s" found!' % (parser.repr, found)
mandatory_violation = Error(msg, location, Error.MANDATORY_CONTINUATION)
......
......@@ -168,6 +168,7 @@ class StringView: # collections.abc.Sized
"""Returns the underlying string."""
return self._text
@cython.locals(_start=cython.int, _end=cython.int)
def count(self, sub: str, start: Optional[int] = None, end: Optional[int] = None) -> int:
"""Returns the number of non-overlapping occurrences of substring
`sub` in StringView S[start:end]. Optional arguments start and end
......@@ -181,8 +182,8 @@ class StringView: # collections.abc.Sized
elif start is None and end is None:
return self._text.count(sub, self._begin, self._end)
else:
start, end = real_indices(start, end, self._len)
return self._text.count(sub, self._begin + start, self._begin + end)
_start, _end = real_indices(start, end, self._len)
return self._text.count(sub, self._begin + _start, self._begin + _end)
@cython.locals(_start=cython.int, _end=cython.int)
def find(self, sub: str, start: Optional[int] = None, end: Optional[int] = None) -> int:
......@@ -202,6 +203,7 @@ class StringView: # collections.abc.Sized
_start, _end = real_indices(start, end, self._len)
return self._text.find(sub, self._begin + _start, self._begin + _end) - self._begin
@cython.locals(_start=cython.int, _end=cython.int)
def rfind(self, sub: str, start: Optional[int] = None, end: Optional[int] = None) -> int:
"""Returns the highest index in S where substring `sub` is found,
such that `sub` is contained within S[start:end]. Optional
......@@ -216,8 +218,8 @@ class StringView: # collections.abc.Sized
if start is None and end is None:
return self._text.rfind(sub, self._begin, self._end) - self._begin
else:
start, end = real_indices(start, end, self._len)
return self._text.rfind(sub, self._begin + start, self._begin + end) - self._begin
_start, _end = real_indices(start, end, self._len)
return self._text.rfind(sub, self._begin + _start, self._begin + _end) - self._begin
def startswith(self,
prefix: str,
......@@ -231,6 +233,7 @@ class StringView: # collections.abc.Sized
end = self._end if end is None else self._begin + end
return self._text.startswith(prefix, start, end)
def endswith(self,
suffix: str,
start: int = 0,
......@@ -286,6 +289,7 @@ class StringView: # collections.abc.Sized
"""
return regex.finditer(self._text, pos=self._begin, endpos=self._end)
@cython.locals(begin=cython.int, end=cython.int)
def strip(self):
"""Returns a copy of the StringView `self` with leading and trailing
whitespace removed.
......@@ -294,16 +298,19 @@ class StringView: # collections.abc.Sized
end = last_char(self._text, self._begin, self._end) - self._begin
return self if begin == 0 and end == self._len else self[begin:end]
@cython.locals(begin=cython.int)
def lstrip(self):
"""Returns a copy of `self` with leading whitespace removed."""
begin = first_char(self._text, self._begin, self._end) - self._begin
return self if begin == 0 else self[begin:]
@cython.locals(end=cython.int)
def rstrip(self):
"""Returns a copy of `self` with trailing whitespace removed."""
end = last_char(self._text, self._begin, self._end) - self._begin
return self if end == self._len else self[:end]
@cython.locals(length=cython.int, i=cython.int, k=cython.int)
def split(self, sep=None):
"""Returns a list of the words in `self`, using `sep` as the
delimiter string. If `sep` is not specified or is None, any
......
......@@ -29,9 +29,7 @@ try:
except ImportError:
import re
from DHParser.error import linebreaks, line_col, Error
from DHParser.dsl import grammar_provider, CompilationError
from DHParser.error import linebreaks, line_col
class TestErrorSupport:
def mini_suite(self, s, lbreaks, offset):
......
......@@ -728,6 +728,21 @@ class TestReentryAfterError:
assert len(cst.collect_errors()) == 2
class TestConfiguredErrorMessages:
def test_(self):
lang = """
document = series | /.*/
@series_error = "a badly configured error message {5}"
series = "X" | head §"C" "D"
head = "A" "B"
"""
parser = grammar_provider(lang)()
st = parser("AB_D"); assert st.error_flag
assert st.collect_errors()[0].code == Error.MALFORMED_ERROR_STRING
assert st.collect_errors()[1].code == Error.MANDATORY_CONTINUATION
# print(st.collect_errors())
class TestUnknownParserError:
def test_unknown_parser_error(self):
gr = Grammar()
......@@ -738,6 +753,7 @@ class TestUnknownParserError:
pass
if __name__ == "__main__":
from DHParser.testing import runner
with logging(False):
......
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