99 lines
4.1 KiB
C++
99 lines
4.1 KiB
C++
|
#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;
|
||
|
}
|
||
|
}
|