bool TypesystemStructHandler::startCommand(Variant::mapType &args)
{
	scope().setFlag(ParserFlag::POST_HEAD, true);

	// Fetch the arguments used for creating this type
	const std::string &structName = args["name"].asString();
	const std::string &parent = args["parent"].asString();

	// Fetch the current typesystem and create the struct node
	Rooted<Typesystem> typesystem = scope().selectOrThrow<Typesystem>();
	Rooted<StructType> structType = typesystem->createStructType(structName);
	structType->setLocation(location());

	// Try to resolve the parent type and set it as parent structure
	if (!parent.empty()) {
		scope().resolve<StructType>(
		    parent, structType, logger(),
		    [](Handle<Node> parent, Handle<Node> structType, Logger &logger) {
			    if (parent != nullptr) {
				    structType.cast<StructType>()->setParentStructure(
				        parent.cast<StructType>(), logger);
			    }
			});
	}
	scope().push(structType);

	return true;
}
bool TypesystemHandler::startCommand(Variant::mapType &args)
{
	// Create the typesystem instance
	Rooted<Typesystem> typesystem =
	    context().getProject()->createTypesystem(args["name"].asString());
	typesystem->setLocation(location());

	// If the typesystem is defined inside a ontology, add a reference to the
	// typesystem to the ontology -- do the same with a document, if no ontology
	// is found
	Rooted<Ontology> ontology = scope().select<Ontology>();
	if (ontology != nullptr) {
		ontology->reference(typesystem);
	} else {
		Rooted<Document> document = scope().select<Document>();
		if (document != nullptr) {
			document->reference(typesystem);
		}
	}

	// Push the typesystem onto the scope, set the POST_HEAD flag to true
	scope().push(typesystem);
	scope().setFlag(ParserFlag::POST_HEAD, false);

	return true;
}
bool TypesystemEnumHandler::startCommand(Variant::mapType &args)
{
	scope().setFlag(ParserFlag::POST_HEAD, true);

	// Fetch the current typesystem and create the enum node
	Rooted<Typesystem> typesystem = scope().selectOrThrow<Typesystem>();
	Rooted<EnumType> enumType =
	    typesystem->createEnumType(args["name"].asString());
	enumType->setLocation(location());

	scope().push(enumType);

	return true;
}
bool TypesystemConstantHandler::startCommand(Variant::mapType &args)
{
	scope().setFlag(ParserFlag::POST_HEAD, true);

	// Read the argument values
	const std::string &constantName = args["name"].asString();
	const std::string &type = args["type"].asString();
	const Variant &value = args["value"];

	Rooted<Typesystem> typesystem = scope().selectOrThrow<Typesystem>();
	Rooted<Constant> constant = typesystem->createConstant(constantName, value);
	constant->setLocation(location());

	// Try to resolve the type
	scope().resolveTypeWithValue(
	    type, constant, constant->getValue(), logger(),
	    [](Handle<Node> type, Handle<Node> constant, Logger &logger) {
		    if (type != nullptr) {
			    constant.cast<Constant>()->setType(type.cast<Type>(), logger);
		    }
		});

	return true;
}
bool TypesystemStructFieldHandler::startCommand(Variant::mapType &args)
{
	// Read the argument values
	const std::string &fieldName = args["name"].asString();
	const std::string &type = args["type"].asString();
	const Variant &defaultValue = args["default"];
	const bool optional =
	    !(defaultValue.isObject() && defaultValue.asObject() == nullptr);

	Rooted<StructType> structType = scope().selectOrThrow<StructType>();
	Rooted<Attribute> attribute = structType->createAttribute(
	    fieldName, defaultValue, optional, logger());
	attribute->setLocation(location());

	// Try to resolve the type and default value
	if (optional) {
		scope().resolveTypeWithValue(
		    type, attribute, attribute->getDefaultValue(), logger(),
		    [](Handle<Node> type, Handle<Node> attribute, Logger &logger) {
			    if (type != nullptr) {
				    attribute.cast<Attribute>()->setType(type.cast<Type>(),
				                                         logger);
			    }
			});
	} else {
		scope().resolveType(type, attribute, logger(),
		                    [](Handle<Node> type, Handle<Node> attribute,
		                       Logger &logger) {
			if (type != nullptr) {
				attribute.cast<Attribute>()->setType(type.cast<Type>(), logger);
			}
		});
	}

	return true;
}