#include "core.h" #include "alotalot.h" #include #include #include namespace nytl { std::string rendering_core(const std::string& entry_func, const std::vector& entry_arguments, std::map& elem_ns, const std::function& 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 passed_args; /* This parameter incapsulates `cur_line_width` at some point for multiline `put-parts` */ size_t multiline_put_start = 0; }; std::vector> stack; auto make_frame = [&](const std::string& name, std::vector 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(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 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; } }