diff --git a/assets/html/chat.html b/assets/HypertextPages/chat.html
similarity index 100%
rename from assets/html/chat.html
rename to assets/HypertextPages/chat.html
diff --git a/assets/html/list-rooms.html b/assets/HypertextPages/list-rooms.html
similarity index 100%
rename from assets/html/list-rooms.html
rename to assets/HypertextPages/list-rooms.html
diff --git a/assets/html/profile.html b/assets/HypertextPages/profile.html
similarity index 100%
rename from assets/html/profile.html
rename to assets/HypertextPages/profile.html
diff --git a/assets/html/registration.html b/assets/HypertextPages/registration.html
similarity index 100%
rename from assets/html/registration.html
rename to assets/HypertextPages/registration.html
diff --git a/src/http_server/new_york_transit_line/alotalot.h b/src/http_server/new_york_transit_line/alotalot.h
index 491bf7b..a78344a 100644
--- a/src/http_server/new_york_transit_line/alotalot.h
+++ b/src/http_server/new_york_transit_line/alotalot.h
@@ -11,6 +11,12 @@ namespace nytl {
template
using uptr = std::unique_ptr;
+
+ template
+ constexpr std::remove_reference_t&&
+ mv(Tp&& t) noexcept
+ { return static_cast&&>(t); }
+
class FUp : public std::exception{
std::string WHAT;
public:
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 2655962..440918d 100644
--- a/src/http_server/new_york_transit_line/execute_expression.cpp
+++ b/src/http_server/new_york_transit_line/execute_expression.cpp
@@ -58,8 +58,8 @@ namespace nytl {
} else
assert(false);
}
+ const std::vector& chain = expr["C"].g().asArray();
while (true) {
- const std::vector& chain = expr["C"].g().asArray();
if (chain_el >= chain.size())
return NULL;
const json::JSON& t = chain[chain_el++];
@@ -79,9 +79,9 @@ namespace nytl {
while (!stack.empty()) {
EEFrame& cur = *stack.back();
uptr todo = cur.toMe(returned, global_elems, local_vars);
- returned = (bool)todo;
+ returned = !(bool)todo;
if (todo)
- stack.push_back(todo);
+ stack.push_back(mv(todo));
else
stack.pop_back();
}
diff --git a/src/http_server/new_york_transit_line/parser.cpp b/src/http_server/new_york_transit_line/parser.cpp
index 303c9d8..2dee160 100644
--- a/src/http_server/new_york_transit_line/parser.cpp
+++ b/src/http_server/new_york_transit_line/parser.cpp
@@ -22,7 +22,7 @@ namespace nytl {
}
void parse_bare_file(const std::string& filename, const std::string& content,
- std::map& result)
+ global_elem_set_t& result)
{
ASSERT(result.count(filename) == 0, "Repeated element " + filename);
std::vector lines;
@@ -66,23 +66,19 @@ namespace nytl {
}
Element& el = result[filename];
el.parts = {ElementPart{element_part_types::code}};
- // std::string concatenated = "";
- // el.parts[0].when_code.lines = std::move(lines);
std::string lines_cat;
- // todo: concatenate lines
size_t n = lines.size();
for (size_t i = 0; i < n; i++) {
lines_cat += lines[i];
if (i + 1 < n)
lines_cat += '\n';
}
- json::JSON a;
- json::JSON b;
+ el.parts[0].when_code.lines = mv(lines_cat);
}
void parse_special_file(const std::string& filename, const std::string& content,
std::map& result)
{
- // todo
+ THROW("Don't know how to parse it yet");
}
}
diff --git a/src/http_server/new_york_transit_line/rendering.cpp b/src/http_server/new_york_transit_line/rendering.cpp
index 21b17f2..5d1ffe5 100644
--- a/src/http_server/new_york_transit_line/rendering.cpp
+++ b/src/http_server/new_york_transit_line/rendering.cpp
@@ -9,21 +9,39 @@ namespace nytl {
std::string result;
size_t cur_line_width = 0;
- void append(const std::string& text) {
+ void append(const std::string& text, size_t wsp_before_newlines, bool& newlined_somewhere) {
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')
+ size_t m = text.size();
+ result.reserve(n + m);
+ for (size_t i = 0; i < m; i++) {
+ if (text[i] == '\n') {
+ newlined_somewhere = true;
cur_line_width = 0;
- else
+ } else {
+ if (cur_line_width == 0 && newlined_somewhere) {
+ result.resize(result.size() + wsp_before_newlines, ' ');
+ cur_line_width = wsp_before_newlines;
+ }
cur_line_width++;
+ }
+ result += text[i];
}
}
};
#define RFrame_passed const global_elem_set_t& elem_ns, Ditch& result, const std::function& escape
struct RFrame {
+ size_t wsp_before_newlines = 0;
+ bool newlined_somewhere = false;
+
+ void append(const std::string& text, Ditch& ditch) {
+ ditch.append(text, wsp_before_newlines, newlined_somewhere);
+ }
+
+ explicit RFrame(size_t multiline_put_start)
+ : wsp_before_newlines(multiline_put_start) {
+ }
+
virtual uptr toMe(bool returned, RFrame_passed) {assert(false);}
virtual ~RFrame() = default;
@@ -33,85 +51,181 @@ namespace nytl {
std::string name;
std::vector passed_args;
/* This parameter incapsulates `cur_line_width` at some point for multiline `put-parts` */
- size_t multiline_put_start = 0;
/* main iterator of this frame. Persistent across control returns */
size_t part_to_do = 0;
- RFrame_OverParts(const std::string &name, const std::vector &passed_args,
+ RFrame_OverParts(const std::string &name, const std::vector& passed_args,
size_t multiline_put_start)
- : name(name),
- passed_args(passed_args),
- multiline_put_start(multiline_put_start) {
+ : RFrame(multiline_put_start), name(name),
+ passed_args(passed_args) {
}
- uptr toMe(bool returned, RFrame_passed) override {
- if (!returned)
- ASSERT(elem_ns.count(name) == 1, "No such element");
- const Element& el = elem_ns.at(name);
- if (!returned) {
- /* Continue to do checks */
- size_t n = el.arguments.size();
- ASSERT(n == passed_args.size(), "Argument count mismatch");
- for (size_t i = 0; i < n; i++) {
- if (el.arguments[i].type == json::true_symbol) {
- ASSERT(passed_args[i].is_json, "Expected json element argument, got element");
- } else {
- // If not json is expected, element must be expected
- assert(el.arguments[i].isArray());
- ASSERT(!passed_args[i].is_json, "Expected element element arguemnt, got json");
- ASSERT(elem_ns.count(passed_args[i].EL_name), "No such element, can't compare signatures of argument value");
- const Element& arg_element = elem_ns.at(passed_args[i].EL_name);
- // ASSERT(passed_args);
- if(el.arguments[i].asArray() != arg_element.arguments)
- THROW("Signature of argument " + std::to_string(i) + " does not match");
- }
- }
- }
- if (el.base) {
- assert(!returned);
- assert(passed_args.size() == 1);
- const json::JSON* X = passed_args[0].JSON_subval;
- assert(X);
- if (name == "jesc") {
- result.append(escape(json::generate_str(*X, json::print_pretty)));
- } else if (name == "str2text") {
- ASSERT(X->isString(), "str2text takes json string");
- result.append(escape(X->asString()));
- } else if (name == "str2code") {
- ASSERT(X->isString(), "str2code takes json string");
- result.append(X->asString());
- }
- return NULL;
- }
- while (true) {
- 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) {
- const ElementPart::when_code_S& pt = cur_part.when_code;
- result.append(pt.lines);
- } else if (cur_part.type == element_part_types::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");
- size_t AN = pt.passed_arguments.size();
- std::vector passed_arguments_expv(AN);
- for (size_t i = 0; i < AN; i++)
- passed_arguments_expv[i] = rendering_core_execute_expression(elem_ns, passed_args, pt.passed_arguments[i]);
- return uptr(new RFrame_OverParts(called_element_expv.EL_name, passed_arguments_expv, result.cur_line_width));
- } 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
- }
- }
+ uptr toMe(bool returned, RFrame_passed) override;
+ };
+
+ struct RFrame_OverJSON: public RFrame {
+ const ElementPart::when_for_put_S& part;
+ /* During the course of iteration execution, given arg list will expand and shrink back */
+ std::vector saved_args_plus_iter;
+
+ RFrame_OverJSON(const ElementPart::when_for_put_S &part, size_t multiline_put_start,
+ const std::vector &saved_args)
+ : RFrame(multiline_put_start), part(part),
+ saved_args_plus_iter(saved_args) {
+ if (part.where_key_var > -1)
+ this->saved_args_plus_iter.emplace_back();
+ if (part.where_value_var > -1)
+ this->saved_args_plus_iter.emplace_back();
}
};
+ struct RFrame_OverArray : public RFrame_OverJSON {
+ const std::vector& arr;
+ size_t it = 0;
+ /* Crutch. I can't pass simple integer as nytl local variable, I need persistent json wrapper */
+ json::JSON additional_json_wrapper;
+
+ RFrame_OverArray(const ElementPart::when_for_put_S& part, size_t multiline_put_start, const std::vector &saved_args,
+ const std::vector &arr): RFrame_OverJSON(part, multiline_put_start, saved_args),
+ arr(arr) {
+ if (part.where_key_var < 0)
+ additional_json_wrapper = json::JSON(json::Integer(0l));
+ }
+
+ uptr toMe(bool returned, const global_elem_set_t &elem_ns, Ditch &result,
+ const std::function &escape) override;
+ };
+
+ struct RFrame_OverDictionary: public RFrame_OverJSON {
+ const std::map& dict;
+ std::map::const_iterator it;
+ /* Crutch */
+ json::JSON addition_json_wrapper;
+
+ RFrame_OverDictionary(const ElementPart::when_for_put_S& part, size_t multiline_put_start, const std::vector &saved_args_plus_iter,
+ const std::map &dict): RFrame_OverJSON(part, multiline_put_start, saved_args_plus_iter),
+ dict(dict) {
+ it = dict.begin();
+ if (part.where_key_var < 0)
+ addition_json_wrapper = json::JSON("");
+ }
+
+ uptr toMe(bool returned, const global_elem_set_t &elem_ns, Ditch &result,
+ const std::function &escape) override;
+ };
+
+ uptr RFrame_OverParts::toMe(bool returned, const global_elem_set_t &elem_ns, Ditch &result,
+ const std::function &escape) {
+ if (!returned)
+ ASSERT(elem_ns.count(name) == 1, "No such element");
+ const Element& el = elem_ns.at(name);
+ if (!returned) {
+ /* Continue to do checks */
+ size_t n = el.arguments.size();
+ ASSERT(n == passed_args.size(), "Argument count mismatch");
+ for (size_t i = 0; i < n; i++) {
+ if (el.arguments[i].type == json::true_symbol) {
+ ASSERT(passed_args[i].is_json, "Expected json element argument, got element");
+ } else {
+ // If not json is expected, element must be expected
+ assert(el.arguments[i].isArray());
+ ASSERT(!passed_args[i].is_json, "Expected element element arguemnt, got json");
+ ASSERT(elem_ns.count(passed_args[i].EL_name), "No such element, can't compare signatures of argument value");
+ const Element& arg_element = elem_ns.at(passed_args[i].EL_name);
+ // ASSERT(passed_args);
+ if(el.arguments[i].asArray() != arg_element.arguments)
+ THROW("Signature of argument " + std::to_string(i) + " does not match");
+ }
+ }
+ }
+ if (el.base) {
+ assert(!returned);
+ assert(passed_args.size() == 1);
+ const json::JSON* X = passed_args[0].JSON_subval;
+ assert(X);
+ if (name == "jesc") {
+ append(escape(json::generate_str(*X, json::print_pretty)), result);
+ } else if (name == "str2text") {
+ ASSERT(X->isString(), "str2text takes json string");
+ append(escape(X->asString()), result);
+ } else if (name == "str2code") {
+ ASSERT(X->isString(), "str2code takes json string");
+ append(X->asString(), result);
+ }
+ return NULL;
+ }
+ while (true) {
+ 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) {
+ const ElementPart::when_code_S& pt = cur_part.when_code;
+ append(pt.lines, result);
+ } else if (cur_part.type == element_part_types::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");
+ size_t AN = pt.passed_arguments.size();
+ std::vector passed_arguments_expv(AN);
+ for (size_t i = 0; i < AN; i++)
+ 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) {
+ 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");
+ const json::JSON& container = *iting_over.JSON_subval;
+ if (container.isArray()) {
+ return std::make_unique(pt, result.cur_line_width, passed_args, container.asArray());
+ } else if (container.isDictionary()) {
+ 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) {
+ 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());
+ more_variables.back() = rendering_core_execute_expression(elem_ns, passed_args, pt.ref_over);
+ return std::make_unique(pt.internal_element, more_variables, result.cur_line_width);
+ }
+ }
+ }
+
+ uptr RFrame_OverArray::toMe(bool returned, RFrame_passed) {
+ if (returned && part.line_feed)
+ append("\n", result);
+ if (it >= arr.size())
+ return NULL;
+ if (part.where_key_var > -1) {
+ additional_json_wrapper.asInteger() = json::Integer((int64_t)it);
+ saved_args_plus_iter[part.where_key_var] = {true, "", &additional_json_wrapper};
+ }
+ if (part.where_value_var > -1) {
+ saved_args_plus_iter[part.where_value_var] = {true, "", &(arr[it])};
+ }
+ it++;
+ return std::make_unique(part.internal_element, saved_args_plus_iter, wsp_before_newlines);
+ }
+
+ uptr RFrame_OverDictionary::toMe(bool returned, RFrame_passed) {
+ if (returned && part.line_feed)
+ append("\n", result);
+ if (it == dict.end())
+ return NULL;
+ if (part.where_key_var > -1) {
+ addition_json_wrapper.asString() = it->first;
+ saved_args_plus_iter[part.where_key_var] = {true, "", &addition_json_wrapper};
+ }
+ if (part.where_value_var > -1) {
+ saved_args_plus_iter[part.where_value_var] = {true, "", &it->second};
+ }
+ ++it;
+ return std::make_unique(part.internal_element, saved_args_plus_iter, wsp_before_newlines);
+ }
+
std::string rendering_core(const std::string& entry_func, const std::vector& entry_arguments,
- const global_elem_set_t& elem_ns, const std::function& escape)
+ const global_elem_set_t& elem_ns, const std::function& escape)
{
Ditch result;
@@ -122,13 +236,18 @@ namespace nytl {
std::vector entry_arguments_conv(AN);
for (size_t i = 0; i < AN; i++)
entry_arguments_conv[i] = {true, "", &entry_arguments[i]};
- // stack.push_back(std::make_unique<>());
- // make_frame(entry_func, entry_arguments_conv);
+ stack.push_back(std::make_unique(entry_func, entry_arguments_conv, 0));
}
+ bool returned = false;
while (!stack.empty()) {
- // Frame& cur = *stack.back();
-
+ uptr ret = stack.back()->toMe(returned, elem_ns, result, escape);
+ returned = !(bool)ret;
+ if (ret)
+ stack.push_back(mv(ret));
+ else
+ stack.pop_back();
}
+ assert(returned);
return result.result;
}
}
diff --git a/src/http_server/new_york_transit_line/templater.cpp b/src/http_server/new_york_transit_line/templater.cpp
index 6e9e150..e129063 100644
--- a/src/http_server/new_york_transit_line/templater.cpp
+++ b/src/http_server/new_york_transit_line/templater.cpp
@@ -38,7 +38,7 @@ namespace nytl {
std::vector todo;
todo.emplace_back();
while (!todo.empty()) {
- std::string cur = std::move(todo.back());
+ std::string cur = mv(todo.back());
todo.pop_back();
std::string path_to_cur_dir = rules.root_dir_path + "/" + cur;
DIR* D = opendir(path_to_cur_dir.c_str());
@@ -61,7 +61,7 @@ namespace nytl {
ASSERT_on_iret(ret, "stat(" + path_to_cur_child + ")");
if (S_ISDIR(info.st_mode)) {
if (isUname(child_entry))
- todo.push_back(cur + "/" + child_entry);
+ todo.push_back(cur.empty() ? child_entry : cur + "/" + child_entry);
} else if (S_ISREG(info.st_mode)) {
auto replace_sep = [](const std::string& slashed) -> std::string {
std::string dotted;
@@ -76,7 +76,7 @@ namespace nytl {
};
auto np_reg_categ_result = [&](const std::string& no_postfix, bool applied) {
if (isUname(no_postfix))
- result.push_back({path_to_cur_child, replace_sep(cur + "/" + no_postfix), applied});
+ result.push_back({path_to_cur_child, replace_sep(cur.empty() ? no_postfix : cur + "/" + no_postfix), applied});
};
if (endsIn(child_entry, rules.postfix_rule_for_element_cont)) {
np_reg_categ_result(throwout_postfix(child_entry, rules.postfix_rule_for_element_cont.size()), true);
diff --git a/src/http_server/new_york_transit_line/templater.h b/src/http_server/new_york_transit_line/templater.h
index fafd945..0e247f2 100644
--- a/src/http_server/new_york_transit_line/templater.h
+++ b/src/http_server/new_york_transit_line/templater.h
@@ -34,14 +34,14 @@ namespace nytl {
} when_put;
struct when_for_put_S {
expression_t ref_over;
- bool have_av_key = false;
- bool have_av_value = false;
- expression_t internal_element;
+ ssize_t where_key_var = -1;
+ ssize_t where_value_var = -1;
+ std::string internal_element;
bool line_feed = true;
} when_for_put;
struct when_ref_put_S {
expression_t ref_over;
- expression_t internal_element;
+ std::string internal_element;
} when_ref_put;
};
diff --git a/src/http_server/nytl_tests/test0.cpp b/src/http_server/nytl_tests/test0.cpp
new file mode 100644
index 0000000..5336d0b
--- /dev/null
+++ b/src/http_server/nytl_tests/test0.cpp
@@ -0,0 +1,17 @@
+#include
+
+/* Yep, tests for nytl depend on assets for website. Yep, I see no problem with that */
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: test assets_dir");
+ exit(1);
+ }
+
+ std::string dir_path = argv[1];
+ nytl::Templater templater(nytl::TemplaterSettings{nytl::TemplaterDetourRules{dir_path}});
+ templater.update();
+ std::string answer = templater.render("chat", {});
+ printf("%s\n<>\n", answer.c_str());
+ return 0;
+}
\ No newline at end of file
diff --git a/src/web_chat/main.cpp b/src/web_chat/main.cpp
index dd07275..745b5d7 100644
--- a/src/web_chat/main.cpp
+++ b/src/web_chat/main.cpp
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
bool termination = false;
@@ -54,7 +55,7 @@ int main(int argc, char** argv){
een9::StaticAssetManagerSlaveModule samI;
samI.update({
- een9::StaticAssetManagerRule{assets_dir + "/html", "/assets/html", {{".html", "text/html"}} },
+ een9::StaticAssetManagerRule{assets_dir + "/HypertextPages", "/assets/html", {{".html", "text/html"}} },
een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} },
een9::StaticAssetManagerRule{assets_dir + "/js", "/assets/js", {{".js", "text/js"}} },
een9::StaticAssetManagerRule{assets_dir + "/img", "/assets/img", {