From 662eee92f3de1806657a04ca80b1df6b9b13add6 Mon Sep 17 00:00:00 2001 From: MarcoFavorito Date: Wed, 7 Jun 2023 14:28:10 +0200 Subject: [PATCH] feat: use TypesIndex to parse and validate typed_list_variables --- pddl/parser/domain.lark | 2 +- pddl/parser/domain.py | 58 +++++++++++++++----------------------- pddl/parser/types_index.py | 4 +++ 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/pddl/parser/domain.lark b/pddl/parser/domain.lark index 09fed45..d8633f8 100644 --- a/pddl/parser/domain.lark +++ b/pddl/parser/domain.lark @@ -50,7 +50,7 @@ atomic_formula_term: LPAR predicate term* RPAR constant: NAME typed_list_variable: variable* - | variable+ TYPE_SEP type_def (typed_list_variable) + | (variable+ TYPE_SEP type_def)+ variable* ?variable: "?" NAME typed_list_name: NAME* diff --git a/pddl/parser/domain.py b/pddl/parser/domain.py index 531fa7b..0c41a2a 100644 --- a/pddl/parser/domain.py +++ b/pddl/parser/domain.py @@ -12,14 +12,16 @@ """Implementation of the PDDL domain parser.""" import sys -from typing import AbstractSet, Dict, List, Mapping, Optional, Sequence, Set, Tuple +from typing import AbstractSet, Dict, Optional +from typing import OrderedDict as OrderedDictType +from typing import Sequence, Set from lark import Lark, ParseError, Transformer from pddl.core import Action, Domain, Requirements from pddl.custom_types import name from pddl.exceptions import PDDLMissingRequirementError, PDDLParsingError -from pddl.helpers.base import assert_, safe_index +from pddl.helpers.base import assert_ from pddl.logic.base import ( And, ExistsCondition, @@ -307,7 +309,7 @@ def typed_list_name(self, args) -> Dict[name, Optional[name]]: f"error while parsing tokens {list(map(str, args))}: {str(e)}" ) from None - def typed_list_variable(self, args) -> Dict[str, Set[str]]: + def typed_list_variable(self, args) -> OrderedDictType[name, Set[name]]: """ Process the 'typed_list_variable' rule. @@ -316,28 +318,27 @@ def typed_list_variable(self, args) -> Dict[str, Set[str]]: :param args: the argument of this grammar rule :return: a typed list (variable), i.e. a mapping from variables to the supported types """ - type_sep_index = safe_index(args, Symbols.TYPE_SEP.value) - if type_sep_index is None: - result = self._parse_simple_typed_list(args, check_for_duplicates=False) - return {var: set() for var in result} - - # if we are here, the matched pattern is: [name_1 ... name_n], "-", type_def, other_typed_list_dict # noqa - # make sure there are only two tokens after "-" - assert_(len(args[type_sep_index:]) == 3, "unexpected parser state") - - variables: Tuple[str, ...] = tuple(args[:type_sep_index]) - type_def: Set[str] = self._process_type_def(args[type_sep_index + 1]) - other_typed_list_dict: Mapping[str, Set[str]] = args[type_sep_index + 2] - new_typed_list_dict: Mapping[str, Set[str]] = {v: type_def for v in variables} - - # check type conflicts - self._check_duplicates(other_typed_list_dict.keys(), new_typed_list_dict.keys()) - - return {**new_typed_list_dict, **other_typed_list_dict} + try: + types_index = TypesIndex.parse_typed_list(args) + return types_index.get_typed_list_of_variables() + except ValueError as e: + raise PDDLParsingError( + f"error while parsing tokens {list(map(str, args))}: {str(e)}" + ) from None def type_def(self, args): """Parse the 'type_def' rule.""" - return args if len(args) == 1 else args[1:-1] + assert_(len(args) != 0, "unexpected parser state: empty type_def") + + if len(args) == 1: + # single-typed type-def, return + return args + + # if we are here, type_def is of the form (either t1 ... tn) + # ignore first and last tokens since they are brackets. + either_keyword, types = args[1], args[2:-1] + assert_(str(either_keyword) == Symbols.EITHER.value) + return types def _has_requirement(self, requirement: Requirements) -> bool: """Check whether a requirement is satisfied by the current state of the domain parsing.""" @@ -377,19 +378,6 @@ def _parse_simple_typed_list( return {arg: None for arg in args} - def _process_type_def(self, type_def: List[str]) -> Set[str]: - """Process a raw type_def and return a set of types.""" - assert_(len(type_def) != 0, "unexpected parser state: empty type_def") - - if len(type_def) == 1: - # single-typed type-def, return - return set(type_def) - - # if we are here, type_def is of the form (either t1 ... tn) - either_keyword, types = type_def[0], type_def[1:] - assert_(str(either_keyword) == Symbols.EITHER.value) - return set(types) - _domain_parser_lark = DOMAIN_GRAMMAR_FILE.read_text() diff --git a/pddl/parser/types_index.py b/pddl/parser/types_index.py index 3629cbe..121eec0 100644 --- a/pddl/parser/types_index.py +++ b/pddl/parser/types_index.py @@ -63,6 +63,10 @@ def get_typed_list_of_names(self) -> Dict[name, Optional[name]]: result[item] = type_tag return result + def get_typed_list_of_variables(self) -> OrderedDictType[name, Set[name]]: + """Get the typed list of variables in form of dictionary.""" + return self._item_to_types + @classmethod def parse_typed_list(cls, tokens: List[Union[str, List[str]]]) -> "TypesIndex": """