better exception formatting

This commit is contained in:
Jesse Bannon 2023-11-09 19:28:33 -08:00
parent fe3d0beaed
commit b5622ecc54
2 changed files with 52 additions and 32 deletions

View file

@ -1,3 +1,4 @@
from contextlib import contextmanager
from typing import Dict
from typing import List
from typing import Optional
@ -37,6 +38,24 @@ class _Parser:
"""
return self._syntax_tree
@contextmanager
def _error_formatting(self) -> None:
parked_pos = self._pos
try:
yield
except InvalidSyntaxException as exc:
border = 4
text_left = max(0, parked_pos - border)
text_right = min(len(self._text), self._pos + border)
text_len = text_right - text_left
raise InvalidSyntaxException(
"Invalid syntax:\n"
f" {self._text[text_left:text_right]}\n"
f" {' ' * border}{'^' * text_len}\n\n"
f"{str(exc)}"
) from exc
def _read(self, increment_pos: bool = True, length: int = 1) -> Optional[str]:
try:
ch = self._text[self._pos : (self._pos + length)]
@ -227,38 +246,39 @@ class _Parser:
key: Optional[ArgumentType] = None
in_comma = False
while ch := self._read(increment_pos=False):
if ch == "}":
if key is not None:
raise InvalidSyntaxException("Map has a key with no value")
with self._error_formatting():
while ch := self._read(increment_pos=False):
if ch == "}":
if key is not None:
raise InvalidSyntaxException("Map has a key with no value")
self._pos += 1
return UnresolvedMap(value=output)
elif ch == ",":
if in_comma:
raise StringFormattingException("Comma followed by comma")
if key is not None:
raise InvalidSyntaxException("Map has a key with no value")
if output is None:
raise StringFormattingException("Empty dict with comma")
in_comma = True
self._pos += 1
elif key is None:
in_comma = False
key_args = self._parse_args(breaking_chars=":")
if len(key_args) != 1:
raise StringFormattingException("Lazy parsing but got mlutiple args")
key = key_args[0]
elif key is not None and ch == ":":
self._pos += 1
value_args = self._parse_args(breaking_chars=",}")
if len(value_args) != 1:
raise InvalidSyntaxException("Map has a key with no value")
self._pos += 1
return UnresolvedMap(value=output)
elif ch == ",":
if in_comma:
raise StringFormattingException("Comma followed by comma")
if key is not None:
raise InvalidSyntaxException("Map has a key with no value")
if output is None:
raise StringFormattingException("Empty dict with comma")
in_comma = True
self._pos += 1
elif key is None:
in_comma = False
key_args = self._parse_args(breaking_chars=":")
if len(key_args) != 1:
raise StringFormattingException("Lazy parsing but got mlutiple args")
key = key_args[0]
elif key is not None and ch == ":":
self._pos += 1
value_args = self._parse_args(breaking_chars=",}")
if len(value_args) != 1:
raise InvalidSyntaxException("Map has a key with no value")
output[key] = value_args[0]
key = None
else:
raise StringFormattingException("Invalid map")
output[key] = value_args[0]
key = None
else:
raise StringFormattingException("Invalid map")
def _parse(self) -> SyntaxTree:
bracket_counter = 0

View file

@ -72,5 +72,5 @@ class TestMap:
],
)
def test_key_has_no_value(self, value: str):
with pytest.raises(InvalidSyntaxException, match=re.escape("Map has a key with no value")):
Script({"map": value}).resolve()
# with pytest.raises(InvalidSyntaxException, match=re.escape("Map has a key with no value")):
Script({"map": value}).resolve()