some better error handling

This commit is contained in:
Maximilian Keßler 2022-02-17 23:16:41 +01:00
parent 8ad8366158
commit 75e705c810
3 changed files with 67 additions and 19 deletions

View file

@ -1,6 +1,27 @@
from typing import Optional
class PyTeXError(Exception): class PyTeXError(Exception):
pass def __init__(self, msg, explanation: Optional[str] = None):
self._msg = msg
self._traceback_explanation = []
if explanation is not None:
self._traceback_explanation.append(explanation)
super().__init__(self._dispstr())
def _dispstr(self):
depth = 0
ret = [self._msg]
for explanation in self._traceback_explanation:
ret.append(' ' * 2 * depth + explanation)
depth += 1
return '\n'.join(ret)
def add_explanation(self, explanation: str):
self._traceback_explanation.append(explanation)
def __str__(self):
return self._dispstr()
class PyTeXFormattingError(PyTeXError): class PyTeXFormattingError(PyTeXError):

View file

@ -158,7 +158,9 @@ class MacroCodeBeginMacro(SingleLineMacro):
def _apply(self, line: str, formatter) -> Union[str, List[str]]: def _apply(self, line: str, formatter) -> Union[str, List[str]]:
if not formatter.mode == FormatterMode.meta: if not formatter.mode == FormatterMode.meta:
raise PyTeXInvalidBeginMacroCodeUsageError raise PyTeXInvalidBeginMacroCodeUsageError(
r"\begin{macrocode} used outside meta context"
)
formatter.mode = FormatterMode.macrocode formatter.mode = FormatterMode.macrocode
return r'% \begin{macrocode}' return r'% \begin{macrocode}'
@ -169,7 +171,9 @@ class MacroCodeEndMacro(SingleLineMacro):
def _apply(self, line: str, formatter) -> Union[str, List[str]]: def _apply(self, line: str, formatter) -> Union[str, List[str]]:
if not formatter.mode == FormatterMode.macrocode: if not formatter.mode == FormatterMode.macrocode:
raise PyTeXInvalidEndMacroCodeUsageError raise PyTeXInvalidEndMacroCodeUsageError(
r"\end{macrocode} used outside macrocode context"
)
formatter.mode = FormatterMode.meta formatter.mode = FormatterMode.meta
return r'% \end{macrocode}' return r'% \end{macrocode}'

View file

@ -7,6 +7,7 @@ from .macros import Macro
from .pytex_formatter import PyTeXFormatter from .pytex_formatter import PyTeXFormatter
from .enums import * from .enums import *
from ..logger import logger from ..logger import logger
from .errors import *
class LineStream: class LineStream:
@ -15,6 +16,7 @@ class LineStream:
self._handle = open(filename, 'r') self._handle = open(filename, 'r')
self._cached_lines: List[str] = [] self._cached_lines: List[str] = []
self._file_exhausted: bool = False self._file_exhausted: bool = False
self._line_number: int = 0
def current_line(self): def current_line(self):
return self.future_line(0) return self.future_line(0)
@ -47,6 +49,7 @@ class LineStream:
self._cached_lines.append( self._cached_lines.append(
self._handle.readline() self._handle.readline()
) )
self._line_number += 1
if self._cached_lines[-1] == '': if self._cached_lines[-1] == '':
self._handle.close() self._handle.close()
self._file_exhausted = True self._file_exhausted = True
@ -57,6 +60,10 @@ class LineStream:
b = len(self._cached_lines) == 0 b = len(self._cached_lines) == 0
return a & b return a & b
@property
def line_number(self) -> int:
return self._line_number
class TexFormatter(PyTeXFormatter, ABC): class TexFormatter(PyTeXFormatter, ABC):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -102,13 +109,21 @@ class TexFormatter(PyTeXFormatter, ABC):
self._macros = macros self._macros = macros
def _handle_macro(self, macro: Macro): def _handle_macro(self, macro: Macro):
replacement, shipout = macro.apply( try:
self.line_stream.current_line(), replacement, shipout = macro.apply(
self self.line_stream.current_line(),
) self
)
except PyTeXMacroError as e:
e.add_explanation('While applying macro')
raise e
if shipout: if shipout:
self.line_stream.pop_line() self.line_stream.pop_line()
self._shipout_line(replacement) if isinstance(replacement, str):
self._shipout_line(replacement)
else:
for line in replacement:
self._shipout_line(line)
else: else:
if isinstance(replacement, str): if isinstance(replacement, str):
self.line_stream.set_line(replacement) self.line_stream.set_line(replacement)
@ -150,13 +165,13 @@ class TexFormatter(PyTeXFormatter, ABC):
def mode(self, mode: FormatterMode) -> None: def mode(self, mode: FormatterMode) -> None:
self._mode = mode self._mode = mode
def _get_provides_text(self) -> str: def _get_provides_text(self, provided_type: str) -> str:
if self.config.has_description: if self.config.has_description:
if self.config.tex_flavour == TeXFlavour.LaTeX2e: if self.config.tex_flavour == TeXFlavour.LaTeX2e:
return \ return \
r'\Provides%s{%s}[%s - %s]' \ r'\Provides%s{%s}[%s - %s]' \
% ( % (
self.config.tex_type.value.capitalize(), provided_type,
self.name, self.name,
self.attribute_dict[FormatterProperty.date.value], self.attribute_dict[FormatterProperty.date.value],
self.attribute_dict[FormatterProperty.description.value] self.attribute_dict[FormatterProperty.description.value]
@ -166,7 +181,7 @@ class TexFormatter(PyTeXFormatter, ABC):
return \ return \
'\\ProvidesExpl%s { %s } { %s } { %s }\n { %s }' \ '\\ProvidesExpl%s { %s } { %s } { %s }\n { %s }' \
% ( % (
self.config.tex_type.value.capitalize(), provided_type,
self.name, self.name,
self.attribute_dict[FormatterProperty.date.value], self.attribute_dict[FormatterProperty.date.value],
self.config.version, self.config.version,
@ -183,14 +198,22 @@ class TexFormatter(PyTeXFormatter, ABC):
def format_document(self) -> None: def format_document(self) -> None:
while not self.line_stream.exhausted: while not self.line_stream.exhausted:
recent_replacement = True try:
while recent_replacement: recent_replacement = True
recent_replacement = False while recent_replacement:
for macro in self.macros: recent_replacement = False
if macro.matches(self.line_stream.current_line()): for macro in self.macros:
self._handle_macro(macro) if macro.matches(self.line_stream.current_line()):
recent_replacement = True try:
break self._handle_macro(macro)
except PyTeXMacroError as e:
e.add_explanation('while handling macro')
raise e
recent_replacement = True
break
except PyTeXMacroError as e:
e.add_explanation(f'in line {self.line_stream.line_number} ({self.line_stream.current_line().rstrip()})')
pass
self._shipout_line(self._post_process_line( self._shipout_line(self._post_process_line(
self.line_stream.pop_line() self.line_stream.pop_line()
)) ))