Implemented variable type requirement checking.
This commit is contained in:
		@@ -36,16 +36,11 @@ class PrimitiveType: public Expression
 | 
			
		||||
		const std::string &name() const;
 | 
			
		||||
		const std::vector<const PrimitiveType *> &parentTypes() const;
 | 
			
		||||
 | 
			
		||||
		bool isDeclared() const;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void setDirty(bool isDirty = true);
 | 
			
		||||
		bool isDirty() const;
 | 
			
		||||
 | 
			
		||||
		void setDeclared();
 | 
			
		||||
 | 
			
		||||
		bool m_isDirty;
 | 
			
		||||
		bool m_isDeclared;
 | 
			
		||||
 | 
			
		||||
		std::string m_name;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,10 @@ class Variable: public Expression
 | 
			
		||||
{
 | 
			
		||||
	public:
 | 
			
		||||
		static void parseTypedDeclaration(Context &context, ExpressionContext &expressionContext);
 | 
			
		||||
		static void parseTypedDeclarations(Context &context, ExpressionContext &expressionContext);
 | 
			
		||||
 | 
			
		||||
		static const Variable *parseAndFind(Context &context, const ExpressionContext &expressionContext);
 | 
			
		||||
		static const Variable *parseAndFind(Context &context,
 | 
			
		||||
			const ExpressionContext &expressionContext);
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		void accept(ExpressionVisitor &expressionVisitor) const override;
 | 
			
		||||
 
 | 
			
		||||
@@ -40,12 +40,7 @@ void Action::parseDeclaration(Context &context, Domain &domain)
 | 
			
		||||
	ExpressionContext expressionContext(domain, action->m_parameters);
 | 
			
		||||
 | 
			
		||||
	// Read parameters
 | 
			
		||||
	while (context.parser.currentCharacter() != ')')
 | 
			
		||||
	{
 | 
			
		||||
		expressions::Variable::parseTypedDeclaration(context, expressionContext);
 | 
			
		||||
 | 
			
		||||
		context.parser.skipWhiteSpace();
 | 
			
		||||
	}
 | 
			
		||||
	expressions::Variable::parseTypedDeclarations(context, expressionContext);
 | 
			
		||||
 | 
			
		||||
	context.parser.expect<std::string>(")");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -111,8 +111,6 @@ void Description::findSections()
 | 
			
		||||
 | 
			
		||||
		if (m_context.parser.probe<std::string>("domain"))
 | 
			
		||||
		{
 | 
			
		||||
			std::cout << "Found domain at " << position << std::endl;
 | 
			
		||||
 | 
			
		||||
			if (m_domainPosition != -1)
 | 
			
		||||
				throw utils::ParserException(m_context.parser, "PDDL description may not contain two domains");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -315,52 +315,6 @@ void Domain::parseActionSection()
 | 
			
		||||
 | 
			
		||||
void Domain::checkConsistency()
 | 
			
		||||
{
 | 
			
		||||
	// TODO: implement requirement declaration checking
 | 
			
		||||
 | 
			
		||||
	// Verify that typing requirement is correctly declared if used
 | 
			
		||||
	if (!m_primitiveTypes.empty() && !hasRequirement(Requirement::Type::Typing))
 | 
			
		||||
	{
 | 
			
		||||
		m_context.logger.parserWarning(m_context.parser, "Domain contains typing information but does not declare typing requirement");
 | 
			
		||||
 | 
			
		||||
		m_requirements.push_back(Requirement(Requirement::Type::Typing));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Verify that all variables and constants have types if and only if typing enabled
 | 
			
		||||
	if (hasRequirement(Requirement::Type::Typing))
 | 
			
		||||
	{
 | 
			
		||||
		const auto acceptType =
 | 
			
		||||
			[&](const auto *type)
 | 
			
		||||
			{
 | 
			
		||||
				return ((type == nullptr) != this->hasRequirement(Requirement::Type::Typing));
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
		std::for_each(m_constants.cbegin(), m_constants.cend(),
 | 
			
		||||
			[&](const auto &constant)
 | 
			
		||||
			{
 | 
			
		||||
				if (!acceptType(constant->type()))
 | 
			
		||||
					throw ConsistencyException("Constant \"" + constant->name() + "\" has no type");
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
		std::for_each(m_predicateDeclarations.cbegin(), m_predicateDeclarations.cend(),
 | 
			
		||||
			[&](const auto &predicateDeclaration)
 | 
			
		||||
			{
 | 
			
		||||
				std::for_each(predicateDeclaration->arguments().cbegin(), predicateDeclaration->arguments().cend(),
 | 
			
		||||
					[&](const auto &argument)
 | 
			
		||||
					{
 | 
			
		||||
						if (!acceptType(argument->type()))
 | 
			
		||||
							throw ConsistencyException("Variable \"" + argument->name() + "\" has no type");
 | 
			
		||||
					});
 | 
			
		||||
			});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Verify that all used types have been declared
 | 
			
		||||
	std::for_each(m_primitiveTypes.cbegin(), m_primitiveTypes.cend(),
 | 
			
		||||
		[&](const auto &type)
 | 
			
		||||
		{
 | 
			
		||||
			if (!type->isDeclared())
 | 
			
		||||
				throw ConsistencyException("Type \"" + type->name() + "\" used but never declared");
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
	// Verify that all used constants have been declared
 | 
			
		||||
	std::for_each(m_constants.cbegin(), m_constants.cend(),
 | 
			
		||||
		[&](const auto &constant)
 | 
			
		||||
 
 | 
			
		||||
@@ -45,12 +45,7 @@ void PredicateDeclaration::parse(Context &context, Domain &domain)
 | 
			
		||||
	ExpressionContext expressionContext(domain, predicate->m_parameters);
 | 
			
		||||
 | 
			
		||||
	// Parse arguments
 | 
			
		||||
	while (context.parser.currentCharacter() != ')')
 | 
			
		||||
	{
 | 
			
		||||
		expressions::Variable::parseTypedDeclaration(context, expressionContext);
 | 
			
		||||
 | 
			
		||||
		context.parser.skipWhiteSpace();
 | 
			
		||||
	}
 | 
			
		||||
	expressions::Variable::parseTypedDeclarations(context, expressionContext);
 | 
			
		||||
 | 
			
		||||
	context.parser.expect<std::string>(")");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,7 @@ namespace expressions
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
PrimitiveType::PrimitiveType()
 | 
			
		||||
:	m_isDirty{true},
 | 
			
		||||
	m_isDeclared{false}
 | 
			
		||||
:	m_isDirty{true}
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -32,7 +31,6 @@ PrimitiveType::PrimitiveType()
 | 
			
		||||
 | 
			
		||||
PrimitiveType::PrimitiveType(std::string name)
 | 
			
		||||
:	m_isDirty{true},
 | 
			
		||||
	m_isDeclared{false},
 | 
			
		||||
	m_name{name}
 | 
			
		||||
{
 | 
			
		||||
	BOOST_ASSERT(!m_name.empty());
 | 
			
		||||
@@ -61,13 +59,11 @@ void PrimitiveType::parseDeclaration(Context &context, Domain &domain)
 | 
			
		||||
		auto *type = match->get();
 | 
			
		||||
 | 
			
		||||
		type->setDirty();
 | 
			
		||||
		type->setDeclared();
 | 
			
		||||
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	types.emplace_back(std::make_unique<PrimitiveType>(typeName));
 | 
			
		||||
	types.back()->setDeclared();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
@@ -93,9 +89,6 @@ void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain)
 | 
			
		||||
 | 
			
		||||
	parentType->setDirty(false);
 | 
			
		||||
 | 
			
		||||
	// Flag parent tpe as correctly declared in the types section
 | 
			
		||||
	parentType->setDeclared();
 | 
			
		||||
 | 
			
		||||
	// Assign parent type to all types that were previously flagged
 | 
			
		||||
	std::for_each(types.begin(), types.end(),
 | 
			
		||||
		[&](auto &childType)
 | 
			
		||||
@@ -164,20 +157,6 @@ bool PrimitiveType::isDirty() const
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void PrimitiveType::setDeclared()
 | 
			
		||||
{
 | 
			
		||||
	m_isDeclared = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
bool PrimitiveType::isDeclared() const
 | 
			
		||||
{
 | 
			
		||||
	return m_isDeclared;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
const std::string &PrimitiveType::name() const
 | 
			
		||||
{
 | 
			
		||||
	return m_name;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
#include <boost/assert.hpp>
 | 
			
		||||
 | 
			
		||||
#include <plasp/pddl/Context.h>
 | 
			
		||||
#include <plasp/pddl/Domain.h>
 | 
			
		||||
#include <plasp/pddl/ExpressionContext.h>
 | 
			
		||||
#include <plasp/pddl/ExpressionVisitor.h>
 | 
			
		||||
#include <plasp/pddl/Identifier.h>
 | 
			
		||||
@@ -67,8 +68,6 @@ void Variable::parseTypedDeclaration(Context &context, ExpressionContext &expres
 | 
			
		||||
	if (!context.parser.probe('-'))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// TODO: do not allow nested either expressions
 | 
			
		||||
 | 
			
		||||
	const auto setType =
 | 
			
		||||
		[&](const auto *type)
 | 
			
		||||
		{
 | 
			
		||||
@@ -108,6 +107,27 @@ void Variable::parseTypedDeclaration(Context &context, ExpressionContext &expres
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void Variable::parseTypedDeclarations(Context &context, ExpressionContext &expressionContext)
 | 
			
		||||
{
 | 
			
		||||
	while (context.parser.currentCharacter() != ')')
 | 
			
		||||
		parseTypedDeclaration(context, expressionContext);
 | 
			
		||||
 | 
			
		||||
	if (expressionContext.parameters.empty())
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// Check correct use of typing requirement
 | 
			
		||||
	const auto typingUsed = (expressionContext.parameters.back()->type() != nullptr);
 | 
			
		||||
	const auto typingDeclared = expressionContext.domain.hasRequirement(Requirement::Type::Typing);
 | 
			
		||||
 | 
			
		||||
	if (!typingUsed && typingDeclared)
 | 
			
		||||
		throw utils::ParserException(context.parser, "Object has undeclared type");
 | 
			
		||||
 | 
			
		||||
	if (typingUsed && !typingDeclared)
 | 
			
		||||
		throw utils::ParserException(context.parser, "Typing used but not declared as a requirement");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
const Variable *Variable::parseAndFind(Context &context, const ExpressionContext &expressionContext)
 | 
			
		||||
{
 | 
			
		||||
	context.parser.skipWhiteSpace();
 | 
			
		||||
 
 | 
			
		||||
@@ -255,10 +255,10 @@ bool Parser::probe<std::string>(const std::string &expectedValue)
 | 
			
		||||
{
 | 
			
		||||
	BOOST_ASSERT(!std::isspace(expectedValue[0]));
 | 
			
		||||
 | 
			
		||||
	skipWhiteSpace();
 | 
			
		||||
 | 
			
		||||
	const auto previousPosition = position();
 | 
			
		||||
 | 
			
		||||
	skipWhiteSpace();
 | 
			
		||||
 | 
			
		||||
	const auto match = std::find_if(expectedValue.cbegin(), expectedValue.cend(),
 | 
			
		||||
		[&](const auto &expectedCharacter)
 | 
			
		||||
		{
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user