diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/model/Domain.cpp | 133 | ||||
| -rw-r--r-- | src/core/model/Domain.hpp | 246 | ||||
| -rw-r--r-- | src/plugins/html/DemoOutput.cpp | 2 | ||||
| -rw-r--r-- | src/plugins/xml/XmlParser.cpp | 8 | 
4 files changed, 198 insertions, 191 deletions
diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp index 787f1ff..3fb525f 100644 --- a/src/core/model/Domain.cpp +++ b/src/core/model/Domain.cpp @@ -173,20 +173,38 @@ bool Descriptor::doValidate(Logger &logger) const  	}  	// ensure that no attribute with the key "name" exists.  	if (attributesDescriptor == nullptr) { -		logger.error("This Descriptor has no Attribute specification!"); +		logger.error(std::string("Descriptor \"") + getName() + +		             "\" has no Attribute specification!");  		valid = false;  	} else {  		if (attributesDescriptor->hasAttribute("name")) {  			logger.error( -			    "This Descriptor has an attribute \"name\" which is a reserved " -			    "word!"); +			    std::string("Descriptor \"") + getName() + +			    "\" has an attribute \"name\" which is a reserved word!");  			valid = false;  		}  		valid = valid & attributesDescriptor->validate(logger);  	} +	// check that only one FieldDescriptor is of type TREE. +	auto fds = Descriptor::getFieldDescriptors(); +	bool hasTREE = false; +	for (auto fd : fds) { +		if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { +			if (!hasTREE) { +				hasTREE = true; +			} else { +				logger.error( +				    std::string("Descriptor \"") + getName() + +				        "\" has multiple TREE fields, which is not permitted", +				    *fd); +				valid = false; +				break; +			} +		} +	}  	// check attributes and the FieldDescriptors -	return valid & continueValidationCheckDuplicates(fieldDescriptors, logger); +	return valid & continueValidationCheckDuplicates(fds, logger);  }  std::vector<Rooted<Node>> Descriptor::pathTo( @@ -259,18 +277,39 @@ bool Descriptor::continuePath(Handle<StructuredClass> target,  	return found;  } -ssize_t Descriptor::getFieldDescriptorIndex(const std::string &name) const +static ssize_t getFieldDescriptorIndex(const NodeVector<FieldDescriptor> &fds, +                                       const std::string &name)  { -	size_t f = 0; -	for (auto &fd : getFieldDescriptors()) { -		if (fd->getName() == name) { +	if (fds.empty()) { +		return -1; +	} + +	if (name == DEFAULT_FIELD_NAME) { +		if (fds.back()->getFieldType() == FieldDescriptor::FieldType::TREE) { +			return fds.size() - 1; +		} else { +			/* The last field has to be the TREE field. If the last field does +			 * not have the FieldType TREE no TREE-field exists at all. So we +			 * return -1. +			 */ +			return -1; +		} +	} + +	for (size_t f = 0; f < fds.size(); f++) { +		if (fds[f]->getName() == name) {  			return f;  		} -		f++;  	}  	return -1;  } +ssize_t Descriptor::getFieldDescriptorIndex(const std::string &name) const +{ +	NodeVector<FieldDescriptor> fds = getFieldDescriptors(); +	return ousia::getFieldDescriptorIndex(fds, name); +} +  ssize_t Descriptor::getFieldDescriptorIndex(Handle<FieldDescriptor> fd) const  {  	size_t f = 0; @@ -286,33 +325,54 @@ ssize_t Descriptor::getFieldDescriptorIndex(Handle<FieldDescriptor> fd) const  Rooted<FieldDescriptor> Descriptor::getFieldDescriptor(      const std::string &name) const  { -	for (auto &fd : getFieldDescriptors()) { -		if (fd->getName() == name) { -			return fd; -		} +	NodeVector<FieldDescriptor> fds = getFieldDescriptors(); +	ssize_t idx = ousia::getFieldDescriptorIndex(fds, name); +	if (idx != -1) { +		return fds[idx]; +	} else { +		return nullptr;  	} -	return nullptr;  } -void Descriptor::addFieldDescriptor(Handle<FieldDescriptor> fd) +void Descriptor::addAndSortFieldDescriptor(Handle<FieldDescriptor> fd, +                                           Logger &logger)  {  	// only add it if we need to. -	if (fieldDescriptors.find(fd) == fieldDescriptors.end()) { +	auto fds = getFieldDescriptors(); +	if (fds.find(fd) == fds.end()) {  		invalidate(); -		fieldDescriptors.push_back(fd); +		// check if the previous field is a tree field already. +		if (!fds.empty() && +		    fds.back()->getFieldType() == FieldDescriptor::FieldType::TREE && +		    fd->getFieldType() != FieldDescriptor::FieldType::TREE) { +			// if so we add the new field before the TREE field and log a +			// warning. + +			logger.warning( +			    std::string("Field \"") + fd->getName() + +			        "\" was declared after main field \"" + +			        fds.back()->getName() + +			        "\". The order of fields was changed to make the " +			        "main field the last field.", +			    *fd); +			fieldDescriptors.insert(fieldDescriptors.end() - 1, fd); +		} else { +			fieldDescriptors.push_back(fd); +		}  	} +} + +void Descriptor::addFieldDescriptor(Handle<FieldDescriptor> fd, Logger &logger) +{ +	addAndSortFieldDescriptor(fd, logger);  	if (fd->getParent() == nullptr) {  		fd->setParent(this);  	}  } -void Descriptor::moveFieldDescriptor(Handle<FieldDescriptor> fd) +void Descriptor::moveFieldDescriptor(Handle<FieldDescriptor> fd, Logger &logger)  { -	// only add it if we need to. -	if (fieldDescriptors.find(fd) == fieldDescriptors.end()) { -		invalidate(); -		fieldDescriptors.push_back(fd); -	} +	addAndSortFieldDescriptor(fd, logger);  	Handle<Managed> par = fd->getParent();  	if (par != this) {  		if (par != nullptr) { @@ -494,18 +554,35 @@ void StructuredClass::removeSubclass(Handle<StructuredClass> sc, Logger &logger)  	sc->setSuperclass(nullptr, logger);  } -const void StructuredClass::gatherFieldDescriptors( +void StructuredClass::gatherFieldDescriptors(      NodeVector<FieldDescriptor> ¤t, -    std::set<std::string> &overriddenFields) const +    std::set<std::string> &overriddenFields, bool hasTREE) const  {  	// append all FieldDescriptors that are not overridden.  	for (auto &f : Descriptor::getFieldDescriptors()) {  		if (overriddenFields.insert(f->getName()).second) { -			current.push_back(f); +			bool isTREE = f->getFieldType() == FieldDescriptor::FieldType::TREE; +			if (hasTREE) { +				if (!isTREE) { +					/* +					 * If we already have a tree field it has to be at the end +					 * of the current vector. So ensure that all new non-TREE +					 * fields are inserted before the TREE field such that after +					 * this method the TREE field is still at the end. +					 */ +					current.insert(current.end() - 1, f); +				} +			} else { +				if (isTREE) { +					hasTREE = true; +				} +				current.push_back(f); +			}  		}  	} +	// if we have a superclass, go there.  	if (superclass != nullptr) { -		superclass->gatherFieldDescriptors(current, overriddenFields); +		superclass->gatherFieldDescriptors(current, overriddenFields, hasTREE);  	}  } @@ -514,7 +591,7 @@ NodeVector<FieldDescriptor> StructuredClass::getFieldDescriptors() const  	// in this case we return a NodeVector of Rooted entries without owner.  	NodeVector<FieldDescriptor> vec;  	std::set<std::string> overriddenFields; -	gatherFieldDescriptors(vec, overriddenFields); +	gatherFieldDescriptors(vec, overriddenFields, false);  	return vec;  } diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp index 241c25d..43661c2 100644 --- a/src/core/model/Domain.hpp +++ b/src/core/model/Domain.hpp @@ -34,74 +34,46 @@   *   * \code{.xml}   * <domain name="book"> - * 	<structs> - * 		<struct name="book" cardinality="1" isRoot="true"> - * 			<fields> - * 				<field> - * 					<children> - * 						<child name="book.chapter"/> - * 						<child name="book.paragraph"/> - * 					</children> - * 				</field> - * 			</fields> - * 		</struct> - * 		<struct name="chapter"> - * 			<fields> - * 				<field> - * 					<children> - * 						<child name="book.section"/> - * 						<child name="book.paragraph"/> - * 					</children> - * 				</field> - * 			</fields> - * 		</struct> - * 		<struct name="section"> - * 			<fields> - * 				<field> - * 					<children> - * 						<child name="book.subsection"/> - * 						<child name="book.paragraph"/> - * 					</children> - * 				</field> - * 			</fields> - * 		</struct> - * 		<struct name="subsection"> - * 			<fields> - * 				<field> - * 					<children> - * 						<child name="book.paragraph"/> - * 					</children> - * 				</field> - * 			</fields> - * 		</struct> - * 		<struct name="paragraph" transparent="true" role="paragraph"> - * 			<fields> - * 				<field> - * 					<children> - * 						<child name="book.text"/> - * 					</children> - * 				</field> - * 			</fields> - * 		</struct> - * 		<struct name="text" transparent="true" role="text"> - * 			<fields> - * 				<field name="content" type="PRIMITIVE" primitiveType="string"/> - * 			</fields> - * 		</struct> - * 	</structs> + * 	<struct name="book" cardinality="1" isRoot="true"> + * 		<field> + * 			<childRef ref="book.chapter"/> + * 			<childRef ref="book.paragraph"/> + * 		</field> + * 	</struct> + * 	<struct name="chapter"> + * 		<field> + * 			<childRef ref="book.section"/> + * 			<childRef ref="book.paragraph"/> + * 		</field> + * 	</struct> + * 	<struct name="section"> + * 		<field> + * 			<childRef ref="book.subsection"/> + * 			<childRef ref="book.paragraph"/> + * 		</field> + * 	</struct> + * 	<struct name="subsection"> + * 		<field> + * 			<childRef ref="book.paragraph"/> + * 		</field> + * 	</struct> + * 	<struct name="paragraph" transparent="true"> + * 		<field> + * 			<childRef ref="book.text"/> + * 		</field> + * 	</struct> + * 	<struct name="text" transparent="true"> + * 		<primitive type="string"/> + * 	</struct>   * </domain>   * \endcode   *   * Note that we define one field as the TREE (meaning the main or default   * document structure) and one mearly as SUBTREE, relating to supporting   * information. You are not allowed to define more than one field of type - * "TREE". Accordingly for each StructuredClass in the main TREE there must be - * at least one possible primitive child or one TREE field. Otherwise the - * grammar would be nonterminal. For SUBTREE fields no children may define a - * TREE field and at least one permitted child must exist, either primitive or - * as another StructuredClass. + * "TREE".   * - * The translation to context free grammars is as follows: + * The translation to a context free grammar is as follows:   *   * \code{.txt}   * BOOK              := <book> BOOK_TREE </book> @@ -128,21 +100,14 @@   *   * \code{.xml}   * <domain name="headings"> - * 	<head> - * 		<import rel="domain" src="book.oxm"/> - * 	</head> - * 	<structs> - * 		<struct name="heading" cardinality="0-1" transparent="true"> - * 			<parents> - * 				<parent name="book.book"> - * 					<field name="heading" type="SUBTREE"/> - * 				</parent> - * 				... - * 			</parents> - * 			<fields> - * 				<fieldRef name="book.paragraph."> - * 			</fields> - * 	</structs> + *	<import rel="domain" src="./book_domain.osxml"/> + * 	<struct name="heading" cardinality="1" transparent="true"> + * 		<parentRef ref="book.book"> + * 			<field name="heading" isSubtree="true" optional="true"/> + * 		</parentRef> + * 		... + * 		<fieldRef name="book.paragraph."> + * 	</struct>   * </domain>   * \endcode   * @@ -161,36 +126,36 @@   *   * \code{.xml}   * <domain name="comments"> - * 	<head> - * 		<import rel="domain" src="book.oxm"/> - * 	</head> - * 	<annos> - * 		<anno name="comment"> - * 			<fields> - * 				<field name="replies" type="SUBTREE"> - * 					<children> - * 						<child name="reply"/> - * 					</children> - * 				</field> - * 			</fields> - * 		</anno> - * 	</annos> - * 	<structs> - * 		<struct name="reply"> - * 			<fields> - * 				<field name="replies" type="SUBTREE"> - * 					<children> - * 						<child name="reply"/> - * 					</children> - * 				</field> - * 				<field name="content" type="SUBTREE"> - * 					<children> - * 						<child name="book.paragraph"/> - * 					</children> - * 				</field> - * 			</fields> - * 		</struct> - * 	</structs> + *	<import rel="domain" src="./book_domain.osxml"/> + * + *	<annotation name="comment"> + *		<field name="content" isSubtree="true"> + *			<childRef ref="book.paragraph"/> + *		</field> + *		<field name="replies" isSubtree="true"> + *			<childRef ref="reply"/> + *		</field> + *	</annotation> + * + *	<struct name="comment"> + *		<field name="content"> + *			<childRef ref="book.paragraph"/> + *		</field> + *		<field name="replies" isSubtree="true"> + *			<childRef ref="reply"/> + *		</field> + *		<parentRef ref="book.paragraph"> + *			<fieldRef ref="$default"/> + *		</parentRef> + *	</struct> + *	<struct name="reply"> + *		<field name="content" isSubtree="true"> + *			<childRef ref="book.paragraph"/> + *		</field> + *		<field name="replies" isSubtree="true"> + *			<childRef ref="reply"/> + *		</field> + *	</struct>   * </domain>   * \endcode   * @@ -227,25 +192,15 @@ static const std::string DEFAULT_FIELD_NAME = "$default";   * accordingly typed content without further descending in the Structure   * Hierarchy.   * - * As an example consider the "paragraph" StructuredClass, which might allow + * As an example consider the "text" StructuredClass, which might allow   * the actual text content. Here is the according XML:   *   * \code{.xml} - * <struct name="paragraph" transparent="true" role="paragraph"> - * 	<fields> - * 		<field> - * 			<children> - * 				<child name="book.text"/> - * 			</children> - * 		</field> - * 	</fields> - * </struct> + * 	<struct name="text" transparent="true"> + * 		<primitive type="string"/> + * 	</struct>   * \endcode   * - * Accordingly the primitiveType field of a FieldDescriptor may only be - * defined if the type is set to "PRIMITIVE". If the type is something else - * at least one child must be defined and the primitiveType remains in an - * undefined state.   */  class FieldDescriptor : public Node {  	friend Descriptor; @@ -370,11 +325,11 @@ public:  	}  	/** -	 * Returns true if and only if the type of this field is PRIMITIVE. +	 * Returns if this field is primitive.  	 * -	 * @return true if and only if the type of this field is PRIMITIVE. +	 * @return true if and only if this field is primitive.  	 */ -	bool isPrimitive() const { return fieldType == FieldType::PRIMITIVE; } +	bool isPrimitive() const { return primitive; }  	/**  	 * Returns the primitive type of this field, which is only allowed to be @@ -449,8 +404,10 @@ private:  	Owned<StructType> attributesDescriptor;  	NodeVector<FieldDescriptor> fieldDescriptors; -	bool continuePath(Handle<StructuredClass> target, -	                  std::vector<Rooted<Node>> &path) const; +	bool continuePath(Handle<StructuredClass> target, NodeVector<Node> &path, +	                  bool start) const; + +	void addAndSortFieldDescriptor(Handle<FieldDescriptor> fd, Logger &logger);  protected:  	void doResolve(ResolutionState &state) override; @@ -539,20 +496,7 @@ public:  	 *  	 * @param fd is a FieldDescriptor.  	 */ -	void addFieldDescriptor(Handle<FieldDescriptor> fd); - -	/** -	 * Adds the given FieldDescriptors to this Descriptor. This also sets the -	 * parent of each given FieldDescriptor if it is not set yet. -	 * -	 * @param fds are FieldDescriptors. -	 */ -	void addFieldDescriptors(const std::vector<Handle<FieldDescriptor>> &fds) -	{ -		for (Handle<FieldDescriptor> fd : fds) { -			addFieldDescriptor(fd); -		} -	} +	void addFieldDescriptor(Handle<FieldDescriptor> fd, Logger &logger);  	/**  	 * Adds the given FieldDescriptor to this Descriptor. This also sets the @@ -561,21 +505,7 @@ public:  	 *  	 * @param fd is a FieldDescriptor.  	 */ -	void moveFieldDescriptor(Handle<FieldDescriptor> fd); - -	/** -	 * Adds the given FieldDescriptors to this Descriptor. This also sets the -	 * parent of each given FieldDescriptor if it is not set to this Descriptor -	 * already and removes it from the old parent Descriptor. -	 * -	 * @param fds are FieldDescriptors. -	 */ -	void moveFieldDescriptors(const std::vector<Handle<FieldDescriptor>> &fds) -	{ -		for (Handle<FieldDescriptor> fd : fds) { -			moveFieldDescriptor(fd); -		} -	} +	void moveFieldDescriptor(Handle<FieldDescriptor> fd, Logger &logger);  	/**  	 * Copies a FieldDescriptor that belongs to another Descriptor to this @@ -583,7 +513,7 @@ public:  	 *  	 * @param fd some FieldDescriptor belonging to another Descriptor.  	 */ -	void copyFieldDescriptor(Handle<FieldDescriptor> fd); +	void copyFieldDescriptor(Handle<FieldDescriptor> fd, Logger &logger);  	/**  	 * Removes the given FieldDescriptor from this Descriptor. This also sets @@ -751,9 +681,9 @@ private:  	/**  	 * Helper method for getFieldDescriptors.  	 */ -	const void gatherFieldDescriptors( -	    NodeVector<FieldDescriptor> ¤t, -	    std::set<std::string> &overriddenFields) const; +	void gatherFieldDescriptors(NodeVector<FieldDescriptor> ¤t, +	                            std::set<std::string> &overriddenFields, +	                            bool hasTREE) const;  protected:  	bool doValidate(Logger &logger) const override; diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp index d041c1d..cb34cbe 100644 --- a/src/plugins/html/DemoOutput.cpp +++ b/src/plugins/html/DemoOutput.cpp @@ -324,7 +324,7 @@ Rooted<xml::Element> DemoHTMLTransformer::transformParagraph(  		if (childDescriptorName == "text") {  			Handle<DocumentPrimitive> primitive =  			    t->getField()[0].cast<DocumentPrimitive>(); -			if (primitive.isNull()) { +			if (primitive == nullptr) {  				throw OusiaException("Text field is not primitive!");  			}  			current->addChild(new xml::Text( diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp index 22498f4..d7efa4d 100644 --- a/src/plugins/xml/XmlParser.cpp +++ b/src/plugins/xml/XmlParser.cpp @@ -603,7 +603,7 @@ public:  		    [](Handle<Node> field, Handle<Node> parent, Logger &logger) {  			    if (field != nullptr) {  				    parent.cast<StructuredClass>()->addFieldDescriptor( -				        field.cast<FieldDescriptor>()); +				        field.cast<FieldDescriptor>(), logger);  			    }  			});  	} @@ -969,7 +969,7 @@ static const ParserState DomainField =          .parents({&DomainStruct, &DomainAnnotation})          .createdNodeType(&RttiTypes::FieldDescriptor)          .elementHandler(DomainFieldHandler::create) -        .arguments({Argument::String("name", DEFAULT_FIELD_NAME), +        .arguments({Argument::String("name", ""),                      Argument::Bool("isSubtree", false),                      Argument::Bool("optional", false)}); @@ -985,7 +985,7 @@ static const ParserState DomainStructPrimitive =          .parents({&DomainStruct, &DomainAnnotation})          .createdNodeType(&RttiTypes::FieldDescriptor)          .elementHandler(DomainPrimitiveHandler::create) -        .arguments({Argument::String("name", DEFAULT_FIELD_NAME), +        .arguments({Argument::String("name", ""),                      Argument::Bool("isSubtree", false),                      Argument::Bool("optional", false),                      Argument::String("type")}); @@ -1008,7 +1008,7 @@ static const ParserState DomainStructParentField =          .parent(&DomainStructParent)          .createdNodeType(&RttiTypes::FieldDescriptor)          .elementHandler(DomainParentFieldHandler::create) -        .arguments({Argument::String("name", DEFAULT_FIELD_NAME), +        .arguments({Argument::String("name", ""),                      Argument::Bool("isSubtree", false),                      Argument::Bool("optional", false)});  | 
