feat: support alternative vcm models syntax

This commit is contained in:
MihailRis
2025-06-01 23:08:59 +03:00
parent 8f342fe429
commit 4333d9ab06
10 changed files with 155 additions and 28 deletions
+14 -7
View File
@@ -5,6 +5,7 @@
#include "xml.hpp"
#include "util/stringutil.hpp"
#include "graphics/commons/Model.hpp"
#include "io/io.hpp"
using namespace vcm;
using namespace xml;
@@ -143,12 +144,18 @@ static std::unique_ptr<model::Model> load_model(const xmlelement& root) {
std::unique_ptr<model::Model> vcm::parse(
std::string_view file, std::string_view src
) {
auto doc = xml::parse(file, src);
const auto& root = *doc->getRoot();
if (root.getTag() != "model") {
throw std::runtime_error(
"'model' tag expected as root, got '" + root.getTag() + "'"
);
try {
auto doc = io::path(std::string(file)).extension() == ".xml"
? xml::parse(file, src) : xml::parse_vcm(file, src, "model");
const auto& root = *doc->getRoot();
if (root.getTag() != "model") {
throw std::runtime_error(
"'model' tag expected as root, got '" + root.getTag() + "'"
);
}
std::cout << xml::stringify(*doc) << std::endl;
return load_model(root);
} catch (const parsing_error& err) {
throw std::runtime_error(err.errorLog());
}
return load_model(root);
}
+77
View File
@@ -355,6 +355,83 @@ std::unique_ptr<Document> xml::parse(
return parser.parse();
}
namespace {
class VcmParser : public BasicParser<char> {
public:
VcmParser(std::string_view filename, std::string_view source)
: BasicParser(filename, source) {
document = std::make_unique<Document>("1.0", "UTF-8");
hashComment = true;
}
std::string parseValue() {
char c = peek();
if (c == '"' || c == '\'') {
nextChar();
return parseString(c);
}
if (c == '(') {
nextChar();
// TODO: replace with array parsing after moving to dv::value's
std::string value = std::string(readUntil(')'));
expect(')');
return value;
}
return std::string(readUntilWhitespace());
}
void parseSubElements(Node& node) {
skipWhitespace();
while (hasNext()) {
if (peek() != '@') {
throw error("unexpected character in element");
}
nextChar();
auto subnodePtr = std::make_unique<Node>(parseName());
auto subnode = subnodePtr.get();
node.add(std::move(subnodePtr));
skipWhitespace();
while (hasNext() && peek() != '@' && peek() != '{' && peek() != '}') {
std::string attrname = parseName();
skipWhitespace();
std::string value = parseValue();
subnode->set(attrname, value);
skipWhitespace();
}
if (!hasNext()) {
break;
}
char c = peek();
if (c == '{') {
nextChar();
parseSubElements(*subnode);
expect('}');
skipWhitespace();
} else if (c == '}') {
break;
}
}
}
std::unique_ptr<Document> parse(const std::string& rootTag) {
auto root = std::make_unique<Node>(rootTag);
parseSubElements(*root);
document->setRoot(std::move(root));
return std::move(document);
}
private:
std::unique_ptr<Document> document;
};
}
std::unique_ptr<Document> xml::parse_vcm(
std::string_view filename, std::string_view source, std::string_view tag
) {
VcmParser parser(filename, source);
return parser.parse(std::string(tag));
}
inline void newline(
std::stringstream& ss, bool nice, const std::string& indentStr, int indent
) {
+4
View File
@@ -126,5 +126,9 @@ namespace xml {
std::string_view filename, std::string_view source
);
std::unique_ptr<Document> parse_vcm(
std::string_view filename, std::string_view source, std::string_view tag
);
using xmlelement = Node;
}