patrick
/
plasp
Archived
1
0
Fork 0
This repository has been archived on 2023-07-19. You can view files and clone it, but cannot push or open issues or pull requests.
plasp/src/plasp/pddl/Domain.cpp

259 lines
6.4 KiB
C++

#include <plasp/pddl/Domain.h>
#include <algorithm>
#include <plasp/pddl/ConsistencyException.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/utils/ParserException.h>
namespace plasp
{
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Domain
//
////////////////////////////////////////////////////////////////////////////////////////////////////
Domain Domain::fromPDDL(utils::Parser &parser)
{
Domain domain;
domain.m_name = parser.parseIdentifier(isIdentifier);
std::cout << "Parsing domain " << domain.m_name << std::endl;
parser.expect<std::string>(")");
while (true)
{
parser.skipWhiteSpace();
if (parser.currentCharacter() == ')')
break;
domain.parseSection(parser);
}
domain.computeDerivedRequirements();
domain.checkConsistency();
return domain;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
const std::string &Domain::name() const
{
return m_name;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
const Requirement::Types &Domain::requirements() const
{
return m_requirements;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
const Domain::TypesHashMap &Domain::types() const
{
return m_types;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Domain::parseSection(utils::Parser &parser)
{
parser.expect<std::string>("(:");
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier);
const auto skipSection =
[&]()
{
std::cout << "Skipping section " << sectionIdentifier << std::endl;
size_t openParentheses = 1;
while (true)
{
const auto character = parser.currentCharacter();
parser.advance();
if (character == '(')
openParentheses++;
else if (character == ')')
{
openParentheses--;
if (openParentheses == 0)
return;
}
}
};
if (sectionIdentifier == "requirements")
parseRequirementsSection(parser);
else if (sectionIdentifier == "types")
parseTypingSection(parser);
else if (sectionIdentifier == "constants")
skipSection();
else if (sectionIdentifier == "predicates")
skipSection();
else if (sectionIdentifier == "functions")
skipSection();
else if (sectionIdentifier == "constraints")
skipSection();
else if (sectionIdentifier == "action")
skipSection();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Domain::parseRequirementsSection(utils::Parser &parser)
{
while (true)
{
parser.skipWhiteSpace();
if (parser.currentCharacter() == ')')
break;
if (parser.currentCharacter() == ':')
parser.advance();
m_requirements.emplace_back(Requirement::fromPDDL(parser));
}
if (m_requirements.empty())
throw utils::ParserException(parser.row(), parser.column(), "Requirements section does not contain any requirements");
parser.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool Domain::hasRequirement(Requirement::Type requirement) const
{
const auto match = std::find(m_requirements.cbegin(), m_requirements.cend(), requirement);
return match != m_requirements.cend();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Domain::computeDerivedRequirements()
{
const auto addRequirementUnique =
[&](const auto requirement)
{
if (hasRequirement(requirement))
return;
m_requirements.push_back(requirement);
};
// If no requirements are specified, assume STRIPS
if (m_requirements.empty())
addRequirementUnique(Requirement::Type::STRIPS);
if (hasRequirement(Requirement::Type::ADL))
{
addRequirementUnique(Requirement::Type::STRIPS);
addRequirementUnique(Requirement::Type::Typing);
addRequirementUnique(Requirement::Type::NegativePreconditions);
addRequirementUnique(Requirement::Type::DisjunctivePreconditions);
addRequirementUnique(Requirement::Type::Equality);
addRequirementUnique(Requirement::Type::QuantifiedPreconditions);
addRequirementUnique(Requirement::Type::ConditionalEffects);
}
if (hasRequirement(Requirement::Type::QuantifiedPreconditions))
{
addRequirementUnique(Requirement::Type::ExistentialPreconditions);
addRequirementUnique(Requirement::Type::UniversalPreconditions);
}
if (hasRequirement(Requirement::Type::Fluents))
{
addRequirementUnique(Requirement::Type::NumericFluents);
addRequirementUnique(Requirement::Type::ObjectFluents);
}
if (hasRequirement(Requirement::Type::TimedInitialLiterals))
addRequirementUnique(Requirement::Type::DurativeActions);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Domain::parseTypingSection(utils::Parser &parser)
{
// Parses a single type identifier
const auto parseType =
[&]() -> auto &
{
parser.skipWhiteSpace();
const auto typeName = parser.parseIdentifier(isIdentifier);
const auto insertionResult = m_types.emplace(std::make_pair(typeName, Type(typeName)));
auto &type = insertionResult.first->second;
// Flag type for potentially upcoming parent type declaration
type.setDirty();
parser.skipWhiteSpace();
return type;
};
// Parses a type and potentially its parent type
while (parser.currentCharacter() != ')')
{
parseType();
// Check for type inheritance
if (!parser.advanceIf('-'))
continue;
// If existing, parse parent type
auto &parentType = parseType();
parentType.setDirty(false);
// Assign parent type to all types that were previously flagged
std::for_each(m_types.begin(), m_types.end(),
[&](auto &childType)
{
if (!childType.second.isDirty())
return;
childType.second.addParentType(parentType);
childType.second.setDirty(false);
});
}
parser.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Domain::checkConsistency()
{
if (!m_types.empty() && !hasRequirement(Requirement::Type::Typing))
{
throw ConsistencyException("Domain contains typing information but does not declare typing requirement");
m_requirements.push_back(Requirement::Type::Typing);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}