#ifndef FML_H #define FML_H #include #include #include #include #include #include #include #include #include #include namespace FML { /////////////////////////////////////////////////////////////////////////////// // Utilities bool fml_convert(const std::string& input, bool& b); bool fml_convert(const std::string& input, std::string& output); template bool fml_convert(const V& in, T& out) { std::stringstream ss; ss << in; ss >> out; return !!ss; } std::string fml_int2str(int v); /////////////////////////////////////////////////////////////////////////////// // Exception class Exception : public std::runtime_error { public: explicit Exception(const std::string& what) : std::runtime_error(what) {} }; /////////////////////////////////////////////////////////////////////////////// // Node class Parser; class Node : boost::noncopyable { public: typedef std::vector NodeList; Node(Parser* parser = 0) : m_parser(parser), m_parent(0), m_line(0) { } ~Node(); bool hasTag() const { return !m_tag.empty(); } bool hasChildren() const { return size() > 0; } bool hasValue() const { return !m_value.empty(); } bool hasNode(const std::string childTag) const { return at(childTag) != 0; } void setTag(std::string tag) { m_tag = tag; } void setLine(int line) { m_line = line; } void setValue(const std::string& value) { m_value = value; } void setParent(Node* parent) { m_parent = parent; } std::string tag() const { return m_tag; } int line() const { return m_line; } int size() const { return m_children.size(); } Node* parent() { return m_parent; } std::string what() const; // iterators typedef NodeList::iterator iterator; typedef NodeList::const_iterator const_iterator; iterator begin() { return m_children.begin(); } iterator end() { return m_children.end(); } const_iterator begin() const { return m_children.begin(); } const_iterator end() const { return m_children.end(); } Node* front() const { return at(0); } Node* back() const { return at(size()-1); } // util for generating error message std::string generateErrorMessage(const std::string& message) const; void throwError(const std::string& message) const { throw Exception(generateErrorMessage(message)); } // extracting values operator template friend bool operator >> (const Node& node, T& value); // get nodes Node* at(const std::string& childTag) const; Node* at(int pos) const; // get values std::string value(const std::string& def = std::string()) const { if(!m_value.empty()) return m_value; return def; } std::string valueAt(const std::string childTag, const std::string& def = std::string()) const { if(Node* node = at(childTag)) return node->value(); return def; } std::string valueAt(int pos, const std::string& def = std::string()) const { if(Node* node = at(pos)) return node->value(); return def; } // read values into memory template void read(T* v) const { if(!(*this >> *v)) throw Exception(generateErrorMessage("failed to cast node value to type " + std::string(typeid(T).name()))); } template bool readAt(const std::string& childTag, T* v) const { if(Node* node = at(childTag)) { node->read(v); return true; } return false; } template bool readAt(int pos, T* v) const { if(Node* node = at(pos)) { node->read(v); return true; } return false; } // read values template T read() const { T v; read(&v); return v; } template T readAt(const std::string& childTag) const { if(Node* node = at(childTag)) return node->read(); throw Exception(generateErrorMessage("child node " + childTag + " not found")); return T(); } template T readAt(int pos) const { if(Node* node = at(pos)) return node->read(); throw Exception(generateErrorMessage("child node at pos " + fml_int2str(pos) + " not found")); return T(); } // read values with defaults template T readAt(const std::string& childTag, const T& def) const { if(Node* node = at(childTag)) return node->read(); else return def; } template T readAt(int pos, const T& def) const { if(Node* node = at(pos)) return node->read(); else return def; } void addNode(Node* node); std::string emitValue(); std::string emit(int depth = 0); private: Parser* m_parser; Node* m_parent; int m_line; NodeList m_children; std::string m_tag; std::string m_value; }; /////////////////////////////////////////////////////////////////////////////// // Node operators template bool operator >> (const Node& node, T& v) { return fml_convert(node.value(), v); } template bool operator >> (const Node& node, std::vector& v) { std::vector& tmp; tmp.resize(node.size()); for(unsigned i=0;i(i); v = tmp; return true; } template bool operator >> (const Node& node, std::map& m) { std::map tmp; for(Node::const_iterator it = node.begin(); it != node.end(); ++it) { K k; T v; if(fml_convert((*it)->tag(), k)) { (*it)->read(&v); tmp[k] = v; } else return false; } m = tmp; return true; } /////////////////////////////////////////////////////////////////////////////// // Parser class Parser { enum MultilineMode { DONT_MULTILINE = 0, MULTILINE_DONT_FOLD, MULTILINE_FOLD_BLOCK, MULTILINE_FOLD_FLOW }; public: Parser(std::string what = std::string()) : m_rootNode(0), m_what(what) { } Parser(std::istream& in, std::string what = std::string()) : m_rootNode(0), m_what(what) { load(in); } ~Parser(); void load(std::istream& in); Node* getDocument() const { return m_rootNode; } std::string what() { return m_what; } protected: void parseLine(std::string& line); Node* parseNode(std::string& line); std::string parseTextScalar(std::string value); void startMultilining(const std::string& param); void stopMultilining(); bool parseMultiline(std::string line); bool isMultilining() { return m_multilineMode != DONT_MULTILINE; } void throwError(const std::string& message, int line = 0); private: int m_currentDepth; int m_currentLine; Node* m_currentParent; Node* m_previousNode; Node* m_rootNode; MultilineMode m_multilineMode; std::string m_multilineData; std::string m_what; }; } // namespace FML { #endif // FML_H