iu9-ca-web-chat/src/http_server/new_york_transit_line/rendering.cpp

99 lines
4.1 KiB
C++
Raw Normal View History

2024-08-10 20:56:07 +00:00
#include "core.h"
#include "alotalot.h"
#include <string.h>
#include <libjsonincpp/string_representation.h>
#include <assert.h>
namespace nytl {
std::string rendering_core(const std::string& entry_func, const std::vector<json::JSON>& entry_arguments,
std::map<std::string, Element>& elem_ns, const std::function<std::string(std::string)>& escape)
{
size_t cur_line_width = 0;
std::string result;
struct Frame {
const Element* el = NULL;
/* Use by base elements to distinguish them */
std::string base_name;
size_t part_to_do = 0;
std::vector<LocalVarValue> passed_args;
/* This parameter incapsulates `cur_line_width` at some point for multiline `put-parts` */
size_t multiline_put_start = 0;
};
std::vector<uptr<Frame>> stack;
auto make_frame = [&](const std::string& name, std::vector<LocalVarValue> passed_args){
const Element* el = &elem_ns[name];
Frame* us = new Frame{el, el->base ? name : "", 0, std::move(passed_args), cur_line_width};
stack.push_back(uptr<Frame>(us));
};
ASSERT(elem_ns.count(entry_func) == 1, "No such element " + entry_func);
const Element& el = elem_ns[entry_func];
ASSERT(el.arguments.size() == entry_arguments.size(), "Signature mismatch " + entry_func);
for (const json::JSON& sigtbj: el.arguments) {
ASSERT(sigtbj.type == json::true_symbol, "Signature mismatch. Entry element can take only JSON arguments");
}
{
size_t AN = entry_arguments.size();
std::vector<LocalVarValue> entry_arguments_conv(AN);
for (size_t i = 0; i < AN; i++)
entry_arguments_conv[i] = {"", &entry_arguments[i]};
make_frame(entry_func, entry_arguments_conv);
}
auto append2res = [&](const std::string& text) {
size_t n = result.size();
result.resize(n + text.size());
memcpy((void*)&result.c_str()[n], text.c_str(), text.size());
for (char ch: text) {
if (ch == '\n')
cur_line_width = 0;
else
cur_line_width++;
}
};
auto linefeed2res = [&]() {
result += "\n";
cur_line_width = 0;
};
while (!stack.empty()) {
Frame& cur = *stack.back();
if (cur.el->base) {
assert(cur.passed_args.size() == 1);
const json::JSON* X = cur.passed_args[0].JSON_subval;
assert(X);
if (cur.base_name == "jesc") {
append2res(escape(json::generate_str(*X, json::print_pretty)));
} else if (cur.base_name == "str2text") {
ASSERT(X->isString(), "str2text takes json string");
append2res(escape(X->asString()));
} else if (cur.base_name == "str2code") {
ASSERT(X->isString(), "str2code takes json string");
append2res(X->asString());
}
stack.pop_back();
continue;
}
if (cur.part_to_do == cur.el->parts.size()) {
stack.pop_back();
continue;
}
const ElementPart& cur_part = cur.el->parts[cur.part_to_do++];
if (cur_part.type == element_part_types::code) {
const ElementPart::when_code_S& pt = cur_part.when_code;
append2res(pt.lines);
} else if (cur_part.type == element_part_types::put) {
const ElementPart::when_put_S& pt = cur_part.when_put;
// todo
} else if (cur_part.type == element_part_types::for_put) {
const ElementPart::when_for_put_S& pt = cur_part.when_for_put;
// todo
} else if (cur_part.type == element_part_types::ref_put) {
const ElementPart::when_ref_put_S& pt = cur_part.when_ref_put;
// todo
}
}
return result;
}
}