summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/Exceptions.cpp7
-rw-r--r--src/core/Logger.cpp2
-rw-r--r--src/core/Logger.hpp90
-rw-r--r--src/core/Registry.cpp47
-rw-r--r--src/core/Registry.hpp51
-rw-r--r--src/core/Utils.cpp22
-rw-r--r--src/core/Utils.hpp52
-rw-r--r--src/core/parser/Parser.cpp (renamed from src/core/Parser.cpp)9
-rw-r--r--src/core/parser/Parser.hpp (renamed from src/core/Parser.hpp)85
-rw-r--r--src/core/parser/ParserStack.cpp150
-rw-r--r--src/core/parser/ParserStack.hpp341
-rw-r--r--src/core/parser/Scope.cpp26
-rw-r--r--src/core/parser/Scope.hpp172
-rw-r--r--src/core/parser/XmlParser.cpp134
-rw-r--r--src/core/variant/Variant.cpp155
-rw-r--r--src/core/variant/Variant.hpp693
-rw-r--r--src/plugins/mozjs/MozJsScriptEngine.cpp2
-rw-r--r--src/plugins/mozjs/MozJsScriptEngine.hpp2
-rw-r--r--src/plugins/xml/XmlParser.cpp226
-rw-r--r--src/plugins/xml/XmlParser.hpp (renamed from src/core/parser/XmlParser.hpp)14
20 files changed, 2099 insertions, 181 deletions
diff --git a/src/core/Exceptions.cpp b/src/core/Exceptions.cpp
index 92d9293..735dac6 100644
--- a/src/core/Exceptions.cpp
+++ b/src/core/Exceptions.cpp
@@ -29,16 +29,17 @@ std::string LoggableException::formatMessage(const std::string &msg,
int column, bool fatal)
{
std::stringstream ss;
+ ss << "error ";
if (!file.empty()) {
ss << "while processing \"" << file << "\" ";
}
if (line >= 0) {
- ss << "at line: " << line << " ";
+ ss << "at line " << line << ", ";
if (column >= 0) {
- ss << "col: " << column << " ";
+ ss << "column " << column << " ";
}
}
- ss << "message: " << msg;
+ ss << "with message: " << msg;
return ss.str();
}
}
diff --git a/src/core/Logger.cpp b/src/core/Logger.cpp
index 1a3b6c6..17f55a6 100644
--- a/src/core/Logger.cpp
+++ b/src/core/Logger.cpp
@@ -149,7 +149,7 @@ void TerminalLogger::process(const Message &msg)
os << t.color(Terminal::RED, true) << "error: ";
break;
case Severity::FATAL_ERROR:
- os << t.color(Terminal::RED, true) << "error: ";
+ os << t.color(Terminal::RED, true) << "fatal: ";
break;
}
os << t.reset();
diff --git a/src/core/Logger.hpp b/src/core/Logger.hpp
index 260d010..a30374c 100644
--- a/src/core/Logger.hpp
+++ b/src/core/Logger.hpp
@@ -256,6 +256,22 @@ public:
* the file name stack.
*
* @param msg is the actual log message.
+ * @param file is the name of the file the message refers to. May be empty.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
+ void debug(const std::string &msg, const std::string &file, int line = -1, int column = -1)
+ {
+ log(Severity::DEBUG, msg, file, line, column);
+ }
+
+ /**
+ * Logs a debug message. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param msg is the actual log message.
* @param line is the line in the above file at which the error occured.
* Ignored if negative.
* @param column is the column in the above file at which the error occured.
@@ -263,7 +279,23 @@ public:
*/
void debug(const std::string &msg, int line = -1, int column = -1)
{
- log(Severity::DEBUG, msg, line, column);
+ debug(msg, currentFilename(), line, column);
+ }
+
+ /**
+ * Logs a note. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param msg is the actual log message.
+ * @param file is the name of the file the message refers to. May be empty.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
+ void note(const std::string &msg, const std::string &file, int line = -1, int column = -1)
+ {
+ log(Severity::NOTE, msg, file, line, column);
}
/**
@@ -278,7 +310,23 @@ public:
*/
void note(const std::string &msg, int line = -1, int column = -1)
{
- log(Severity::NOTE, msg, line, column);
+ note(msg, currentFilename(), line, column);
+ }
+
+ /**
+ * Logs a warning. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param msg is the actual log message.
+ * @param file is the name of the file the message refers to. May be empty.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
+ void warning(const std::string &msg, const std::string &file, int line = -1, int column = -1)
+ {
+ log(Severity::WARNING, msg, file, line, column);
}
/**
@@ -293,7 +341,23 @@ public:
*/
void warning(const std::string &msg, int line = -1, int column = -1)
{
- log(Severity::WARNING, msg, line, column);
+ warning(msg, currentFilename(), line, column);
+ }
+
+ /**
+ * Logs an error message. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param msg is the actual log message.
+ * @param file is the name of the file the message refers to. May be empty.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
+ void error(const std::string &msg, const std::string &file, int line = -1, int column = -1)
+ {
+ log(Severity::ERROR, msg, file, line, column);
}
/**
@@ -308,7 +372,23 @@ public:
*/
void error(const std::string &msg, int line = -1, int column = -1)
{
- log(Severity::ERROR, msg, line, column);
+ error(msg, currentFilename(), line, column);
+ }
+
+ /**
+ * Logs a fatal error. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param msg is the actual log message.
+ * @param file is the name of the file the message refers to. May be empty.
+ * @param line is the line in the above file at which the error occured.
+ * Ignored if negative.
+ * @param column is the column in the above file at which the error occured.
+ * Ignored if negative.
+ */
+ void fatalError(const std::string &msg, const std::string &file, int line = -1, int column = -1)
+ {
+ log(Severity::FATAL_ERROR, msg, file, line, column);
}
/**
@@ -323,7 +403,7 @@ public:
*/
void fatalError(const std::string &msg, int line = -1, int column = -1)
{
- log(Severity::FATAL_ERROR, msg, line, column);
+ fatalError(msg, currentFilename(), line, column);
}
/**
diff --git a/src/core/Registry.cpp b/src/core/Registry.cpp
new file mode 100644
index 0000000..1961b35
--- /dev/null
+++ b/src/core/Registry.cpp
@@ -0,0 +1,47 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <core/Logger.hpp>
+
+#include <core/parser/Parser.hpp>
+
+namespace ousia {
+
+using namespace parser;
+
+/* Class Registry */
+
+void Registry::registerParser(parser::Parser *parser)
+{
+ parsers.push_back(parser);
+ for (const auto &mime : parser.mimetypes()) {
+ parserMimetypes.insert(std::make_pair(mime, parser));
+ }
+}
+
+Parser* Registry::getParserForMimetype(const std::string &mimetype)
+{
+ const auto it = parserMimetypes.find(mimetype);
+ if (it != parserMimetypes.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+}
+
diff --git a/src/core/Registry.hpp b/src/core/Registry.hpp
new file mode 100644
index 0000000..235e427
--- /dev/null
+++ b/src/core/Registry.hpp
@@ -0,0 +1,51 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _OUSIA_REGISTRY_HPP_
+#define _OUSIA_REGISTRY_HPP_
+
+#include <map>
+#include <vector>
+
+namespace ousia {
+
+// TODO: Add support for ScriptEngine type
+
+class Logger;
+
+namespace parser {
+class Parser;
+}
+
+class Registry {
+private:
+ Logger &logger;
+ std::vector<parser::Parser*> parsers;
+ std::map<std::string, parser::Parser*> parserMimetypes;
+
+public:
+ Registry(Logger &logger) : logger(logger) {}
+
+ void registerParser(parser::Parser *parser);
+
+ parser::Parser *getParserForMimetype(std::string mimetype);
+};
+}
+
+#endif /* _OUSIA_REGISTRY_HPP_ */
+
diff --git a/src/core/Utils.cpp b/src/core/Utils.cpp
index 184fdd0..c460ed4 100644
--- a/src/core/Utils.cpp
+++ b/src/core/Utils.cpp
@@ -16,10 +16,31 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <algorithm>
+#include <limits>
+
#include "Utils.hpp"
namespace ousia {
+std::string Utils::trim(const std::string &s)
+{
+ size_t firstNonWhitespace = std::numeric_limits<size_t>::max();
+ size_t lastNonWhitespace = 0;
+ for (size_t i = 0; i < s.size(); i++) {
+ if (!isWhitespace(s[i])) {
+ firstNonWhitespace = std::min(i, firstNonWhitespace);
+ lastNonWhitespace = std::max(i, lastNonWhitespace);
+ }
+ }
+
+ if (firstNonWhitespace < lastNonWhitespace) {
+ return s.substr(firstNonWhitespace,
+ lastNonWhitespace - firstNonWhitespace + 1);
+ }
+ return std::string{};
+}
+
bool Utils::isIdentifier(const std::string &name)
{
bool first = true;
@@ -34,6 +55,5 @@ bool Utils::isIdentifier(const std::string &name)
}
return true;
}
-
}
diff --git a/src/core/Utils.hpp b/src/core/Utils.hpp
index 2fcd794..14bd7b4 100644
--- a/src/core/Utils.hpp
+++ b/src/core/Utils.hpp
@@ -16,18 +16,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
#ifndef _OUSIA_UTILS_H_
#define _OUSIA_UTILS_H_
+#include <sstream>
#include <string>
namespace ousia {
class Utils {
-
public:
-
/**
* Returns true if the given character is in [A-Za-z]
*/
@@ -39,10 +37,7 @@ public:
/**
* Returns true if the given character is in [0-9]
*/
- static bool isNumeric(const char c)
- {
- return (c >= '0') && (c <= '9');
- }
+ static bool isNumeric(const char c) { return (c >= '0') && (c <= '9'); }
/**
* Returns true if the given character is in [A-Za-z0-9]
@@ -57,8 +52,49 @@ public:
*/
static bool isIdentifier(const std::string &name);
-};
+ /**
+ * Returns true if the given character is a whitespace character.
+ */
+ static bool isWhitespace(const char c)
+ {
+ return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
+ }
+ /**
+ * Removes whitespace at the beginning and the end of the given string.
+ */
+ static std::string trim(const std::string &s);
+
+ /**
+ * Turns the elements of a collection into a string separated by the
+ * given delimiter.
+ *
+ * @param es is an iterable container of elements that can be appended to an
+ * output stream (the << operator must be implemented).
+ * @param delim is the delimiter that should be used to separate the items.
+ * @param start is a character sequence that should be prepended to the
+ * result.
+ * @param end is a character sequence that should be appended to the result.
+ */
+ template <class T>
+ static std::string join(T es, const std::string &delim,
+ const std::string &start = "",
+ const std::string &end = "")
+ {
+ std::stringstream res;
+ bool first = true;
+ res << start;
+ for (const auto &e : es) {
+ if (!first) {
+ res << delim;
+ }
+ res << e;
+ first = false;
+ }
+ res << end;
+ return res.str();
+ }
+};
}
#endif /* _OUSIA_UTILS_H_ */
diff --git a/src/core/Parser.cpp b/src/core/parser/Parser.cpp
index bc98ac0..23fd9b7 100644
--- a/src/core/Parser.cpp
+++ b/src/core/parser/Parser.cpp
@@ -21,12 +21,13 @@
#include "Parser.hpp"
namespace ousia {
+namespace parser {
-Rooted<Node> Parser::parse(const std::string &str, Handle<Node> context, Logger &logger)
+Rooted<Node> Parser::parse(const std::string &str, ParserContext &ctx)
{
- std::istringstream is(str);
- return parse(is, context, logger);
+ std::istringstream is{str};
+ return parse(is, ctx);
+}
}
-
}
diff --git a/src/core/Parser.hpp b/src/core/parser/Parser.hpp
index 74a1988..fa5dd49 100644
--- a/src/core/Parser.hpp
+++ b/src/core/parser/Parser.hpp
@@ -19,7 +19,7 @@
/**
* @file Parser.hpp
*
- * Contains the abstract "Parser" class. Parsers are objects capable of reading
+ * Contains the abstract Parser class. Parsers are objects capable of reading
* a certain file format and transforming it into a node.
*
* @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
@@ -32,11 +32,15 @@
#include <set>
#include <string>
-#include "Exceptions.hpp"
-#include "Node.hpp"
-#include "Logger.hpp"
+#include <core/Exceptions.hpp>
+#include <core/Node.hpp>
+#include <core/Logger.hpp>
+#include <core/Registry.hpp>
+
+#include "Scope.hpp"
namespace ousia {
+namespace parser {
// TODO: Implement a proper Mimetype class
@@ -49,15 +53,61 @@ public:
};
/**
+ * Struct containing the objects that are passed to a parser instance.
+ */
+struct ParserContext {
+ /**
+ * Reference to the Scope instance that should be used within the parser.
+ */
+ Scope &scope;
+
+ /**
+ * Reference to the Registry instance that should be used within the parser.
+ */
+ Registry &registry;
+
+ /**
+ * Reference to the Logger the parser should log any messages to.
+ */
+ Logger &logger;
+
+ /**
+ * Constructor of the ParserContext class.
+ *
+ * @param scope is a reference to the Scope instance that should be used to
+ * lookup names.
+ * @param registry is a reference at the Registry class, which allows to
+ * obtain references at parsers for other formats or script engine
+ * implementations.
+ * @param logger is a reference to the Logger instance that should be used
+ * to log error messages and warnings that occur while parsing the document.
+ */
+ ParserContext(Scope &scope, Registry &registry, Logger &logger)
+ : scope(scope), registry(registry), logger(logger){};
+};
+
+struct StandaloneParserContext : public ParserContext {
+private:
+ Logger logger;
+ Scope scope;
+ Registry registry;
+
+public:
+ StandaloneParserContext()
+ : ParserContext(scope, registry, logger),
+ scope(nullptr),
+ registry(logger){};
+};
+
+/**
* Abstract parser class. This class builds the basic interface that should be
* used by any parser which reads data from an input stream and transforms it
* into an Ousía node graph.
*/
class Parser {
public:
-
- Parser() {};
- Parser(const Parser&) = delete;
+ Parser(){};
+ Parser(const Parser &) = delete;
/**
* Returns a set containing all mime types supported by the parser. The mime
@@ -78,18 +128,14 @@ public:
* derived classes.
*
* @param is is a reference to the input stream that should be parsed.
- * @param context defines the context in which the input stream should be
- * parsed. The context represents the scope from which element names should
- * be looked up.
- * @param logger is a reference to the Logger instance that should be used
- * to log error messages and warnings that occur while parsing the document.
+ * @param ctx is a reference to the context that should be used while
+ * parsing the document.
* @return a reference to the node representing the subgraph that has been
* created. The resulting node may point at not yet resolved entities, the
* calling code will try to resolve these. If no valid node can be produced,
* a corresponding LoggableException must be thrown by the parser.
*/
- virtual Rooted<Node> parse(std::istream &is, Handle<Node> context,
- Logger &logger) = 0;
+ virtual Rooted<Node> parse(std::istream &is, ParserContext &ctx) = 0;
/**
* Parses the given string and returns a corresponding node for
@@ -97,20 +143,17 @@ public:
* derived classes.
*
* @param str is the string that should be parsed.
- * @param context defines the context in which the input stream should be
- * parsed. The context represents the scope from which element names should
- * be looked up.
- * @param logger is a reference to the Logger instance that should be used
- * to log error messages and warnings that occur while parsing the document.
+ * @param ctx is a reference to the context that should be used while
+ * parsing the document.
* @return a reference to the node representing the subgraph that has been
* created. The resulting node may point at not yet resolved entities, the
* calling code will try to resolve these. If no valid node can be produced,
* a corresponding ParserException must be thrown by the parser.
*/
- Rooted<Node> parse(const std::string &str, Handle<Node> context,
- Logger &logger);
+ Rooted<Node> parse(const std::string &str, ParserContext &ctx);
};
}
+}
#endif /* _OUSIA_PARSER_HPP_ */
diff --git a/src/core/parser/ParserStack.cpp b/src/core/parser/ParserStack.cpp
new file mode 100644
index 0000000..dca7f35
--- /dev/null
+++ b/src/core/parser/ParserStack.cpp
@@ -0,0 +1,150 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <sstream>
+
+#include "ParserStack.hpp"
+
+#include <core/Utils.hpp>
+#include <core/Exceptions.hpp>
+
+namespace ousia {
+namespace parser {
+
+/* Class Handler */
+
+void Handler::data(const std::string &data, int field)
+{
+ for (auto &c : data) {
+ if (!Utils::isWhitespace(c)) {
+ throw LoggableException{"No data allowed here."};
+ }
+ }
+}
+
+/* Class HandlerDescriptor */
+
+HandlerInstance HandlerDescriptor::create(const ParserContext &ctx,
+ std::string name, State parentState,
+ bool isChild,
+ const Variant &args) const
+{
+ Handler *h = ctor(ctx, name, targetState, parentState, isChild);
+ h->start(args);
+ return HandlerInstance(h, this);
+}
+
+/* Class ParserStack */
+
+/**
+ * Returns an Exception that should be thrown when a currently invalid command
+ * is thrown.
+ */
+static LoggableException invalidCommand(const std::string &name,
+ const std::set<std::string> &expected)
+{
+ if (expected.empty()) {
+ return LoggableException{
+ std::string{"No nested elements allowed, but got \""} + name +
+ std::string{"\""}};
+ } else {
+ return LoggableException{
+ std::string{"Expected "} +
+ (expected.size() == 1 ? std::string{"\""}
+ : std::string{"one of \""}) +
+ Utils::join(expected, "\", \"") + std::string{"\", but got \""} + name +
+ std::string{"\""}};
+ }
+}
+
+std::set<std::string> ParserStack::expectedCommands(State state)
+{
+ std::set<std::string> res;
+ for (const auto &v : handlers) {
+ if (v.second.parentStates.count(state)) {
+ res.insert(v.first);
+ }
+ }
+ return res;
+}
+
+void ParserStack::start(std::string name, const Variant &args)
+{
+ // Fetch the current handler and the current state
+ const HandlerInstance *h = stack.empty() ? nullptr : &stack.top();
+ const State curState = currentState();
+ bool isChild = false;
+
+ // Fetch the correct Handler descriptor for this
+ const HandlerDescriptor *descr = nullptr;
+ auto range = handlers.equal_range(name);
+ for (auto it = range.first; it != range.second; it++) {
+ const std::set<State> &parentStates = it->second.parentStates;
+ if (parentStates.count(curState) || parentStates.count(STATE_ALL)) {
+ descr = &(it->second);
+ break;
+ }
+ }
+ if (!descr && currentArbitraryChildren()) {
+ isChild = true;
+ descr = h->descr;
+ }
+
+ // No descriptor found, throw an exception.
+ if (!descr) {
+ throw invalidCommand(name, expectedCommands(curState));
+ }
+
+ // Instantiate the handler and call its start function
+ stack.emplace(descr->create(ctx, name, curState, isChild, args));
+}
+
+void ParserStack::end()
+{
+ // Check whether the current command could be ended
+ if (stack.empty()) {
+ throw LoggableException{"No command to end."};
+ }
+
+ // Remove the current HandlerInstance from the stack
+ HandlerInstance inst{stack.top()};
+ stack.pop();
+
+ // Call the end function of the last Handler
+ inst.handler->end();
+
+ // Call the "child" function of the parent Handler in the stack
+ // (if one exists).
+ if (!stack.empty()) {
+ stack.top().handler->child(inst.handler);
+ }
+}
+
+void ParserStack::data(const std::string &data, int field)
+{
+ // Check whether there is any command the data can be sent to
+ if (stack.empty()) {
+ throw LoggableException{"No command to receive data."};
+ }
+
+ // Pass the data to the current Handler instance
+ stack.top().handler->data(data, field);
+}
+}
+}
+
diff --git a/src/core/parser/ParserStack.hpp b/src/core/parser/ParserStack.hpp
new file mode 100644
index 0000000..c5ed4e4
--- /dev/null
+++ b/src/core/parser/ParserStack.hpp
@@ -0,0 +1,341 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file ParserStack.hpp
+ *
+ * Helper classes for document or description parsers. Contains the ParserStack
+ * class, which is an pushdown automaton responsible for accepting commands in
+ * the correct order and calling specified handlers.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_PARSER_STACK_HPP_
+#define _OUSIA_PARSER_STACK_HPP_
+
+#include <cstdint>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <stack>
+#include <vector>
+
+#include <core/variant/Variant.hpp>
+
+#include "Parser.hpp"
+
+namespace ousia {
+namespace parser {
+
+/**
+ * The State type alias is used to
+ */
+using State = int16_t;
+
+static const State STATE_ALL = -2;
+static const State STATE_NONE = -1;
+
+/**
+ * The handler class provides a context for handling an XML tag. It has to be
+ * overridden and registered in the StateStack class to form handlers for
+ * concrete XML tags.
+ */
+class Handler {
+private:
+ Rooted<Node> node;
+
+protected:
+ void setNode(Handle<Node> node) { this->node = node; }
+
+public:
+ /**
+ * Reference to the ParserContext instance that should be used to resolve
+ * references to nodes in the Graph.
+ */
+ const ParserContext &ctx;
+
+ /**
+ * Contains the name of the tag that is being handled.
+ */
+ const std::string name;
+
+ /**
+ * Contains the current state of the state machine.
+ */
+ const State state;
+
+ /**
+ * Contains the state of the state machine when the parent node was handled.
+ */
+ const State parentState;
+
+ /**
+ * Set to true if the tag that is being handled is not the tag that was
+ * specified in the state machine but a child tag of that tag.
+ */
+ const bool isChild;
+
+ /**
+ * Constructor of the Handler class.
+ *
+ * @param ctx is the parser context the handler should be executed in.
+ * @param name is the name of the string.
+ * @param state is the state this handler was called for.
+ * @param parentState is the state of the parent command.
+ * @param isChild specifies whether this handler was called not for the
+ * command that was specified in the state machine but a child command.
+ */
+ Handler(const ParserContext &ctx, std::string name, State state,
+ State parentState, bool isChild)
+ : ctx(ctx),
+ name(std::move(name)),
+ state(state),
+ parentState(parentState),
+ isChild(isChild){};
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~Handler(){};
+
+ /**
+ * Returns the node instance that was created by the handler.
+ *
+ * @return the Node instance created by the handler. May be nullptr if no
+ * Node was created.
+ */
+ Rooted<Node> getNode() { return node; }
+
+ /**
+ * Called when the command that was specified in the constructor is
+ * instanciated.
+ *
+ * @param args is a map from strings to variants (argument name and value).
+ */
+ virtual void start(const Variant &args) = 0;
+
+ /**
+ * Called whenever the command for which this handler
+ */
+ virtual void end() = 0;
+
+ /**
+ * Called whenever raw data (int the form of a string) is available for the
+ * Handler instance. In the default handler an exception is raised if the
+ * received data contains non-whitespace characters.
+ *
+ * @param data is a pointer at the character data that is available for the
+ * Handler instance.
+ * @param field is the field number (the interpretation of this value
+ * depends on the format that is being parsed).
+ */
+ virtual void data(const std::string &data, int field);
+
+ /**
+ * Called whenever a direct child element was created and has ended.
+ *
+ * @param handler is a reference at the child Handler instance.
+ */
+ virtual void child(std::shared_ptr<Handler> handler){};
+};
+
+/**
+ * HandlerConstructor is a function pointer type used to create concrete
+ * instances of the Handler class.
+ */
+using HandlerConstructor = Handler *(*)(const ParserContext &ctx,
+ std::string name, State state,
+ State parentState, bool isChild);
+
+struct HandlerDescriptor;
+
+/**
+ * Used internlly by StateStack to store Handler instances and parameters
+ * from HandlerDescriptor that are not stored in the Handler instance
+ * itself. Instances of the HandlerInstance class can be created using the
+ * HandlerDescriptor "create" method.
+ */
+struct HandlerInstance {
+ /**
+ * Pointer at the actual handler instance.
+ */
+ std::shared_ptr<Handler> handler;
+
+ const HandlerDescriptor *descr;
+
+ HandlerInstance(Handler *handler, const HandlerDescriptor *descr)
+ : handler(handler), descr(descr)
+ {
+ }
+};
+
+/**
+ * Used internally by StateStack to store the pushdown automaton
+ * description.
+ */
+struct HandlerDescriptor {
+ /**
+ * The valid parent states.
+ */
+ const std::set<State> parentStates;
+
+ /**
+ * Pointer at a function which creates a new concrete Handler instance.
+ */
+ const HandlerConstructor ctor;
+
+ /**
+ * The target state for the registered handler.
+ */
+ const State targetState;
+
+ /**
+ * Set to true if this handler instance allows arbitrary children as
+ * tags.
+ */
+ const bool arbitraryChildren;
+
+ HandlerDescriptor(std::set<State> parentStates, HandlerConstructor ctor,
+ State targetState, bool arbitraryChildren = false)
+ : parentStates(std::move(parentStates)),
+ ctor(ctor),
+ targetState(targetState),
+ arbitraryChildren(arbitraryChildren)
+ {
+ }
+
+ /**
+ * Creates an instance of the concrete Handler class represented by the
+ * HandlerDescriptor and calls its start function.
+ */
+ HandlerInstance create(const ParserContext &ctx, std::string name,
+ State parentState, bool isChild,
+ const Variant &args) const;
+};
+
+/**
+ * The ParserStack class is a pushdown automaton responsible for turning a
+ * command stream into a tree of Node instances.
+ */
+class ParserStack {
+private:
+ /**
+ * Reference at the parser context.
+ */
+ const ParserContext &ctx;
+
+ /**
+ * User specified data that will be passed to all handlers.
+ */
+ void *userData;
+
+ /**
+ * Map containing all registered command names and the corresponding
+ * handler
+ * descriptor.
+ */
+ const std::multimap<std::string, HandlerDescriptor> &handlers;
+
+ /**
+ * Internal stack used for managing the currently active Handler instances.
+ */
+ std::stack<HandlerInstance> stack;
+
+ /**
+ * Used internally to get all expected command names for the given state
+ * (does not work if the current Handler instance allows arbitrary
+ * children). This function is used to build error messages.
+ *
+ * @param state is the state for which all expected command names should be
+ * returned.
+ */
+ std::set<std::string> expectedCommands(State state);
+
+public:
+ /**
+ * Creates a new instance of the ParserStack class.
+ *
+ * @param handlers is a map containing the command names and the
+ * corresponding HandlerDescriptor instances.
+ */
+ ParserStack(const ParserContext &ctx,
+ const std::multimap<std::string, HandlerDescriptor> &handlers)
+ : ctx(ctx), handlers(handlers){};
+
+ /**
+ * Returns the state the ParserStack instance currently is in.
+ *
+ * @return the state of the currently active Handler instance or STATE_NONE
+ * if no handler is on the stack.
+ */
+ State currentState()
+ {
+ return stack.empty() ? STATE_NONE : stack.top().handler->state;
+ }
+
+ /**
+ * Returns the command name that is currently being handled.
+ *
+ * @return the name of the command currently being handled by the active
+ * Handler instance or an empty string if no handler is currently active.
+ */
+ std::string currentName()
+ {
+ return stack.empty() ? std::string{} : stack.top().handler->name;
+ }
+
+ /**
+ * Returns whether the current command handler allows arbitrary children.
+ *
+ * @return true if the handler allows arbitrary children, false otherwise.
+ */
+ bool currentArbitraryChildren()
+ {
+ return stack.empty() ? false : stack.top().descr->arbitraryChildren;
+ }
+
+ /**
+ * Function that should be called whenever a new command starts.
+ *
+ * @param name is the name of the command.
+ * @param args is a map from strings to variants (argument name and value).
+ */
+ void start(std::string name, const Variant &args);
+
+ /**
+ * Function called whenever a command ends.
+ */
+ void end();
+
+ /**
+ * Function that should be called whenever data is available for the
+ * command.
+ *
+ * @param data is the data that should be passed to the handler.
+ * @param field is the field number (the interpretation of this value
+ * depends on the format that is being parsed).
+ */
+ void data(const std::string &data, int field = 0);
+};
+}
+}
+
+#endif /* _OUSIA_PARSER_STACK_HPP_ */
+
diff --git a/src/core/parser/Scope.cpp b/src/core/parser/Scope.cpp
new file mode 100644
index 0000000..a60ade0
--- /dev/null
+++ b/src/core/parser/Scope.cpp
@@ -0,0 +1,26 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "Scope.hpp"
+
+namespace ousia {
+namespace parser {
+
+
+}
+}
diff --git a/src/core/parser/Scope.hpp b/src/core/parser/Scope.hpp
new file mode 100644
index 0000000..9c5504f
--- /dev/null
+++ b/src/core/parser/Scope.hpp
@@ -0,0 +1,172 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _OUSIA_PARSER_SCOPE_H_
+#define _OUSIA_PARSER_SCOPE_H_
+
+#include <deque>
+
+#include <core/Node.hpp>
+
+/**
+ * @file Scope.hpp
+ *
+ * Contains the Scope class used for resolving references based on the current
+ * parser state.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+namespace ousia {
+namespace parser {
+
+class Scope;
+
+/**
+ * The ScopedScope class takes care of pushing a Node instance into the
+ * name resolution stack of a Scope instance and poping this node once the
+ * ScopedScope instance is deletes. This way you cannot forget to pop a Node
+ * from a Scope instance as this operation is performed automatically.
+ */
+class ScopedScope {
+private:
+ /**
+ * Reference at the backing scope instance.
+ */
+ Scope *scope;
+
+public:
+ /**
+ * Creates a new ScopedScope instance.
+ *
+ * @param scope is the backing Scope instance.
+ * @param node is the Node instance that should be poped onto the stack of
+ * the Scope instance.
+ */
+ ScopedScope(Scope *scope, Handle<Node> node);
+
+ /**
+ * Pops the Node given in the constructor form the stack of the Scope
+ * instance.
+ */
+ ~ScopedScope();
+
+ /**
+ * Copying a ScopedScope is invalid.
+ */
+ ScopedScope(const ScopedScope &) = delete;
+
+ /**
+ * Move constructor of the ScopedScope class.
+ */
+ ScopedScope(ScopedScope &&);
+
+ /**
+ * Provides access at the underlying Scope instance.
+ */
+ Scope *operator->() { return scope; }
+
+ /**
+ * Provides access at the underlying Scope instance.
+ */
+ Scope &operator*() { return *scope; }
+};
+
+/**
+ * Provides an interface for document parsers to resolve references based on the
+ * current position in the created document tree. The Scope class itself is
+ * represented as a chain of Scope objects where each element has a reference to
+ * a Node object attached to it. The descend method can be used to add a new
+ * scope element to the chain.
+ */
+class Scope {
+private:
+ std::deque<Rooted<Node>> nodes;
+
+public:
+ /**
+ * Constructor of the Scope class.
+ *
+ * @param rootNode is the top-most Node from which elements can be looked
+ * up.
+ */
+ Scope(Handle<Node> rootNode) { nodes.push_back(rootNode); }
+
+ /**
+ * Returns a reference at the Manager instance all nodes belong to.
+ */
+ Manager &getManager() { return getRoot()->getManager(); }
+
+ /**
+ * Pushes a new node onto the scope.
+ *
+ * @param node is the node that should be used for local lookup.
+ */
+ void push(Handle<Node> node) { nodes.push_back(node); }
+
+ /**
+ * Removes the last pushed node from the scope.
+ */
+ void pop() { nodes.pop_back(); }
+
+ /**
+ * Returns a ScopedScope instance, which automatically pushes the given node
+ * into the Scope stack and pops it once the ScopedScope is destroyed.
+ */
+ ScopedScope descend(Handle<Node> node) { return ScopedScope{this, node}; }
+
+ /**
+ * Returns the top-most Node instance in the Scope hirarchy.
+ *
+ * @return a reference at the root node.
+ */
+ Rooted<Node> getRoot() { return nodes.front(); }
+
+ /**
+ * Returns the bottom-most Node instance in the Scope hirarchy, e.g. the
+ * node that was pushed last onto the stack.
+ *
+ * @return a reference at the leaf node.
+ */
+ Rooted<Node> getLeaf() { return nodes.back(); }
+};
+
+/* Class ScopedScope -- inline declaration of some methods */
+
+inline ScopedScope::ScopedScope(Scope *scope, Handle<Node> node) : scope(scope)
+{
+ scope->push(node);
+}
+
+inline ScopedScope::~ScopedScope()
+{
+ if (scope) {
+ scope->pop();
+ }
+}
+
+inline ScopedScope::ScopedScope(ScopedScope &&s)
+{
+ scope = s.scope;
+ s.scope = nullptr;
+}
+}
+}
+
+#endif /* _OUSIA_PARSER_SCOPE_H_ */
+
diff --git a/src/core/parser/XmlParser.cpp b/src/core/parser/XmlParser.cpp
deleted file mode 100644
index f9bb43e..0000000
--- a/src/core/parser/XmlParser.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- 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 <http://www.gnu.org/licenses/>.
-*/
-
-#include <expat.h>
-
-#include "XmlParser.hpp"
-
-namespace ousia {
-
-/**
- * The XmlParserData struct holds all information relevant to the expat callback
- * functions.
- */
-struct XmlParserData {
- Rooted<Node> context;
- Logger &logger;
-
- XmlParserData(Handle<Node> context, Logger &logger)
- : context(context), logger(logger)
- {
- }
-};
-
-/**
- * Wrapper class around the XML_Parser pointer which safely frees it whenever
- * the scope is left (e.g. because an exception was thrown).
- */
-class ScopedExpatXmlParser {
-private:
- /**
- * Internal pointer to the XML_Parser instance.
- */
- XML_Parser parser;
-
-public:
- /**
- * Constructor of the ScopedExpatXmlParser class. Calls XML_ParserCreateNS
- * from the expat library. Throws a parser exception if the XML parser
- * cannot be initialized.
- *
- * @param encoding is the protocol-defined encoding passed to expat (or
- * nullptr if expat should determine the encoding by itself).
- * @param namespaceSeparator is the separator used to separate the namespace
- * components in the node name given by expat.
- */
- ScopedExpatXmlParser(const XML_Char *encoding, XML_Char namespaceSeparator)
- : parser(nullptr)
- {
- parser = XML_ParserCreateNS("UTF-8", ':');
- if (!parser) {
- throw ParserException{
- "Internal error: Could not create expat XML parser!"};
- }
- }
-
- /**
- * Destuctor of the ScopedExpatXmlParser, frees the XML parser instance.
- */
- ~ScopedExpatXmlParser()
- {
- if (parser) {
- XML_ParserFree(parser);
- parser = nullptr;
- }
- }
-
- /**
- * Returns the XML_Parser pointer.
- */
- XML_Parser operator&() { return parser; }
-};
-
-std::set<std::string> XmlParser::mimetypes()
-{
- return std::set<std::string>{{"text/vnd.ousia.oxm", "text/vnd.ousia.oxd"}};
-}
-
-Rooted<Node> XmlParser::parse(std::istream &is, Handle<Node> context,
- Logger &logger)
-{
- // Create the parser object
- ScopedExpatXmlParser p{"UTF-8", ':'};
-
- // Set the callback functions, provide a pointer to a XmlParserData instance
- // as user data.
- XmlParserData ctx{context, logger};
-
- // Feed data into expat while there is data to process
- const std::streamsize BUFFER_SIZE = 4096; // TODO: Move to own header?
- while (true) {
- // Fetch a buffer from expat for the input data
- char *buf = static_cast<char *>(XML_GetBuffer(&p, BUFFER_SIZE));
- if (!buf) {
- throw ParserException{"Internal error: XML parser out of memory!"};
- }
-
- // Read the input data from the stream
- const std::streamsize bytesRead = is.read(buf, BUFFER_SIZE).gcount();
-
- // Parse the data and handle any XML error
- if (!XML_ParseBuffer(&p, bytesRead, bytesRead == 0)) {
- const int line = XML_GetCurrentLineNumber(&p);
- const int column = XML_GetCurrentColumnNumber(&p);
- const XML_Error code = XML_GetErrorCode(&p);
- const std::string msg = std::string{XML_ErrorString(code)};
- logger.error("XML: " + msg, line, column);
- break;
- }
-
- // Abort once there are no more bytes in the stream
- if (bytesRead == 0) {
- break;
- }
- }
-
- return nullptr;
-}
-}
-
diff --git a/src/core/variant/Variant.cpp b/src/core/variant/Variant.cpp
new file mode 100644
index 0000000..d33cd4f
--- /dev/null
+++ b/src/core/variant/Variant.cpp
@@ -0,0 +1,155 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <sstream>
+
+#include <core/Utils.hpp>
+
+#include "Variant.hpp"
+
+namespace ousia {
+
+/* Class Variant::TypeException */
+
+Variant::TypeException::TypeException(Type actualType, Type requestedType)
+ : OusiaException(std::string("Variant: Requested \"") +
+ Variant::getTypeName(requestedType) +
+ std::string("\" but is \"") +
+ Variant::getTypeName(actualType) + std::string("\"")),
+ actualType(actualType),
+ requestedType(requestedType)
+{
+}
+
+/* Class Variant */
+
+const char *Variant::getTypeName(Type type)
+{
+ switch (type) {
+ case Type::NULLPTR:
+ return "null";
+ case Type::BOOL:
+ return "boolean";
+ case Type::INT:
+ return "integer";
+ case Type::DOUBLE:
+ return "double";
+ case Type::STRING:
+ return "string";
+ case Type::ARRAY:
+ return "array";
+ case Type::MAP:
+ return "map";
+ }
+ return "unknown";
+}
+
+Variant::boolType Variant::toBool() const
+{
+ switch (getType()) {
+ case Type::NULLPTR:
+ return false;
+ case Type::BOOL:
+ return asBool();
+ case Type::INT:
+ return asInt() != 0;
+ case Type::DOUBLE:
+ return asDouble() != 0.0;
+ case Type::STRING:
+ return true;
+ case Type::ARRAY:
+ return true;
+ case Type::MAP:
+ return true;
+ }
+ return false;
+}
+
+Variant::intType Variant::toInt() const
+{
+ switch (getType()) {
+ case Type::NULLPTR:
+ return 0;
+ case Type::BOOL:
+ return asBool() ? 1 : 0;
+ case Type::INT:
+ return asInt();
+ case Type::DOUBLE:
+ return asDouble();
+ case Type::STRING:
+ return 0; // TODO: Parse string as int
+ case Type::ARRAY: {
+ const arrayType &a = asArray();
+ return (a.size() == 1) ? a[0].toInt() : 0;
+ }
+ case Type::MAP:
+ return 0;
+ }
+ return false;
+}
+
+Variant::doubleType Variant::toDouble() const
+{
+ switch (getType()) {
+ case Type::NULLPTR:
+ return 0.0;
+ case Type::BOOL:
+ return asBool() ? 1.0 : 0.0;
+ case Type::INT:
+ return asInt();
+ case Type::DOUBLE:
+ return asDouble();
+ case Type::STRING:
+ return 0.0; // TODO: Parse string as double
+ case Type::ARRAY: {
+ const arrayType &a = asArray();
+ return (a.size() == 1) ? a[0].toDouble() : 0;
+ }
+ case Type::MAP:
+ return 0;
+ }
+ return false;
+}
+
+Variant::stringType Variant::toString(bool escape) const
+{
+ switch (getType()) {
+ case Type::NULLPTR:
+ return "null";
+ case Type::BOOL:
+ return asBool() ? "true" : "false";
+ case Type::INT:
+ return std::to_string(asInt());
+ case Type::DOUBLE:
+ return std::to_string(asDouble());
+ case Type::STRING: {
+ // TODO: Use proper serialization function
+ std::stringstream ss;
+ ss << "\"" << asString() << "\"";
+ return ss.str();
+ }
+ case Type::ARRAY:
+ return Utils::join(asArray(), ", ", "[", "]");
+ case Type::MAP:
+ return Utils::join(asMap(), ", ", "{", "}");
+ }
+ return "";
+}
+
+}
+
diff --git a/src/core/variant/Variant.hpp b/src/core/variant/Variant.hpp
new file mode 100644
index 0000000..d65e14a
--- /dev/null
+++ b/src/core/variant/Variant.hpp
@@ -0,0 +1,693 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file Variant.hpp
+ *
+ * The Variant class is used to efficiently represent a variables of varying
+ * type. Variant instances are used to represent data given by the end user and
+ * to exchange information between the host application and the script clients.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_VARIANT_HPP_
+#define _OUSIA_VARIANT_HPP_
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+#include <ostream>
+
+// TODO: Use
+// http://nikic.github.io/2012/02/02/Pointer-magic-for-efficient-dynamic-value-representations.html
+// later (will allow to use 8 bytes for a variant)
+
+#include <core/Exceptions.hpp>
+
+namespace ousia {
+
+/**
+ * Instances of the Variant class represent any kind of data that is exchanged
+ * between the host application and the script engine. Variants are immutable.
+ */
+class Variant {
+public:
+ /**
+ * Enum containing the possible types a variant may have.
+ */
+ enum class Type : int16_t {
+ NULLPTR,
+ BOOL,
+ INT,
+ DOUBLE,
+ STRING,
+ ARRAY,
+ MAP
+ };
+
+ /**
+ * Exception thrown whenever a variant is accessed via a getter function
+ * that
+ * is not supported for the current variant type.
+ */
+ class TypeException : public OusiaException {
+ private:
+ /**
+ * Internally used string holding the exception message.
+ */
+ const std::string msg;
+
+ public:
+ /**
+ * Contains the actual type of the variant.
+ */
+ const Type actualType;
+
+ /**
+ * Contains the requested type of the variant.
+ */
+ const Type requestedType;
+
+ /**
+ * Constructor of the TypeException.
+ *
+ * @param actualType describes the actual type of the variant.
+ * @param requestedType describes the type in which the variant was
+ * requested.
+ */
+ TypeException(Type actualType, Type requestedType);
+ };
+
+ using boolType = bool;
+ using intType = int32_t;
+ using doubleType = double;
+ using stringType = std::string;
+ using arrayType = std::vector<Variant>;
+ using mapType = std::map<std::string, Variant>;
+
+private:
+ /**
+ * Used to store the actual type of the variant.
+ */
+ Type type = Type::NULLPTR;
+
+ /**
+ * Anonymous union containing the possible value of the variant.
+ */
+ union {
+ /**
+ * The boolean value. Only valid if type is Type::BOOL.
+ */
+ boolType boolVal;
+ /**
+ * The integer value. Only valid if type is Type::INT.
+ */
+ intType intVal;
+ /**
+ * The number value. Only valid if type is Type::DOUBLE.
+ */
+ doubleType doubleVal;
+ /**
+ * Pointer to the more complex data structures on the free store. Only
+ * valid if type is one of Type::STRING, Type::ARRAY,
+ * Type::MAP.
+ */
+ void *ptrVal;
+ };
+
+ /**
+ * Internally used to convert the current pointer value to a reference of
+ * the specified type.
+ */
+ template <typename T>
+ T &asObj(Type requestedType) const
+ {
+ const Type actualType = getType();
+ if (actualType == requestedType) {
+ return *(static_cast<T *>(ptrVal));
+ }
+ throw TypeException{actualType, requestedType};
+ }
+
+ /**
+ * Used internally to assign the value of another Variant instance to this
+ * instance.
+ *
+ * @param v is the Variant instance that should be copied to this instance.
+ */
+ void copy(const Variant &v)
+ {
+ destroy();
+ type = v.type;
+ switch (type) {
+ case Type::NULLPTR:
+ break;
+ case Type::BOOL:
+ boolVal = v.boolVal;
+ break;
+ case Type::INT:
+ intVal = v.intVal;
+ break;
+ case Type::DOUBLE:
+ doubleVal = v.doubleVal;
+ break;
+ case Type::STRING:
+ ptrVal = new stringType(v.asString());
+ break;
+ case Type::ARRAY:
+ ptrVal = new arrayType(v.asArray());
+ break;
+ case Type::MAP:
+ ptrVal = new mapType(v.asMap());
+ break;
+ }
+ }
+
+ /**
+ * Used internally to move the value of another Variant instance to this
+ * instance.
+ *
+ * @param v is the Variant instance that should be copied to this instance.
+ */
+ void move(Variant &&v)
+ {
+ destroy();
+ type = v.type;
+ switch (type) {
+ case Type::NULLPTR:
+ break;
+ case Type::BOOL:
+ boolVal = v.boolVal;
+ break;
+ case Type::INT:
+ intVal = v.intVal;
+ break;
+ case Type::DOUBLE:
+ doubleVal = v.doubleVal;
+ break;
+ case Type::STRING:
+ case Type::ARRAY:
+ case Type::MAP:
+ ptrVal = v.ptrVal;
+ v.ptrVal = nullptr;
+ break;
+ }
+ v.type = Type::NULLPTR;
+ }
+
+ /**
+ * Used internally to destroy any value that was allocated on the heap.
+ */
+ void destroy()
+ {
+ if (ptrVal) {
+ switch (type) {
+ case Type::STRING:
+ delete static_cast<stringType *>(ptrVal);
+ break;
+ case Type::ARRAY:
+ delete static_cast<arrayType *>(ptrVal);
+ break;
+ case Type::MAP:
+ delete static_cast<mapType *>(ptrVal);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+public:
+ /**
+ * Copy constructor of the Variant class.
+ *
+ * @param v is the Variant instance that should be cloned.
+ */
+ Variant(const Variant &v) : ptrVal(nullptr) { copy(v); }
+
+ /**
+ * Move constructor of the Variant class.
+ *
+ * @param v is the reference to the Variant instance that should be moved,
+ * this instance is invalidated afterwards.
+ */
+ Variant(Variant &&v) : ptrVal(nullptr) { move(std::move(v)); }
+
+ /**
+ * Default constructor. Type is set to Type:null.
+ */
+ Variant() : ptrVal(nullptr) { setNull(); }
+
+ /**
+ * Default destructor, frees any memory that was allocated on the heap.
+ */
+ ~Variant() { destroy(); }
+
+ /**
+ * Constructor for null values. Initializes the variant as null value.
+ */
+ Variant(std::nullptr_t) : ptrVal(nullptr) { setNull(); }
+
+ /**
+ * Constructor for boolean values.
+ *
+ * @param b boolean value.
+ */
+ Variant(boolType b) : ptrVal(nullptr) { setBool(b); }
+
+ /**
+ * Constructor for integer values.
+ *
+ * @param i integer value.
+ */
+ Variant(intType i) : ptrVal(nullptr) { setInt(i); }
+
+ /**
+ * Constructor for double values.
+ *
+ * @param d double value.
+ */
+ Variant(doubleType d) : ptrVal(nullptr) { setDouble(d); }
+
+ /**
+ * Constructor for string values. The given string is copied and managed by
+ * the new Variant instance.
+ *
+ * @param s is a reference to a C-Style string used as string value.
+ */
+ Variant(const char *s) : ptrVal(nullptr) { setString(s); }
+
+ /**
+ * Constructor for array values. The given array is copied and managed by
+ * the new Variant instance.
+ *
+ * @param a is a reference to the array
+ */
+ Variant(arrayType a) : ptrVal(nullptr) { setArray(std::move(a)); }
+
+ /**
+ * Constructor for map values. The given map is copied and managed by the
+ * new Variant instance.
+ *
+ * @param m is a reference to the map.
+ */
+ Variant(mapType m) : ptrVal(nullptr) { setMap(std::move(m)); }
+
+ /**
+ * Copy assignment operator.
+ */
+ Variant &operator=(const Variant &v)
+ {
+ copy(v);
+ return *this;
+ }
+
+ /**
+ * Move assignment operator.
+ */
+ Variant &operator=(Variant &&v)
+ {
+ move(std::move(v));
+ return *this;
+ }
+
+ /**
+ * Assign nullptr_t operator (allows to write Variant v = nullptr).
+ *
+ * @param p is an instance of std::nullptr_t.
+ */
+ Variant &operator=(std::nullptr_t)
+ {
+ setNull();
+ return *this;
+ }
+
+ /**
+ * Assign a boolean value.
+ *
+ * @param b is the boolean value to which the variant should be set.
+ */
+ Variant &operator=(boolType b)
+ {
+ setBool(b);
+ return *this;
+ }
+
+ /**
+ * Assign an integer value.
+ *
+ * @param i is the integer value to which the variant should be set.
+ */
+ Variant &operator=(intType i)
+ {
+ setInt(i);
+ return *this;
+ }
+
+ /**
+ * Assign a double value.
+ *
+ * @param d is the double value to which the variant should be set.
+ */
+ Variant &operator=(doubleType d)
+ {
+ setDouble(d);
+ return *this;
+ }
+
+ /**
+ * Assign a zero terminated const char array.
+ *
+ * @param s is the zero terminated const char array to which the variant
+ * should be set.
+ */
+ Variant &operator=(const char *s)
+ {
+ setString(s);
+ return *this;
+ }
+
+ /**
+ * Checks whether this Variant instance represents the nullptr.
+ *
+ * @return true if the Variant instance represents the nullptr, false
+ * otherwise.
+ */
+ bool isNull() const { return type == Type::NULLPTR; }
+
+ /**
+ * Checks whether this Variant instance is a boolean.
+ *
+ * @return true if the Variant instance is a boolean, false otherwise.
+ */
+ bool isBool() const { return type == Type::BOOL; }
+
+ /**
+ * Checks whether this Variant instance is an integer.
+ *
+ * @return true if the Variant instance is an integer, false otherwise.
+ */
+ bool isInt() const { return type == Type::INT; }
+
+ /**
+ * Checks whether this Variant instance is a double.
+ *
+ * @return true if the Variant instance is a double, false otherwise.
+ */
+ bool isDouble() const { return type == Type::DOUBLE; }
+
+ /**
+ * Checks whether this Variant instance is a string.
+ *
+ * @return true if the Variant instance is a string, false otherwise.
+ */
+ bool isString() const { return type == Type::STRING; }
+
+ /**
+ * Checks whether this Variant instance is an array.
+ *
+ * @return true if the Variant instance is an array, false otherwise.
+ */
+ bool isArray() const { return type == Type::ARRAY; }
+
+ /**
+ * Checks whether this Variant instance is a map.
+ *
+ * @return true if the Variant instance is a map, false otherwise.
+ */
+ bool isMap() const { return type == Type::MAP; }
+
+ /**
+ * Returns the Variant boolean value. Performs no type conversion. Throws an
+ * exception if the underlying type is not a boolean.
+ *
+ * @return the boolean value.
+ */
+ boolType asBool() const
+ {
+ if (isBool()) {
+ return boolVal;
+ }
+ throw TypeException{getType(), Type::BOOL};
+ }
+
+ /**
+ * Returns the Variant integer value. Performs no type conversion. Throws an
+ * exception if the underlying type is not an integer.
+ *
+ * @return the integer value.
+ */
+ intType asInt() const
+ {
+ if (isInt()) {
+ return intVal;
+ }
+ throw TypeException{getType(), Type::INT};
+ }
+
+ /**
+ * Returns the Variant double value. Performs no type conversion. Throws an
+ * exception if the underlying type is not a double.
+ *
+ * @return the double value.
+ */
+ doubleType asDouble() const
+ {
+ if (isDouble()) {
+ return doubleVal;
+ }
+ throw TypeException{getType(), Type::DOUBLE};
+ }
+
+ /**
+ * Returns a const reference to the string value. Performs no type
+ * conversion. Throws an exception if the underlying type is not a string.
+ *
+ * @return the string value as const reference.
+ */
+ const stringType &asString() const
+ {
+ return asObj<stringType>(Type::STRING);
+ }
+
+ /**
+ * Returns a const reference to the string value. Performs no type
+ * conversion. Throws an exception if the underlying type is not a string.
+ *
+ * @return the string value as reference.
+ */
+ stringType &asString() { return asObj<stringType>(Type::STRING); }
+
+ /**
+ * Returns a const reference to the array value. Performs no type
+ * conversion. Throws an exception if the underlying type is not an array.
+ *
+ * @return the array value as const reference.
+ */
+ const arrayType &asArray() const { return asObj<arrayType>(Type::ARRAY); }
+
+ /**
+ * Returns a const reference to the array value. Performs no type
+ * conversion. Throws an exception if the underlying type is not an array.
+ *
+ * @return the array value as reference.
+ */
+ arrayType &asArray() { return asObj<arrayType>(Type::ARRAY); }
+
+ /**
+ * Returns a const reference to the map value. Performs no type
+ * conversion. Throws an exception if the underlying type is not a map.
+ *
+ * @return the map value as const reference.
+ */
+ const mapType &asMap() const { return asObj<mapType>(Type::MAP); }
+
+ /**
+ * Returns a reference to the map value. Performs no type conversion.
+ * Throws an exception if the underlying type is not a map.
+ *
+ * @return the map value as reference.
+ */
+ mapType &asMap() { return asObj<mapType>(Type::MAP); }
+
+ /**
+ * Returns the value of the Variant as boolean, performs type conversion.
+ *
+ * @return the Variant value converted to a boolean value.
+ */
+ boolType toBool() const;
+
+ /**
+ * Returns the value of the Variant as integer, performs type conversion.
+ *
+ * @return the Variant value converted to an integer value.
+ */
+ intType toInt() const;
+
+ /**
+ * Returns the value of the Variant as double, performs type conversion.
+ *
+ * @return the Variant value converted to a double value.
+ */
+ doubleType toDouble() const;
+
+ /**
+ * Returns the value of the Variant as string, performs type conversion.
+ *
+ * @return the value of the variant as string.
+ * @param escape if set to true, adds double quotes to strings and escapes
+ * them properly (resulting in a more or less JSONesque output).
+ */
+ stringType toString(bool escape = false) const;
+
+ /**
+ * Sets the variant to null.
+ */
+ void setNull()
+ {
+ destroy();
+ type = Type::NULLPTR;
+ ptrVal = nullptr;
+ }
+
+ /**
+ * Sets the variant to the given boolean value.
+ *
+ * @param b is the new boolean value.
+ */
+ void setBool(boolType b)
+ {
+ destroy();
+ type = Type::BOOL;
+ boolVal = b;
+ }
+
+ /**
+ * Sets the variant to the given integer value.
+ *
+ * @param i is the new integer value.
+ */
+ void setInt(intType i)
+ {
+ destroy();
+ type = Type::INT;
+ intVal = i;
+ }
+
+ /**
+ * Sets the variant to the given double value.
+ *
+ * @param d is the new double value.
+ */
+ void setDouble(doubleType d)
+ {
+ destroy();
+ type = Type::DOUBLE;
+ doubleVal = d;
+ }
+
+ /**
+ * Sets the variant to the given string value.
+ *
+ * @param d is the new string value.
+ */
+ void setString(const char *s)
+ {
+ if (isString()) {
+ asString().assign(s);
+ } else {
+ destroy();
+ type = Type::STRING;
+ ptrVal = new stringType(s);
+ }
+ }
+
+ /**
+ * Sets the variant to the given array value.
+ *
+ * @param a is the new array value.
+ */
+ void setArray(arrayType a)
+ {
+ if (isArray()) {
+ asArray().swap(a);
+ } else {
+ destroy();
+ type = Type::ARRAY;
+ ptrVal = new arrayType(std::move(a));
+ }
+ }
+
+ /**
+ * Sets the variant to the given map value.
+ *
+ * @param a is the new map value.
+ */
+ void setMap(mapType m)
+ {
+ if (isMap()) {
+ asMap().swap(m);
+ } else {
+ destroy();
+ type = Type::MAP;
+ ptrVal = new mapType(std::move(m));
+ }
+ }
+
+ /**
+ * Returns the current type of the Variant.
+ *
+ * @return the current type of the Variant.
+ */
+ Type getType() const { return type; }
+
+ /**
+ * Returns the name of the given variant type as C-style string.
+ */
+ static const char *getTypeName(Type type);
+
+ /**
+ * Returns the name of the type of this variant instance.
+ */
+ const char *getTypeName() { return Variant::getTypeName(getType()); }
+
+ /**
+ * Prints the Variant to the output stream.
+ */
+ friend std::ostream &operator<<(std::ostream &os, const Variant &v)
+ {
+ return os << v.toString(true);
+ }
+
+ /**
+ * Prints a key value pair to the output stream.
+ */
+ friend std::ostream &operator<<(std::ostream &os,
+ const mapType::value_type &v)
+ {
+ // TODO: Use proper serialization function
+ return os << "\"" << v.first << "\": " << v.second.toString(true);
+ }
+};
+
+}
+
+#endif /* _OUSIA_VARIANT_HPP_ */
+
diff --git a/src/plugins/mozjs/MozJsScriptEngine.cpp b/src/plugins/mozjs/MozJsScriptEngine.cpp
index f269eb7..47394a0 100644
--- a/src/plugins/mozjs/MozJsScriptEngine.cpp
+++ b/src/plugins/mozjs/MozJsScriptEngine.cpp
@@ -27,6 +27,7 @@
namespace ousia {
namespace script {
+namespace mozjs {
/*
* Some important links to the SpiderMonkey (mozjs) documentation:
@@ -504,4 +505,5 @@ MozJsScriptEngineScope *MozJsScriptEngine::createScope() {
}
}
}
+}
diff --git a/src/plugins/mozjs/MozJsScriptEngine.hpp b/src/plugins/mozjs/MozJsScriptEngine.hpp
index 72e8ad7..385c676 100644
--- a/src/plugins/mozjs/MozJsScriptEngine.hpp
+++ b/src/plugins/mozjs/MozJsScriptEngine.hpp
@@ -46,6 +46,7 @@ typedef Rooted<Value> RootedValue;
namespace ousia {
namespace script {
+namespace mozjs {
class MozJsScriptEngineScope;
@@ -121,6 +122,7 @@ public:
};
}
}
+}
#endif /* _MOZ_JS_SCRIPT_ENGINE_HPP_ */
diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp
new file mode 100644
index 0000000..afc7f14
--- /dev/null
+++ b/src/plugins/xml/XmlParser.cpp
@@ -0,0 +1,226 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <iostream>
+
+#include <expat.h>
+
+#include <core/Utils.hpp>
+#include <core/parser/ParserStack.hpp>
+
+#include "XmlParser.hpp"
+
+namespace ousia {
+namespace parser {
+namespace xml {
+
+/* Document structure */
+static const State STATE_DOCUMENT = 0;
+static const State STATE_HEAD = 1;
+static const State STATE_BODY = 2;
+
+/* Special commands */
+static const State STATE_USE = 100;
+static const State STATE_INCLUDE = 101;
+static const State STATE_INLINE = 102;
+
+/* Type system definitions */
+static const State STATE_TYPES = 200;
+static const State STATE_CONSTANT = 201;
+static const State STATE_ENUM = 202;
+static const State STATE_STRUCT = 203;
+
+class TestHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ void start(const Variant &args) override
+ {
+ std::cout << this->name << ": start (isChild: " << (this->isChild)
+ << ", args: " << args << ")" << std::endl;
+ }
+
+ void end() override
+ {
+ // TODO
+ }
+
+ void data(const std::string &data, int field) override
+ {
+ std::cout << this->name << ": data \"" << data << "\"" << std::endl;
+ }
+
+ void child(std::shared_ptr<Handler> handler) override
+ {
+ // TODO
+ }
+};
+
+static Handler *createTestHandler(const ParserContext &ctx, std::string name,
+ State state, State parentState, bool isChild)
+{
+ return new TestHandler{ctx, name, state, parentState, isChild};
+}
+
+static const std::multimap<std::string, HandlerDescriptor> XML_HANDLERS{
+ /* Documents */
+ {"document", {{STATE_NONE}, createTestHandler, STATE_DOCUMENT}},
+ {"head", {{STATE_DOCUMENT}, createTestHandler, STATE_HEAD}},
+ {"body", {{STATE_DOCUMENT}, createTestHandler, STATE_BODY, true}},
+
+ /* Special commands */
+ {"use", {{STATE_HEAD}, createTestHandler, STATE_USE}},
+ {"include", {{STATE_ALL}, createTestHandler, STATE_INCLUDE}},
+ {"inline", {{STATE_ALL}, createTestHandler, STATE_INLINE}},
+
+ /* Typesystem definitions */
+ {"typesystem", {{STATE_NONE, STATE_HEAD}, createTestHandler, STATE_TYPES}},
+ {"enum", {{STATE_TYPES}, createTestHandler, STATE_ENUM}},
+ {"struct", {{STATE_TYPES}, createTestHandler, STATE_STRUCT}},
+ {"constant", {{STATE_TYPES}, createTestHandler, STATE_CONSTANT}}};
+
+/**
+ * Wrapper class around the XML_Parser pointer which safely frees it whenever
+ * the scope is left (e.g. because an exception was thrown).
+ */
+class ScopedExpatXmlParser {
+private:
+ /**
+ * Internal pointer to the XML_Parser instance.
+ */
+ XML_Parser parser;
+
+public:
+ /**
+ * Constructor of the ScopedExpatXmlParser class. Calls XML_ParserCreateNS
+ * from the expat library. Throws a parser exception if the XML parser
+ * cannot be initialized.
+ *
+ * @param encoding is the protocol-defined encoding passed to expat (or
+ * nullptr if expat should determine the encoding by itself).
+ */
+ ScopedExpatXmlParser(const XML_Char *encoding) : parser(nullptr)
+ {
+ parser = XML_ParserCreate(encoding);
+ if (!parser) {
+ throw ParserException{
+ "Internal error: Could not create expat XML parser!"};
+ }
+ }
+
+ /**
+ * Destuctor of the ScopedExpatXmlParser, frees the XML parser instance.
+ */
+ ~ScopedExpatXmlParser()
+ {
+ if (parser) {
+ XML_ParserFree(parser);
+ parser = nullptr;
+ }
+ }
+
+ /**
+ * Returns the XML_Parser pointer.
+ */
+ XML_Parser operator&() { return parser; }
+};
+
+/* Adapter Expat -> ParserStack */
+
+static void xmlStartElementHandler(void *userData, const XML_Char *name,
+ const XML_Char **attrs)
+{
+ Variant::mapType args;
+ const XML_Char **attr = attrs;
+ while (*attr) {
+ const std::string key{*(attr++)};
+ args.emplace(std::make_pair(key, Variant{*(attr++)}));
+ }
+ (static_cast<ParserStack *>(userData))->start(std::string(name), args);
+}
+
+static void xmlEndElementHandler(void *userData, const XML_Char *name)
+{
+ (static_cast<ParserStack *>(userData))->end();
+}
+
+static void xmlCharacterDataHandler(void *userData, const XML_Char *s, int len)
+{
+ const std::string data =
+ Utils::trim(std::string{s, static_cast<size_t>(len)});
+ if (!data.empty()) {
+ (static_cast<ParserStack *>(userData))->data(data);
+ }
+}
+
+/* Class XmlParser */
+
+std::set<std::string> XmlParser::mimetypes()
+{
+ return std::set<std::string>{{"text/vnd.ousia.oxm", "text/vnd.ousia.oxd"}};
+}
+
+Rooted<Node> XmlParser::parse(std::istream &is, ParserContext &ctx)
+{
+ // Create the parser object
+ ScopedExpatXmlParser p{"UTF-8"};
+
+ // Create the parser stack instance and pass the reference to the state
+ // machine descriptor
+ ParserStack stack{ctx, XML_HANDLERS};
+ XML_SetUserData(&p, &stack);
+
+ // Set the callback functions
+ XML_SetStartElementHandler(&p, xmlStartElementHandler);
+ XML_SetEndElementHandler(&p, xmlEndElementHandler);
+ XML_SetCharacterDataHandler(&p, xmlCharacterDataHandler);
+
+ // Feed data into expat while there is data to process
+ const std::streamsize BUFFER_SIZE = 4096; // TODO: Move to own header?
+ while (true) {
+ // Fetch a buffer from expat for the input data
+ char *buf = static_cast<char *>(XML_GetBuffer(&p, BUFFER_SIZE));
+ if (!buf) {
+ throw ParserException{"Internal error: XML parser out of memory!"};
+ }
+
+ // Read the input data from the stream
+ const std::streamsize bytesRead = is.read(buf, BUFFER_SIZE).gcount();
+
+ // Parse the data and handle any XML error
+ if (!XML_ParseBuffer(&p, bytesRead, bytesRead == 0)) {
+ const int line = XML_GetCurrentLineNumber(&p);
+ const int column = XML_GetCurrentColumnNumber(&p);
+ const XML_Error code = XML_GetErrorCode(&p);
+ const std::string msg = std::string{XML_ErrorString(code)};
+ throw ParserException{"XML Syntax Error: " + msg, line, column,
+ false};
+ }
+
+ // Abort once there are no more bytes in the stream
+ if (bytesRead == 0) {
+ break;
+ }
+ }
+
+ return nullptr;
+}
+}
+}
+}
+
diff --git a/src/core/parser/XmlParser.hpp b/src/plugins/xml/XmlParser.hpp
index f6fb060..b19af1e 100644
--- a/src/core/parser/XmlParser.hpp
+++ b/src/plugins/xml/XmlParser.hpp
@@ -28,9 +28,11 @@
#ifndef _OUSIA_XML_PARSER_HPP_
#define _OUSIA_XML_PARSER_HPP_
-#include <core/Parser.hpp>
+#include <core/parser/Parser.hpp>
namespace ousia {
+namespace parser {
+namespace xml {
/**
* The XmlParser class implements parsing the various types of Ousía XML
@@ -48,15 +50,19 @@ public:
/**
* Parses the given input stream as XML file and returns the parsed
- * top-level node. Throws
+ * top-level node.
*
* @param is is the input stream that will be parsed.
+ * @param ctx is a reference to the ParserContext instance that should be
+ * used.
*/
- Rooted<Node> parse(std::istream &is, Handle<Node> context,
- Logger &logger) override;
+ Rooted<Node> parse(std::istream &is, ParserContext &ctx) override;
using Parser::parse;
};
+
+}
+}
}
#endif /* _OUSIA_XML_PARSER_HPP_ */