FML emitter

This commit is contained in:
Eduardo Bart 2011-05-22 00:56:58 -03:00
parent d7bc083014
commit a54f5dd3f9
4 changed files with 281 additions and 396 deletions

View File

@ -53,11 +53,10 @@ bool Configs::load(const std::string& fileName)
void Configs::save() void Configs::save()
{ {
if(!m_fileName.empty()) { if(!m_fileName.empty()) {
std::stringstream out; FML::Emitter emitter;
foreach(auto pair, m_confsMap) { FML::Node *doc = emitter.createDocument();
out << pair.first << ": " << pair.second << std::endl; doc->write(m_confsMap);
} g_resources.saveFile(m_fileName, emitter.emitDocument());
g_resources.saveFile(m_fileName, out);
} }
} }

View File

@ -49,6 +49,7 @@ public:
bool loadFile(const std::string& fileName, std::iostream& out); bool loadFile(const std::string& fileName, std::iostream& out);
bool saveFile(const std::string& fileName, const uchar *data, uint size); bool saveFile(const std::string& fileName, const uchar *data, uint size);
bool saveFile(const std::string& fileName, const std::string& data) { return saveFile(fileName, (const uchar*)data.c_str(), data.size()); }
bool saveFile(const std::string& fileName, std::istream& in); bool saveFile(const std::string& fileName, std::istream& in);
bool deleteFile(const std::string& fileName); bool deleteFile(const std::string& fileName);

View File

@ -1,217 +1,88 @@
#include "fml.h" #include "fml.h"
#include <boost/algorithm/string.hpp> namespace FML
#include <boost/tokenizer.hpp>
namespace FML {
///////////////////////////////////////////////////////////////////////////////
// Utilities
bool fml_convert(const std::string& input, bool& b)
{ {
std::string names[5][2] = { { "1", "0" },
{ "y", "n" },
{ "yes", "no" },
{ "true", "false" },
{ "on", "off" } };
std::string processedInput = input;
boost::trim(processedInput);
boost::to_lower(processedInput);
for(int i=0;i<5;i++) {
if(names[i][0] == processedInput) {
b = true;
return true;
}
if(names[i][1] == processedInput) { bool fml_convert(const std::string& input, bool& b) {
static std::string validNames[2][4] = {{"true","yes","on","1"}, {"false","no","off","0"}};
bool ret = false;
for(int i=0;i<4;++i) {
if(input == validNames[0][i]) {
b = true;
ret = true;
break;
} else if(input == validNames[1][i]) {
b = false; b = false;
return true; ret = true;
break;
} }
} }
return false; return ret;
} }
bool fml_convert(const std::string& input, std::string& output) { bool fml_convert(const std::string& input, std::string& output)
{
output = input; output = input;
return true; return true;
} }
std::string fml_int2str(int v) Node* Node::at(const std::string& childTag) const {
{ int i=0;
std::stringstream ss; while(i<size() && at(i)->tag()!=childTag)
ss << v; ++i;
return ss.str(); return at(i);
} }
/////////////////////////////////////////////////////////////////////////////// Node* Node::createNode(std::string tag)
// Node
Node::~Node()
{ {
for(NodeList::iterator it = m_children.begin(); it != m_children.end(); ++it) Node* node = new Node;
delete (*it); node->setTag(tag);
addNode(node);
return node;
} }
std::string Node::what() const void Node::addNode(Node* node) {
{
if(m_parser)
return m_parser->what();
return std::string();
}
Node* Node::at(const std::string& childTag) const
{
for(NodeList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
if((*it)->tag() == childTag)
return (*it);
}
return NULL;
}
Node* Node::at(int pos) const
{
if(pos < 0 || pos >= size())
return NULL;
return m_children[pos];
}
void Node::addNode(Node *node)
{
if(node->hasTag() && node->hasValue()) { if(node->hasTag() && node->hasValue()) {
// remove nodes wit the same tag if(Node* other = at(node->tag())) {
for(NodeList::iterator it = m_children.begin(); it != m_children.end(); ++it) { if(removeNode(other))
if((*it)->tag() == node->tag()) { delete node;
delete (*it);
m_children.erase(it);
break;
}
} }
} }
m_children.push_back(node); m_children.push_back(node);
node->setParent(this); node->setParent(this);
} }
std::string Node::generateErrorMessage(const std::string& message) const bool Node::removeNode(Node* node) {
{ for(NodeList::iterator it = m_children.begin(); it != m_children.end(); ++it) {
if((*it) == node) {
m_children.erase(it);
return true;
}
}
return false;
}
std::string Node::generateErrorMessage(const std::string& message) const {
std::stringstream ss; std::stringstream ss;
ss << "FML error"; ss << "FML error";
if(!(what().empty())) if(!what().empty())
ss << " in '" << what() << "'"; ss << " in '" << what() << "'";
if(m_line > 0) { if(m_line > 0)
ss << " at line " << m_line; ss << " at line " << m_line;
if(hasTag()) if(m_line > 0 && hasTag())
ss << ", in node '" << tag() << "'"; ss << ", in node '" << tag() << "'";
}
ss << ": " << message; ss << ": " << message;
return ss.str(); return ss.str();
} }
std::string Node::emitValue()
{
std::string tmpValue = value();
bool shouldQuote = false;
if(tmpValue.find_first_of("\\") != std::string::npos) {
boost::replace_all(tmpValue, "\\", "\\\\");
shouldQuote = true;
}
if(tmpValue.find_first_of("\"") != std::string::npos) {
boost::replace_all(tmpValue, "\"", "\\\"");
shouldQuote = true;
}
if(tmpValue.find_first_of("\n") != std::string::npos) {
boost::replace_all(tmpValue, "\n", "\\n");
shouldQuote = true;
}
if(shouldQuote) {
tmpValue.append("\"");
tmpValue.insert(0, "\"");
}
return tmpValue;
}
std::string Node::emit(int depth)
{
std::stringstream ss;
std::stringstream inlinestr;
bool shouldInline = false;
for(int i=1;i<depth;++i)
ss << " ";
if(depth > 0) {
shouldInline = true;
if(hasTag())
ss << tag();
if(hasValue()) {
if(hasTag())
ss << ": ";
else
ss << "- ";
ss << emitValue();
ss << std::endl;
shouldInline = false;
}
if(size() > 8 || size() == 0)
shouldInline = false;
}
if(shouldInline) {
inlinestr << "[";
for(NodeList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
Node* child = (*it);
if(child->hasTag() || ss.str().length() > 31) {
shouldInline = false;
break;
} else {
if(it != m_children.begin())
inlinestr << ", ";
inlinestr << child->emitValue();
}
}
inlinestr << "]";
}
if(shouldInline) {
ss << ": " << inlinestr.str() << std::endl;
} else {
if(!hasValue())
ss << std::endl;
for(NodeList::const_iterator it = m_children.begin(); it != m_children.end(); ++it)
ss << (*it)->emit(depth+1);
}
return ss.str();
}
///////////////////////////////////////////////////////////////////////////////
// Parser
Parser::~Parser()
{
if(m_rootNode)
delete m_rootNode;
}
void Parser::load(std::istream& in) void Parser::load(std::istream& in)
{ {
// initialize root node
if(m_rootNode) if(m_rootNode)
delete m_rootNode; delete m_rootNode;
m_rootNode = new Node(); m_rootNode = new Node(what());
m_rootNode->setTag("root"); m_rootNode->setTag("root");
m_currentParent = m_rootNode; m_currentParent = m_rootNode;
m_currentDepth = 0; m_currentDepth = m_currentLine = 0;
m_currentLine = 0;
m_multilineMode = DONT_MULTILINE; m_multilineMode = DONT_MULTILINE;
m_multilineData.clear(); m_multilineData.clear();
@ -222,7 +93,6 @@ void Parser::load(std::istream& in)
parseLine(line); parseLine(line);
} }
// stop multilining if enabled
if(isMultilining()) if(isMultilining())
stopMultilining(); stopMultilining();
} }
@ -239,49 +109,43 @@ void Parser::parseLine(std::string& line)
// trim left whitespaces // trim left whitespaces
boost::trim_left(line); boost::trim_left(line);
// skip comment lines // skip comment or empty lines
if(line[0] == '#') if(line[0] == '#' || line.empty())
return;
// skip empty lines
if(line.empty())
return; return;
// calculate depth
int depth = 0; int depth = 0;
if(numSpaces != std::string::npos) { if(numSpaces != std::string::npos)
depth = numSpaces / 2; depth = numSpaces / 2;
// check for syntax error
if(numSpaces % 2 != 0) { // check for syntax error
throwError("file must be idented every 2 whitespaces", m_currentLine); if(numSpaces != std::string::npos && numSpaces % 2 != 0)
return; throwError("file must be idented every 2 whitespaces", m_currentLine);
}
}
// a depth above // a depth above
if(depth == m_currentDepth+1) { if(depth == m_currentDepth+1) {
// change current parent to the previous added node // change current parent to the previous added node
m_currentParent = m_previousNode; m_currentParent = m_previousNode;
// a depth below, change parent to previus parent and add new node inside previuos parent // a depth below, change parent to previus parent and add new node inside previuos parent
} else if(depth < m_currentDepth) { } else if(depth < m_currentDepth) {
// change current parent to the the new depth parent // change current parent to the the new depth parent
for(int i=0;i<m_currentDepth-depth;++i) for(int i=0;i<m_currentDepth-depth;++i)
m_currentParent = m_currentParent->parent(); m_currentParent = m_currentParent->parent();
// else if nots the same depth it's a syntax error // else if nots the same depth it's a syntax error
} else if(depth != m_currentDepth) { } else if(depth != m_currentDepth) {
throwError("invalid indentation level", m_currentLine); throwError("invalid indentation level", m_currentLine);
return;
} }
// update current depth // update current depth
m_currentDepth = depth; m_currentDepth = depth;
// add node // add node
Node *node = parseNode(line); Node* node = m_currentParent->createNode();
m_currentParent->addNode(node); parseNode(node, line);
m_previousNode = node; m_previousNode = node;
} }
Node *Parser::parseNode(std::string& line) void Parser::parseNode(Node* node, std::string& line)
{ {
// determine node tag and value // determine node tag and value
std::string tag; std::string tag;
@ -292,61 +156,75 @@ Node *Parser::parseNode(std::string& line)
if(dotsPos != std::string::npos) { if(dotsPos != std::string::npos) {
tag = line.substr(0, dotsPos); tag = line.substr(0, dotsPos);
value = line.substr(dotsPos+1); value = line.substr(dotsPos+1);
} } else if(line[0] == '-') // its a node that has a value but no tag
// its a node that has a value but no tag
else if(line[0] == '-') {
value = line.substr(1); value = line.substr(1);
} else // its a node that has only a tag
// its a node that has only a tag
else {
tag = line; tag = line;
}
// trim the tag and value // set node tag
boost::trim(tag); boost::trim(tag);
boost::trim(value);
// create the node
Node *node = new Node(this);
node->setLine(m_currentLine);
node->setTag(tag); node->setTag(tag);
// process node value // set node line
if(!value.empty()) { node->setLine(m_currentLine);
// multiline text scalar
if(value[0] == '|') {
startMultilining(value);
}
// sequence
else if(value[0] == '[') {
if(boost::ends_with(value, "]")) {
value.erase(value.length()-1, 1);
value.erase(0, 1);
boost::trim(value);
boost::tokenizer<boost::escaped_list_separator<char> > tokens(value);
for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator it = tokens.begin(); it != tokens.end(); ++it) {
std::string tmp = (*it);
boost::trim(tmp);
if(!tmp.empty()) {
Node *child = new Node(this);
child->setLine(m_currentLine);
child->setValue(tmp);
node->addNode(child);
}
}
} else
throwError("missing ']' in sequence", m_currentLine);
}
// text scalar
else {
node->setValue(parseTextScalar(value));
}
}
return node; // process node value
parseNodeValue(node, value);
} }
std::string Parser::parseTextScalar(std::string value) void Parser::parseNodeValue(Node* node, std::string& value)
{
boost::trim(value);
if(value.empty())
return;
// multiline text scalar
if(value[0] == '|') {
// determine multiline mode
m_multilineMode = MULTILINE_DONT_FOLD;
if(value.length() == 2) {
switch(value[1]) {
case '-':
m_multilineMode = MULTILINE_FOLD_BLOCK;
break;
case '+':
m_multilineMode = MULTILINE_FOLD_FLOW;
break;
default:
throwError("invalid multiline identifier", m_currentLine);
break;
}
}
m_currentDepth++;
}
// sequence
else if(value[0] == '[') {
if(!boost::ends_with(value, "]"))
throwError("missing ']' in sequence", m_currentLine);
// erase '[' and ']'
value.erase(value.length()-1, 1);
value.erase(0, 1);
// split commas
boost::tokenizer<boost::escaped_list_separator<char> > tokens(value);
for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator it = tokens.begin(); it != tokens.end(); ++it) {
std::string tmp = (*it);
boost::trim(tmp);
if(!tmp.empty()) {
Node* child = node->createNode();
child->setLine(m_currentLine);
child->setValue(tmp);
}
}
}
// text scalar
else {
node->setValue(parseTextValue(value));
}
}
std::string Parser::parseTextValue(std::string value)
{ {
if(value[0] == '"' && value[value.length()-1] == '"') { if(value[0] == '"' && value[value.length()-1] == '"') {
value = value.substr(1, value.length()-2); value = value.substr(1, value.length()-2);
@ -358,35 +236,12 @@ std::string Parser::parseTextScalar(std::string value)
return value; return value;
} }
void Parser::startMultilining(const std::string& param)
{
m_multilineMode = MULTILINE_DONT_FOLD;
m_currentDepth++;
if(param.length() == 2) {
switch(param[1]) {
case '-':
m_multilineMode = MULTILINE_FOLD_BLOCK;
break;
case '+':
m_multilineMode = MULTILINE_FOLD_FLOW;
break;
default:
throwError("invalid multiline identifier", m_currentLine);
break;
}
}
}
void Parser::stopMultilining() void Parser::stopMultilining()
{ {
// remove all new lines at the end // remove all new lines at the end
if(m_multilineMode == MULTILINE_DONT_FOLD || m_multilineMode == MULTILINE_FOLD_BLOCK) { if(m_multilineMode == MULTILINE_DONT_FOLD || m_multilineMode == MULTILINE_FOLD_BLOCK) {
while(true) { while(*m_multilineData.rbegin() == '\n')
int lastPos = m_multilineData.length()-1; m_multilineData.erase(m_multilineData.length()-1, 1);
if(m_multilineData[lastPos] != '\n')
break;
m_multilineData.erase(lastPos, 1);
}
} }
if(m_multilineMode == MULTILINE_FOLD_BLOCK) if(m_multilineMode == MULTILINE_FOLD_BLOCK)
@ -405,7 +260,7 @@ bool Parser::parseMultiline(std::string line)
// depth above or equal current depth, add the text to the multiline // depth above or equal current depth, add the text to the multiline
if(numSpaces != std::string::npos && (int)numSpaces >= m_currentDepth*2) { if(numSpaces != std::string::npos && (int)numSpaces >= m_currentDepth*2) {
m_multilineData += parseTextScalar(line.substr(m_currentDepth*2)) + "\n"; m_multilineData += parseTextValue(line.substr(m_currentDepth*2)) + "\n";
return true; return true;
// depth below the current depth, check if it is a node // depth below the current depth, check if it is a node
} else if(numSpaces == std::string::npos || (int)numSpaces < m_currentDepth*2) { } else if(numSpaces == std::string::npos || (int)numSpaces < m_currentDepth*2) {
@ -435,4 +290,35 @@ void Parser::throwError(const std::string& message, int line)
throw Exception(ss.str()); throw Exception(ss.str());
} }
} // namespace FML { std::string Emitter::emitNodeValue(Node* node)
{
std::string value = node->value();
if(value[0] == '"' || *value.rbegin() == '"' || value.find("\n") != std::string::npos) {
boost::replace_all(value, "\\", "\\\\");
boost::replace_all(value, "\"", "\\\"");
boost::replace_all(value, "\n", "\\n");
value.append("\"");
value.insert(0, "\"");
}
return value;
}
std::string Emitter::emitNode(Node* node, int currentDepth)
{
std::stringstream ss;
for(int i=1;i<currentDepth;++i)
ss << " ";
if(currentDepth > 0) {
if(node->hasTag())
ss << node->tag();
if(node->hasValue())
ss << (node->hasTag() ? ": " : "- ") << emitNodeValue(node) << std::endl;
else
ss << std::endl;
}
for(int i=0;i<node->size();++i)
ss << emitNode(node->at(i), currentDepth+1);
return ss.str();
}
}

View File

@ -1,62 +1,53 @@
#ifndef FML_H #ifndef __FML_H
#define FML_H #define __FML_H
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <list>
#include <iterator> #include <iterator>
#include <map> #include <map>
#include <iostream>
#include <stdexcept> #include <stdexcept>
#include <typeinfo> #include <typeinfo>
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/foreach.hpp>
namespace FML { namespace FML {
///////////////////////////////////////////////////////////////////////////////
// Utilities
bool fml_convert(const std::string& input, bool& b); bool fml_convert(const std::string& input, bool& b);
bool fml_convert(const std::string& input, std::string& output); bool fml_convert(const std::string& input, std::string& output);
template <typename V, typename T> template <typename V, typename T>
bool fml_convert(const V& in, T& out) { bool fml_convert(const V& in, T& out) { std::stringstream ss; ss << in; ss >> out; return !!ss; }
std::stringstream ss;
ss << in;
ss >> out;
return !!ss;
}
std::string fml_int2str(int v); inline std::string fml_tostr(bool b) { return (b ? "true" : "false"); }
/////////////////////////////////////////////////////////////////////////////// template < typename T>
// Exception std::string fml_tostr(T v) { std::stringstream ss; ss << v; return ss.str(); }
class Exception : public std::runtime_error { class Exception : public std::runtime_error {
public: public:
explicit Exception(const std::string& what) : std::runtime_error(what) {} Exception(const std::string& what) : std::runtime_error(what) {}
}; };
///////////////////////////////////////////////////////////////////////////////
// Node
class Parser; class Parser;
class Node : boost::noncopyable class Node : boost::noncopyable
{ {
public: public:
typedef std::vector<Node*> NodeList; typedef std::vector<Node*> NodeList;
typedef NodeList::iterator iterator;
typedef NodeList::const_iterator const_iterator;
Node(Parser* parser = 0) : m_parser(parser), m_parent(0), m_line(0) { } Node(std::string what = "") : m_parent(0), m_line(0), m_what(what) { }
~Node(); ~Node() { for(int i=0;i<size();++i) delete at(i); }
bool hasTag() const { return !m_tag.empty(); } bool hasTag() const { return !m_tag.empty(); }
bool hasChildren() const { return size() > 0; } bool hasChildren() const { return size() > 0; }
bool hasValue() const { return !m_value.empty(); } bool hasValue() const { return !m_value.empty(); }
bool hasNode(const std::string childTag) const { return at(childTag) != 0; } bool hasNode(const std::string ctag) const { return at(ctag) != 0; }
void setTag(std::string tag) { m_tag = tag; } void setTag(std::string tag) { m_tag = tag; }
void setLine(int line) { m_line = line; } void setLine(int line) { m_line = line; }
@ -67,11 +58,7 @@ public:
int line() const { return m_line; } int line() const { return m_line; }
int size() const { return m_children.size(); } int size() const { return m_children.size(); }
Node* parent() { return m_parent; } Node* parent() { return m_parent; }
std::string what() const; std::string what() const { return (m_parent ? m_parent->what() : m_what); }
// iterators
typedef NodeList::iterator iterator;
typedef NodeList::const_iterator const_iterator;
iterator begin() { return m_children.begin(); } iterator begin() { return m_children.begin(); }
iterator end() { return m_children.end(); } iterator end() { return m_children.end(); }
@ -81,38 +68,22 @@ public:
Node* front() const { return at(0); } Node* front() const { return at(0); }
Node* back() const { return at(size()-1); } 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)); } void throwError(const std::string& message) const { throw Exception(generateErrorMessage(message)); }
// extracting values operator Node* at(const std::string& ctag) const;
template <typename T> Node* at(int pos) const { return ((pos < size() && pos >= 0) ? m_children[pos] : 0); }
friend bool operator >> (const Node& node, T& value);
// get nodes std::string value(const std::string& def = "") const { return (m_value.empty() ? def : m_value); }
Node* at(const std::string& childTag) const; std::string valueAt(const std::string ctag, const std::string& def = "") const { Node* c = at(ctag); return (c ? c->value() : def); }
Node* at(int pos) const; std::string valueAt(int pos, const std::string& def = "") const { Node* n = at(pos); return (n ? n->value() : def); }
// get values Node* createNode(std::string tag = "");
std::string value(const std::string& def = std::string()) const { void addNode(Node* node);
if(!m_value.empty()) bool removeNode(Node* node);
return m_value;
return def;
}
std::string valueAt(const std::string childTag, const std::string& def = std::string()) const { std::string generateErrorMessage(const std::string& message) const;
if(Node* node = at(childTag))
return node->value();
return def;
}
std::string valueAt(int pos, const std::string& def = std::string()) const { // read into memory
if(Node* node = at(pos))
return node->value();
return def;
}
// read values into memory
template <typename T> template <typename T>
void read(T* v) const { void read(T* v) const {
if(!(*this >> *v)) if(!(*this >> *v))
@ -120,8 +91,8 @@ public:
} }
template <typename T> template <typename T>
bool readAt(const std::string& childTag, T* v) const { bool readAt(const std::string& ctag, T* v) const {
if(Node* node = at(childTag)) { if(Node* node = at(ctag)) {
node->read<T>(v); node->read<T>(v);
return true; return true;
} }
@ -137,102 +108,114 @@ public:
return false; return false;
} }
// read values // read returning the result
template <typename T> template <typename T>
T read() const { T read() const { T v; read<T>(&v); return v;}
template <typename T>
T readAt(const std::string& ctag) const {
T v; T v;
read<T>(&v); if(!readAt(ctag, &v))
throw Exception(generateErrorMessage("child node " + ctag + " not found"));
return v; return v;
} }
template <typename T>
T readAt(const std::string& childTag) const {
if(Node* node = at(childTag))
return node->read<T>();
throw Exception(generateErrorMessage("child node " + childTag + " not found"));
return T();
}
template <typename T> template <typename T>
T readAt(int pos) const { T readAt(int pos) const {
if(Node* node = at(pos)) T v;
return node->read<T>(); if(!readAt(pos, &v))
throw Exception(generateErrorMessage("child node at pos " + fml_int2str(pos) + " not found")); throw Exception(generateErrorMessage("child node at pos " + fml_tostr(pos) + " not found"));
return T(); return v;
} }
// read values with defaults // read with default supplied
template <typename T> template <typename T>
T readAt(const std::string& childTag, const T& def) const { T readAt(const std::string& ctag, const T& def) const { Node* c = at(ctag); return (c ? c->read<T>() : def); }
if(Node* node = at(childTag))
return node->read<T>(); template <typename T>
else T readAt(int pos, const T& def) const { Node* c = at(pos); return (c ? c->read<T>() : def); }
return def;
// writing
template <typename T>
void write(T v) {
if(!(*this << v))
throw Exception(generateErrorMessage("failed to cast to string node value of type " + std::string(typeid(T).name())));
} }
template <typename T> template <typename T>
T readAt(int pos, const T& def) const { void writeIn(int pos, T v) {
if(Node* node = at(pos)) Node* c;
return node->read<T>(); while(!at(pos))
else c = createNode();
return def; c->write<T>(v);
} }
void addNode(Node* node); template <typename T>
void writeIn(const std::string& ctag, T v) {
std::string emitValue(); Node* c = createNode(ctag);
std::string emit(int depth = 0); c->write<T>(v);
}
private: private:
Parser* m_parser;
Node* m_parent; Node* m_parent;
int m_line; int m_line;
std::string m_what;
NodeList m_children; NodeList m_children;
std::string m_tag; std::string m_tag;
std::string m_value; std::string m_value;
}; };
// read operators
/////////////////////////////////////////////////////////////////////////////// template <typename T>
// Node operators bool operator >> (const Node& node, T& v) { return fml_convert(node.value(), v); }
template <typename T> template <typename T>
bool operator >> (const Node& node, T& v) bool operator >> (const Node& node, std::vector<T>& v) {
{ v.resize(node.size());
return fml_convert(node.value(), v); for(unsigned i=0;i<node.size();++i)
v[i] = node.readAt<T>(i);
return true;
} }
template <typename T> template <typename T>
bool operator >> (const Node& node, std::vector<T>& v) bool operator >> (const Node& node, std::list<T>& v) {
{
std::vector<T>& tmp;
tmp.resize(node.size());
for(unsigned i=0;i<node.size();++i) for(unsigned i=0;i<node.size();++i)
v[i] = node.readAt<T>(i); v.push_back(node.readAt<T>(i));
v = tmp;
return true; return true;
} }
template <typename K, typename T> template <typename K, typename T>
bool operator >> (const Node& node, std::map<K, T>& m) bool operator >> (const Node& node, std::map<K, T>& m) {
{ for(int i=0;i<node.size();++i)
std::map<K, T> tmp; m[node.at(i)->read<K>()] = node.at(i)->read<T>();
for(Node::const_iterator it = node.begin(); it != node.end(); ++it) {
K k;
T v;
if(fml_convert<std::string, K>((*it)->tag(), k)) {
(*it)->read(&v);
tmp[k] = v;
} else
return false;
}
m = tmp;
return true; return true;
} }
// write operators
template <typename T>
bool operator << (Node& node, const T& v) { node.setValue(fml_tostr(v)); return true; }
/////////////////////////////////////////////////////////////////////////////// template <typename T>
// Parser bool operator << (Node& node, const std::vector<T>& v) {
for(unsigned i=0;i<v.size();++i)
node.createNode()->write(v[i]);
return true;
}
template <typename T>
bool operator << (Node& node, const std::list<T>& v) {
for(unsigned i=0;i<v.size();++i)
node.createNode()->write(v[i]);
return true;
}
template <typename K, typename T>
bool operator << (Node& node, const std::map<K, T>& m) {
typename std::map<K, T>::const_iterator it;
for(it = m.begin(); it != m.end(); ++it)
node.createNode(fml_tostr(it->first))->write(it->second);
return true;
}
class Parser class Parser
{ {
@ -246,24 +229,24 @@ class Parser
public: public:
Parser(std::string what = std::string()) : m_rootNode(0), m_what(what) { } 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(std::istream& in, std::string what = std::string()) : m_rootNode(0), m_what(what) { load(in); }
~Parser(); ~Parser() { if(m_rootNode) delete m_rootNode; }
void load(std::istream& in);
Node* getDocument() const { return m_rootNode; } Node* getDocument() const { return m_rootNode; }
std::string what() { return m_what; } std::string what() { return m_what; }
void load(std::istream& in);
protected: protected:
void parseLine(std::string& line); void parseLine(std::string& line);
Node* parseNode(std::string& line); void parseNode(Node* node, std::string& line);
std::string parseTextScalar(std::string value); void parseNodeValue(Node* node, std::string& value);
std::string parseTextValue(std::string value);
void startMultilining(const std::string& param);
void stopMultilining(); void stopMultilining();
bool parseMultiline(std::string line); bool parseMultiline(std::string line);
bool isMultilining() { return m_multilineMode != DONT_MULTILINE; } bool isMultilining() { return m_multilineMode != DONT_MULTILINE; }
void throwError(const std::string& message, int line = 0); void throwError(const std::string& message, int line);
private: private:
int m_currentDepth; int m_currentDepth;
@ -276,6 +259,22 @@ private:
std::string m_what; std::string m_what;
}; };
class Emitter
{
public:
Emitter() : m_rootNode(0) { }
~Emitter() { if(m_rootNode) delete m_rootNode; }
Node* createDocument() { m_rootNode = new Node; return m_rootNode; }
std::string emitDocument() { if(m_rootNode) return emitNode(m_rootNode, 0); return std::string(); }
static std::string emitNodeValue(Node* node);
static std::string emitNode(Node* node, int currentDepth = 0);
private:
Node* m_rootNode;
};
} // namespace FML { } // namespace FML {
#endif // FML_H #endif // __FML_H