Skip to content

Commit

Permalink
feat: use TypesIndex to parse and validate typed_list_variables
Browse files Browse the repository at this point in the history
  • Loading branch information
marcofavorito committed Jun 7, 2023
1 parent 889b3fc commit 662eee9
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 36 deletions.
2 changes: 1 addition & 1 deletion pddl/parser/domain.lark
Original file line number Diff line number Diff line change
Expand Up @@ -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*
Expand Down
58 changes: 23 additions & 35 deletions pddl/parser/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand All @@ -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."""
Expand Down Expand Up @@ -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()

Expand Down
4 changes: 4 additions & 0 deletions pddl/parser/types_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -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":
"""
Expand Down

0 comments on commit 662eee9

Please sign in to comment.