Compare commits
2 Commits
2e0dbf8bfe
...
1f9d16f430
Author | SHA1 | Date | |
---|---|---|---|
1f9d16f430 | |||
177a64bdb8 |
@ -1,25 +1,25 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ru">
|
<html lang="ru">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Веб-Чат</title>
|
<title>Веб-Чат</title>
|
||||||
<link rel="stylesheet" href="/assets/css/chat.css">
|
<link rel="stylesheet" href="/assets/css/chat.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="chat-container">
|
<div class="chat-container">
|
||||||
<div class="chat-header">
|
<div class="chat-header">
|
||||||
Веб чат
|
Веб чат
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-messages" id="chat-messages">
|
<div class="chat-messages" id="chat-messages">
|
||||||
<!-- Сообщения чата будут здесь -->
|
<!-- Сообщения чата будут здесь -->
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-footer">
|
<div class="chat-footer">
|
||||||
<input type="text" class="chat-input" id="chat-input" placeholder="Введите сообщение...">
|
<input type="text" class="chat-input" id="chat-input" placeholder="Введите сообщение...">
|
||||||
<button class="chat-send-button" onclick="sendMessage()">Отправить</button>
|
<button class="chat-send-button" onclick="sendMessage()">Отправить</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/assets/js/chat.js"></script>
|
<script src="/assets/js/chat.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -42,8 +42,12 @@ namespace nytl {
|
|||||||
return isALPHA(ch) || isNUM(ch) || ch == '-' || ch == '_';
|
return isALPHA(ch) || isNUM(ch) || ch == '-' || ch == '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isUNCHARnonNUM(char ch) {
|
||||||
|
return isALPHA(ch) || ch == '-' || ch == '_';
|
||||||
|
}
|
||||||
|
|
||||||
bool isSPACE(char ch) {
|
bool isSPACE(char ch) {
|
||||||
return ch == ' ' || ch == '\r' || ch == '\t' || ch == '\r';
|
return ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isUname(const std::string &str) {
|
bool isUname(const std::string &str) {
|
||||||
@ -73,4 +77,14 @@ namespace nytl {
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string make_uppercase(const std::string &source) {
|
||||||
|
std::string result(source);
|
||||||
|
for (size_t i = 0; i < source.size(); i++) {
|
||||||
|
char ch = source[i];
|
||||||
|
if ('a' <= ch && ch <= 'z')
|
||||||
|
result[i] = (char)(ch - 'a' + 'A');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,10 +39,13 @@ namespace nytl {
|
|||||||
bool isALPHA(char ch);
|
bool isALPHA(char ch);
|
||||||
bool isNUM(char ch);
|
bool isNUM(char ch);
|
||||||
bool isUNCHAR(char ch);
|
bool isUNCHAR(char ch);
|
||||||
|
bool isUNCHARnonNUM(char ch);
|
||||||
bool isSPACE(char ch);
|
bool isSPACE(char ch);
|
||||||
|
|
||||||
bool isUname(const std::string& str);
|
bool isUname(const std::string& str);
|
||||||
bool is_uname_dotted_sequence(const std::string& uinp);
|
bool is_uname_dotted_sequence(const std::string& uinp);
|
||||||
|
|
||||||
|
std::string make_uppercase(const std::string& source);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -13,20 +13,27 @@ namespace nytl {
|
|||||||
size_t line = 0;
|
size_t line = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef EOFVAL
|
constexpr int EOFVAL = -999;
|
||||||
#error Son in my shift
|
|
||||||
#endif
|
|
||||||
#define EOFVAL -999
|
|
||||||
int peep(ParsingContext& ctx);
|
int peep(ParsingContext& ctx);
|
||||||
|
|
||||||
void skip(ParsingContext& ctx);
|
char skip(ParsingContext& ctx);
|
||||||
void skip(ParsingContext& ctx, char ch);
|
void skip(ParsingContext& ctx, char ch);
|
||||||
|
|
||||||
void skipWhitespace(ParsingContext& ctx);
|
void skipWhitespace(ParsingContext& ctx);
|
||||||
|
|
||||||
|
void skipString(ParsingContext& ctx, const std::string& str);
|
||||||
|
|
||||||
|
/* Returns empty if what is ahead of us is not name */
|
||||||
|
std::string readName(ParsingContext& ctx);
|
||||||
|
|
||||||
|
/* Returns empty if what is ahead of us is not uint */
|
||||||
|
std::string readUint(ParsingContext& ctx);
|
||||||
|
|
||||||
std::vector<std::string> splitIntoLines(const std::string& str);
|
std::vector<std::string> splitIntoLines(const std::string& str);
|
||||||
std::string concatenateLines(const std::vector<std::string>& lines);
|
std::string concatenateLines(const std::vector<std::string>& lines);
|
||||||
|
void one_part_update_min_start_wsp_non_empty(const std::string& str, bool is_first, size_t& min);
|
||||||
|
std::string one_part_cut_excess_tab(const std::string& str, bool is_first, size_t cut);
|
||||||
|
|
||||||
void parse_bare_file(const std::string& filename, const std::string& content,
|
void parse_bare_file(const std::string& filename, const std::string& content,
|
||||||
global_elem_set_t& result);
|
global_elem_set_t& result);
|
||||||
|
@ -34,73 +34,25 @@ namespace nytl {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_bare_file(const std::string& filename, const std::string& content,
|
|
||||||
global_elem_set_t& result)
|
|
||||||
{
|
|
||||||
ASSERT(result.count(filename) == 0, "Repeated element " + filename);
|
|
||||||
std::vector<std::string> lines;
|
|
||||||
bool had_nw_line = false;
|
|
||||||
size_t smallest_tab;
|
|
||||||
std::string current_line;
|
|
||||||
auto finish = [&]() {
|
|
||||||
size_t tab_sz = first_nw_char(current_line);
|
|
||||||
if (tab_sz == current_line.size()) {
|
|
||||||
if (had_nw_line)
|
|
||||||
lines.emplace_back();
|
|
||||||
} else {
|
|
||||||
if (had_nw_line) {
|
|
||||||
if (smallest_tab > tab_sz)
|
|
||||||
smallest_tab = tab_sz;
|
|
||||||
} else {
|
|
||||||
smallest_tab = tab_sz;
|
|
||||||
had_nw_line = true;
|
|
||||||
}
|
|
||||||
lines.push_back(current_line);
|
|
||||||
}
|
|
||||||
current_line.clear();
|
|
||||||
};
|
|
||||||
for (char ch: content) {
|
|
||||||
if (ch == '\n') {
|
|
||||||
finish();
|
|
||||||
} else {
|
|
||||||
current_line += ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finish();
|
|
||||||
while (!lines.empty() && lines.back().empty())
|
|
||||||
lines.pop_back();
|
|
||||||
|
|
||||||
for (std::string& line: lines) {
|
|
||||||
if (!line.empty()) {
|
|
||||||
assert(line.size() > smallest_tab);
|
|
||||||
line = line.substr(smallest_tab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Element& el = result[filename];
|
|
||||||
el.parts = {ElementPart{element_part_types::code}};
|
|
||||||
std::string lines_cat = concatenateLines(lines);
|
|
||||||
el.parts[0].when_code.lines = mv(lines_cat);
|
|
||||||
}
|
|
||||||
|
|
||||||
int peep(ParsingContext &ctx) {
|
int peep(ParsingContext &ctx) {
|
||||||
if (ctx.text.size() <= ctx.pos)
|
if (ctx.text.size() <= ctx.pos)
|
||||||
return EOFVAL;
|
return EOFVAL;
|
||||||
return ctx.text[ctx.pos];
|
return ctx.text[ctx.pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
void advance(ParsingContext& ctx) {
|
char advance(ParsingContext& ctx) {
|
||||||
if (ctx.text[ctx.pos] == '\n') {
|
if (ctx.text[ctx.pos] == '\n') {
|
||||||
ctx.line++;
|
ctx.line++;
|
||||||
ctx.column = 0;
|
ctx.column = 0;
|
||||||
} else {
|
} else {
|
||||||
ctx.column++;
|
ctx.column++;
|
||||||
}
|
}
|
||||||
ctx.pos++;
|
return ctx.text[ctx.pos++];
|
||||||
}
|
}
|
||||||
|
|
||||||
void skip(ParsingContext& ctx) {
|
char skip(ParsingContext& ctx) {
|
||||||
ASSERT(ctx.pos < ctx.text.size(), "Unexpected EOF");
|
ASSERT(ctx.pos < ctx.text.size(), "Unexpected EOF");
|
||||||
advance(ctx);
|
return advance(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void skip(ParsingContext& ctx, char ch) {
|
void skip(ParsingContext& ctx, char ch) {
|
||||||
@ -110,12 +62,40 @@ namespace nytl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void skipWhitespace(ParsingContext &ctx) {
|
void skipWhitespace(ParsingContext &ctx) {
|
||||||
while (peep(ctx) > 0 && isSPACE((char)peep(ctx)))
|
while (peep(ctx) >= 0 && isSPACE((char)peep(ctx)))
|
||||||
skip(ctx);
|
skip(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void skipString(ParsingContext &ctx, const std::string &str) {
|
||||||
|
for (char ch: str)
|
||||||
|
skip(ctx, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string readName(ParsingContext &ctx) {
|
||||||
|
std::string result;
|
||||||
|
int f = peep(ctx);
|
||||||
|
if (f >= 0 && isUNCHARnonNUM((char)f)) {
|
||||||
|
skip(ctx);
|
||||||
|
result += (char)f;
|
||||||
|
while (peep(ctx) >= 0 && isUNCHAR((char)peep(ctx)))
|
||||||
|
result += skip(ctx);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string readUint(ParsingContext &ctx) {
|
||||||
|
if (peep(ctx) == '0') {
|
||||||
|
skip(ctx);
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
std::string result;
|
||||||
|
while (peep(ctx) >= 0 && isNUM((char)peep(ctx)))
|
||||||
|
result += skip(ctx);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> splitIntoLines(const std::string &str) {
|
std::vector<std::string> splitIntoLines(const std::string &str) {
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result = {""};
|
||||||
for (char ch: str) {
|
for (char ch: str) {
|
||||||
if (ch == '\n')
|
if (ch == '\n')
|
||||||
result.emplace_back();
|
result.emplace_back();
|
||||||
@ -136,9 +116,354 @@ namespace nytl {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void one_part_update_min_start_wsp_non_empty(const std::string& str, bool is_first, size_t& min) {
|
||||||
|
std::vector<std::string> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string one_part_cut_excess_tab(const std::string& str, bool is_first, size_t cut) {
|
||||||
|
std::vector<std::string> 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);
|
||||||
|
}
|
||||||
|
return concatenateLines(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_bare_file(const std::string& filename, const std::string& content,
|
||||||
|
global_elem_set_t& result)
|
||||||
|
{
|
||||||
|
ASSERT(result.count(filename) == 0, "Repeated element " + filename);
|
||||||
|
std::string P = clement_lstrip(content);
|
||||||
|
rstrip(P);
|
||||||
|
size_t cut = 9999999999999;
|
||||||
|
one_part_update_min_start_wsp_non_empty(P, true, cut);
|
||||||
|
P = one_part_cut_excess_tab(P, true, cut);
|
||||||
|
Element& el = result[filename];
|
||||||
|
el.parts = {ElementPart{element_part_types::code}};
|
||||||
|
el.parts[0].when_code.lines = mv(P);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function parses variable type */
|
||||||
|
struct TPFrame {
|
||||||
|
json::JSON& result;
|
||||||
|
|
||||||
|
explicit TPFrame(json::JSON& result_): result(result_){}
|
||||||
|
|
||||||
|
uptr<TPFrame> toMe(bool returned, ParsingContext& ctx) {
|
||||||
|
if (!returned) {
|
||||||
|
std::string nm = readName(ctx);
|
||||||
|
ASSERT(!nm.empty, "Type specification expected");
|
||||||
|
nm = make_uppercase(nm);
|
||||||
|
if (nm == "JSON") {
|
||||||
|
result = json::JSON(true);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ASSERT(nm == "EL", "Type of argument variable is either JSON or EL(...signature)")
|
||||||
|
skip(ctx, '(');
|
||||||
|
result = json::JSON(json::array);
|
||||||
|
assert(result.isArray());
|
||||||
|
}
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
if (peep(ctx) == ')')
|
||||||
|
return NULL;
|
||||||
|
result.asArray().emplace_back();
|
||||||
|
return std::make_unique<TPFrame>(result.asArray().back());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
json::JSON parse_type(ParsingContext& ctx) {
|
||||||
|
json::JSON result;
|
||||||
|
std::vector<uptr<TPFrame>> stack;
|
||||||
|
stack.push_back(mv(std::make_unique<TPFrame>(result)));
|
||||||
|
bool returned = false;
|
||||||
|
while (!stack.empty) {
|
||||||
|
uptr<TPFrame> ret = stack.back()->toMe(returned, ctx);
|
||||||
|
returned = !(bool)ret;
|
||||||
|
if (ret)
|
||||||
|
stack.push_back(mv(ret));
|
||||||
|
else
|
||||||
|
stack.pop_back();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* From arg name to arg ID */
|
||||||
|
typedef std::map<std::string, size_t> arg_name_list_t;
|
||||||
|
|
||||||
|
struct EPFrame {
|
||||||
|
json::JSON& result;
|
||||||
|
|
||||||
|
explicit EPFrame(json::JSON& result_): result(result_){}
|
||||||
|
|
||||||
|
uptr<EPFrame> toMe(bool returned, ParsingContext& ctx, const arg_name_list_t& local_var_names) {
|
||||||
|
if (!returned) {
|
||||||
|
std::string first = readName(ctx);
|
||||||
|
ASSERT(!first.empty(), "Expression should start with 'root' name of global package or local variable");
|
||||||
|
ASSERT(first != "_", "_ ??? ARE YOU KIDDING???");
|
||||||
|
if (local_var_names.count(first) == 1) {
|
||||||
|
result["V"] = json::JSON(json::Integer((int64_t)local_var_names.at(first)));
|
||||||
|
} else {
|
||||||
|
result["V"] = json::JSON(first);
|
||||||
|
}
|
||||||
|
result["C"] = json::JSON(json::array);
|
||||||
|
} else {
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
skip(ctx, ']');
|
||||||
|
}
|
||||||
|
std::vector<json::JSON>& chain = result["C"].g().asArray();
|
||||||
|
while (true) {
|
||||||
|
if (peep(ctx) == '.') {
|
||||||
|
skip(ctx, '.');
|
||||||
|
chain.emplace_back();
|
||||||
|
std::string t;
|
||||||
|
t = readName(ctx);
|
||||||
|
if (!t.empty()) {
|
||||||
|
chain.back() = json::JSON(t);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
t = readUint(ctx);
|
||||||
|
if (!t.empty()) {
|
||||||
|
size_t v = std::stoul(t);
|
||||||
|
ASSERT(v < INT64_MAX, "Index is too big");
|
||||||
|
chain.back() = json::JSON((int64_t)v);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
THROW("Bad expression after . operator in expression");
|
||||||
|
} else if (peep(ctx) == '[') {
|
||||||
|
skip(ctx, '[');
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
chain.emplace_back();
|
||||||
|
return std::make_unique<EPFrame>(chain.back());
|
||||||
|
} else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
json::JSON parse_expression(ParsingContext& ctx, const arg_name_list_t& local_var_names) {
|
||||||
|
json::JSON result;
|
||||||
|
std::vector<uptr<EPFrame>> stack;
|
||||||
|
stack.push_back(mv(std::make_unique<EPFrame>(result)));
|
||||||
|
bool returned = false;
|
||||||
|
while (!stack.empty) {
|
||||||
|
uptr<EPFrame> ret = stack.back()->toMe(returned, ctx, local_var_names);
|
||||||
|
returned = !(bool)ret;
|
||||||
|
if (ret)
|
||||||
|
stack.push_back(mv(ret));
|
||||||
|
else
|
||||||
|
stack.pop_back();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string read_code_up_to_mag_block_start(ParsingContext& ctx, const TemplaterSettings& syntax) {
|
||||||
|
size_t begin = ctx.pos;
|
||||||
|
while (peep(ctx) != EOFVAL && peep(ctx) != syntax.magic_block_start[0]) {
|
||||||
|
skip(ctx);
|
||||||
|
}
|
||||||
|
size_t end = ctx.pos;
|
||||||
|
return ctx.text.substr(begin, end - begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void skip_magic_block_start(ParsingContext& ctx, const TemplaterSettings& syntax) {
|
||||||
|
skipString(ctx, syntax.magic_block_start);
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void skip_magic_block_end(ParsingContext& ctx, const TemplaterSettings& syntax) {
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
skipString(ctx, syntax.magic_block_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isIt_magic_block_end(ParsingContext& ctx, const TemplaterSettings& syntax) {
|
||||||
|
return peep(ctx) == syntax.magic_block_start[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ECPFrame {
|
||||||
|
enum block_type{
|
||||||
|
gone_for_nothing,
|
||||||
|
gone_for_for,
|
||||||
|
gone_for_ref,
|
||||||
|
};
|
||||||
|
std::string el_name;
|
||||||
|
block_type myself;
|
||||||
|
arg_name_list_t local_var_names;
|
||||||
|
int& ret_data_int; // Received from the top (and passed down to get for_put LF mode value)
|
||||||
|
Element& result;
|
||||||
|
|
||||||
|
block_type stopped_for = gone_for_nothing;
|
||||||
|
size_t free_hidden = 0;
|
||||||
|
|
||||||
|
ECPFrame(const std::string& el_name, block_type myself, const arg_name_list_t &local_var_names, int &ret_data_int,
|
||||||
|
Element& result)
|
||||||
|
: el_name(el_name),
|
||||||
|
myself(myself),
|
||||||
|
local_var_names(local_var_names),
|
||||||
|
ret_data_int(ret_data_int),
|
||||||
|
result(result) {
|
||||||
|
}
|
||||||
|
|
||||||
|
uptr<ECPFrame> 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);
|
||||||
|
if (ret_data_int == 1)
|
||||||
|
result.parts.back().when_for_put.line_feed = false;
|
||||||
|
else if (ret_data_int == 2)
|
||||||
|
result.parts.back().when_for_put.line_feed = true;
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
// skip_magic_block_start(ctx, syntax);
|
||||||
|
// std::string ender = make_uppercase(readName(ctx));
|
||||||
|
// if (gone_for == gone_for_for) {
|
||||||
|
// ASSERT(ender == "ENDFOR", "Expected ENDFOR");
|
||||||
|
// skipWhitespace(ctx);
|
||||||
|
// std::string lf_arg = make_uppercase(readName(ctx));
|
||||||
|
// if (lf_arg == "LF") {
|
||||||
|
// result.back().when_for_put.line_feed = true;
|
||||||
|
// } else if (lf_arg == "NOLF") {
|
||||||
|
// result.back().when_for_put.line_feed = false;
|
||||||
|
// } else
|
||||||
|
// ASSERT(lf_arg == "", "Expected nothing, LF or NOLF");
|
||||||
|
// skip_magic_block_end(ctx, syntax);
|
||||||
|
// } else if (gone_for == gone_for_ref) {
|
||||||
|
// skip_magic_block_start(ctx, syntax);
|
||||||
|
// ASSERT(ender == "ENDREF", "Expected ENDREF");
|
||||||
|
// } else
|
||||||
|
// assert(false);
|
||||||
|
// skip_magic_block_end(ctx, syntax);
|
||||||
|
}
|
||||||
|
ya_e_ya_h_i_ya_g_d_o:
|
||||||
|
result.parts.emplace_back();
|
||||||
|
result.parts.back().when_code.lines = read_code_up_to_mag_block_start(ctx, syntax);
|
||||||
|
skip_magic_block_start(ctx, syntax);
|
||||||
|
if (isIt_magic_block_end(ctx, syntax)) {
|
||||||
|
skip_magic_block_end(ctx, syntax);
|
||||||
|
goto ya_e_ya_h_i_ya_g_d_o;
|
||||||
|
}
|
||||||
|
std::string op = make_uppercase(readName(ctx));
|
||||||
|
if (op == "FOR") {
|
||||||
|
result.parts.emplace_back();
|
||||||
|
result.parts.back().type = element_part_type_t::for_put;
|
||||||
|
ElementPart::when_for_put_S& P = result.parts.back().when_for_put;
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
std::string V1 = readName(ctx);
|
||||||
|
ASSERT(!V1.empty(), "Expected variable name");
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
bool have_colon_and_2 = false;
|
||||||
|
std::string V2;
|
||||||
|
if (peep(ctx) == ':') {
|
||||||
|
have_colon_and_2 = true;
|
||||||
|
skip(ctx, ':');
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
V2 = readName(ctx);
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
}
|
||||||
|
op = make_uppercase(readName(ctx));
|
||||||
|
ASSERT(op == "IN", "Expected IN");
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
P.ref_over = parse_expression(ctx, local_var_names);
|
||||||
|
P.internal_element = el_name + ".~" + std::to_string(free_hidden++);
|
||||||
|
Element& newborn = elem_ns[P.internal_element];
|
||||||
|
newborn.is_hidden = true;
|
||||||
|
arg_name_list_t local_var_names_of_nxt = local_var_names;
|
||||||
|
if (V1 != "_") {
|
||||||
|
ASSERT(local_var_names_of_nxt.count(V1) == 0, "Repeated local variable");
|
||||||
|
size_t k = local_var_names_of_nxt.size();
|
||||||
|
local_var_names_of_nxt.emplace(V1, k);
|
||||||
|
(have_colon_and_2 ? P.where_key_var : P.where_value_var) = (ssize_t)k;
|
||||||
|
}
|
||||||
|
if (have_colon_and_2 && V2 != "_") {
|
||||||
|
ASSERT(local_var_names_of_nxt.count(V2) == 0, "Repeated local variable");
|
||||||
|
size_t k = local_var_names_of_nxt.size();
|
||||||
|
local_var_names_of_nxt.emplace(V2, k);
|
||||||
|
P.where_value_var = (ssize_t)k;
|
||||||
|
}
|
||||||
|
skip_magic_block_end(ctx, syntax);
|
||||||
|
/* Yep, I am passing this int random data reference, that was actually given to me, I CAN DO THAT TRUST ME */
|
||||||
|
stopped_for = gone_for_for;
|
||||||
|
return std::make_unique<ECPFrame>(P.internal_element, gone_for_for, local_var_names_of_nxt,
|
||||||
|
ret_data_int, newborn);
|
||||||
|
}
|
||||||
|
if (op == "REF") {
|
||||||
|
result.parts.emplace_back();
|
||||||
|
result.parts.back().type = element_part_type_t::ref_put;
|
||||||
|
ElementPart::when_ref_put_S& P = result.parts.back().when_ref_put;
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
std::string Vn = readName(ctx);
|
||||||
|
ASSERT(!Vn.empty(), "Expected variable name");
|
||||||
|
ASSERT(Vn != "_", "Are you kidding???");
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
op = make_uppercase(readName(ctx));
|
||||||
|
ASSERT(op == "AS", "Expected AS");
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
P.ref_over = parse_expression(ctx, local_var_names);
|
||||||
|
P.internal_element = el_name + ".~" + std::to_string(free_hidden++);
|
||||||
|
Element& newborn = elem_ns[P.internal_element];
|
||||||
|
newborn.is_hidden = true;
|
||||||
|
arg_name_list_t local_var_names_of_nxt = local_var_names;
|
||||||
|
size_t k = local_var_names_of_nxt.size();
|
||||||
|
local_var_names_of_nxt.emplace(Vn, k);
|
||||||
|
skip_magic_block_end(ctx, syntax);
|
||||||
|
stopped_for = gone_for_ref;
|
||||||
|
return std::make_unique<ECPFrame>(P.internal_element, gone_for_ref, local_var_names_of_nxt,
|
||||||
|
ret_data_int, newborn);
|
||||||
|
}
|
||||||
|
if (op == "PUT") {
|
||||||
|
result.parts.emplace_back();
|
||||||
|
result.parts.back().type = element_part_type_t::put;
|
||||||
|
ElementPart::when_put_S& P = result.parts.back().when_put;
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
P.called_element = parse_expression(ctx, local_var_names);
|
||||||
|
while (true) {
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
if (isIt_magic_block_end(ctx, syntax)) {
|
||||||
|
skip_magic_block_end(ctx, syntax);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
P.passed_arguments.push_back(parse_expression(ctx, local_var_names));
|
||||||
|
}
|
||||||
|
goto ya_e_ya_h_i_ya_g_d_o;
|
||||||
|
}
|
||||||
|
auto mediocre_operator = [&](const std::string& base_el) -> void {
|
||||||
|
result.parts.emplace_back();
|
||||||
|
result.parts.back().type = element_part_type_t::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);
|
||||||
|
skipWhitespace(ctx);
|
||||||
|
};
|
||||||
|
// todo REF, PUT, WRITE, ROUGHINSERT todo enders todo else (error)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void parse_element_content(const std::string& el_name, ParsingContext& ctx, const TemplaterSettings& syntax,
|
||||||
|
const arg_name_list_t& local_var_names, Element& result, global_elem_set_t& elem_ns) {
|
||||||
|
int random_junk; // Used onlt for for_put blocks
|
||||||
|
std::vector<uptr<ECPFrame>> stack;
|
||||||
|
stack.push_back(mv(std::make_unique<ECPFrame>(el_name, ECPFrame::gone_for_nothing, local_var_names, random_junk, result)));
|
||||||
|
bool returned = false;
|
||||||
|
while (!stack.empty()) {
|
||||||
|
uptr<ECPFrame> ret = stack.back()->toMe(returned, ctx, syntax, elem_ns);
|
||||||
|
returned = !(bool)ret;
|
||||||
|
if (ret)
|
||||||
|
stack.push_back(mv(ret));
|
||||||
|
else
|
||||||
|
stack.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void parse_special_file(const std::string& filename, const std::string& content,
|
void parse_special_file(const std::string& filename, const std::string& content,
|
||||||
std::map<std::string, Element>& result)
|
std::map<std::string, Element>& result)
|
||||||
{
|
{
|
||||||
THROW("Don't know how to parse it yet");
|
// THROW("Don't know how to parse it yet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,20 +121,23 @@ namespace nytl {
|
|||||||
const Element& el = elem_ns.at(name);
|
const Element& el = elem_ns.at(name);
|
||||||
if (!returned) {
|
if (!returned) {
|
||||||
/* Continue to do checks */
|
/* Continue to do checks */
|
||||||
size_t n = el.arguments.size();
|
/* hidden elements (internal) do not need any check */
|
||||||
ASSERT(n == passed_args.size(), "Argument count mismatch");
|
if (!el.is_hidden) {
|
||||||
for (size_t i = 0; i < n; i++) {
|
size_t n = el.arguments.size();
|
||||||
if (el.arguments[i].type == json::true_symbol) {
|
ASSERT(n == passed_args.size(), "Argument count mismatch");
|
||||||
ASSERT(passed_args[i].is_json, "Expected json element argument, got element");
|
for (size_t i = 0; i < n; i++) {
|
||||||
} else {
|
if (el.arguments[i].type == json::true_symbol) {
|
||||||
// If not json is expected, element must be expected
|
ASSERT(passed_args[i].is_json, "Expected json element argument, got element");
|
||||||
assert(el.arguments[i].isArray());
|
} else {
|
||||||
ASSERT(!passed_args[i].is_json, "Expected element element arguemnt, got json");
|
// If not json is expected, element must be expected
|
||||||
ASSERT(elem_ns.count(passed_args[i].EL_name), "No such element, can't compare signatures of argument value");
|
assert(el.arguments[i].isArray());
|
||||||
const Element& arg_element = elem_ns.at(passed_args[i].EL_name);
|
ASSERT(!passed_args[i].is_json, "Expected element element arguemnt, got json");
|
||||||
// ASSERT(passed_args);
|
ASSERT(elem_ns.count(passed_args[i].EL_name), "No such element, can't compare signatures of argument value");
|
||||||
if(el.arguments[i].asArray() != arg_element.arguments)
|
const Element& arg_element = elem_ns.at(passed_args[i].EL_name);
|
||||||
THROW("Signature of argument " + std::to_string(i) + " does not match");
|
// ASSERT(passed_args);
|
||||||
|
if(el.arguments[i].asArray() != arg_element.arguments)
|
||||||
|
THROW("Signature of argument " + std::to_string(i) + " does not match");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ namespace nytl {
|
|||||||
std::vector<json::JSON> arguments;
|
std::vector<json::JSON> arguments;
|
||||||
/* `base` is true for builtin elements (jesc str2code str2text). Parts for such ' are empty */
|
/* `base` is true for builtin elements (jesc str2code str2text). Parts for such ' are empty */
|
||||||
bool base = false;
|
bool base = false;
|
||||||
|
bool is_hidden = false;
|
||||||
std::vector<ElementPart> parts;
|
std::vector<ElementPart> parts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ int main(int argc, char** argv) {
|
|||||||
std::string dir_path = argv[1];
|
std::string dir_path = argv[1];
|
||||||
nytl::Templater templater(nytl::TemplaterSettings{nytl::TemplaterDetourRules{dir_path}});
|
nytl::Templater templater(nytl::TemplaterSettings{nytl::TemplaterDetourRules{dir_path}});
|
||||||
templater.update();
|
templater.update();
|
||||||
std::string answer = templater.render("chat", {});
|
std::string answer = templater.render("list-rooms", {});
|
||||||
printf("%s\n<a><f><t><e><r><><l><f>\n", answer.c_str());
|
printf("%s\n<a><f><t><e><r><><l><f>\n", answer.c_str());
|
||||||
std::string answer2 = templater.render("test", {});
|
std::string answer2 = templater.render("test", {});
|
||||||
printf("%s\n<a><f><t><e><r><><l><f>\n", answer.c_str());
|
printf("%s\n<a><f><t><e><r><><l><f>\n", answer.c_str());
|
||||||
|
Loading…
Reference in New Issue
Block a user