Skip to content

Commit

Permalink
added error handling for inconsistent object assignments to variables
Browse files Browse the repository at this point in the history
  • Loading branch information
drexlerd committed Apr 23, 2024
1 parent 5a8d902 commit e714ffc
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 64 deletions.
4 changes: 2 additions & 2 deletions include/loki/details/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class DomainParser
friend class ProblemParser;

public:
explicit DomainParser(const fs::path& file_path);
DomainParser(const fs::path& file_path, bool quiet = true);

/// @brief Get factories to create additional PDDL objects.
PDDLFactories& get_factories();
Expand Down Expand Up @@ -73,7 +73,7 @@ class ProblemParser
Problem m_problem;

public:
explicit ProblemParser(const fs::path& file_path, DomainParser& domain_parser);
explicit ProblemParser(const fs::path& file_path, DomainParser& domain_parser, bool quiet = true);

/// @brief Get position caches to be able to reference back to the input PDDL file.
const PDDLPositionCache& get_position_cache() const;
Expand Down
4 changes: 2 additions & 2 deletions include/loki/details/pddl/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,10 @@ class MismatchedFunctionSkeletonTermListError : public SemanticParserError
MismatchedFunctionSkeletonTermListError(const FunctionSkeleton& function_skeleton, const TermList& term_list, const std::string& error_handler_output);
};

class IncompatibleObjectTypeError : public SemanticParserError
class IncompatibleObjectToVariableError : public SemanticParserError
{
public:
IncompatibleObjectTypeError(const Object& object, const Variable& variable, const std::string& error_handler_output);
IncompatibleObjectToVariableError(const Object& object, const Variable& variable, const std::string& error_handler_output);
};

class UnexpectedDerivedPredicateInEffect : public SemanticParserError
Expand Down
4 changes: 0 additions & 4 deletions include/loki/details/pddl/scope.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@ class Scope
Bindings<Predicate> m_predicates;
Bindings<Predicate> m_derived_predicates;

std::unordered_map<Variable, TypeSet> m_variable_types;

public:
Scope(const PDDLErrorHandler& error_handler, const Scope* parent_scope = nullptr);

Expand All @@ -85,7 +83,6 @@ class Scope
std::optional<BindingSearchResult<Variable>> get_variable(const std::string& name) const;
std::optional<BindingSearchResult<Predicate>> get_predicate(const std::string& name) const;
std::optional<BindingSearchResult<Predicate>> get_derived_predicate(const std::string& name) const;
const TypeSet& get_variable_types(const Variable& variable) const;

/// @brief Insert a binding.
void insert_type(const std::string& name, const Type& type, const std::optional<Position>& position);
Expand All @@ -94,7 +91,6 @@ class Scope
void insert_variable(const std::string& name, const Variable& variable, const std::optional<Position>& position);
void insert_predicate(const std::string& name, const Predicate& predicate, const std::optional<Position>& position);
void insert_derived_predicate(const std::string& name, const Predicate& derived_predicate, const std::optional<Position>& position);
void insert_variable_types(const Variable& variable, const TypeSet& types);

/// @brief Get the error handler to print an error message.
const PDDLErrorHandler& get_error_handler() const;
Expand Down
File renamed without changes.
32 changes: 22 additions & 10 deletions src/utils/parser.cpp → src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,17 @@
namespace loki
{

DomainParser::DomainParser(const fs::path& file_path) :
DomainParser::DomainParser(const fs::path& file_path, bool quiet) :
m_file_path(file_path),
m_source(loki::read_file(file_path)),
m_position_cache(nullptr),
m_scopes(nullptr)
{
const auto start = std::chrono::high_resolution_clock::now();
std::cout << "Started parsing domain file: " << file_path << std::endl;
if (!quiet)
{
std::cout << "Started parsing domain file: " << file_path << std::endl;
}

/* Parse the AST */
auto node = ast::Domain();
Expand Down Expand Up @@ -83,9 +86,12 @@ DomainParser::DomainParser(const fs::path& file_path) :
const auto [vm_usage, resident_set] = process_mem_usage();
const auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
std::cout << "Finished parsing after " << duration.count() << " milliseconds." << std::endl;
std::cout << "Peak virtual memory: " << vm_usage << " KB." << std::endl;
std::cout << "Peak resident set size: " << resident_set << " KB." << std::endl;
if (!quiet)
{
std::cout << "Finished parsing after " << duration.count() << " milliseconds." << std::endl;
std::cout << "Peak virtual memory: " << vm_usage << " KB." << std::endl;
std::cout << "Peak resident set size: " << resident_set << " KB." << std::endl;
}
}

PDDLFactories& DomainParser::get_factories() { return m_factories; }
Expand All @@ -94,14 +100,17 @@ const PDDLPositionCache& DomainParser::get_position_cache() const { return *m_po

const Domain& DomainParser::get_domain() const { return m_domain; }

ProblemParser::ProblemParser(const fs::path& file_path, DomainParser& domain_parser) :
ProblemParser::ProblemParser(const fs::path& file_path, DomainParser& domain_parser, bool quiet) :
m_file_path(file_path),
m_source(loki::read_file(file_path)),
m_position_cache(nullptr),
m_scopes(nullptr)
{
const auto start = std::chrono::high_resolution_clock::now();
std::cout << "Started parsing problem file: " << file_path << std::endl;
if (!quiet)
{
std::cout << "Started parsing problem file: " << file_path << std::endl;
}

/* Parse the AST */
auto problem_node = ast::Problem();
Expand All @@ -128,9 +137,12 @@ ProblemParser::ProblemParser(const fs::path& file_path, DomainParser& domain_par
const auto [vm_usage, resident_set] = process_mem_usage();
const auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
std::cout << "Finished parsing after " << duration.count() << " milliseconds." << std::endl;
std::cout << "Peak virtual memory: " << vm_usage << " KB." << std::endl;
std::cout << "Peak resident set size: " << resident_set << " KB." << std::endl;
if (!quiet)
{
std::cout << "Finished parsing after " << duration.count() << " milliseconds." << std::endl;
std::cout << "Peak virtual memory: " << vm_usage << " KB." << std::endl;
std::cout << "Peak resident set size: " << resident_set << " KB." << std::endl;
}
}

const PDDLPositionCache& ProblemParser::get_position_cache() const { return *m_position_cache; }
Expand Down
2 changes: 1 addition & 1 deletion src/pddl/exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ UnexpectedDerivedPredicateInEffect::UnexpectedDerivedPredicateInEffect(const std
{
}

IncompatibleObjectTypeError::IncompatibleObjectTypeError(const Object& object, const Variable& variable, const std::string& error_handler_output) :
IncompatibleObjectToVariableError::IncompatibleObjectToVariableError(const Object& object, const Variable& variable, const std::string& error_handler_output) :
SemanticParserError("The object with name \"" + object->get_name() + "\" does not satisfy the type requirement of variable with name \""
+ variable->get_name() + "\".",
error_handler_output)
Expand Down
4 changes: 4 additions & 0 deletions src/pddl/parser/ground_literal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "common.hpp"
#include "loki/details/pddl/exceptions.hpp"
#include "objects.hpp"
#include "reference_utils.hpp"

namespace loki
{
Expand All @@ -34,15 +35,18 @@ Atom parse(const ast::AtomicFormulaOfNamesPredicate& node, Context& context)
throw UndefinedPredicateError(name, context.scopes.top().get_error_handler()(node, ""));
}
auto term_list = TermList();
auto positions = PositionList();
for (const auto& name_node : node.names)
{
term_list.push_back(context.factories.get_or_create_term_object(parse_object_reference(name_node, context)));
positions.push_back(name_node);
}
const auto [predicate, _position, _error_handler] = binding.value();
if (predicate->get_parameters().size() != term_list.size())
{
throw MismatchedPredicateTermListError(predicate, term_list, context.scopes.top().get_error_handler()(node, ""));
}
test_consistent_object_to_variable_assignment(predicate->get_parameters(), term_list, positions, context);
const auto atom = context.factories.get_or_create_atom(predicate, term_list);
context.positions.push_back(atom, node);
return atom;
Expand Down
4 changes: 4 additions & 0 deletions src/pddl/parser/literal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "common.hpp"
#include "loki/details/pddl/exceptions.hpp"
#include "reference_utils.hpp"

namespace loki
{
Expand All @@ -32,15 +33,18 @@ Atom parse(const ast::AtomicFormulaOfTermsPredicate& node, Context& context)
throw UndefinedPredicateError(predicate_name, context.scopes.top().get_error_handler()(node.predicate, ""));
}
auto term_list = TermList();
auto positions = PositionList();
for (const auto& term_node : node.terms)
{
term_list.push_back(boost::apply_visitor(TermReferenceTermVisitor(context), term_node));
positions.push_back(term_node);
}
const auto [predicate, _position, _error_handler] = binding.value();
if (predicate->get_parameters().size() != term_list.size())
{
throw MismatchedPredicateTermListError(predicate, term_list, context.scopes.top().get_error_handler()(node, ""));
}
test_consistent_object_to_variable_assignment(predicate->get_parameters(), term_list, positions, context);
context.references.untrack(predicate);
const auto atom = context.factories.get_or_create_atom(predicate, term_list);
context.positions.push_back(atom, node);
Expand Down
35 changes: 22 additions & 13 deletions src/pddl/parser/reference_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "reference_utils.hpp"

#include "loki/details/ast/ast.hpp"
#include "loki/details/pddl/exceptions.hpp"

namespace loki
Expand All @@ -42,30 +43,38 @@ void test_variable_references(const ParameterList& parameter_list, const Context
}
}

void track_variable_type_information(const ParameterList& parameter_list, Context& context)
static void test_object_type_consistent_with_variable(const Parameter& parameter, const Object& object, const Position& position, const Context& context)
{
for (const auto& parameter : parameter_list)
{
context.scopes.top().insert_variable_types(parameter->get_variable(), collect_types_from_hierarchy(parameter->get_bases()));
}
}

void test_object_type_consistent_with_variable(const Object& object, const Variable& variable, const Context& context)
{
const auto& variable_types = context.scopes.top().get_variable_types(variable);
// Object type must match any of those types.
const auto& parameter_types = TypeSet(parameter->get_bases().begin(), parameter->get_bases().end());
bool is_consistent = false;
for (const auto& type : collect_types_from_hierarchy(object->get_bases()))
{
if (variable_types.count(type))
if (parameter_types.count(type))
{
is_consistent = true;
break;
}
}
if (!is_consistent)
{
const auto [_object, position, error_handler] = context.scopes.top().get_object(object->get_name()).value();
throw IncompatibleObjectTypeError(object, variable, error_handler(position.value(), ""));
throw IncompatibleObjectToVariableError(object, parameter->get_variable(), context.scopes.top().get_error_handler()(position, ""));
}
}

void test_consistent_object_to_variable_assignment(const ParameterList& parameters,
const TermList& terms,
const PositionList& positions,
const Context& context)
{
assert(parameters.size() == terms.size());

for (size_t i = 0; i < parameters.size(); ++i)
{
if (const auto term_object = std::get_if<TermObjectImpl>(terms[i]))
{
test_object_type_consistent_with_variable(parameters[i], term_object->get_object(), positions[i], context);
}
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/pddl/parser/reference_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ extern void track_variable_references(const ParameterList& parameter_list, Conte

extern void test_variable_references(const ParameterList& parameter_list, const Context& context);

extern void track_variable_type_information(const ParameterList& parameter_list, Context& context);

extern void test_object_type_consistent_with_variable(const Object& object, const Variable& variable, const Context& context);
extern void
test_consistent_object_to_variable_assignment(const ParameterList& parameters, const TermList& terms, const PositionList& positions, const Context& context);

extern void track_predicate_references(const PredicateList& predicate_list, Context& context);

Expand Down
35 changes: 6 additions & 29 deletions src/pddl/scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ std::optional<BindingSearchResult<Type>> Scope::get_type(const std::string& name
{
const auto it = m_types.find(name);
if (it != m_types.end())
return std::make_tuple(it->second.first, it->second.second, m_error_handler);
return std::make_tuple(it->second.first, it->second.second, std::cref(m_error_handler));
if (m_parent_scope)
{
return m_parent_scope->get_type(name);
Expand All @@ -37,7 +37,7 @@ std::optional<BindingSearchResult<Object>> Scope::get_object(const std::string&
{
const auto it = m_objects.find(name);
if (it != m_objects.end())
return std::make_tuple(it->second.first, it->second.second, m_error_handler);
return std::make_tuple(it->second.first, it->second.second, std::cref(m_error_handler));
if (m_parent_scope)
{
return m_parent_scope->get_object(name);
Expand All @@ -49,7 +49,7 @@ std::optional<BindingSearchResult<FunctionSkeleton>> Scope::get_function_skeleto
{
const auto it = m_function_skeletons.find(name);
if (it != m_function_skeletons.end())
return std::make_tuple(it->second.first, it->second.second, m_error_handler);
return std::make_tuple(it->second.first, it->second.second, std::cref(m_error_handler));
if (m_parent_scope)
{
return m_parent_scope->get_function_skeleton(name);
Expand All @@ -61,7 +61,7 @@ std::optional<BindingSearchResult<Variable>> Scope::get_variable(const std::stri
{
const auto it = m_variables.find(name);
if (it != m_variables.end())
return std::make_tuple(it->second.first, it->second.second, m_error_handler);
return std::make_tuple(it->second.first, it->second.second, std::cref(m_error_handler));
if (m_parent_scope)
{
return m_parent_scope->get_variable(name);
Expand All @@ -73,7 +73,7 @@ std::optional<BindingSearchResult<Predicate>> Scope::get_predicate(const std::st
{
const auto it = m_predicates.find(name);
if (it != m_predicates.end())
return std::make_tuple(it->second.first, it->second.second, m_error_handler);
return std::make_tuple(it->second.first, it->second.second, std::cref(m_error_handler));
if (m_parent_scope)
{
return m_parent_scope->get_predicate(name);
Expand All @@ -85,31 +85,14 @@ std::optional<BindingSearchResult<Predicate>> Scope::get_derived_predicate(const
{
const auto it = m_derived_predicates.find(name);
if (it != m_derived_predicates.end())
return std::make_tuple(it->second.first, it->second.second, m_error_handler);
return std::make_tuple(it->second.first, it->second.second, std::cref(m_error_handler));
if (m_parent_scope)
{
return m_parent_scope->get_derived_predicate(name);
}
return std::nullopt;
}

const TypeSet& Scope::get_variable_types(const Variable& variable) const
{
const auto it = m_variable_types.find(variable);
if (it != m_variable_types.end())
{
return it->second;
}
if (m_parent_scope)
{
return m_parent_scope->get_variable_types(variable);
}
else
{
throw std::logic_error("Expected types of variable to be known.");
}
}

void Scope::insert_type(const std::string& name, const Type& element, const std::optional<Position>& position)
{
assert(!this->get_type(name));
Expand Down Expand Up @@ -146,12 +129,6 @@ void Scope::insert_derived_predicate(const std::string& name, const Predicate& e
m_derived_predicates.emplace(name, BindingValueType<Predicate>(element, position));
}

void Scope::insert_variable_types(const Variable& variable, const TypeSet& types)
{
assert(!this->m_variable_types.count(variable));
m_variable_types.emplace(variable, types);
}

const PDDLErrorHandler& Scope::get_error_handler() const { return m_error_handler; }

ScopeStack::ScopeStack(const PDDLErrorHandler& error_handler, const ScopeStack* parent) : m_error_handler(error_handler), m_parent(parent) {}
Expand Down

0 comments on commit e714ffc

Please sign in to comment.