- Serialitzador acabat
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# THE JAIL
|
||||
room: 1
|
||||
room:
|
||||
name: "THE JAIL"
|
||||
bgColor: bright_blue
|
||||
border: blue
|
||||
|
||||
60
main.cpp
60
main.cpp
@@ -1,30 +1,46 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "yamal.hpp"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
/*if (argc < 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " <yaml_file>\n";
|
||||
return 1;
|
||||
}*/
|
||||
|
||||
std::ifstream file("data/room/01.yaml"); //argv[1]);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Could not open file " << argv[1] << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ostringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
std::string yamlText = buffer.str();
|
||||
|
||||
yamal_ns::yamal root;
|
||||
root.deserialize(yamlText);
|
||||
|
||||
//for (auto &att : root.attributes())
|
||||
// std::cout << att.first << ": " << att.second.asString() << std::endl;
|
||||
yamal root;
|
||||
root["room"]["name"] = "THE JAIL";
|
||||
root["room"]["name"].setQuoted(true);
|
||||
root["room"]["bgColor"] = "bright_blue";
|
||||
root["room"]["connections"]["up"] = "null";
|
||||
root["room"]["connections"]["down"] = "null";
|
||||
root["room"]["connections"]["left"] = "null";
|
||||
root["room"]["connections"]["right"] = "02.yaml";
|
||||
root["room"]["itemColor1"] = "yellow";
|
||||
root["tilemap"][0][0] = 00;
|
||||
root["tilemap"][0][1] = 01;
|
||||
root["tilemap"][1][0] = 10;
|
||||
root["tilemap"][1][1] = 11;
|
||||
root["tilemap"][0].setInline(true);
|
||||
root["tilemap"][1].setInline(true);
|
||||
root["enemies"][0]["animation"] = "jailer_1.yaml";
|
||||
root["enemies"][0]["position"]["x"] = 1;
|
||||
root["enemies"][0]["position"]["y"] = 13;
|
||||
root["enemies"][0]["position"].setInline(true);
|
||||
root["enemies"][0]["boundaries"]["position1"]["x"] = 1;
|
||||
root["enemies"][0]["boundaries"]["position1"]["y"] = 1;
|
||||
root["enemies"][0]["boundaries"]["position1"].setInline(true);
|
||||
root["enemies"][0]["color"]= "white";
|
||||
root["enemies"][1]["animation"] = "jailer_2.yaml";
|
||||
root["enemies"][1]["position"]["x"] = 2;
|
||||
root["enemies"][1]["position"]["y"] = 23;
|
||||
root["enemies"][1]["position"].setInline(true);
|
||||
root["enemies"][1]["boundaries"]["position1"]["x"] = 2;
|
||||
root["enemies"][1]["boundaries"]["position1"]["y"] = 2;
|
||||
root["enemies"][1]["boundaries"]["position1"].setInline(true);
|
||||
root["enemies"][1]["color"]= "black";
|
||||
root["items"].clearToVector();
|
||||
root["items"].setInline(true);
|
||||
|
||||
root["room"].setComment("THE JAIL");
|
||||
root["room"].setBlankLine(false);
|
||||
root["tilemap"].setComment("Tilemap: 16 filas x 32 columnas (256x192 píxeles @ 8px/tile)");
|
||||
root["tilemap"].appendComment("Índices de tiles (-1 = vacío)");
|
||||
root["room"]["bgColor"].setInlineComment("Azul oscuro");
|
||||
std::cout << root.serialize() << std::endl;
|
||||
|
||||
return 0;
|
||||
|
||||
28
test.yaml
Normal file
28
test.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
# THE JAIL
|
||||
room:
|
||||
name: "THE JAIL"
|
||||
bgColor: bright_blue # Azul oscuro
|
||||
connections:
|
||||
up: null
|
||||
down: null
|
||||
left: null
|
||||
right: 02.yaml
|
||||
itemColor1: yellow
|
||||
|
||||
# Tilemap: 16 filas x 32 columnas (256x192 píxeles @ 8px/tile)
|
||||
# Índices de tiles (-1 = vacío)
|
||||
tilemap:
|
||||
- [ 0, 1 ]
|
||||
- [ 10, 11 ]
|
||||
enemies:
|
||||
- animation: jailer_1.yaml
|
||||
position: { x: 1, y: 13 }
|
||||
boundaries:
|
||||
position1: { x: 1, y: 1 }
|
||||
color: white
|
||||
- animation: jailer_2.yaml
|
||||
position: { x: 2, y: 23 }
|
||||
boundaries:
|
||||
position1: { x: 2, y: 2 }
|
||||
color: black
|
||||
items: [ ]
|
||||
358
yamal.cpp
358
yamal.cpp
@@ -1,358 +0,0 @@
|
||||
#include "yamal.hpp"
|
||||
|
||||
using namespace yamal_ns;
|
||||
|
||||
bool yamal::isScalar() const { return mode == SCALAR; }
|
||||
bool yamal::isVector() const { return mode == VECTOR; }
|
||||
bool yamal::isMap() const { return mode == MAP; }
|
||||
|
||||
void yamal::clearToScalar() { mode = SCALAR; vec_data.clear(); map_data.clear(); }
|
||||
void yamal::clearToVector() { mode = VECTOR; value.clear(); map_data.clear(); }
|
||||
void yamal::clearToMap() { mode = MAP; value.clear(); vec_data.clear(); }
|
||||
|
||||
yamal& yamal::operator=(const std::string& v) { clearToScalar(); value = v; return *this; }
|
||||
yamal& yamal::operator=(int v) { clearToScalar(); value = std::to_string(v); return *this; }
|
||||
yamal& yamal::operator=(float v) { clearToScalar(); value = std::to_string(v); return *this; }
|
||||
yamal& yamal::operator=(bool b) { clearToScalar(); value = b ? "true" : "false"; return *this; }
|
||||
|
||||
std::string yamal::asString() const { return value; }
|
||||
int yamal::asInt() const { return std::stoi(value); }
|
||||
float yamal::asFloat() const { return std::stof(value); }
|
||||
|
||||
bool yamal::asBool() const {
|
||||
std::string s = value;
|
||||
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
||||
if (s == "true") return true;
|
||||
if (s == "false") return false;
|
||||
try {
|
||||
size_t idx;
|
||||
float f = std::stof(s, &idx);
|
||||
return (idx != 0 && f != 0.0f);
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& yamal::getComment() const { return pre_comment; }
|
||||
yamal& yamal::setComment(const std::string& c) { pre_comment = c; return *this; }
|
||||
yamal& yamal::appendComment(const std::string& c) {
|
||||
if (!pre_comment.empty()) pre_comment += "\n";
|
||||
pre_comment += c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
yamal& yamal::setQuoted(bool q) { quoted = q; return *this; }
|
||||
yamal& yamal::setInline(bool in) { inline_map = in; return *this; }
|
||||
|
||||
void yamal::push_back(const yamal& item) { clearToVector(); vec_data.push_back(item); }
|
||||
yamal& yamal::operator[](size_t i) { clearToVector(); return vec_data[i]; }
|
||||
yamal& yamal::operator[](const std::string& key) { clearToMap(); return map_data[key]; }
|
||||
|
||||
std::vector<std::pair<std::string, yamal>> yamal::attributes() const {
|
||||
return map_data.items();
|
||||
}
|
||||
|
||||
bool yamal::isBoolLiteral() const {
|
||||
std::string s = value;
|
||||
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
||||
return s == "true" || s == "false";
|
||||
}
|
||||
|
||||
bool yamal::isNumericLiteral() const {
|
||||
if (value.empty()) return false;
|
||||
char* end = nullptr;
|
||||
std::strtod(value.c_str(), &end);
|
||||
return end != value.c_str() && *end == '\0';
|
||||
}
|
||||
|
||||
bool yamal::isSafeUnquotedString() const {
|
||||
if (value.empty()) return false;
|
||||
if (std::isdigit(value[0])) return false;
|
||||
for (char c : value) {
|
||||
if (!std::isalnum(c) && c != '_' && c != '-') return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Parsing helpers ---
|
||||
static std::vector<std::string> splitLines(const std::string& text) {
|
||||
std::vector<std::string> lines;
|
||||
std::istringstream stream(text);
|
||||
std::string line;
|
||||
while (std::getline(stream, line)) lines.push_back(line);
|
||||
return lines;
|
||||
}
|
||||
|
||||
static std::string trim(const std::string& s) {
|
||||
size_t start = s.find_first_not_of(" \t");
|
||||
size_t end = s.find_last_not_of(" \t");
|
||||
return (start == std::string::npos) ? "" : s.substr(start, end - start + 1);
|
||||
}
|
||||
|
||||
static std::string removeWhitespace(const std::string& s) {
|
||||
size_t start = s.find_first_not_of(" \t\n\r");
|
||||
size_t end = s.find_last_not_of(" \t\n\r");
|
||||
return (start == std::string::npos) ? "" : s.substr(start, end - start + 1);
|
||||
}
|
||||
|
||||
static int countIndent(const std::string& line) {
|
||||
int count = 0;
|
||||
for (char c : line) if (c == ' ') ++count; else break;
|
||||
return count;
|
||||
}
|
||||
|
||||
static std::string joinCommentLines(const std::vector<std::string>& lines) {
|
||||
std::ostringstream oss;
|
||||
for (const auto& line : lines) oss << line << "\n";
|
||||
return trim(oss.str());
|
||||
}
|
||||
|
||||
static yamal parseInlineSequence(const std::string& text) {
|
||||
yamal node;
|
||||
node.clearToVector();
|
||||
node.setInline(true);
|
||||
std::string inner = text.substr(1, text.size() - 2);
|
||||
std::istringstream ss(inner);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, ',')) {
|
||||
yamal child;
|
||||
child.deserialize(trim(item));
|
||||
node.push_back(child);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static yamal parseInlineMap(const std::string& text) {
|
||||
yamal node;
|
||||
node.clearToMap();
|
||||
node.setInline(true);
|
||||
std::string inner = text.substr(1, text.size() - 2);
|
||||
std::istringstream ss(inner);
|
||||
std::string pair;
|
||||
while (std::getline(ss, pair, ',')) {
|
||||
auto pos = pair.find(':');
|
||||
if (pos != std::string::npos) {
|
||||
std::string key = trim(pair.substr(0, pos));
|
||||
std::string val = trim(pair.substr(pos + 1));
|
||||
yamal& child = node[key];
|
||||
child.deserialize(val);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static yamal parseBlock(const std::vector<std::string>& lines, size_t& i, int indent) {
|
||||
yamal node;
|
||||
bool is_sequence = false;
|
||||
std::vector<std::string> pending_comment_lines;
|
||||
|
||||
while (i < lines.size()) {
|
||||
const std::string& line = lines[i];
|
||||
|
||||
std::string trimmed = trim(line);
|
||||
if (trimmed.empty()) {
|
||||
pending_comment_lines.push_back("");
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed[0] == '#') {
|
||||
pending_comment_lines.push_back(trimmed.substr(1));
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
int currentIndent = countIndent(line);
|
||||
if (currentIndent < indent) break;
|
||||
|
||||
std::string content = trimmed;
|
||||
std::string inline_comment;
|
||||
size_t hash_pos = content.find('#');
|
||||
if (hash_pos != std::string::npos && hash_pos > 0) {
|
||||
inline_comment = trim(content.substr(hash_pos + 1));
|
||||
content = trim(content.substr(0, hash_pos));
|
||||
}
|
||||
|
||||
if (content[0] == '-') {
|
||||
if (!is_sequence) {
|
||||
node.clearToVector();
|
||||
is_sequence = true;
|
||||
}
|
||||
|
||||
std::string item = trim(content.substr(1));
|
||||
yamal child;
|
||||
|
||||
if (!pending_comment_lines.empty()) {
|
||||
child.pre_comment = joinCommentLines(pending_comment_lines);
|
||||
pending_comment_lines.clear();
|
||||
}
|
||||
|
||||
if (!inline_comment.empty()) child.inline_comment = inline_comment;
|
||||
|
||||
++i;
|
||||
if (item.empty()) child = parseBlock(lines, i, indent + 2);
|
||||
else if (item[0] == '[') child = parseInlineSequence(item);
|
||||
else if (item[0] == '{') child = parseInlineMap(item);
|
||||
else child.deserialize(item);
|
||||
|
||||
node.push_back(child);
|
||||
}
|
||||
else if (auto pos = content.find(':'); pos != std::string::npos) {
|
||||
node.clearToMap();
|
||||
std::string key = trim(content.substr(0, pos));
|
||||
std::string val = trim(content.substr(pos + 1));
|
||||
yamal& child = node[key];
|
||||
|
||||
if (!pending_comment_lines.empty()) {
|
||||
child.pre_comment = joinCommentLines(pending_comment_lines);
|
||||
pending_comment_lines.clear();
|
||||
}
|
||||
|
||||
if (!inline_comment.empty()) child.inline_comment = inline_comment;
|
||||
|
||||
++i;
|
||||
if (val.empty()) child = parseBlock(lines, i, indent + 2);
|
||||
else if (val[0] == '[') child = parseInlineSequence(val);
|
||||
else if (val[0] == '{') child = parseInlineMap(val);
|
||||
else {
|
||||
child.clearToScalar();
|
||||
if (val.size() >= 2 && val.front() == '"' && val.back() == '"') {
|
||||
child.value = val.substr(1, val.size() - 2);
|
||||
child.quoted = true;
|
||||
} else {
|
||||
child.value = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void yamal::deserialize(const std::string& yamlText) {
|
||||
auto lines = splitLines(yamlText);
|
||||
clearToMap();
|
||||
size_t index = 0;
|
||||
yamal top = parseBlock(lines, index, 0);
|
||||
for (const auto& [key, val] : top.attributes()) {
|
||||
(*this)[key] = val;
|
||||
}
|
||||
}
|
||||
|
||||
std::string yamal::serialize(int indent) const {
|
||||
std::ostringstream out;
|
||||
std::string pad(indent, ' ');
|
||||
|
||||
std::string trimmed;// = removeWhitespace(pre_comment);
|
||||
/*if (!trimmed.empty()) {
|
||||
std::istringstream ss(pre_comment);
|
||||
std::string line;
|
||||
while (std::getline(ss, line)) {
|
||||
out << pad << "# " << line << "\n";
|
||||
}
|
||||
}*/
|
||||
|
||||
if (isScalar()) {
|
||||
if (isBoolLiteral()) {
|
||||
out << pad << value;
|
||||
} else if (quoted) {
|
||||
out << pad << "\"" << value << "\"";
|
||||
} else if (isNumericLiteral() || isSafeUnquotedString()) {
|
||||
out << pad << value;
|
||||
} else {
|
||||
out << pad << "\"" << value << "\"";
|
||||
}
|
||||
|
||||
trimmed = removeWhitespace(inline_comment);
|
||||
if (!trimmed.empty()) {
|
||||
out << " # " << inline_comment;
|
||||
}
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
if (isVector()) {
|
||||
if (inline_map) {
|
||||
out << pad << "[";
|
||||
for (size_t i = 0; i < vec_data.size(); ++i) {
|
||||
out << vec_data[i].serialize(0);
|
||||
if (i + 1 < vec_data.size()) out << ", ";
|
||||
}
|
||||
out << "]";
|
||||
trimmed = removeWhitespace(inline_comment);
|
||||
if (!trimmed.empty()) out << " # " << inline_comment;
|
||||
out << "\n";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
for (const auto& item : vec_data) {
|
||||
trimmed = removeWhitespace(item.pre_comment);
|
||||
if (!trimmed.empty()) {
|
||||
std::istringstream ss(item.pre_comment);
|
||||
std::string line;
|
||||
while (std::getline(ss, line)) {
|
||||
out << pad << "# " << line << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
out << pad << "-";
|
||||
if (item.isScalar()) {
|
||||
out << " " << item.serialize(0);
|
||||
trimmed = removeWhitespace(item.inline_comment);
|
||||
if (!trimmed.empty()) {
|
||||
out << " # " << item.inline_comment;
|
||||
}
|
||||
out << "\n";
|
||||
} else {
|
||||
out << "\n" << item.serialize(indent + 2);
|
||||
}
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
if (isMap()) {
|
||||
if (inline_map) {
|
||||
out << pad << "{";
|
||||
auto items = map_data.items();
|
||||
for (size_t i = 0; i < items.size(); ++i) {
|
||||
const auto& [key, val] = items[i];
|
||||
out << key << ": " << val.serialize(0);
|
||||
if (i + 1 < items.size()) out << ", ";
|
||||
}
|
||||
out << "}";
|
||||
trimmed = removeWhitespace(inline_comment);
|
||||
if (!trimmed.empty()) out << " # " << inline_comment;
|
||||
out << "\n";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
for (const auto& [key, val] : map_data.items()) {
|
||||
trimmed = removeWhitespace(val.pre_comment);
|
||||
if (!trimmed.empty()) {
|
||||
std::istringstream ss(val.pre_comment);
|
||||
std::string line;
|
||||
while (std::getline(ss, line)) {
|
||||
out << pad << "# " << line << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
out << pad << key << ":";
|
||||
if (val.isScalar()) {
|
||||
out << " " << val.serialize(0);
|
||||
trimmed = removeWhitespace(val.inline_comment);
|
||||
if (!trimmed.empty()) {
|
||||
out << " # " << val.inline_comment;
|
||||
}
|
||||
out << "\n";
|
||||
} else {
|
||||
out << "\n" << val.serialize(indent + 2);
|
||||
}
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
236
yamal.hpp
236
yamal.hpp
@@ -6,8 +6,6 @@
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
namespace yamal_ns {
|
||||
|
||||
template<typename Value>
|
||||
class ordered_map {
|
||||
std::unordered_map<std::string, Value> map;
|
||||
@@ -29,6 +27,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool is_last(const std::string& key) const {
|
||||
return !keys.empty() && keys.back() == key;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
map.clear();
|
||||
keys.clear();
|
||||
@@ -59,59 +61,215 @@ public:
|
||||
std::string inline_comment;
|
||||
bool quoted = false;
|
||||
bool inline_map = false;
|
||||
bool blank_line = false;
|
||||
|
||||
// Mode checks
|
||||
bool isScalar() const;
|
||||
bool isVector() const;
|
||||
bool isMap() const;
|
||||
bool isScalar() const { return mode == SCALAR; }
|
||||
bool isVector() const { return mode == VECTOR; }
|
||||
bool isMap() const { return mode == MAP; }
|
||||
|
||||
// Mode setters
|
||||
void clearToScalar();
|
||||
void clearToVector();
|
||||
void clearToMap();
|
||||
void clearToScalar() { mode = SCALAR; vec_data.clear(); map_data.clear(); }
|
||||
void clearToVector() { mode = VECTOR; value.clear(); map_data.clear(); }
|
||||
void clearToMap() { mode = MAP; value.clear(); vec_data.clear(); }
|
||||
|
||||
// Accessors
|
||||
operator std::string() const;
|
||||
operator int() const;
|
||||
operator float() const;
|
||||
operator bool() const;
|
||||
yamal& operator=(const char* v) { clearToScalar(); value = std::string(v); return *this; }
|
||||
yamal& operator=(const std::string& v) { clearToScalar(); value = v; return *this; }
|
||||
yamal& operator=(int v) { clearToScalar(); value = std::to_string(v); return *this; }
|
||||
yamal& operator=(float v) { clearToScalar(); value = std::to_string(v); return *this; }
|
||||
yamal& operator=(bool b) { clearToScalar(); value = b ? "true" : "false"; return *this; }
|
||||
|
||||
yamal& operator=(const std::string& v);
|
||||
yamal& operator=(int v);
|
||||
yamal& operator=(float v);
|
||||
yamal& operator=(bool b);
|
||||
std::string asString() const { return value; }
|
||||
int asInt() const { return std::stoi(value); }
|
||||
float asFloat() const { return std::stof(value); }
|
||||
|
||||
std::string asString() const;
|
||||
int asInt() const;
|
||||
float asFloat() const;
|
||||
bool asBool() const;
|
||||
bool asBool() const {
|
||||
std::string s = value;
|
||||
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
||||
if (s == "true") return true;
|
||||
if (s == "false") return false;
|
||||
try {
|
||||
size_t idx;
|
||||
float f = std::stof(s, &idx);
|
||||
return (idx != 0 && f != 0.0f);
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Comment accessors
|
||||
const std::string& getComment() const;
|
||||
yamal& setComment(const std::string& c);
|
||||
yamal& appendComment(const std::string& c);
|
||||
const std::string& getComment() const { return pre_comment; }
|
||||
yamal& setComment(const std::string& c) { pre_comment = c; blank_line = true; return *this; }
|
||||
yamal& appendComment(const std::string& c) {
|
||||
if (!pre_comment.empty()) pre_comment += "\n";
|
||||
pre_comment += c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Inline comment accessors
|
||||
const std::string& getInlineComment() const { return inline_comment; }
|
||||
yamal& setInlineComment(const std::string& c) { inline_comment = c; return *this; }
|
||||
|
||||
// Formatting
|
||||
yamal& setQuoted(bool q = true);
|
||||
yamal& setInline(bool in = true);
|
||||
yamal& setQuoted(bool q = true) { quoted = q; return *this; }
|
||||
yamal& setInline(bool in = true) { inline_map = in; return *this; }
|
||||
yamal& setBlankLine(bool b = true) { blank_line = b; return *this; }
|
||||
|
||||
// Vector and map access
|
||||
void push_back(const yamal& item);
|
||||
yamal& operator[](size_t i);
|
||||
yamal& operator[](const std::string& key);
|
||||
void push_back(const yamal& item) {
|
||||
clearToVector();
|
||||
vec_data.push_back(item);
|
||||
}
|
||||
yamal& operator[](size_t i) {
|
||||
clearToVector();
|
||||
if (vec_data.size() <= i) vec_data.resize(i+1);
|
||||
return vec_data[i];
|
||||
}
|
||||
yamal& operator[](const std::string& key) {
|
||||
clearToMap();
|
||||
return map_data[key];
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, yamal>> attributes() const;
|
||||
std::vector<std::pair<std::string, yamal>> attributes() const {
|
||||
return map_data.items();
|
||||
}
|
||||
|
||||
// Serialization
|
||||
std::string serialize(int indent = 0) const;
|
||||
|
||||
// Deserialization
|
||||
void deserialize(const std::string& yamlText);
|
||||
std::string serialize(int indent = 0, bool emit_self_comment = true) const {
|
||||
std::ostringstream out;
|
||||
|
||||
switch (mode) {
|
||||
|
||||
case SCALAR: {
|
||||
if (emit_self_comment && !pre_comment.empty()) {
|
||||
out << formatComment(pre_comment, indent);
|
||||
}
|
||||
std::string val = quoted ? "\"" + value + "\"" : value;
|
||||
out << std::string(indent, ' ') << val;
|
||||
if (!inline_comment.empty()) out << " # " << inline_comment;
|
||||
break;
|
||||
}
|
||||
|
||||
case MAP: {
|
||||
if (inline_map) {
|
||||
if (emit_self_comment && blank_line) { out << "\n"; }
|
||||
if (emit_self_comment && !pre_comment.empty()) {
|
||||
out << formatComment(pre_comment, indent);
|
||||
}
|
||||
out << std::string(indent, ' ') << "{ ";
|
||||
bool first = true;
|
||||
for (auto& kv : map_data.items()) {
|
||||
if (!first) out << ", ";
|
||||
out << kv.first << ": " << kv.second.serialize(0, false);
|
||||
first = false;
|
||||
}
|
||||
out << " }";
|
||||
if (!inline_comment.empty()) out << " # " << inline_comment;
|
||||
} else {
|
||||
if (emit_self_comment && blank_line) { out << "\n"; }
|
||||
// Only emit this node’s own comment at the start if requested
|
||||
if (emit_self_comment && !pre_comment.empty()) {
|
||||
out << formatComment(pre_comment, indent);
|
||||
}
|
||||
for (auto& kv : map_data.items()) {
|
||||
// Emit child’s pre-comment BEFORE the key line
|
||||
if (kv.second.blank_line) { out << "\n"; }
|
||||
if (!kv.second.pre_comment.empty()) {
|
||||
out << formatComment(kv.second.pre_comment, indent);
|
||||
}
|
||||
out << std::string(indent, ' ') << kv.first << ": ";
|
||||
if (kv.second.inline_map || kv.second.isScalar()) {
|
||||
out << kv.second.serialize(0, false);
|
||||
} else {
|
||||
out << "\n" << kv.second.serialize(indent + 2, false);
|
||||
}
|
||||
//if (!kv.second.inline_comment.empty()) {
|
||||
// out << " # " << kv.second.inline_comment;
|
||||
//}
|
||||
if (!map_data.is_last(kv.first)) out << "\n";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VECTOR: {
|
||||
if (inline_map) {
|
||||
if (emit_self_comment && blank_line) { out << "\n"; }
|
||||
if (emit_self_comment && !pre_comment.empty()) {
|
||||
out << formatComment(pre_comment, indent);
|
||||
}
|
||||
out << std::string(indent, ' ') << "[ ";
|
||||
for (size_t i = 0; i < vec_data.size(); ++i) {
|
||||
if (i > 0) out << ", ";
|
||||
out << vec_data[i].serialize(0, false);
|
||||
}
|
||||
out << " ]";
|
||||
if (!inline_comment.empty()) out << " # " << inline_comment;
|
||||
} else {
|
||||
if (emit_self_comment && blank_line) { out << "\n"; }
|
||||
if (emit_self_comment && !pre_comment.empty()) {
|
||||
out << formatComment(pre_comment, indent);
|
||||
}
|
||||
if (vec_data.empty()) {
|
||||
out << std::string(indent, ' ') << "[]";
|
||||
if (!inline_comment.empty()) out << " # " << inline_comment;
|
||||
} else {
|
||||
for (size_t i = 0; i < vec_data.size(); ++i) {
|
||||
const yamal& item = vec_data[i];
|
||||
if (emit_self_comment && item.blank_line) { out << "\n"; }
|
||||
// Emit item’s comment BEFORE the dash line
|
||||
if (!item.pre_comment.empty()) {
|
||||
out << formatComment(item.pre_comment, indent);
|
||||
}
|
||||
|
||||
if (i > 0) out << "\n";
|
||||
out << std::string(indent, ' ') << "- ";
|
||||
|
||||
if (item.isScalar() || item.inline_map) {
|
||||
out << item.serialize(0, false);
|
||||
} else if (item.isMap()) {
|
||||
auto attrs = item.attributes();
|
||||
if (!attrs.empty()) {
|
||||
out << attrs[0].first << ": " << attrs[0].second.serialize(0, false);
|
||||
for (size_t j = 1; j < attrs.size(); ++j) {
|
||||
out << "\n" << std::string(indent + 2, ' ')
|
||||
<< attrs[j].first << ": ";
|
||||
if (attrs[j].second.inline_map || attrs[j].second.isScalar()) {
|
||||
out << attrs[j].second.serialize(0, false);
|
||||
} else {
|
||||
out << "\n" << attrs[j].second.serialize(indent + 4, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out << "\n" << item.serialize(indent + 2, false);
|
||||
}
|
||||
}
|
||||
if (!inline_comment.empty()) out << " # " << inline_comment;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
private:
|
||||
bool isBoolLiteral() const;
|
||||
bool isNumericLiteral() const;
|
||||
bool isSafeUnquotedString() const;
|
||||
};
|
||||
static std::string formatComment(const std::string& c, int indent) {
|
||||
std::ostringstream out;
|
||||
std::istringstream in(c);
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
if (line.empty()) {
|
||||
// preserve blank line
|
||||
out << "\n";
|
||||
} else {
|
||||
out << std::string(indent, ' ') << "# " << line << "\n";
|
||||
}
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
} // namespace yamal_ns
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user