diff --git a/pddl/helpers/base.py b/pddl/helpers/base.py index d13bd6c..5839e27 100644 --- a/pddl/helpers/base.py +++ b/pddl/helpers/base.py @@ -13,6 +13,7 @@ """Helper functions.""" import re +import sys from pathlib import Path from typing import ( AbstractSet, @@ -25,8 +26,11 @@ Sequence, Set, Type, + TypeVar, ) +from lark import Lark, Transformer + def _get_current_path() -> Path: """Get the path to the file where the function is called.""" @@ -191,3 +195,30 @@ def find_cycle(graph: Dict[str, Optional[AbstractSet[str]]]) -> Optional[Sequenc stack.append((neighbor, path + [current])) return None + + +T = TypeVar("T") + + +def call_parser(text: str, parser: Lark, transformer: Transformer[Any, T]) -> T: + """ + Parse a text with a Lark parser and transformer. + + To produce a better traceback in case of an error, the function will temporarily overwrite the sys.tracebacklimit + value of the current interpreter. + + :param text: the text to parse + :param parser: the Lark parser object + :param transformer: the Lark transformer object + :return: the object returned by the parser + """ + old_tracebacklimit = getattr(sys, "tracebacklimit", None) + try: + sys.tracebacklimit = 0 # noqa + tree = parser.parse(text) + sys.tracebacklimit = None # type: ignore + result = transformer.transform(tree) + finally: + if old_tracebacklimit is not None: + sys.tracebacklimit = old_tracebacklimit + return result diff --git a/pddl/parser/domain.py b/pddl/parser/domain.py index d9e00cc..d257e0d 100644 --- a/pddl/parser/domain.py +++ b/pddl/parser/domain.py @@ -11,7 +11,6 @@ # """Implementation of the PDDL domain parser.""" -import sys from typing import Any, Dict, Optional, Set, Tuple from lark import Lark, ParseError, Transformer @@ -20,7 +19,7 @@ from pddl.core import Domain from pddl.custom_types import name from pddl.exceptions import PDDLMissingRequirementError, PDDLParsingError -from pddl.helpers.base import assert_ +from pddl.helpers.base import assert_, call_parser from pddl.logic.base import And, ExistsCondition, ForallCondition, Imply, Not, OneOf, Or from pddl.logic.effects import AndEffect, Forall, When from pddl.logic.functions import Assign, Decrease, Divide @@ -462,8 +461,4 @@ def __init__(self): def __call__(self, text: str) -> Domain: """Call.""" - sys.tracebacklimit = 0 # noqa - tree = self._parser.parse(text) - sys.tracebacklimit = None # type: ignore - formula = self._transformer.transform(tree) - return formula + return call_parser(text, self._parser, self._transformer) diff --git a/pddl/parser/problem.py b/pddl/parser/problem.py index c59b172..314cb97 100644 --- a/pddl/parser/problem.py +++ b/pddl/parser/problem.py @@ -11,14 +11,13 @@ # """Implementation of the PDDL problem parser.""" -import sys from typing import Any, Dict from lark import Lark, ParseError, Transformer from pddl.core import Problem from pddl.exceptions import PDDLParsingError -from pddl.helpers.base import assert_ +from pddl.helpers.base import assert_, call_parser from pddl.logic.base import And, Not from pddl.logic.functions import Divide from pddl.logic.functions import EqualTo as FunctionEqualTo @@ -242,10 +241,6 @@ def __init__(self): _problem_parser_lark, parser="lalr", import_paths=[PARSERS_DIRECTORY] ) - def __call__(self, text) -> Problem: + def __call__(self, text: str) -> Problem: """Call.""" - sys.tracebacklimit = 0 # noqa - tree = self._parser.parse(text) - sys.tracebacklimit = None # type: ignore - formula = self._transformer.transform(tree) - return formula + return call_parser(text, self._parser, self._transformer)