- No se, estic netejant i estos canvis no estaven comitats...
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
libs = -lSDL3
|
||||
cppflags = -g
|
||||
cppflags = -g -std=c++20
|
||||
executable = dilemmaker
|
||||
sourcepath = source source/japi
|
||||
buildpath = build
|
||||
|
||||
14726
source/fkYAML/node.hpp
14726
source/fkYAML/node.hpp
File diff suppressed because it is too large
Load Diff
@@ -6,9 +6,10 @@
|
||||
#include "treeview.h"
|
||||
#include "propertygrid.h"
|
||||
#include "tilemap.h"
|
||||
#include "fkYAML/node.hpp"
|
||||
#include "yamal.hpp"
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include "misc.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
@@ -17,32 +18,30 @@ bool loop();
|
||||
|
||||
std::map<std::string, std::string> rooms;
|
||||
|
||||
fkyaml::node room;
|
||||
yamal root;
|
||||
std::string current_room = "";
|
||||
|
||||
void loadRoom(std::string room_file)
|
||||
{
|
||||
int filesize;
|
||||
char *f = file::getFileBuffer(std::string("room/"+room_file+".yaml").c_str(), filesize, true);
|
||||
room = fkyaml::node::deserialize(std::string(f));
|
||||
root.deserialize(std::string(f));
|
||||
current_room = room_file;
|
||||
free(f);
|
||||
|
||||
uint16_t tiles[32*16];
|
||||
int i=0;
|
||||
for(auto row : room.at("tilemap").as_seq())
|
||||
for(auto row : root["tilemap"].vec_data)
|
||||
{
|
||||
for (auto t : row.as_seq())
|
||||
for (auto t : row.vec_data)
|
||||
{
|
||||
tiles[i] = t.get_value<int>();
|
||||
tiles[i] = t.asInt();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
tilemap::set(tiles);
|
||||
tilemap::setBackground(misc::getColorByName(room["room"]["bgColor"].get_value<std::string>()));
|
||||
tilemap::setBorder(misc::getColorByName(room["room"]["border"].get_value<std::string>()));
|
||||
//fkyaml::node name_node = room["room"]["name"];
|
||||
//printf("%s\n", name_node.get_value<std::string>().c_str());
|
||||
tilemap::setBackground(misc::getColorByName(root["room"]["bgColor"]));
|
||||
tilemap::setBorder(misc::getColorByName(root["room"]["border"]));
|
||||
}
|
||||
|
||||
void game::init()
|
||||
@@ -66,7 +65,8 @@ void game::init()
|
||||
|
||||
for (auto& entry : room_names) {
|
||||
loadRoom(entry);
|
||||
rooms[entry] = room["room"]["name"].get_value<std::string>();
|
||||
std::string peiv = root["room"]["name"];
|
||||
rooms[entry] = root["room"]["name"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,12 +104,12 @@ bool loop()
|
||||
if (current_room != r) {
|
||||
loadRoom(r);
|
||||
} else {
|
||||
auto enemies = room.at("enemies").as_seq();
|
||||
auto& enemies = root["enemies"].vec_data;
|
||||
if (!enemies.empty()) treeview::option("ENEMIES:", 1);
|
||||
for (auto enemy : enemies) {
|
||||
treeview::option(enemy["animation"].get_value<std::string>().c_str(), 2);
|
||||
for (auto& enemy : enemies) {
|
||||
treeview::option(enemy["animation"].value.c_str(), 2);
|
||||
}
|
||||
auto items = room.at("items").as_seq();
|
||||
auto& items = root["items"].vec_data;
|
||||
if (!items.empty()) treeview::option("ITEMS:", 1);
|
||||
char tmp[5];
|
||||
for (int i=0; i<items.size(); ++i) {
|
||||
@@ -122,42 +122,44 @@ bool loop()
|
||||
|
||||
tilemap::start();
|
||||
tilemap::draw();
|
||||
|
||||
|
||||
char tmp[256];
|
||||
propertygrid::start();
|
||||
if (treeview::getSelected(0) > -1) {
|
||||
if (treeview::getSelected(2) == -1) {
|
||||
propertygrid::sectionProperty("ROOM:");
|
||||
if (propertygrid::stringProperty("NAME", room["room"]["name"].get_value<std::string>())) room["room"]["name"] = propertygrid::getStringPropertyResult();
|
||||
propertygrid::stringProperty("BGCOLOR", room["room"]["bgColor"].get_value<std::string>());
|
||||
propertygrid::stringProperty("BORDER", room["room"]["border"].get_value<std::string>());
|
||||
propertygrid::stringProperty("TILESET", room["room"]["tileSetFile"].get_value<std::string>());
|
||||
propertygrid::stringProperty("ITEMCOL1", room["room"]["itemColor1"].get_value<std::string>());
|
||||
propertygrid::stringProperty("ITEMCOL2", room["room"]["itemColor2"].get_value<std::string>());
|
||||
propertygrid::stringProperty("CONVEYOR", room["room"]["conveyorBelt"].get_value<std::string>());
|
||||
if (propertygrid::stringProperty("NAME", root["room"]["name"])) root["room"]["name"] = propertygrid::getStringPropertyResult();
|
||||
propertygrid::stringProperty("BGCOLOR", root["room"]["bgColor"]);
|
||||
propertygrid::stringProperty("BORDER", root["room"]["border"]);
|
||||
propertygrid::stringProperty("TILESET", root["room"]["tileSetFile"]);
|
||||
propertygrid::stringProperty("ITEMCOL1", root["room"]["itemColor1"]);
|
||||
propertygrid::stringProperty("ITEMCOL2", root["room"]["itemColor2"]);
|
||||
propertygrid::stringProperty("CONVEYOR", root["room"]["conveyorBelt"]);
|
||||
propertygrid::sectionProperty("CONNECTIONS:");
|
||||
propertygrid::stringProperty("UP", room["room"]["connections"]["up"].is_null()?"null":room["room"]["connections"]["up"].get_value<std::string>().substr(0,2)+": "+rooms[room["room"]["connections"]["up"].get_value<std::string>().substr(0,2)]);
|
||||
propertygrid::stringProperty("DOWN", room["room"]["connections"]["down"].is_null()?"null":room["room"]["connections"]["down"].get_value<std::string>().substr(0,2)+": "+rooms[room["room"]["connections"]["down"].get_value<std::string>().substr(0,2)]);
|
||||
propertygrid::stringProperty("LEFT", room["room"]["connections"]["left"].is_null()?"null":room["room"]["connections"]["left"].get_value<std::string>().substr(0,2)+": "+rooms[room["room"]["connections"]["left"].get_value<std::string>().substr(0,2)]);
|
||||
propertygrid::stringProperty("RIGHT", room["room"]["connections"]["right"].is_null()?"null":room["room"]["connections"]["right"].get_value<std::string>().substr(0,2)+": "+rooms[room["room"]["connections"]["right"].get_value<std::string>().substr(0,2)]);
|
||||
propertygrid::stringProperty("UP", root["room"]["connections"]["up" ].value=="null"?"null":root["room"]["connections"]["up"].value.substr(0,2)+": "+rooms[root["room"]["connections"]["up"].value.substr(0,2)]);
|
||||
propertygrid::stringProperty("DOWN", root["room"]["connections"]["down" ].value=="null"?"null":root["room"]["connections"]["down"].value.substr(0,2)+": "+rooms[root["room"]["connections"]["down"].value.substr(0,2)]);
|
||||
propertygrid::stringProperty("LEFT", root["room"]["connections"]["left" ].value=="null"?"null":root["room"]["connections"]["left"].value.substr(0,2)+": "+rooms[root["room"]["connections"]["left"].value.substr(0,2)]);
|
||||
propertygrid::stringProperty("RIGHT", root["room"]["connections"]["right"].value=="null"?"null":root["room"]["connections"]["right"].value.substr(0,2)+": "+rooms[root["room"]["connections"]["right"].value.substr(0,2)]);
|
||||
} else {
|
||||
const int num_enemies = room.at("enemies").as_seq().size();
|
||||
const int num_enemies = root["enemies"].vec_data.size();
|
||||
if (treeview::getSelected(2) < num_enemies) {
|
||||
auto enemy = room.at("enemies").as_seq()[treeview::getSelected(2)];
|
||||
auto& enemy = root["enemies"][treeview::getSelected(2)];
|
||||
propertygrid::sectionProperty("ENEMY:");
|
||||
propertygrid::stringProperty("ANIMATION", enemy["animation"].get_value<std::string>());
|
||||
propertygrid::stringProperty("POSITION", std::to_string(enemy["position"]["x"].get_value<int>())+std::string(", ")+std::to_string(enemy["position"]["y"].get_value<int>()));
|
||||
propertygrid::stringProperty("VELOCITY", misc::floatToString(enemy["velocity"]["x"].get_value<float>())+std::string(", ")+misc::floatToString(enemy["velocity"]["y"].get_value<float>()));
|
||||
propertygrid::stringProperty("COLOR", enemy["color"].get_value<std::string>());
|
||||
propertygrid::stringProperty("ANIMATION", enemy["animation"]);
|
||||
propertygrid::stringProperty("POSITION", enemy["position"]["x"].value+", "+enemy["position"]["y"].value);
|
||||
propertygrid::stringProperty("VELOCITY", enemy["velocity"]["x"].value+", "+enemy["velocity"]["y"].value);
|
||||
propertygrid::stringProperty("COLOR", enemy["color"]);
|
||||
propertygrid::sectionProperty("BOUNDARIES:");
|
||||
propertygrid::stringProperty("START", std::to_string(enemy["boundaries"]["position1"]["x"].get_value<int>())+std::string(", ")+std::to_string(enemy["boundaries"]["position1"]["y"].get_value<int>()));
|
||||
propertygrid::stringProperty("END", std::to_string(enemy["boundaries"]["position2"]["x"].get_value<int>())+std::string(", ")+std::to_string(enemy["boundaries"]["position2"]["y"].get_value<int>()));
|
||||
propertygrid::stringProperty("START", enemy["boundaries"]["position1"]["x"].value+", "+enemy["boundaries"]["position1"]["y"].value);
|
||||
propertygrid::stringProperty("END", enemy["boundaries"]["position2"]["x"].value+", "+enemy["boundaries"]["position2"]["y"].value);
|
||||
} else {
|
||||
auto item = room.at("items").as_seq()[treeview::getSelected(2)-num_enemies];
|
||||
auto& item = root["items"][treeview::getSelected(2)-num_enemies];
|
||||
propertygrid::sectionProperty("ITEM:");
|
||||
propertygrid::stringProperty("TILESET", item["tileSetFile"].get_value<std::string>());
|
||||
propertygrid::stringProperty("TILE", std::to_string(item["tile"].get_value<int>()));
|
||||
propertygrid::stringProperty("POSITION", std::to_string(item["position"]["x"].get_value<int>())+std::string(", ")+std::to_string(item["position"]["y"].get_value<int>()));
|
||||
propertygrid::stringProperty("COUNTER", std::to_string(item["counter"].get_value<int>()));
|
||||
propertygrid::stringProperty("TILESET", item["tileSetFile"]);
|
||||
propertygrid::stringProperty("TILE", item["tile"]);
|
||||
propertygrid::stringProperty("POSITION", item["position"]["x"].value+", "+item["position"]["y"].value);
|
||||
propertygrid::stringProperty("COUNTER", item["counter"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
529
source/yamal.hpp
Normal file
529
source/yamal.hpp
Normal file
@@ -0,0 +1,529 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
|
||||
template<typename Value>
|
||||
class ordered_map {
|
||||
std::unordered_map<std::string, Value> map;
|
||||
std::vector<std::string> keys;
|
||||
|
||||
public:
|
||||
|
||||
Value& operator[](const std::string& key) {
|
||||
if (!map.contains(key)) keys.push_back(key);
|
||||
return map[key];
|
||||
}
|
||||
|
||||
bool contains(const std::string& key) const {
|
||||
return map.find(key) != map.end();
|
||||
}
|
||||
|
||||
void erase(const std::string& key) {
|
||||
if (map.erase(key)) {
|
||||
keys.erase(std::remove(keys.begin(), keys.end(), key), keys.end());
|
||||
}
|
||||
}
|
||||
|
||||
bool is_last(const std::string& key) const {
|
||||
return !keys.empty() && keys.back() == key;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
map.clear();
|
||||
keys.clear();
|
||||
}
|
||||
|
||||
size_t size() const { return keys.size(); }
|
||||
|
||||
std::vector<std::pair<std::string, Value>> items() const {
|
||||
std::vector<std::pair<std::string, Value>> result;
|
||||
for (const auto& k : keys) result.emplace_back(k, map.at(k));
|
||||
return result;
|
||||
}
|
||||
|
||||
const Value& at(const std::string& key) const { return map.at(key); }
|
||||
Value& at(const std::string& key) { return map.at(key); }
|
||||
};
|
||||
|
||||
class yamal {
|
||||
public:
|
||||
enum Mode { SCALAR, VECTOR, MAP };
|
||||
Mode mode = SCALAR;
|
||||
|
||||
std::string value;
|
||||
std::vector<yamal> vec_data;
|
||||
ordered_map<yamal> map_data;
|
||||
|
||||
std::string pre_comment;
|
||||
std::string inline_comment;
|
||||
bool quoted = false;
|
||||
bool inline_map = false;
|
||||
bool blank_line = false;
|
||||
|
||||
// Mode checks
|
||||
bool isScalar() const { return mode == SCALAR; }
|
||||
bool isVector() const { return mode == VECTOR; }
|
||||
bool isMap() const { return mode == MAP; }
|
||||
|
||||
// Mode setters
|
||||
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(); }
|
||||
|
||||
operator std::string() const { return asString(); }
|
||||
|
||||
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; }
|
||||
|
||||
std::string asString() const { return value; }
|
||||
int asInt() const { return std::stoi(value); }
|
||||
float asFloat() const { return std::stof(value); }
|
||||
|
||||
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 { return pre_comment; }
|
||||
yamal& setComment(const std::string& c) { pre_comment = c; /*blank_line = true;*/ return *this; }
|
||||
yamal& appendComment(const std::string& c) {
|
||||
if (c.empty()) {
|
||||
pre_comment += "\n";
|
||||
} else {
|
||||
std::string trimmed = pre_comment;
|
||||
while (trimmed[0]=='\n') trimmed = trimmed.substr(1);
|
||||
if (!trimmed.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) { 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) {
|
||||
clearToVector();
|
||||
vec_data.push_back(item);
|
||||
}
|
||||
yamal& emplace_back() {
|
||||
clearToVector();
|
||||
return vec_data.emplace_back();
|
||||
}
|
||||
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 {
|
||||
return map_data.items();
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void deserialize(std::string buffer) {
|
||||
tokenizer::init(buffer);
|
||||
deserialize(-1);
|
||||
}
|
||||
|
||||
inline static std::string current_comment = "";
|
||||
//inline static bool current_blank_line = false;
|
||||
|
||||
void deserialize(int indent) {
|
||||
if (tokenizer::error()) return;
|
||||
int current_indent = -2;
|
||||
tokenizer::getNextToken();
|
||||
while(tokenizer::type != tokenizer::types::ENDOFFILE) {
|
||||
switch (tokenizer::type) {
|
||||
case tokenizer::types::COMMENT:
|
||||
//if (!current_comment.empty()) current_comment += "\n";
|
||||
current_comment += tokenizer::string + "\n";
|
||||
tokenizer::getNextToken();
|
||||
// Ignore for now
|
||||
break;
|
||||
case tokenizer::types::BLANKLINE:
|
||||
tokenizer::getNextToken();
|
||||
if (tokenizer::type == tokenizer::types::BLANKLINE) {
|
||||
current_comment += "\n"; //current_blank_line = true;
|
||||
tokenizer::getNextToken();
|
||||
}
|
||||
break;
|
||||
case tokenizer::types::KEY: {
|
||||
if (tokenizer::indent <= indent)
|
||||
return;
|
||||
if (current_indent<0) current_indent = tokenizer::indent;
|
||||
if (tokenizer::indent != current_indent) { tokenizer::error("Wrong indent"); return; }
|
||||
yamal& key = (*this)[tokenizer::string];
|
||||
if (!current_comment.empty()) { key.setComment(current_comment); current_comment = ""; }
|
||||
//if (current_blank_line) { key.setBlankLine(true); current_blank_line = false; }
|
||||
key.deserialize(current_indent);
|
||||
break;
|
||||
}
|
||||
case tokenizer::types::STRINGSCALAR:
|
||||
this->setQuoted(true);
|
||||
case tokenizer::types::SCALAR:
|
||||
*(this) = tokenizer::string;
|
||||
tokenizer::getNextToken();
|
||||
return;
|
||||
case tokenizer::types::VECTOR: {
|
||||
if (tokenizer::indent <= indent) return;
|
||||
if (current_indent<0) current_indent = tokenizer::indent;
|
||||
if (tokenizer::indent != current_indent) { tokenizer::error("Wrong indent"); return; }
|
||||
yamal& vec = (*this).emplace_back();
|
||||
if (!current_comment.empty()) { vec.setComment(current_comment); current_comment = ""; }
|
||||
//if (current_blank_line) { vec.setBlankLine(true); current_blank_line = false; }
|
||||
vec.deserialize(current_indent);
|
||||
break;
|
||||
}
|
||||
case tokenizer::types::INLINEVEC: {
|
||||
(*this).setInline(true);
|
||||
(*this).clearToVector();
|
||||
tokenizer::getNextToken();
|
||||
if (tokenizer::type == tokenizer::types::INLINEVECOFF) return;
|
||||
while (tokenizer::type != tokenizer::types::ENDOFFILE) {
|
||||
if (tokenizer::type != tokenizer::types::SCALAR && tokenizer::type != tokenizer::types::STRINGSCALAR) { tokenizer::error("Scalar expected"); return; }
|
||||
(*this).emplace_back() = tokenizer::string;
|
||||
tokenizer::getNextToken();
|
||||
if (tokenizer::type == tokenizer::types::INLINEVECOFF) return;
|
||||
if (tokenizer::type != tokenizer::types::COMMA) { tokenizer::error("Comma expected"); return; }
|
||||
tokenizer::getNextToken();
|
||||
}
|
||||
tokenizer::error("Unexpected end of file"); return;
|
||||
break;
|
||||
}
|
||||
case tokenizer::types::INLINEKEY: {
|
||||
(*this).setInline(true);
|
||||
(*this).clearToMap();
|
||||
tokenizer::getNextToken();
|
||||
if (tokenizer::type == tokenizer::types::INLINEKEYOFF) return;
|
||||
while (tokenizer::type != tokenizer::types::ENDOFFILE) {
|
||||
if (tokenizer::type != tokenizer::types::KEY) { tokenizer::error("Key expected"); return; }
|
||||
std::string key = tokenizer::string;
|
||||
tokenizer::getNextToken();
|
||||
if (tokenizer::type != tokenizer::types::SCALAR && tokenizer::type != tokenizer::types::STRINGSCALAR) { tokenizer::error("Scalar expected"); return; }
|
||||
(*this)[key] = tokenizer::string;
|
||||
tokenizer::getNextToken();
|
||||
if (tokenizer::type == tokenizer::types::INLINEKEYOFF) return;
|
||||
if (tokenizer::type != tokenizer::types::COMMA) { tokenizer::error("Comma expected"); return; }
|
||||
tokenizer::getNextToken();
|
||||
}
|
||||
tokenizer::error("Unexpected end of file"); return;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
tokenizer::getNextToken();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
class tokenizer
|
||||
{
|
||||
public:
|
||||
enum class types { COMMENT, BLANKLINE, KEY, SCALAR, STRINGSCALAR, VECTOR, INLINEVEC, COMMA, INLINEVECOFF,
|
||||
INLINEKEY, INLINEKEYOFF, ENDOFFILE };
|
||||
inline static types type;
|
||||
inline static int indent;
|
||||
inline static std::string string;
|
||||
|
||||
inline static std::string buffer_string;
|
||||
inline static const char *buffer;
|
||||
inline static int line;
|
||||
inline static int col;
|
||||
inline static bool inlined;
|
||||
|
||||
inline static bool error_state;
|
||||
|
||||
static void init(std::string file) {
|
||||
buffer_string = file;
|
||||
buffer = buffer_string.c_str();
|
||||
col = line = 0;
|
||||
inlined = false;
|
||||
error_state = false;
|
||||
}
|
||||
static bool error() { return error_state; }
|
||||
static void error(std::string message) {
|
||||
error_state = true;
|
||||
printf("YAML ERROR: %s at line %i col %i\n", message.c_str(), line+1, col+1);
|
||||
}
|
||||
static char next() {
|
||||
if (*buffer==0) return *buffer;
|
||||
if (*buffer==13) buffer++;
|
||||
if (*buffer==10) { col=0; line++; } else { col++; }
|
||||
return *(buffer++);
|
||||
}
|
||||
static void ignoreWhiteSpace() { while (*buffer==32 || *buffer==9) next(); }
|
||||
static void getEverythingUntilEOL() {
|
||||
char tmp[256]; int i=0;
|
||||
next(); ignoreWhiteSpace();
|
||||
while (*buffer!=10 && *buffer!=13 && *buffer!=0) tmp[i++]=next();
|
||||
//if (*buffer==13) next(); next();
|
||||
tmp[i]=0; string = tmp;
|
||||
}
|
||||
static void getEverythingUntilQuote() {
|
||||
char tmp[256]; int i=0; next();
|
||||
while (*buffer!='"' && *buffer!=0) tmp[i++]=next();
|
||||
next(); tmp[i]=0; string = tmp;
|
||||
}
|
||||
static types getWord() {
|
||||
char tmp[256]; int i=0;
|
||||
const char *delimiters = inlined ? " \t\r\n[]{}," : " \t\r\n";
|
||||
while (!strchr(delimiters,*buffer)) tmp[i++]=next();
|
||||
if (tmp[i-1]==':') {
|
||||
//printf("KEY at line %i col %i\n", line, indent);
|
||||
tmp[i-1]=0; string=tmp; return types::KEY;
|
||||
}
|
||||
else {
|
||||
//printf("SCALAR at line %i col %i\n", line, indent);
|
||||
tmp[i]=0; string = tmp;; return types::SCALAR;
|
||||
}
|
||||
}
|
||||
static void getNextToken()
|
||||
{
|
||||
ignoreWhiteSpace();
|
||||
indent = col;
|
||||
switch (*buffer) {
|
||||
case 0: {
|
||||
//printf("ENDOFFILE at line %i col %i\n", line, indent);
|
||||
type = types::ENDOFFILE;
|
||||
break;
|
||||
}
|
||||
case '#': {
|
||||
//printf("COMMENT at line %i col %i\n", line, indent);
|
||||
getEverythingUntilEOL();
|
||||
type = types::COMMENT;
|
||||
break;
|
||||
}
|
||||
case '"': {
|
||||
//printf("STRING SCALAR at line %i col %i\n", line, indent);
|
||||
getEverythingUntilQuote();
|
||||
type = types::STRINGSCALAR;
|
||||
break;
|
||||
}
|
||||
case '\r':
|
||||
case '\n': {
|
||||
//printf("BLANKLINE at line %i col %i\n", line, indent);
|
||||
type = types::BLANKLINE;
|
||||
if (*buffer==13) next(); next();
|
||||
break;
|
||||
}
|
||||
case '-': {
|
||||
if (*(buffer+1)==' ') {
|
||||
//printf("VECTOR at line %i col %i\n", line, indent);
|
||||
type = types::VECTOR;
|
||||
next();
|
||||
} else {
|
||||
type = getWord();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '[': {
|
||||
//printf("INLINEVEC at line %i col %i\n", line, indent);
|
||||
type = types::INLINEVEC; inlined = true;
|
||||
next();
|
||||
break;
|
||||
}
|
||||
case ']': {
|
||||
//printf("INLINEVECOFF at line %i col %i\n", line, indent);
|
||||
type = types::INLINEVECOFF; inlined = false;
|
||||
next();
|
||||
break;
|
||||
}
|
||||
case '{': {
|
||||
//printf("INLINEKEY at line %i col %i\n", line, indent);
|
||||
type = types::INLINEKEY; inlined = true;
|
||||
next();
|
||||
break;
|
||||
}
|
||||
case '}': {
|
||||
//printf("INLINEKEYOFF at line %i col %i\n", line, indent);
|
||||
type = types::INLINEKEYOFF; inlined = false;
|
||||
next();
|
||||
break;
|
||||
}
|
||||
case ',': {
|
||||
//printf("COMMA at line %i col %i\n", line, indent);
|
||||
type = types::COMMA;
|
||||
next();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
type = getWord();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user