summaryrefslogtreecommitdiff
path: root/src/core/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/parser')
-rw-r--r--src/core/parser/ParserScope.cpp12
-rw-r--r--src/core/parser/ParserScope.hpp18
-rw-r--r--src/core/parser/stack/DocumentHandler.cpp74
-rw-r--r--src/core/parser/stack/DomainHandler.cpp16
-rw-r--r--src/core/parser/stack/Stack.cpp20
-rw-r--r--src/core/parser/stack/TypesystemHandler.cpp20
6 files changed, 112 insertions, 48 deletions
diff --git a/src/core/parser/ParserScope.cpp b/src/core/parser/ParserScope.cpp
index b0a4945..dabb03c 100644
--- a/src/core/parser/ParserScope.cpp
+++ b/src/core/parser/ParserScope.cpp
@@ -216,7 +216,7 @@ void ParserScope::push(Handle<Node> node)
nodes.push_back(node);
}
-void ParserScope::pop()
+void ParserScope::pop(Logger &logger)
{
// Make sure pop is not called without an element on the stack
const size_t currentDepth = nodes.size();
@@ -235,10 +235,14 @@ void ParserScope::pop()
flags.resize(newLen);
// Whenever a RootNode is popped from the stack, we have to perform deferred
- // resolution -- however, postpone issuing error messages
- if (nodes.back()->isa(&RttiTypes::RootNode)) {
- Logger logger;
+ // resolution and validate the subtree
+ Rooted<Node> node = nodes.back();
+ if (node->isa(&RttiTypes::RootNode)) {
+ // Perform pending resolutions -- do not issue errors now
performDeferredResolution(logger, true);
+
+ // Perform validation of the subtree.
+ node->validate(logger);
}
// Remove the element from the stack
diff --git a/src/core/parser/ParserScope.hpp b/src/core/parser/ParserScope.hpp
index 24af6b8..e27c81e 100644
--- a/src/core/parser/ParserScope.hpp
+++ b/src/core/parser/ParserScope.hpp
@@ -286,7 +286,13 @@ enum class ParserFlag {
* Set to the boolean value "true" if the head section of a file has passed.
* This happens once the first non-import tag is reached.
*/
- POST_HEAD
+ POST_HEAD,
+
+ /**
+ * Set to the boolean value "true" if explicit fields may no longer be
+ * defined inside a structure element.
+ */
+ POST_EXPLICIT_FIELDS
};
/**
@@ -423,9 +429,14 @@ public:
void push(Handle<Node> node);
/**
- * Removes the last pushed node from the scope.
+ * Removes the last pushed node from the scope. If the node that is popped
+ * from the internal stack is a RootNode, pending resolutions are performed
+ * and the RootNode is validated.
+ *
+ * @param logger is the Logger instance to which error messages should be
+ * logged.
*/
- void pop();
+ void pop(Logger &logger);
/**
* Returns the top-level nodes. These are the nodes that are pushed onto the
@@ -792,6 +803,7 @@ public:
bool resolveFieldDescriptor(const std::string &name, Handle<Node> owner,
Logger &logger,
ResolutionResultCallback resultCallback);
+
/**
* Tries to resolve all currently deferred resolution steps. The list of
* pending deferred resolutions is cleared after this function has run.
diff --git a/src/core/parser/stack/DocumentHandler.cpp b/src/core/parser/stack/DocumentHandler.cpp
index 35146b1..bb04bd3 100644
--- a/src/core/parser/stack/DocumentHandler.cpp
+++ b/src/core/parser/stack/DocumentHandler.cpp
@@ -47,7 +47,7 @@ bool DocumentHandler::start(Variant::mapType &args)
return true;
}
-void DocumentHandler::end() { scope().pop(); }
+void DocumentHandler::end() { scope().pop(logger()); }
/* DocumentChildHandler */
@@ -98,6 +98,9 @@ void DocumentChildHandler::createPath(const NodeVector<Node> &path,
manager(), scope().getLeaf(),
parent->getDescriptor()->getFieldDescriptorIndex(), true)};
scope().push(field);
+
+ // Generally allow explicit fields in the new field
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, false);
}
void DocumentChildHandler::createPath(const size_t &firstFieldIdx,
@@ -113,6 +116,9 @@ void DocumentChildHandler::createPath(const size_t &firstFieldIdx,
parent = static_cast<DocumentEntity *>(transparent.get());
createPath(path, parent, 2);
+
+ // Generally allow explicit fields in the new field
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, false);
}
bool DocumentChildHandler::start(Variant::mapType &args)
@@ -136,6 +142,14 @@ bool DocumentChildHandler::start(Variant::mapType &args)
Rooted<StructuredEntity> entity;
// handle the root note specifically.
if (parentNode->isa(&RttiTypes::Document)) {
+ // if we already have a root node, stop.
+ if (parentNode.cast<Document>()->getRoot() != nullptr) {
+ logger().warning(
+ "This document already has a root node. The additional "
+ "node is ignored.",
+ location());
+ return false;
+ }
Rooted<StructuredClass> strct = scope().resolve<StructuredClass>(
Utils::split(name(), ':'), logger());
if (strct == nullptr) {
@@ -170,12 +184,25 @@ bool DocumentChildHandler::start(Variant::mapType &args)
ssize_t newFieldIdx =
parent->getDescriptor()->getFieldDescriptorIndex(name());
if (newFieldIdx != -1) {
- Rooted<DocumentField> field{new DocumentField(
- manager(), parentNode, newFieldIdx, false)};
- field->setLocation(location());
- scope().push(field);
- isExplicitField = true;
- return true;
+ // Check whether explicit fields are allowed here, if not
+ if (scope().getFlag(ParserFlag::POST_EXPLICIT_FIELDS)) {
+ logger().note(
+ std::string(
+ "Data or structure commands have already been "
+ "given, command \"") +
+ name() + std::string(
+ "\" is not interpreted explicit "
+ "field. Move explicit field "
+ "references to the beginning."),
+ location());
+ } else {
+ Rooted<DocumentField> field{new DocumentField(
+ manager(), parentNode, newFieldIdx, false)};
+ field->setLocation(location());
+ scope().push(field);
+ isExplicitField = true;
+ return true;
+ }
}
}
@@ -200,9 +227,9 @@ bool DocumentChildHandler::start(Variant::mapType &args)
// if we have transparent elements above us in the structure
// tree we try to unwind them before we give up.
// pop the implicit field.
- scope().pop();
+ scope().pop(logger());
// pop the implicit element.
- scope().pop();
+ scope().pop(logger());
continue;
}
throw LoggableException(
@@ -218,11 +245,17 @@ bool DocumentChildHandler::start(Variant::mapType &args)
parent->getDescriptor()->getFieldDescriptorIndex();
}
// create the entity for the new element at last.
- //TODO: REMOVE
+ // TODO: REMOVE
strct_name = strct->getName();
entity = parent->createChildStructuredEntity(strct, lastFieldIdx,
args, nameAttr);
}
+
+ // We're past the region in which explicit fields can be defined in the
+ // parent structure element
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, true);
+
+ // Bush the entity onto the stack
entity->setLocation(location());
scope().push(entity);
return true;
@@ -237,7 +270,7 @@ void DocumentChildHandler::end()
return;
}
// pop the "main" element.
- scope().pop();
+ scope().pop(logger());
}
bool DocumentChildHandler::fieldStart(bool &isDefault, size_t fieldIdx)
@@ -259,6 +292,9 @@ bool DocumentChildHandler::fieldStart(bool &isDefault, size_t fieldIdx)
parent->getDescriptor()->getFieldDescriptors();
if (isDefault) {
+ if(fields.empty()){
+ return false;
+ }
fieldIdx = fields.size() - 1;
} else {
if (fieldIdx >= fields.size()) {
@@ -271,6 +307,10 @@ bool DocumentChildHandler::fieldStart(bool &isDefault, size_t fieldIdx)
new DocumentField(manager(), parentNode, fieldIdx, false)};
field->setLocation(location());
scope().push(field);
+
+ // Generally allow explicit fields in the new field
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, false);
+
return true;
}
@@ -279,15 +319,15 @@ void DocumentChildHandler::fieldEnd()
assert(scope().getLeaf()->isa(&RttiTypes::DocumentField));
// pop the field from the stack.
- scope().pop();
+ scope().pop(logger());
// pop all remaining transparent elements.
while (scope().getLeaf()->isa(&RttiTypes::StructuredEntity) &&
scope().getLeaf().cast<StructuredEntity>()->isTransparent()) {
// pop the transparent element.
- scope().pop();
+ scope().pop(logger());
// pop the transparent field.
- scope().pop();
+ scope().pop(logger());
}
}
@@ -334,6 +374,10 @@ bool DocumentChildHandler::convertData(Handle<FieldDescriptor> field,
bool DocumentChildHandler::data(Variant &data)
{
+ // We're past the region in which explicit fields can be defined in the
+ // parent structure element
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, true);
+
Rooted<Node> parentField = scope().getLeaf();
assert(parentField->isa(&RttiTypes::DocumentField));
@@ -427,4 +471,4 @@ namespace RttiTypes {
const Rtti DocumentField = RttiBuilder<ousia::parser_stack::DocumentField>(
"DocumentField").parent(&Node);
}
-}
+} \ No newline at end of file
diff --git a/src/core/parser/stack/DomainHandler.cpp b/src/core/parser/stack/DomainHandler.cpp
index ddec1ee..aa18faa 100644
--- a/src/core/parser/stack/DomainHandler.cpp
+++ b/src/core/parser/stack/DomainHandler.cpp
@@ -53,7 +53,7 @@ bool DomainHandler::start(Variant::mapType &args)
return true;
}
-void DomainHandler::end() { scope().pop(); }
+void DomainHandler::end() { scope().pop(logger()); }
/* DomainStructHandler */
@@ -85,7 +85,7 @@ bool DomainStructHandler::start(Variant::mapType &args)
return true;
}
-void DomainStructHandler::end() { scope().pop(); }
+void DomainStructHandler::end() { scope().pop(logger()); }
/* DomainAnnotationHandler */
bool DomainAnnotationHandler::start(Variant::mapType &args)
@@ -102,7 +102,7 @@ bool DomainAnnotationHandler::start(Variant::mapType &args)
return true;
}
-void DomainAnnotationHandler::end() { scope().pop(); }
+void DomainAnnotationHandler::end() { scope().pop(logger()); }
/* DomainAttributesHandler */
@@ -118,7 +118,7 @@ bool DomainAttributesHandler::start(Variant::mapType &args)
return true;
}
-void DomainAttributesHandler::end() { scope().pop(); }
+void DomainAttributesHandler::end() { scope().pop(logger()); }
/* DomainFieldHandler */
@@ -148,7 +148,7 @@ bool DomainFieldHandler::start(Variant::mapType &args)
return true;
}
-void DomainFieldHandler::end() { scope().pop(); }
+void DomainFieldHandler::end() { scope().pop(logger()); }
/* DomainFieldRefHandler */
@@ -218,7 +218,7 @@ bool DomainPrimitiveHandler::start(Variant::mapType &args)
return true;
}
-void DomainPrimitiveHandler::end() { scope().pop(); }
+void DomainPrimitiveHandler::end() { scope().pop(logger()); }
/* DomainChildHandler */
@@ -251,7 +251,7 @@ bool DomainParentHandler::start(Variant::mapType &args)
return true;
}
-void DomainParentHandler::end() { scope().pop(); }
+void DomainParentHandler::end() { scope().pop(logger()); }
/* DomainParentFieldHandler */
@@ -414,4 +414,4 @@ namespace RttiTypes {
const Rtti DomainParent = RttiBuilder<ousia::parser_stack::DomainParent>(
"DomainParent").parent(&Node);
}
-} \ No newline at end of file
+}
diff --git a/src/core/parser/stack/Stack.cpp b/src/core/parser/stack/Stack.cpp
index 08f86e5..5b67248 100644
--- a/src/core/parser/stack/Stack.cpp
+++ b/src/core/parser/stack/Stack.cpp
@@ -16,8 +16,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sstream>
-
#include <core/common/Logger.hpp>
#include <core/common/Utils.hpp>
#include <core/common/Exceptions.hpp>
@@ -256,7 +254,9 @@ void Stack::endCurrentHandler()
// Make sure the fieldEnd handler is called if the element still
// is in a field
if (info.inField) {
- info.handler->fieldEnd();
+ if (info.inValidField) {
+ info.handler->fieldEnd();
+ }
info.fieldEnd();
}
@@ -300,8 +300,6 @@ bool Stack::ensureHandlerIsInField()
// Try to start a new default field, abort if this did not work
bool isDefault = true;
if (!info.handler->fieldStart(isDefault, info.fieldIdx)) {
- info.handler->fieldEnd();
- endCurrentHandler();
return false;
}
@@ -505,10 +503,9 @@ void Stack::fieldStart(bool isDefault)
// (the default field always is the last field) -- mark the command as
// invalid
if (info.hadDefaultField) {
- logger().error(
- std::string("Got field start, but command \"") +
- currentCommandName() +
- std::string("\" does not have any more fields"));
+ logger().error(std::string("Got field start, but command \"") +
+ currentCommandName() +
+ std::string("\" does not have any more fields"));
}
// Copy the isDefault flag to a local variable, the fieldStart method will
@@ -559,7 +556,7 @@ void Stack::fieldEnd()
// Only continue if the current handler stack is in a valid state, do not
// call the fieldEnd function if something went wrong before
- if (handlersValid() && !info.hadDefaultField) {
+ if (handlersValid() && !info.hadDefaultField && info.inValidField) {
try {
info.handler->fieldEnd();
}
@@ -587,5 +584,4 @@ void Stack::token(Variant token)
// TODO
}
}
-}
-
+} \ No newline at end of file
diff --git a/src/core/parser/stack/TypesystemHandler.cpp b/src/core/parser/stack/TypesystemHandler.cpp
index 8fd9525..de8ee49 100644
--- a/src/core/parser/stack/TypesystemHandler.cpp
+++ b/src/core/parser/stack/TypesystemHandler.cpp
@@ -16,11 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <core/model/Typesystem.hpp>
+#include <core/model/Document.hpp>
#include <core/model/Domain.hpp>
+#include <core/model/Typesystem.hpp>
#include <core/parser/ParserScope.hpp>
#include <core/parser/ParserContext.hpp>
+#include "DocumentHandler.hpp"
#include "DomainHandler.hpp"
#include "State.hpp"
#include "TypesystemHandler.hpp"
@@ -38,10 +40,16 @@ bool TypesystemHandler::start(Variant::mapType &args)
typesystem->setLocation(location());
// If the typesystem is defined inside a domain, add a reference to the
- // typesystem to the domain
+ // typesystem to the domain -- do the same with a document, if no domain
+ // is found
Rooted<Domain> domain = scope().select<Domain>();
if (domain != nullptr) {
domain->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
@@ -51,7 +59,7 @@ bool TypesystemHandler::start(Variant::mapType &args)
return true;
}
-void TypesystemHandler::end() { scope().pop(); }
+void TypesystemHandler::end() { scope().pop(logger()); }
/* TypesystemEnumHandler */
@@ -70,7 +78,7 @@ bool TypesystemEnumHandler::start(Variant::mapType &args)
return true;
}
-void TypesystemEnumHandler::end() { scope().pop(); }
+void TypesystemEnumHandler::end() { scope().pop(logger()); }
/* TypesystemEnumEntryHandler */
@@ -112,7 +120,7 @@ bool TypesystemStructHandler::start(Variant::mapType &args)
return true;
}
-void TypesystemStructHandler::end() { scope().pop(); }
+void TypesystemStructHandler::end() { scope().pop(logger()); }
/* TypesystemStructFieldHandler */
@@ -182,7 +190,7 @@ bool TypesystemConstantHandler::start(Variant::mapType &args)
namespace States {
const State Typesystem = StateBuilder()
- .parents({&None, &Domain})
+ .parents({&None, &Domain, &Document})
.createdNodeType(&RttiTypes::Typesystem)
.elementHandler(TypesystemHandler::create)
.arguments({Argument::String("name", "")});