From e03794410b4a8cdcfe055604c5604f523917c5e2 Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Wed, 14 Aug 2024 13:59:54 +0300 Subject: [PATCH] FIXED SOME TABULATION BUGS, DO NOT LOOK AT MY PREVIOUS SYSTEM --- assets/HypertextPages/test.nytl.html | 3 - .../new_york_transit_line/alotalot.cpp | 5 ++ .../new_york_transit_line/alotalot.h | 8 +- src/http_server/new_york_transit_line/core.h | 4 + .../new_york_transit_line/debug_print.cpp | 49 ++++++++++++ .../execute_expression.cpp | 1 + .../new_york_transit_line/parser.cpp | 76 ++++++++++--------- .../new_york_transit_line/rendering.cpp | 13 ++-- .../new_york_transit_line/templater.h | 20 ++--- .../nytl_tests/HypertextPages/test.nytl.html | 8 ++ src/http_server/nytl_tests/test0.cpp | 11 ++- 11 files changed, 132 insertions(+), 66 deletions(-) delete mode 100644 assets/HypertextPages/test.nytl.html create mode 100644 src/http_server/new_york_transit_line/debug_print.cpp create mode 100644 src/http_server/nytl_tests/HypertextPages/test.nytl.html diff --git a/assets/HypertextPages/test.nytl.html b/assets/HypertextPages/test.nytl.html deleted file mode 100644 index ff78735..0000000 --- a/assets/HypertextPages/test.nytl.html +++ /dev/null @@ -1,3 +0,0 @@ -{% ELDEF main %} -AAAAAAAA -{% ENDELDEF %} \ No newline at end of file diff --git a/src/http_server/new_york_transit_line/alotalot.cpp b/src/http_server/new_york_transit_line/alotalot.cpp index c1b12dd..c27206b 100644 --- a/src/http_server/new_york_transit_line/alotalot.cpp +++ b/src/http_server/new_york_transit_line/alotalot.cpp @@ -87,4 +87,9 @@ namespace nytl { } return result; } + + void rstrip(std::string &str) { + while (!str.empty() && isSPACE(str.back())) + str.resize(str.size() - 1); + } } diff --git a/src/http_server/new_york_transit_line/alotalot.h b/src/http_server/new_york_transit_line/alotalot.h index 07a898f..8e8217c 100644 --- a/src/http_server/new_york_transit_line/alotalot.h +++ b/src/http_server/new_york_transit_line/alotalot.h @@ -1,12 +1,12 @@ #ifndef NEW_YORK_TRANSIT_LINE_ALOTALOT_H #define NEW_YORK_TRANSIT_LINE_ALOTALOT_H -/* A little of this, a little of that - * DO NOT EXPORT THIS FILE */ - #include #include +/* A little of this, a little of that + * DO NOT EXPORT THIS FILE */ + namespace nytl { template using uptr = std::unique_ptr; @@ -46,6 +46,8 @@ namespace nytl { bool is_uname_dotted_sequence(const std::string& uinp); std::string make_uppercase(const std::string& source); + + void rstrip(std::string& str); } #endif diff --git a/src/http_server/new_york_transit_line/core.h b/src/http_server/new_york_transit_line/core.h index 49b4273..e03b649 100644 --- a/src/http_server/new_york_transit_line/core.h +++ b/src/http_server/new_york_transit_line/core.h @@ -4,7 +4,11 @@ #include "templater.h" #include +/* Do not export this header */ + namespace nytl { + void debug_print_templater(const Templater& T); + /* ============== For parsing =============================*/ void parse_bare_file(const std::string& filename, const std::string& content, global_elem_set_t& result); diff --git a/src/http_server/new_york_transit_line/debug_print.cpp b/src/http_server/new_york_transit_line/debug_print.cpp new file mode 100644 index 0000000..063f17d --- /dev/null +++ b/src/http_server/new_york_transit_line/debug_print.cpp @@ -0,0 +1,49 @@ +#include "templater.h" +#include "alotalot.h" +#include "jsonincpp/string_representation.h" +#include + +namespace nytl { + void debug_print_templater(const Templater& T) { + printf("===== TEMPLATER INTERNAL RESOURCES =====\n"); + for (auto& p: T.elements) { + printf("=== %s element =====\n", p.first.c_str()); + const Element& el = p.second; + printf("%s, %s\n", el.base ? "BASE" : "NOT BASE", el.is_hidden ? "HIDDEN" : "NOT HIDDEN"); + if (!el.is_hidden) { + std::string signature; + for (const json::JSON& arg_type: el.arguments) { + if (!signature.empty()) + signature += " "; + signature += json::generate_str(arg_type, json::print_compact); + } + printf("Signature: %s\n", signature.c_str()); + } + for (const ElementPart& part: el.parts) { + if (part.type == ElementPart::p_code) { + printf("code: <>\n%s\n<>\n", part.when_code.lines.c_str()); + } else if (part.type == ElementPart::p_for_put) { + const ElementPart::when_for_put_S& P = part.when_for_put; + printf("dor cycle call:\ninternal_element: %s,\nref_over:%s,\nwhere_key_var: %ld, where_value_var: %ld, %s\n", + P.internal_element.c_str(), json::generate_str(P.ref_over, json::print_pretty).c_str(), + P.where_key_var, P.where_value_var, P.line_feed ? "LF" : "NOLF"); + } else if (part.type == ElementPart::p_ref_put) { + const ElementPart::when_ref_put_S& P = part.when_ref_put; + printf("ref block call:\ninternal_element: %s\nref_over:%s\n", + P.internal_element.c_str(), json::generate_str(P.ref_over, json::print_pretty).c_str()); + } else { + assert(part.type == ElementPart::p_put); + const ElementPart::when_put_S& P = part.when_put; + printf("PUT:\ncalled_element: %s\n", + json::generate_str(P.called_element, json::print_pretty).c_str()); + for (size_t i = 0; i < P.passed_arguments.size(); i++) { + printf("passed_arguments[%lu] = %s\n", i, + json::generate_str(P.passed_arguments[i], json::print_pretty).c_str()); + } + } + } + printf("=== That was element %s ====\n", p.first.c_str()); + } + printf("===== DEBUG IS OVER =====\n"); + } +} \ No newline at end of file diff --git a/src/http_server/new_york_transit_line/execute_expression.cpp b/src/http_server/new_york_transit_line/execute_expression.cpp index 440918d..1d7a371 100644 --- a/src/http_server/new_york_transit_line/execute_expression.cpp +++ b/src/http_server/new_york_transit_line/execute_expression.cpp @@ -3,6 +3,7 @@ #include namespace nytl { + /* Expression Execution Frame */ struct EEFrame { const json::JSON& expr; LocalVarValue& result; diff --git a/src/http_server/new_york_transit_line/parser.cpp b/src/http_server/new_york_transit_line/parser.cpp index dbc69da..da8b884 100644 --- a/src/http_server/new_york_transit_line/parser.cpp +++ b/src/http_server/new_york_transit_line/parser.cpp @@ -16,11 +16,6 @@ namespace nytl { return first_nw_char(str) == str.size(); } - void rstrip(std::string& str) { - while (!str.empty() && isSPACE(str.back())) - str.resize(str.size() - 1); - } - std::string clement_lstrip(const std::string& str) { size_t gone = 0; size_t n = str.size(); @@ -28,10 +23,10 @@ namespace nytl { if (str[i] == '\n') { gone = i + 1; } else if (!isSPACE(str[i])) { - return str.substr(gone); + break; } } - return ""; + return str.substr(gone); } struct ParsingContext { @@ -125,22 +120,29 @@ namespace nytl { return result; } - void one_part_update_min_start_wsp_non_empty(const std::string& str, bool is_first, size_t& min) { + bool is_relevant_in_tab_cut(size_t PN, size_t I, size_t LN, size_t j, const std::string& line) { + if (j == 0 && I != 0) + return false; + if (!is_space_only(line)) + return true; + return j + 1 == LN && I + 1 < PN; + } + + void one_part_update_min_start_wsp_non_empty(const std::string& str, size_t I, size_t PN, size_t& min) { std::vector lines = splitIntoLines(str); - size_t L = lines.size(); - for (size_t i = is_first ? 0 : 1; i < L; i++) { - size_t first_nw = first_nw_char(lines[i]); - if (first_nw < lines[i].size()) - min = std::min(min, first_nw); + size_t LN = lines.size(); + for (size_t j = 0; j < LN; j++) { + if (is_relevant_in_tab_cut(PN, I, LN, j, lines[j])) + min = std::min(min, first_nw_char(lines[j])); } } - std::string one_part_cut_excess_tab(const std::string& str, bool is_first, size_t cut) { + std::string one_part_cut_excess_tab(const std::string& str, size_t I, size_t PN, size_t cut) { std::vector lines = splitIntoLines(str); - size_t L = lines.size(); - for (size_t i = is_first ? 0 : 1; i < L; i++) { - if (!is_space_only(lines[i])) - lines[i] = lines[i].substr(cut); + size_t LN = lines.size(); + for (size_t j = 0; j < LN; j++) { + if (is_relevant_in_tab_cut(PN, I, LN, j, lines[j])) + lines[j] = lines[j].substr(cut); } return concatenateLines(lines); } @@ -149,17 +151,17 @@ namespace nytl { global_elem_set_t& result) { ASSERT(result.count(filename) == 0, "Repeated element " + filename); - std::string P = clement_lstrip(content); - rstrip(P); + std::string txt = clement_lstrip(content); + rstrip(txt); size_t cut = 9999999999999; - one_part_update_min_start_wsp_non_empty(P, true, cut); - P = one_part_cut_excess_tab(P, true, cut); + one_part_update_min_start_wsp_non_empty(txt, 0, 1, cut); + txt = one_part_cut_excess_tab(txt, 0, 1, cut); Element& el = result[filename]; - el.parts = {ElementPart{element_part_types::code}}; - el.parts[0].when_code.lines = mv(P); + el.parts = {ElementPart{}}; + el.parts[0].when_code.lines = mv(txt); } - /* This function parses variable type */ + /* Type parsing frame */ struct TPFrame { json::JSON& result; @@ -206,6 +208,7 @@ namespace nytl { /* From arg name to arg ID */ typedef std::map arg_name_list_t; + /* Expression parsing frame */ struct EPFrame { json::JSON& result; @@ -295,6 +298,7 @@ namespace nytl { return peep(ctx) == syntax.magic_block_end[0]; } + /* Element content parsing frame */ struct ECPFrame { enum block_type{ gone_for_nothing, @@ -322,7 +326,7 @@ namespace nytl { uptr toMe(bool returned, ParsingContext& ctx, const TemplaterSettings& syntax, global_elem_set_t& elem_ns) { if (returned) { if (stopped_for == gone_for_for) { - assert(result.parts.back().type == element_part_type_t::for_put); + assert(result.parts.back().type == ElementPart::p_for_put); if (ret_data_int == 1) result.parts.back().when_for_put.line_feed = false; else if (ret_data_int == 2) @@ -344,7 +348,7 @@ namespace nytl { std::string op = make_uppercase(readName(ctx)); if (op == "FOR") { result.parts.emplace_back(); - result.parts.back().type = element_part_type_t::for_put; + result.parts.back().type = ElementPart::p_for_put; ElementPart::when_for_put_S& P = result.parts.back().when_for_put; skipWhitespace(ctx); std::string V1 = readName(ctx); @@ -387,7 +391,7 @@ namespace nytl { } if (op == "REF") { result.parts.emplace_back(); - result.parts.back().type = element_part_type_t::ref_put; + result.parts.back().type = ElementPart::p_ref_put; ElementPart::when_ref_put_S& P = result.parts.back().when_ref_put; skipWhitespace(ctx); std::string Vn = readName(ctx); @@ -411,7 +415,7 @@ namespace nytl { } if (op == "PUT") { result.parts.emplace_back(); - result.parts.back().type = element_part_type_t::put; + result.parts.back().type = ElementPart::p_put; ElementPart::when_put_S& P = result.parts.back().when_put; skipWhitespace(ctx); P.called_element = parse_expression(ctx, local_var_names); @@ -427,7 +431,7 @@ namespace nytl { } auto mediocre_operator = [&](const std::string& base_el) -> void { result.parts.emplace_back(); - result.parts.back().type = element_part_type_t::put; + result.parts.back().type = ElementPart::p_put; ElementPart::when_put_S& P = result.parts.back().when_put; P.called_element["V"] = json::JSON(base_el); P.called_element["C"] = json::JSON(json::array); @@ -446,20 +450,20 @@ namespace nytl { ASSERT(myself == gone_for_nothing, "Unexpected end of element"); skip_magic_block_end(ctx, syntax); if (!result.parts.empty()) { - if (result.parts[0].type == element_part_type_t::code) + if (result.parts[0].type == ElementPart::p_code) result.parts[0].when_code.lines = clement_lstrip(result.parts[0].when_code.lines); - if (result.parts.back().type == element_part_type_t::code) + if (result.parts.back().type == ElementPart::p_code) rstrip(result.parts.back().when_code.lines); size_t cut = 999999999999; size_t N = result.parts.size(); for (size_t i = 0; i < N; i++) { - if (result.parts[i].type == element_part_type_t::code) { - one_part_update_min_start_wsp_non_empty(result.parts[i].when_code.lines, i == 0, cut); + if (result.parts[i].type == ElementPart::p_code) { + one_part_update_min_start_wsp_non_empty(result.parts[i].when_code.lines, i, N, cut); } } for (size_t i = 0; i < N; i++) { - if (result.parts[i].type == element_part_type_t::code) { - result.parts[i].when_code.lines = one_part_cut_excess_tab(result.parts[i].when_code.lines, i == 0, cut); + if (result.parts[i].type == ElementPart::p_code) { + result.parts[i].when_code.lines = one_part_cut_excess_tab(result.parts[i].when_code.lines, i, N, cut); } } } diff --git a/src/http_server/new_york_transit_line/rendering.cpp b/src/http_server/new_york_transit_line/rendering.cpp index f9ab229..1aa3f26 100644 --- a/src/http_server/new_york_transit_line/rendering.cpp +++ b/src/http_server/new_york_transit_line/rendering.cpp @@ -114,6 +114,7 @@ namespace nytl { const std::function &escape) override; }; + /* Rendering Frame */ uptr RFrame_OverParts::toMe(bool returned, const global_elem_set_t &elem_ns, Ditch &result, const std::function &escape) { if (!returned) @@ -147,7 +148,9 @@ namespace nytl { const json::JSON* X = passed_args[0].JSON_subval; assert(X); if (name == "jesc") { - append(escape(json::generate_str(*X, json::print_pretty)), result); + std::string escaped_json = escape(json::generate_str(*X, json::print_pretty)); + rstrip(escaped_json); + append(escaped_json, result); } else if (name == "str2text") { ASSERT(X->isString(), "str2text takes json string"); append(escape(X->asString()), result); @@ -161,10 +164,10 @@ namespace nytl { if (part_to_do == el.parts.size()) return NULL; const ElementPart& cur_part = el.parts[part_to_do++]; - if (cur_part.type == element_part_types::code) { + if (cur_part.type == ElementPart::p_code) { const ElementPart::when_code_S& pt = cur_part.when_code; append(pt.lines, result); - } else if (cur_part.type == element_part_types::put) { + } else if (cur_part.type == ElementPart::p_put) { const ElementPart::when_put_S& pt = cur_part.when_put; LocalVarValue called_element_expv = rendering_core_execute_expression(elem_ns, passed_args, pt.called_element); ASSERT(!called_element_expv.is_json, "Can't PUT json variable"); @@ -174,7 +177,7 @@ namespace nytl { passed_arguments_expv[i] = rendering_core_execute_expression(elem_ns, passed_args, pt.passed_arguments[i]); return std::make_unique(called_element_expv.EL_name, passed_arguments_expv, result.cur_line_width); - } else if (cur_part.type == element_part_types::for_put) { + } else if (cur_part.type == ElementPart::p_for_put) { const ElementPart::when_for_put_S& pt = cur_part.when_for_put; LocalVarValue iting_over = rendering_core_execute_expression(elem_ns, passed_args, pt.ref_over); ASSERT(iting_over.is_json, "Can't iterate over element"); @@ -185,7 +188,7 @@ namespace nytl { return std::make_unique(pt, result.cur_line_width, passed_args, container.asDictionary()); } else THROW("Can't iterate over non-natalistic jsobject"); - } else if (cur_part.type == element_part_types::ref_put) { + } else if (cur_part.type == ElementPart::p_ref_put) { const ElementPart::when_ref_put_S& pt = cur_part.when_ref_put; std::vector more_variables(passed_args.size() + 1); std::copy(passed_args.begin(), passed_args.end(), more_variables.begin()); diff --git a/src/http_server/new_york_transit_line/templater.h b/src/http_server/new_york_transit_line/templater.h index ae3451f..d1018d9 100644 --- a/src/http_server/new_york_transit_line/templater.h +++ b/src/http_server/new_york_transit_line/templater.h @@ -10,21 +10,15 @@ namespace nytl { typedef json::JSON expression_t; - namespace element_part_types { - enum element_part_type_E { - code, - /* write statements really mean PUT str2text X */ - put, - for_put, - ref_put - }; - } - - typedef element_part_types::element_part_type_E element_part_type_t; - struct ElementPart { /* Used with all types */ - element_part_type_t type = element_part_types::code; + enum element_part_type_E { + p_code, + /* write statements really mean PUT str2text X */ + p_put, + p_for_put, + p_ref_put + } type = p_code; struct when_code_S { std::string lines; } when_code; diff --git a/src/http_server/nytl_tests/HypertextPages/test.nytl.html b/src/http_server/nytl_tests/HypertextPages/test.nytl.html new file mode 100644 index 0000000..90c1f6f --- /dev/null +++ b/src/http_server/nytl_tests/HypertextPages/test.nytl.html @@ -0,0 +1,8 @@ +{% ELDEF main JSON abc %} + {% PUT jesc abc %} + + AAAAAAAA + BBB + {% PUT jesc abc %} + +{% ENDELDEF %} \ No newline at end of file diff --git a/src/http_server/nytl_tests/test0.cpp b/src/http_server/nytl_tests/test0.cpp index 9d930f8..6d9732d 100644 --- a/src/http_server/nytl_tests/test0.cpp +++ b/src/http_server/nytl_tests/test0.cpp @@ -1,6 +1,5 @@ #include - -/* Yep, tests for nytl depend on assets for website. Yep, I see no problem with that */ +#include int main(int argc, char** argv) { if (argc < 2) { @@ -11,10 +10,10 @@ int main(int argc, char** argv) { std::string dir_path = argv[1]; nytl::Templater templater(nytl::TemplaterSettings{nytl::TemplaterDetourRules{dir_path}}); templater.update(); - std::string answer = templater.render("list-rooms", {}); - printf("%s\n<>\n", answer.c_str()); - std::string answer2 = templater.render("test", {}); - printf("%s\n<>\n", answer.c_str()); + nytl::debug_print_templater(templater); + + std::string answer2 = templater.render("test", {json::JSON()}); + printf("%s\n<>\n", answer2.c_str()); return 0; } \ No newline at end of file