/*
Ousía
Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include "DocumentHandler.hpp"
#include "DomainHandler.hpp"
#include "State.hpp"
#include "TypesystemHandler.hpp"
namespace ousia {
namespace parser_stack {
/* DomainHandler */
bool DomainHandler::start(Variant::mapType &args)
{
// Create the Domain node
Rooted domain =
context().getProject()->createDomain(args["name"].asString());
domain->setLocation(location());
// If the domain is defined inside a document, add the reference to the
// document
Rooted document = scope().select();
if (document != nullptr) {
document->reference(domain);
}
// Push the typesystem onto the scope, set the POST_HEAD flag to true
scope().push(domain);
scope().setFlag(ParserFlag::POST_HEAD, false);
return true;
}
void DomainHandler::end() { scope().pop(logger()); }
/* DomainStructHandler */
bool DomainStructHandler::start(Variant::mapType &args)
{
scope().setFlag(ParserFlag::POST_HEAD, true);
Rooted domain = scope().selectOrThrow();
Rooted structuredClass = domain->createStructuredClass(
args["name"].asString(), args["cardinality"].asCardinality(), nullptr,
args["transparent"].asBool(), args["isRoot"].asBool());
structuredClass->setLocation(location());
const std::string &isa = args["isa"].asString();
if (!isa.empty()) {
scope().resolve(
isa, structuredClass, logger(),
[](Handle superclass, Handle structuredClass,
Logger &logger) {
if (superclass != nullptr) {
structuredClass.cast()->setSuperclass(
superclass.cast(), logger);
}
});
}
scope().push(structuredClass);
return true;
}
void DomainStructHandler::end() { scope().pop(logger()); }
/* DomainAnnotationHandler */
bool DomainAnnotationHandler::start(Variant::mapType &args)
{
scope().setFlag(ParserFlag::POST_HEAD, true);
Rooted domain = scope().selectOrThrow();
Rooted annotationClass =
domain->createAnnotationClass(args["name"].asString());
annotationClass->setLocation(location());
scope().push(annotationClass);
return true;
}
void DomainAnnotationHandler::end() { scope().pop(logger()); }
/* DomainAttributesHandler */
bool DomainAttributesHandler::start(Variant::mapType &args)
{
// Fetch the current typesystem and create the struct node
Rooted parent = scope().selectOrThrow();
Rooted attrDesc = parent->getAttributesDescriptor();
attrDesc->setLocation(location());
scope().push(attrDesc);
return true;
}
void DomainAttributesHandler::end() { scope().pop(logger()); }
/* DomainFieldHandler */
bool DomainFieldHandler::start(Variant::mapType &args)
{
FieldDescriptor::FieldType type;
if (args["isSubtree"].asBool()) {
type = FieldDescriptor::FieldType::SUBTREE;
} else {
type = FieldDescriptor::FieldType::TREE;
}
Rooted parent = scope().selectOrThrow();
auto res = parent->createFieldDescriptor(
logger(), type, args["name"].asString(), args["optional"].asBool());
res.first->setLocation(location());
if (res.second) {
logger().warning(
std::string("Field \"") + res.first->getName() +
"\" was declared after main field. The order of fields "
"was changed to make the main field the last field.",
*res.first);
}
scope().push(res.first);
return true;
}
void DomainFieldHandler::end() { scope().pop(logger()); }
/* DomainFieldRefHandler */
bool DomainFieldRefHandler::start(Variant::mapType &args)
{
Rooted parent = scope().selectOrThrow();
const std::string &name = args["ref"].asString();
auto loc = location();
scope().resolveFieldDescriptor(name, parent, logger(),
[loc](Handle field,
Handle parent, Logger &logger) {
if (field != nullptr) {
if (parent.cast()->addFieldDescriptor(
field.cast(), logger)) {
logger.warning(
std::string("Field \"") + field->getName() +
"\" was referenced after main field was declared. The "
"order of fields was changed to make the main field "
"the last field.",
loc);
}
}
});
return true;
}
void DomainFieldRefHandler::end() {}
/* DomainPrimitiveHandler */
bool DomainPrimitiveHandler::start(Variant::mapType &args)
{
Rooted parent = scope().selectOrThrow();
FieldDescriptor::FieldType fieldType;
if (args["isSubtree"].asBool()) {
fieldType = FieldDescriptor::FieldType::SUBTREE;
} else {
fieldType = FieldDescriptor::FieldType::TREE;
}
auto res = parent->createPrimitiveFieldDescriptor(
new UnknownType(manager()), logger(), fieldType,
args["name"].asString(), args["optional"].asBool());
res.first->setLocation(location());
if (res.second) {
logger().warning(
std::string("Field \"") + res.first->getName() +
"\" was declared after main field. The order of fields "
"was changed to make the main field the last field.",
*res.first);
}
const std::string &type = args["type"].asString();
scope().resolve(type, res.first, logger(),
[](Handle type, Handle field,
Logger &logger) {
if (type != nullptr) {
field.cast()->setPrimitiveType(type.cast());
}
});
scope().push(res.first);
return true;
}
void DomainPrimitiveHandler::end() { scope().pop(logger()); }
/* DomainChildHandler */
bool DomainChildHandler::start(Variant::mapType &args)
{
Rooted field = scope().selectOrThrow();
const std::string &ref = args["ref"].asString();
scope().resolve(
ref, field, logger(),
[](Handle child, Handle field, Logger &logger) {
if (child != nullptr) {
field.cast()->addChild(
child.cast());
}
});
return true;
}
/* DomainParentHandler */
bool DomainParentHandler::start(Variant::mapType &args)
{
Rooted strct = scope().selectOrThrow();
Rooted parent{
new DomainParent(strct->getManager(), args["ref"].asString(), strct)};
parent->setLocation(location());
scope().push(parent);
return true;
}
void DomainParentHandler::end() { scope().pop(logger()); }
/* DomainParentFieldHandler */
bool DomainParentFieldHandler::start(Variant::mapType &args)
{
Rooted parentNameNode = scope().selectOrThrow();
FieldDescriptor::FieldType type;
if (args["isSubtree"].asBool()) {
type = FieldDescriptor::FieldType::SUBTREE;
} else {
type = FieldDescriptor::FieldType::TREE;
}
const std::string &name = args["name"].asString();
const bool optional = args["optional"].asBool();
Rooted strct =
parentNameNode->getParent().cast();
// resolve the parent, create the declared field and add the declared
// StructuredClass as child to it.
scope().resolve(
parentNameNode->getName(), strct, logger(),
[type, name, optional](Handle parent, Handle strct,
Logger &logger) {
if (parent != nullptr) {
Rooted field =
(parent.cast()->createFieldDescriptor(
logger, type, name, optional)).first;
field->addChild(strct.cast());
}
});
return true;
}
/* DomainParentFieldRefHandler */
bool DomainParentFieldRefHandler::start(Variant::mapType &args)
{
Rooted parentNameNode = scope().selectOrThrow();
const std::string &name = args["ref"].asString();
Rooted strct =
parentNameNode->getParent().cast();
auto loc = location();
// resolve the parent, get the referenced field and add the declared
// StructuredClass as child to it.
scope().resolve(
parentNameNode->getName(), strct, logger(),
[name, loc](Handle parent, Handle strct, Logger &logger) {
if (parent != nullptr) {
Rooted field =
parent.cast()->getFieldDescriptor(name);
if (field == nullptr) {
logger.error(
std::string("Could not find referenced field ") + name,
loc);
return;
}
field->addChild(strct.cast());
}
});
return true;
}
namespace States {
const State Domain = StateBuilder()
.parents({&None, &Document})
.createdNodeType(&RttiTypes::Domain)
.elementHandler(DomainHandler::create)
.arguments({Argument::String("name")});
const State DomainStruct =
StateBuilder()
.parent(&Domain)
.createdNodeType(&RttiTypes::StructuredClass)
.elementHandler(DomainStructHandler::create)
.arguments({Argument::String("name"),
Argument::Cardinality("cardinality", Cardinality::any()),
Argument::Bool("isRoot", false),
Argument::Bool("transparent", false),
Argument::String("isa", "")});
const State DomainAnnotation =
StateBuilder()
.parent(&Domain)
.createdNodeType(&RttiTypes::AnnotationClass)
.elementHandler(DomainAnnotationHandler::create)
.arguments({Argument::String("name")});
const State DomainAttributes =
StateBuilder()
.parents({&DomainStruct, &DomainAnnotation})
.createdNodeType(&RttiTypes::StructType)
.elementHandler(DomainAttributesHandler::create)
.arguments({});
const State DomainAttribute =
StateBuilder()
.parent(&DomainAttributes)
.elementHandler(TypesystemStructFieldHandler::create)
.arguments({Argument::String("name"), Argument::String("type"),
Argument::Any("default", Variant::fromObject(nullptr))});
const State DomainField = StateBuilder()
.parents({&DomainStruct, &DomainAnnotation})
.createdNodeType(&RttiTypes::FieldDescriptor)
.elementHandler(DomainFieldHandler::create)
.arguments({Argument::String("name", ""),
Argument::Bool("isSubtree", false),
Argument::Bool("optional", false)});
const State DomainFieldRef =
StateBuilder()
.parents({&DomainStruct, &DomainAnnotation})
.createdNodeType(&RttiTypes::FieldDescriptor)
.elementHandler(DomainFieldRefHandler::create)
.arguments({Argument::String("ref", DEFAULT_FIELD_NAME)});
const State DomainStructPrimitive =
StateBuilder()
.parents({&DomainStruct, &DomainAnnotation})
.createdNodeType(&RttiTypes::FieldDescriptor)
.elementHandler(DomainPrimitiveHandler::create)
.arguments(
{Argument::String("name", ""), Argument::Bool("isSubtree", false),
Argument::Bool("optional", false), Argument::String("type")});
const State DomainStructChild = StateBuilder()
.parent(&DomainField)
.elementHandler(DomainChildHandler::create)
.arguments({Argument::String("ref")});
const State DomainStructParent =
StateBuilder()
.parent(&DomainStruct)
.createdNodeType(&RttiTypes::DomainParent)
.elementHandler(DomainParentHandler::create)
.arguments({Argument::String("ref")});
const State DomainStructParentField =
StateBuilder()
.parent(&DomainStructParent)
.createdNodeType(&RttiTypes::FieldDescriptor)
.elementHandler(DomainParentFieldHandler::create)
.arguments({Argument::String("name", ""),
Argument::Bool("isSubtree", false),
Argument::Bool("optional", false)});
const State DomainStructParentFieldRef =
StateBuilder()
.parent(&DomainStructParent)
.createdNodeType(&RttiTypes::FieldDescriptor)
.elementHandler(DomainParentFieldRefHandler::create)
.arguments({Argument::String("ref", DEFAULT_FIELD_NAME)});
}
}
namespace RttiTypes {
const Rtti DomainParent = RttiBuilder(
"DomainParent").parent(&Node);
}
}