use exceptions in FML
This commit is contained in:
parent
c3e67fceb9
commit
d7bc083014
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue