diff options
Diffstat (limited to 'src/core/resource')
| -rw-r--r-- | src/core/resource/ResourceManager.cpp | 234 | ||||
| -rw-r--r-- | src/core/resource/ResourceManager.hpp | 173 | 
2 files changed, 195 insertions, 212 deletions
diff --git a/src/core/resource/ResourceManager.cpp b/src/core/resource/ResourceManager.cpp index 184a16d..03fd65b 100644 --- a/src/core/resource/ResourceManager.cpp +++ b/src/core/resource/ResourceManager.cpp @@ -25,33 +25,17 @@  #include <core/common/SourceContextReader.hpp>  #include <core/common/Utils.hpp>  #include <core/model/Node.hpp> -#include <core/parser/ParserContext.hpp> +#include <core/model/Project.hpp>  #include <core/parser/Parser.hpp> +#include <core/parser/ParserContext.hpp> +#include <core/parser/ParserScope.hpp>  #include <core/Registry.hpp>  #include "ResourceManager.hpp" -#include "ResourceUtils.hpp" +#include "ResourceRequest.hpp"  namespace ousia { -/* Static helper functions */ - -static void logUnsopportedType(Logger &logger, Resource &resource, -                               const RttiSet &supportedTypes) -{ -	// Build a list containing the expected type names -	std::vector<std::string> expected; -	for (const Rtti *supportedType : supportedTypes) { -		expected.push_back(supportedType->name); -	} - -	// Log the actual error message -	logger.error( -	    std::string("Expected the file \"") + resource.getLocation() + -	    std::string("\" to define one of the following internal types ") + -	    Utils::join(expected, ", ", "{", "}")); -} -  /* Class ResourceManager */  SourceId ResourceManager::allocateSourceId(const Resource &resource) @@ -86,39 +70,14 @@ void ResourceManager::purgeResource(SourceId sourceId)  	contextReaders.erase(sourceId);  } -Rooted<Node> ResourceManager::parse(ParserContext &ctx, Resource &resource, -                                    const std::string &mimetype, -                                    const RttiSet &supportedTypes) +Rooted<Node> ResourceManager::parse(Registry ®istry, ParserContext &ctx, +                                    const ResourceRequest &req, ParseMode mode)  { -	// Try to deduce the mimetype of no mimetype was given -	std::string mime = mimetype; -	if (mime.empty()) { -		mime = ctx.registry.getMimetypeForFilename(resource.getLocation()); -		if (mime.empty()) { -			ctx.logger.error(std::string("Filename \"") + -			                 resource.getLocation() + -			                 std::string( -			                     "\" has an unknown file extension. Explicitly " -			                     "specify a mimetype.")); -			return nullptr; -		} -	} - -	// Fetch a parser for the mimetype -	const std::pair<Parser *, RttiSet> &parserDescr = -	    ctx.registry.getParserForMimetype(mime); -	Parser *parser = parserDescr.first; - -	// Make sure a parser was found -	if (!parser) { -		ctx.logger.error(std::string("Cannot parse files of type \"") + mime + -		                 std::string("\"")); -		return nullptr; -	} - -	// Make sure the parser returns at least one of the supported types -	if (!Rtti::setIsOneOf(parserDescr.second, supportedTypes)) { -		logUnsopportedType(ctx.logger, resource, supportedTypes); +	// Locate the resource relative to the old resource, abort if this did not +	// work +	Resource resource; +	if (!req.locate(registry, ctx.getLogger(), resource, +	                getResource(ctx.getSourceId()))) {  		return nullptr;  	} @@ -129,16 +88,31 @@ Rooted<Node> ResourceManager::parse(ParserContext &ctx, Resource &resource,  	Rooted<Node> node;  	try {  		// Set the current source id in the logger instance -		GuardedLogger logger(ctx.logger, SourceLocation{sourceId}); - -		// Fetch the input stream and create a char reader -		std::unique_ptr<std::istream> is = resource.stream(); -		CharReader reader(*is, sourceId); - -		// Actually parse the input stream -		node = parser->parse(reader, ctx); +		{ +			GuardedLogger logger(ctx.getLogger(), SourceLocation{sourceId}); + +			// Fetch the input stream and create a char reader +			std::unique_ptr<std::istream> is = resource.stream(); +			CharReader reader(*is, sourceId); + +			// Actually parse the input stream, distinguish the LINK and the +			// INCLUDE +			// mode +			switch (mode) { +				case ParseMode::LINK: { +					ParserScope scope;  // New empty parser scope instance +					ParserContext childCtx = ctx.clone(scope, sourceId); +					node = req.getParser()->parse(reader, childCtx); +				} +				case ParseMode::INCLUDE: { +					ParserContext childCtx = ctx.clone(sourceId); +					node = req.getParser()->parse(reader, childCtx); +				} +			} +		}  		if (node == nullptr) { -			throw LoggableException{"Internal error: Parser returned null."}; +			throw LoggableException{"File \"" + resource.getLocation() + +			                        "\" cannot be parsed."};  		}  	}  	catch (LoggableException ex) { @@ -146,17 +120,66 @@ Rooted<Node> ResourceManager::parse(ParserContext &ctx, Resource &resource,  		purgeResource(sourceId);  		// Log the exception and return nullptr -		ctx.logger.log(ex); +		ctx.getLogger().log(ex);  		return nullptr;  	} -	// Store the parsed node along with the sourceId -	storeNode(sourceId, node); +	// Store the parsed node along with the sourceId, if we are in the LINK mode +	if (mode == ParseMode::LINK) { +		storeNode(sourceId, node); +	}  	// Return the parsed node  	return node;  } +Rooted<Node> ResourceManager::link(Registry ®istry, ParserContext &ctx, +                                   const std::string &path, +                                   const std::string &mimetype, +                                   const std::string &rel, +                                   const RttiSet &supportedTypes) +{ +	ResourceRequest req{path, mimetype, rel, supportedTypes}; +	if (req.deduce(registry, ctx.getLogger())) { +		return parse(registry, ctx, req, ParseMode::LINK); +	} +	return nullptr; +} + +Rooted<Node> ResourceManager::include(Registry ®istry, ParserContext &ctx, +                                      const std::string &path, +                                      const std::string &mimetype, +                                      const std::string &rel, +                                      const RttiSet &supportedTypes) +{ +	ResourceRequest req{path, mimetype, rel, supportedTypes}; +	if (req.deduce(registry, ctx.getLogger())) { +		return parse(registry, ctx, req, ParseMode::INCLUDE); +	} +	return nullptr; +} + +SourceContext ResourceManager::readContext(const SourceLocation &location, +                                           size_t maxContextLength) +{ +	const Resource &resource = getResource(location.getSourceId()); +	if (resource.isValid()) { +		// Fetch a char reader for the resource +		std::unique_ptr<std::istream> is = resource.stream(); +		CharReader reader{*is, location.getSourceId()}; + +		// Return the context +		return contextReaders[location.getSourceId()].readContext( +		    reader, location, maxContextLength, resource.getLocation()); +	} +	return SourceContext{}; +} + +SourceContext ResourceManager::readContext(const SourceLocation &location) +{ +	return readContext(location, SourceContextReader::MAX_MAX_CONTEXT_LENGTH); +} +  SourceId ResourceManager::getSourceId(const std::string &location)  {  	auto it = locations.find(location); @@ -187,7 +210,7 @@ Rooted<Node> ResourceManager::getNode(Manager &mgr, SourceId sourceId)  {  	auto it = nodes.find(sourceId);  	if (it != nodes.end()) { -		Managed *managed = mgr.getManaged(sourceId); +		Managed *managed = mgr.getManaged(it->second);  		if (managed != nullptr) {  			return dynamic_cast<Node *>(managed);  		} else { @@ -206,86 +229,5 @@ Rooted<Node> ResourceManager::getNode(Manager &mgr, const Resource &resource)  {  	return getNode(mgr, getSourceId(resource));  } - -Rooted<Node> ResourceManager::link(ParserContext &ctx, const std::string &path, -                                   const std::string &mimetype, -                                   const std::string &rel, -                                   const RttiSet &supportedTypes, -                                   const Resource &relativeTo) -{ -	// Try to deduce the ResourceType -	ResourceType resourceType = -	    ResourceUtils::deduceResourceType(rel, supportedTypes, ctx.logger); - -	// Lookup the resource for given path and resource type -	Resource resource; -	if (!ctx.registry.locateResource(resource, path, resourceType, -	                                 relativeTo)) { -		ctx.logger.error("File \"" + path + "\" not found."); -		return nullptr; -	} - -	// Try to shrink the set of supportedTypes -	RttiSet types = ResourceUtils::limitRttiTypes(supportedTypes, rel); - -	// Check whether the resource has already been parsed -	Rooted<Node> node = getNode(ctx.manager, resource); -	if (node == nullptr) { -		// Node has not already been parsed, parse it now -		node = parse(ctx, resource, mimetype, supportedTypes); - -		// Abort if parsing failed -		if (node == nullptr) { -			return nullptr; -		} -	} - -	// Make sure the node has one of the supported types -	if (!node->type().isOneOf(supportedTypes)) { -		logUnsopportedType(ctx.logger, resource, supportedTypes); -		return nullptr; -	} - -	return node; -} - -Rooted<Node> ResourceManager::link(ParserContext &ctx, const std::string &path, -                                   const std::string &mimetype, -                                   const std::string &rel, -                                   const RttiSet &supportedTypes, -                                   SourceId relativeTo) -{ -	// Fetch the resource corresponding to the source id, make sure it is valid -	const Resource &relativeResource = getResource(relativeTo); -	if (!relativeResource.isValid()) { -		ctx.logger.fatalError("Internal error: Invalid SourceId supplied."); -		return nullptr; -	} - -	// Continue with the usual include routine -	return link(ctx, path, mimetype, rel, supportedTypes, relativeResource); -} - -SourceContext ResourceManager::readContext(const SourceLocation &location, -                                           size_t maxContextLength) -{ -	const Resource &resource = getResource(location.getSourceId()); -	if (resource.isValid()) { -		// Fetch a char reader for the resource -		std::unique_ptr<std::istream> is = resource.stream(); -		CharReader reader{*is, location.getSourceId()}; - -		// Return the context -		return contextReaders[location.getSourceId()].readContext( -		    reader, location, maxContextLength, resource.getLocation()); -	} -	return SourceContext{}; -} - -SourceContext ResourceManager::readContext(const SourceLocation &location) -{ -	return readContext(location, SourceContextReader::MAX_MAX_CONTEXT_LENGTH); -} -  } diff --git a/src/core/resource/ResourceManager.hpp b/src/core/resource/ResourceManager.hpp index 221e2cc..6cb3249 100644 --- a/src/core/resource/ResourceManager.hpp +++ b/src/core/resource/ResourceManager.hpp @@ -34,6 +34,7 @@  #include <core/common/Location.hpp>  #include <core/common/Rtti.hpp> +#include <core/common/SourceContextReader.hpp>  #include <core/managed/Managed.hpp>  #include "Resource.hpp" @@ -41,8 +42,11 @@  namespace ousia {  // Forward declarations +class Registry;  class Node; +class Parser;  class ParserContext; +class ResourceRequest;  extern const Resource NullResource;  /** @@ -51,6 +55,12 @@ extern const Resource NullResource;   * and returns references for those resources that already have been parsed.   */  class ResourceManager { +public: +	/** +	 * Used internally to set the mode of the Parse function. +	 */ +	enum class ParseMode { LINK, INCLUDE }; +  private:  	/**  	 * Next SourceId to be used. @@ -105,25 +115,113 @@ private:  	void purgeResource(SourceId sourceId);  	/** -	 * Used internally to parse the given resource. +	 * Used internally to parse the given resource. Can either operate in the +	 * "link" or the "include" mode. In the latter case the ParserScope instance +	 * inside the ParserContext is exchanged with an empty one. +	 * +	 * @param registry is the registry that should be used to locate the +	 * resource. +	 * @param ctx is the context that should be passed to the parser. +	 * @param req is a ResourceRequest instance that contains all information +	 * about the requested resource. +	 * @param mode describes whether the file should be included or linked. +	 * @return the parsed node or nullptr if something goes wrong. +	 */ +	Rooted<Node> parse(Registry ®istry, ParserContext &ctx, +	                   const ResourceRequest &req, ParseMode mode); + +public: +	/** +	 * Resolves the reference to the file specified by the given path and -- if +	 * this has not already happened -- parses the file. The parser that is +	 * called is provided a new ParserContext instance with an empty ParserScope +	 * which allows the Node instance returned by the parser to be cached. Logs +	 * any problem in the logger instance of the given ParserContext. +	 * +	 * @param registry is the registry instance that should be used to lookup +	 * the parser instances and to locate the resources. +	 * @param ctx is the context from which the Logger instance will be looked +	 * up. This context instance is not directly passed to the Parser, the +	 * ParserScope instance is replaced with a new one. The sourceId specified +	 * in the context instance will be used as relative location for looking up +	 * the new resource. +	 * @param mimetype is the mimetype of the resource that should be parsed +	 * (may be empty, in which case the mimetype is deduced from the file +	 * extension) +	 * @param rel is a "relation string" supplied by the user which specifies +	 * the relationship of the specified resource. +	 * @param supportedTypes contains the types of the returned Node the caller +	 * can deal with. Note that only the types the parser claims to return are +	 * checked, not the actual result. +	 * @return the parsed node or nullptr if something goes wrong. +	 */ +	Rooted<Node> link(Registry ®istry, ParserContext &ctx, +	                  const std::string &path, const std::string &mimetype = "", +	                  const std::string &rel = "", +	                  const RttiSet &supportedTypes = RttiSet{}); + +	/** +	 * Resolves the reference to the file specified by the given path and parses +	 * the file using the provided context. As the result of the "include" +	 * function depends on the ParserScope inside the provided ParserContext +	 * instance, the resource has to be parsed every time this function is +	 * called. This contasts the behaviour of the "link" function, which creates +	 * a new ParserScope and thus guarantees reproducible results. Logs any +	 * problem in the logger instance of the given ParserContext.  	 * -	 * @param ctx is the context from the Registry and the Logger instance will -	 * be looked up. -	 * @param resource is the resource from which the input stream should be -	 * obtained. +	 * @param registry is the registry instance that should be used to lookup +	 * the parser instances and to locate the resources. +	 * @param ctx is the context from which the Logger instance will be looked +	 * up. The sourceId specified in the context instance will be used as +	 * relative location for looking up the new resource. +	 * @param path is the requested path of the file that should be included.  	 * @param mimetype is the mimetype of the resource that should be parsed  	 * (may be empty, in which case the mimetype is deduced from the file  	 * extension) +	 * @param rel is a "relation string" supplied by the user which specifies +	 * the relationship of the specified resource.  	 * @param supportedTypes contains the types of the returned Node the caller  	 * can deal with. Note that only the types the parser claims to return are  	 * checked, not the actual result.  	 * @return the parsed node or nullptr if something goes wrong.  	 */ -	Rooted<Node> parse(ParserContext &ctx, Resource &resource, -	                   const std::string &mimetype, -	                   const RttiSet &supportedTypes); +	Rooted<Node> include(Registry ®istry, ParserContext &ctx, +	                     const std::string &path, +	                     const std::string &mimetype = "", +	                     const std::string &rel = "", +	                     const RttiSet &supportedTypes = RttiSet{}); + +	/** +	 * Creates and returns a SourceContext structure containing information +	 * about the given SourceLocation (such as line and column number). Throws +	 * a LoggableException if an irrecoverable error occurs while looking up the +	 * context (such as a no longer existing resource). +	 * +	 * @param location is the SourceLocation for which context information +	 * should be retrieved. This method is used by the Logger class to print +	 * pretty messages. +	 * @param maxContextLength is the maximum length in character of context +	 * that should be extracted. +	 * @return a valid SourceContext if a valid SourceLocation was given or an +	 * invalid SourceContext if the location is invalid. +	 */ +	SourceContext readContext(const SourceLocation &location, +	                          size_t maxContextLength); +	/** +	 * Creates and returns a SourceContext structure containing information +	 * about the given SourceLocation (such as line and column number). Throws +	 * a LoggableException if an irrecoverable error occurs while looking up the +	 * context (such as a no longer existing resource). Does not limit the +	 * context length. +	 * +	 * @param location is the SourceLocation for which context information +	 * should be retrieved. This method is used by the Logger class to print +	 * pretty messages. +	 * @return a valid SourceContext if a valid SourceLocation was given or an +	 * invalid SourceContext if the location is invalid. +	 */ +	SourceContext readContext(const SourceLocation &location); -public:  	/**  	 * Returns the sourceId for the given location string.  	 * @@ -188,63 +286,6 @@ public:  	 * @return the Node instance corresponding to the given resource.  	 */  	Rooted<Node> getNode(Manager &mgr, const Resource &resource); - -	/** -	 * Resolves the reference to the file specified by the given path and -- if -	 * this has not already happened -- parses the file. Logs any problem in -	 * the logger instance of the given ParserContext. -	 * -	 * @param ctx is the context from the Registry and the Logger instance will -	 * be looked up. -	 * @param path is the path to the file that should be included. -	 * @param mimetype is the mimetype the file was included with. If no -	 * mimetype is given, the path must have an extension that is known by -	 */ -	Rooted<Node> link(ParserContext &ctx, const std::string &path, -	                  const std::string &mimetype = "", -	                  const std::string &rel = "", -	                  const RttiSet &supportedTypes = RttiSet{}, -	                  const Resource &relativeTo = NullResource); - -	/** -	 * Resolves the reference to the file specified by the given path and -- if -	 * this has not already happened -- parses the file. Logs any problem in -	 * the logger instance of the given ParserContext. -	 */ -	Rooted<Node> link(ParserContext &ctx, const std::string &path, -	                  const std::string &mimetype, const std::string &rel, -	                  const RttiSet &supportedTypes, SourceId relativeTo); - -	/** -	 * Creates and returns a SourceContext structure containing information -	 * about the given SourceLocation (such as line and column number). Throws -	 * a LoggableException if an irrecoverable error occurs while looking up the -	 * context (such as a no longer existing resource). -	 * -	 * @param location is the SourceLocation for which context information -	 * should be retrieved. This method is used by the Logger class to print -	 * pretty messages. -	 * @param maxContextLength is the maximum length in character of context -	 * that should be extracted. -	 * @return a valid SourceContext if a valid SourceLocation was given or an -	 * invalid SourceContext if the location is invalid. -	 */ -	SourceContext readContext(const SourceLocation &location, -	                          size_t maxContextLength); -	/** -	 * Creates and returns a SourceContext structure containing information -	 * about the given SourceLocation (such as line and column number). Throws -	 * a LoggableException if an irrecoverable error occurs while looking up the -	 * context (such as a no longer existing resource). Does not limit the -	 * context length. -	 * -	 * @param location is the SourceLocation for which context information -	 * should be retrieved. This method is used by the Logger class to print -	 * pretty messages. -	 * @return a valid SourceContext if a valid SourceLocation was given or an -	 * invalid SourceContext if the location is invalid. -	 */ -	SourceContext readContext(const SourceLocation &location);  };  }  | 
