use exceptions in FML

This commit is contained in:
Eduardo Bart 2011-05-21 19:24:10 -03:00
parent c3e67fceb9
commit d7bc083014
14 changed files with 306 additions and 175 deletions

View File

@ -86,7 +86,7 @@ window#optionsWindow
margin.bottom: 60 margin.bottom: 60
label#motdLabel label#motdLabel
text: |- text: |
Show the most recent Show the most recent
Message of the Day Message of the Day
anchors.left: parent.left anchors.left: parent.left

View File

@ -36,14 +36,14 @@ bool Configs::load(const std::string& fileName)
if(!g_resources.loadFile(fileName, fin)) if(!g_resources.loadFile(fileName, fin))
return false; return false;
FML::Parser parser; try {
if(parser.load(fin)) { FML::Parser parser(fin, fileName);
FML::Node* doc = parser.getDocument(); FML::Node* doc = parser.getDocument();
foreach(FML::Node* node, *doc) foreach(FML::Node* node, *doc)
m_confsMap[node->tag()] = node->value(); m_confsMap[node->tag()] = node->value();
} else { } catch(FML::Exception e) {
flogError("ERROR: Malformed config file: %s", parser.getErrorMessage()); flogError("ERROR: Malformed config file: %s", e.what());
return false; return false;
} }

View File

@ -118,7 +118,7 @@ bool Resources::loadFile(const std::string& fileName, std::iostream& out)
char *buffer = new char[fileSize]; char *buffer = new char[fileSize];
PHYSFS_read(file, (void*)buffer, 1, fileSize); PHYSFS_read(file, (void*)buffer, 1, fileSize);
out.write(buffer, fileSize); out.write(buffer, fileSize);
delete buffer; delete[] buffer;
} else } else
out.clear(std::ios::eofbit); out.clear(std::ios::eofbit);
PHYSFS_close(file); PHYSFS_close(file);

View File

@ -77,8 +77,8 @@ bool Font::load(const std::string& file)
std::string textureName; std::string textureName;
Size glyphSize; Size glyphSize;
FML::Parser parser(fin); try {
if(!parser.hasError()) { FML::Parser parser(fin, file);
FML::Node* doc = parser.getDocument(); FML::Node* doc = parser.getDocument();
// required values // required values
@ -115,8 +115,8 @@ bool Font::load(const std::string& file)
m_glyphsSize[glyph].width(), m_glyphsSize[glyph].width(),
m_glyphHeight); m_glyphHeight);
} }
} else { } catch(FML::Exception e) {
flogError("ERROR: Malformed font file \"%s\":\n %s", file.c_str() % parser.getErrorMessage()); flogError("ERROR: Malformed font file \"%s\":\n %s", file.c_str() % e.what());
return false; return false;
} }

View File

@ -75,10 +75,8 @@ UIElementPtr UILoader::loadFromFile(std::string filePath, const UIContainerPtr&
return UIElementPtr(); return UIElementPtr();
} }
m_currentFile = filePath; try {
FML::Parser parser(fin, filePath);
FML::Parser parser(fin);
if(!parser.hasError()) {
FML::Node* doc = parser.getDocument(); FML::Node* doc = parser.getDocument();
// get element id // get element id
@ -105,8 +103,8 @@ UIElementPtr UILoader::loadFromFile(std::string filePath, const UIContainerPtr&
// report onLoad events // report onLoad events
element->onLoad(); element->onLoad();
return element; return element;
} else { } catch(FML::Exception e) {
flogError("ERROR: Failed to load ui %s: %s", filePath.c_str() % parser.getErrorMessage()); flogError("ERROR: Failed to load ui %s: %s", filePath.c_str() % e.what());
} }
return UIElementPtr(); return UIElementPtr();
@ -192,14 +190,14 @@ void UILoader::loadElement(const UIElementPtr& element, FML::Node* node)
// load events // load events
if(FML::Node* cnode = node->at("onLoad")) { if(FML::Node* cnode = node->at("onLoad")) {
if(g_lua.loadBufferAsFunction(cnode->value(), getElementSourceDesc(element, "onLoad"))) if(g_lua.loadBufferAsFunction(cnode->value(), getElementSourceDesc(element, cnode)))
g_lua.setScriptableField(element, "onLoad"); g_lua.setScriptableField(element, "onLoad");
else else
logError(cnode->generateErrorMessage("failed to parse inline lua script")); logError(cnode->generateErrorMessage("failed to parse inline lua script"));
} }
if(FML::Node* cnode = node->at("onDestroy")) { if(FML::Node* cnode = node->at("onDestroy")) {
if(g_lua.loadBufferAsFunction(cnode->value(), getElementSourceDesc(element, "onDestroy"))) if(g_lua.loadBufferAsFunction(cnode->value(), getElementSourceDesc(element, cnode)))
g_lua.setScriptableField(element, "onDestroy"); g_lua.setScriptableField(element, "onDestroy");
else else
logError(cnode->generateErrorMessage("failed to parse inline lua script")); logError(cnode->generateErrorMessage("failed to parse inline lua script"));
@ -254,19 +252,19 @@ void UILoader::loadButton(const UIButtonPtr& button, FML::Node* node)
// set on click event // set on click event
if(FML::Node* cnode = node->at("onClick")) { if(FML::Node* cnode = node->at("onClick")) {
if(g_lua.loadBufferAsFunction(cnode->value(), getElementSourceDesc(button, "onClick"))) if(g_lua.loadBufferAsFunction(cnode->value(), getElementSourceDesc(button, cnode)))
g_lua.setScriptableField(button, "onClick"); g_lua.setScriptableField(button, "onClick");
else else
logError(cnode->generateErrorMessage("failed to parse inline lua script")); logError(cnode->generateErrorMessage("failed to parse inline lua script"));
} }
} }
std::string UILoader::getElementSourceDesc(const UIElementPtr& element, const std::string& key) std::string UILoader::getElementSourceDesc(const UIElementPtr& element, const FML::Node *node)
{ {
std::string desc; std::string desc;
desc += g_resources.resolvePath(m_currentFile) + ":" + element->getId(); desc += g_resources.resolvePath(node->what()) + ":" + element->getId();
if(key.length() > 0) if(!node->tag().empty())
desc += "[" + key + "]"; desc += "[" + node->tag() + "]";
return desc; return desc;
} }

View File

@ -55,9 +55,7 @@ private:
// specific elements loading // specific elements loading
void loadButton(const UIButtonPtr& button, FML::Node* node); void loadButton(const UIButtonPtr& button, FML::Node* node);
std::string getElementSourceDesc(const UIElementPtr& element, const std::string& key = ""); std::string getElementSourceDesc(const UIElementPtr& element, const FML::Node *node);
std::string m_currentFile;
}; };
extern UILoader g_uiLoader; extern UILoader g_uiLoader;

View File

@ -43,11 +43,11 @@ void UISkins::load(const std::string& skinName)
if(!g_resources.loadFile(skinName + ".yml", fin)) if(!g_resources.loadFile(skinName + ".yml", fin))
flogFatal("FATAL ERROR: Could not load skin \"%s", skinName.c_str()); flogFatal("FATAL ERROR: Could not load skin \"%s", skinName.c_str());
FML::Parser parser(fin); try {
if(!parser.hasError()) { FML::Parser parser(fin, skinName);
FML::Node* doc = parser.getDocument(); FML::Node* doc = parser.getDocument();
m_defaultFont = g_fonts.get(doc->readAt<std::string>("default font")); m_defaultFont = g_fonts.get(doc->valueAt("default font"));
if(!m_defaultFont) if(!m_defaultFont)
logFatal("FATAL ERROR: Could not load skin default font"); logFatal("FATAL ERROR: Could not load skin default font");
@ -57,48 +57,30 @@ void UISkins::load(const std::string& skinName)
if(!defaultTextureName.empty()) if(!defaultTextureName.empty())
m_defaultTexture = g_textures.get(defaultTextureName); m_defaultTexture = g_textures.get(defaultTextureName);
if(FML::Node* node = doc->at("buttons")) { foreach(FML::Node* node, *doc) {
UIElementSkinPtr skin;
foreach(FML::Node* cnode, *node) { foreach(FML::Node* cnode, *node) {
UIElementSkinPtr skin = UIElementSkinPtr(new UIButtonSkin(cnode->tag())); if(node->tag() == "buttons")
skin = UIElementSkinPtr(new UIButtonSkin(cnode->tag()));
else if(node->tag() == "panels")
skin = UIElementSkinPtr(new UIElementSkin(cnode->tag(), UI::Panel));
else if(node->tag() == "windows")
skin = UIElementSkinPtr(new UIWindowSkin(cnode->tag()));
else if(node->tag() == "labels")
skin = UIElementSkinPtr(new UILabelSkin(cnode->tag()));
else if(node->tag() == "text edits")
skin = UIElementSkinPtr(new UITextEditSkin(cnode->tag()));
else if(node->tag() == "line decorations")
skin = UIElementSkinPtr(new UIElementSkin(cnode->tag(), UI::LineDecoration));
else {
break;
}
skin->load(cnode); skin->load(cnode);
m_elementSkins.push_back(skin); m_elementSkins.push_back(skin);
} }
} }
} catch(FML::Exception e) {
if(FML::Node* node = doc->at("panels")) { flogFatal("FATAL ERROR: Malformed skin file \"%s\":\n %s", skinName.c_str() % e.what());
foreach(FML::Node* cnode, *node) {
UIElementSkinPtr skin = UIElementSkinPtr(new UIElementSkin(cnode->tag(), UI::Panel));
skin->load(cnode);
m_elementSkins.push_back(skin);
}
}
if(FML::Node* node = doc->at("windows")) {
foreach(FML::Node* cnode, *node) {
UIElementSkinPtr skin = UIElementSkinPtr(new UIWindowSkin(cnode->tag()));
skin->load(cnode);
m_elementSkins.push_back(skin);
}
}
if(FML::Node* node = doc->at("labels")) {
foreach(FML::Node* cnode, *node) {
UIElementSkinPtr skin = UIElementSkinPtr(new UILabelSkin(cnode->tag()));
skin->load(cnode);
m_elementSkins.push_back(skin);
}
}
if(FML::Node* node = doc->at("text edits")) {
foreach(FML::Node* cnode, *node) {
UIElementSkinPtr skin = UIElementSkinPtr(new UITextEditSkin(cnode->tag()));
skin->load(cnode);
m_elementSkins.push_back(skin);
}
}
} else {
flogFatal("FATAL ERROR: Malformed skin file \"%s\":\n %s", skinName.c_str() % parser.getErrorMessage());
} }
g_resources.popCurrentPath(); g_resources.popCurrentPath();

View File

@ -76,14 +76,18 @@ inline std::ostream& operator<<(std::ostream& out, const Color& color)
return out; return out;
} }
inline void operator>>(const FML::Node& node, Color& color) inline bool operator>>(const FML::Node& node, Color& color)
{ {
int r, g, b, a; int r, g, b, a;
*node.at(0) >> r; if(node.readAt(0, &r) &&
*node.at(1) >> g; node.readAt(1, &g) &&
*node.at(2) >> b; node.readAt(2, &b)) {
*node.at(3) >> a; a = 255;
color.setRGBA(r,g,b,a); node.readAt(3, &a);
color.setRGBA(r,g,b,a);
return true;
}
return false;
} }
#endif // COLOR_H #endif // COLOR_H

View File

@ -38,6 +38,12 @@ bool fml_convert(const std::string& input, std::string& output) {
return true; return true;
} }
std::string fml_int2str(int v)
{
std::stringstream ss;
ss << v;
return ss.str();
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Node // Node
@ -48,6 +54,13 @@ Node::~Node()
delete (*it); delete (*it);
} }
std::string Node::what() const
{
if(m_parser)
return m_parser->what();
return std::string();
}
Node* Node::at(const std::string& childTag) const Node* Node::at(const std::string& childTag) const
{ {
for(NodeList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) { for(NodeList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
@ -64,22 +77,6 @@ Node* Node::at(int pos) const
return m_children[pos]; return m_children[pos];
} }
std::string Node::value(const std::string& def) const
{
if(!m_value.empty())
return m_value;
return def;
}
std::string Node::valueAt(const std::string childTag, const std::string& def) const
{
for(NodeList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
if((*it)->tag() == childTag)
return (*it)->value();
}
return def;
}
void Node::addNode(Node *node) void Node::addNode(Node *node)
{ {
if(node->hasTag() && node->hasValue()) { if(node->hasTag() && node->hasValue()) {
@ -99,15 +96,101 @@ void Node::addNode(Node *node)
std::string Node::generateErrorMessage(const std::string& message) const std::string Node::generateErrorMessage(const std::string& message) const
{ {
std::stringstream ss; std::stringstream ss;
ss << "FML error "; ss << "FML error";
if(m_parser && !m_parser->getWhat().empty()) if(!(what().empty()))
ss << "in " << m_parser->getWhat(); ss << " in '" << what() << "'";
if(m_line > 0) if(m_line > 0) {
ss << "at line " << m_line; ss << " at line " << m_line;
if(hasTag())
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
@ -118,7 +201,7 @@ Parser::~Parser()
delete m_rootNode; delete m_rootNode;
} }
bool Parser::load(std::istream& in) void Parser::load(std::istream& in)
{ {
// initialize root node // initialize root node
if(m_rootNode) if(m_rootNode)
@ -137,15 +220,11 @@ bool Parser::load(std::istream& in)
std::string line; std::string line;
std::getline(in, line); std::getline(in, line);
parseLine(line); parseLine(line);
if(hasError())
return false;
} }
// stop multilining if enabled // stop multilining if enabled
if(isMultilining()) if(isMultilining())
stopMultilining(); stopMultilining();
return !hasError();
} }
void Parser::parseLine(std::string& line) void Parser::parseLine(std::string& line)
@ -173,7 +252,7 @@ void Parser::parseLine(std::string& line)
depth = numSpaces / 2; depth = numSpaces / 2;
// check for syntax error // check for syntax error
if(numSpaces % 2 != 0) { if(numSpaces % 2 != 0) {
setErrorMessage("file must be idented every 2 whitespaces", m_currentLine); throwError("file must be idented every 2 whitespaces", m_currentLine);
return; return;
} }
} }
@ -189,7 +268,7 @@ void Parser::parseLine(std::string& line)
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) {
setErrorMessage("invalid indentation level", m_currentLine); throwError("invalid indentation level", m_currentLine);
return; return;
} }
@ -246,16 +325,17 @@ Node *Parser::parseNode(std::string& line)
boost::trim(value); boost::trim(value);
boost::tokenizer<boost::escaped_list_separator<char> > tokens(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) { for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator it = tokens.begin(); it != tokens.end(); ++it) {
value = *it; std::string tmp = (*it);
boost::trim(value); boost::trim(tmp);
if(!tmp.empty()) {
Node *child = new Node(this); Node *child = new Node(this);
child->setLine(m_currentLine); child->setLine(m_currentLine);
child->setValue(value); child->setValue(tmp);
node->addNode(child); node->addNode(child);
}
} }
} else } else
setErrorMessage("missing ']' in sequence", m_currentLine); throwError("missing ']' in sequence", m_currentLine);
} }
// text scalar // text scalar
else { else {
@ -291,7 +371,7 @@ void Parser::startMultilining(const std::string& param)
m_multilineMode = MULTILINE_FOLD_FLOW; m_multilineMode = MULTILINE_FOLD_FLOW;
break; break;
default: default:
setErrorMessage("invalid multiline identifier", m_currentLine); throwError("invalid multiline identifier", m_currentLine);
break; break;
} }
} }
@ -343,16 +423,16 @@ bool Parser::parseMultiline(std::string line)
return false; return false;
} }
void Parser::setErrorMessage(const std::string& message, int line) void Parser::throwError(const std::string& message, int line)
{ {
std::stringstream ss; std::stringstream ss;
ss << "FML syntax error in "; ss << "FML syntax error";
if(!m_what.empty()) if(!m_what.empty())
ss << m_what << " "; ss << " in '" << m_what << "'";
if(line > 0) if(line > 0)
ss << "at line " << line; ss << " at line " << line;
ss << ": " << message; ss << ": " << message;
m_error = ss.str(); throw Exception(ss.str());
} }
} // namespace FML { } // namespace FML {

View File

@ -6,6 +6,9 @@
#include <vector> #include <vector>
#include <iterator> #include <iterator>
#include <map> #include <map>
#include <iostream>
#include <stdexcept>
#include <typeinfo>
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -26,6 +29,16 @@ bool fml_convert(const V& in, T& out) {
return !!ss; 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 // Node
@ -54,6 +67,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;
// iterators // iterators
typedef NodeList::iterator iterator; typedef NodeList::iterator iterator;
@ -69,6 +83,7 @@ public:
// util for generating error message // util for generating error message
std::string generateErrorMessage(const std::string& message) const; std::string generateErrorMessage(const std::string& message) const;
void throwError(const std::string& message) const { throw Exception(generateErrorMessage(message)); }
// extracting values operator // extracting values operator
template <typename T> template <typename T>
@ -79,45 +94,95 @@ public:
Node* at(int pos) const; Node* at(int pos) const;
// get values // get values
std::string value(const std::string& def = std::string()) const; std::string value(const std::string& def = std::string()) const {
std::string valueAt(const std::string childTag, const std::string& def = std::string()) const; if(!m_value.empty())
return m_value;
// read values return def;
template <typename T>
T read(T def = T()) const {
T v = def;
*this >> v;
return v;
} }
template <typename T> std::string valueAt(const std::string childTag, const std::string& def = std::string()) const {
bool read(T* v) const { if(Node* node = at(childTag))
return (*this >> *v); 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 <typename T> template <typename T>
T readAt(const std::string& childTag, T def = T()) const { void read(T* v) const {
T v = def; if(!(*this >> *v))
for(NodeList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) { throw Exception(generateErrorMessage("failed to cast node value to type " + std::string(typeid(T).name())));
if((*it)->tag() == childTag) {
*(*it) >> v;
break;
}
}
return v;
} }
template <typename T> template <typename T>
bool readAt(const std::string& childTag, T* v) const { bool readAt(const std::string& childTag, T* v) const {
for(NodeList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) { if(Node* node = at(childTag)) {
if((*it)->tag() == childTag) node->read<T>(v);
return (*(*it) >> *v); return true;
} }
return false; return false;
} }
template <typename T>
bool readAt(int pos, T* v) const {
if(Node* node = at(pos)) {
node->read<T>(v);
return true;
}
return false;
}
// read values
template <typename T>
T read() const {
T v;
read<T>(&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>
T readAt(int pos) const {
if(Node* node = at(pos))
return node->read<T>();
throw Exception(generateErrorMessage("child node at pos " + fml_int2str(pos) + " not found"));
return T();
}
// read values with defaults
template <typename T>
T readAt(const std::string& childTag, const T& def) const {
if(Node* node = at(childTag))
return node->read<T>();
else
return def;
}
template <typename T>
T readAt(int pos, const T& def) const {
if(Node* node = at(pos))
return node->read<T>();
else
return def;
}
void addNode(Node* node); void addNode(Node* node);
std::string emitValue();
std::string emit(int depth = 0);
private: private:
Parser* m_parser; Parser* m_parser;
Node* m_parent; Node* m_parent;
@ -140,32 +205,29 @@ bool operator >> (const Node& node, T& v)
template <typename T> template <typename T>
bool operator >> (const Node& node, std::vector<T>& v) bool operator >> (const Node& node, std::vector<T>& v)
{ {
bool ret = true; std::vector<T>& tmp;
v.clear(); tmp.resize(node.size());
v.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);
if(!(*node.at(i) >> v[i])) v = tmp;
ret = false; return true;
}
return ret;
} }
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)
{ {
bool ret = true; std::map<K, T> tmp;
m.clear();
for(Node::const_iterator it = node.begin(); it != node.end(); ++it) { for(Node::const_iterator it = node.begin(); it != node.end(); ++it) {
Node* child = (*it);
K k; K k;
T v; T v;
if(fml_convert<std::string, K>(child->tag(), k)) { if(fml_convert<std::string, K>((*it)->tag(), k)) {
*child >> v; (*it)->read(&v);
m[k] = v; tmp[k] = v;
ret = false; } else
} return false;
} }
return ret; m = tmp;
return true;
} }
@ -186,12 +248,10 @@ public:
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();
bool load(std::istream& in); void load(std::istream& in);
Node* getDocument() const { return m_rootNode; } Node* getDocument() const { return m_rootNode; }
bool hasError() const { return !m_error.empty(); } std::string what() { return m_what; }
std::string getErrorMessage() { return m_error; }
std::string getWhat() { return m_what; }
protected: protected:
void parseLine(std::string& line); void parseLine(std::string& line);
@ -203,7 +263,7 @@ protected:
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 setErrorMessage(const std::string& message, int line = 0); void throwError(const std::string& message, int line = 0);
private: private:
int m_currentDepth; int m_currentDepth;
@ -213,7 +273,6 @@ private:
Node* m_rootNode; Node* m_rootNode;
MultilineMode m_multilineMode; MultilineMode m_multilineMode;
std::string m_multilineData; std::string m_multilineData;
std::string m_error;
std::string m_what; std::string m_what;
}; };

View File

@ -86,10 +86,15 @@ inline std::ostream& operator<<(std::ostream& out, const TPoint<T>& point)
} }
template <class T> template <class T>
inline void operator>>(const FML::Node& node, TPoint<T>& point) inline bool operator>>(const FML::Node& node, TPoint<T>& point)
{ {
*node.at(0) >> point.x; T x, y;
*node.at(1) >> point.y; if(node.readAt(0, &x) && node.readAt(1, &y)) {
point.x = x;
point.y = y;
return true;
}
return false;
} }
#endif #endif

View File

@ -310,14 +310,17 @@ inline std::ostream& operator<<(std::ostream& out, const TRect<T>& rect)
} }
template <class T> template <class T>
inline void operator>>(const FML::Node& node, TRect<T>& rect) inline bool operator>>(const FML::Node& node, TRect<T>& rect)
{ {
T x, y, width, height; T x, y, width, height;
*node.at(0) >> x; if(node.readAt(0, &x) &&
*node.at(1) >> y; node.readAt(1, &y) &&
*node.at(2) >> width; node.readAt(2, &width) &&
*node.at(3) >> height; node.readAt(3, &height)) {
rect.setRect(x, y, width, height); rect.setRect(x, y, width, height);
return true;
}
return false;
} }
#endif // RECT_H #endif // RECT_H

View File

@ -112,12 +112,14 @@ typedef TSize<int> Size;
typedef TSize<float> SizeF; typedef TSize<float> SizeF;
template <class T> template <class T>
inline void operator>>(const FML::Node& node, TSize<T>& size) inline bool operator>>(const FML::Node& node, TSize<T>& size)
{ {
T w, h; T w, h;
*node.at(0) >> w; if(node.readAt(0, &w) && node.readAt(1, &h)) {
*node.at(1) >> h; size.setSize(w, h);
size.setSize(w, h); return true;
}
return false;
} }
#endif #endif

View File

@ -41,7 +41,7 @@ R convert_cast(T t)
try { try {
ret = boost::lexical_cast<R>(t); ret = boost::lexical_cast<R>(t);
} catch(boost::bad_lexical_cast bad) { } catch(boost::bad_lexical_cast bad) {
flogError("Error converting type: %s", bad.what()); flogError("Error converting value: %s", bad.what());
} }
return ret; return ret;
} }