|
@@ -270,6 +270,7 @@ typedef struct {
|
|
|
|
|
|
T_NUMBER,
|
|
T_NUMBER,
|
|
T_STRING,
|
|
T_STRING,
|
|
|
|
+ T_FSTRING,
|
|
T_NAME,
|
|
T_NAME,
|
|
|
|
|
|
T_VAR,
|
|
T_VAR,
|
|
@@ -349,6 +350,7 @@ typedef struct {
|
|
|
|
|
|
T_INLINE,
|
|
T_INLINE,
|
|
T_HEADER,
|
|
T_HEADER,
|
|
|
|
+ T_INCLUDE,
|
|
|
|
|
|
T_ASSIGN,
|
|
T_ASSIGN,
|
|
T_SEMI
|
|
T_SEMI
|
|
@@ -436,85 +438,96 @@ void format_error(char *filename, char *source, size_t pos, char *fmt, ...) {
|
|
|
|
|
|
#define LEX_ERROR(fmt, ...) { format_error(GETFNAME(-1), source, *pos, fmt, ##__VA_ARGS__); exit(1); }
|
|
#define LEX_ERROR(fmt, ...) { format_error(GETFNAME(-1), source, *pos, fmt, ##__VA_ARGS__); exit(1); }
|
|
|
|
|
|
-token_t *next_token(char *source, size_t *pos) {
|
|
|
|
- if (!source[*pos])
|
|
|
|
- return token(T_EOF, NULL);
|
|
|
|
|
|
+token_t *tokenize_string(char *source, size_t *pos) {
|
|
|
|
+ char term = source[(*pos)++];
|
|
|
|
|
|
- if (source[*pos] == '"' || source[*pos] == '\'' || source[*pos] == '`') {
|
|
|
|
- char term = source[(*pos)++];
|
|
|
|
|
|
+ buffer_t *text = buffer_new();
|
|
|
|
|
|
- buffer_t *text = buffer_new();
|
|
|
|
|
|
+ while (source[*pos] != term) {
|
|
|
|
+ if (!source[*pos])
|
|
|
|
+ LEX_ERROR("unterminated string literal");
|
|
|
|
|
|
- while (source[*pos] != term) {
|
|
|
|
- if (!source[*pos])
|
|
|
|
- LEX_ERROR("unterminated string literal");
|
|
|
|
|
|
+ char c = source[(*pos)++];
|
|
|
|
+ if (c == '\n' && term != '`')
|
|
|
|
+ LEX_ERROR("unterminated string literal");
|
|
|
|
|
|
- char c = source[(*pos)++];
|
|
|
|
- if (c == '\n' && term != '`')
|
|
|
|
- LEX_ERROR("unterminated string literal");
|
|
|
|
|
|
+ if (term != '`' && c == '\\') {
|
|
|
|
+ char nc = source[(*pos)++];
|
|
|
|
|
|
- if (term != '`' && c == '\\') {
|
|
|
|
- char nc = source[(*pos)++];
|
|
|
|
|
|
+ if (!nc)
|
|
|
|
+ continue;
|
|
|
|
|
|
- if (!nc)
|
|
|
|
- continue;
|
|
|
|
|
|
+ switch (nc) {
|
|
|
|
+ case 'n':
|
|
|
|
+ buffer_appends(text, "\\n");
|
|
|
|
+ break;
|
|
|
|
|
|
- switch (nc) {
|
|
|
|
- case 'n':
|
|
|
|
- buffer_appends(text, "\\n");
|
|
|
|
- break;
|
|
|
|
|
|
+ case 't':
|
|
|
|
+ buffer_appends(text, "\\t");
|
|
|
|
+ break;
|
|
|
|
|
|
- case 't':
|
|
|
|
- buffer_appends(text, "\\t");
|
|
|
|
- break;
|
|
|
|
|
|
+ case 'r':
|
|
|
|
+ buffer_appends(text, "\\r");
|
|
|
|
+ break;
|
|
|
|
|
|
- case 'r':
|
|
|
|
- buffer_appends(text, "\\r");
|
|
|
|
- break;
|
|
|
|
|
|
+ case 'b':
|
|
|
|
+ buffer_appends(text, "\\b");
|
|
|
|
+ break;
|
|
|
|
|
|
- case 'b':
|
|
|
|
- buffer_appends(text, "\\b");
|
|
|
|
- break;
|
|
|
|
|
|
+ case 'e':
|
|
|
|
+ buffer_appends(text, "\\e");
|
|
|
|
+ break;
|
|
|
|
|
|
- case 'e':
|
|
|
|
- buffer_appends(text, "\\e");
|
|
|
|
- break;
|
|
|
|
|
|
+ case 's':
|
|
|
|
+ buffer_appends(text, " ");
|
|
|
|
+ break;
|
|
|
|
|
|
- case 's':
|
|
|
|
- buffer_appends(text, " ");
|
|
|
|
- break;
|
|
|
|
|
|
+ case '"':
|
|
|
|
+ buffer_appends(text, "\\\"");
|
|
|
|
+ break;
|
|
|
|
|
|
- case '"':
|
|
|
|
- buffer_appends(text, "\\\"");
|
|
|
|
- break;
|
|
|
|
|
|
+ case '\\':
|
|
|
|
+ buffer_appends(text, "\\\\");
|
|
|
|
+ break;
|
|
|
|
|
|
- case '\\':
|
|
|
|
- buffer_appends(text, "\\\\");
|
|
|
|
- break;
|
|
|
|
|
|
+ case '\n':
|
|
|
|
+ buffer_appends(text, "\\n");
|
|
|
|
+ break;
|
|
|
|
|
|
- case '\n':
|
|
|
|
- buffer_appends(text, "\\n");
|
|
|
|
- break;
|
|
|
|
|
|
+ default:
|
|
|
|
+ buffer_append(text, nc);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
|
|
- default:
|
|
|
|
- buffer_append(text, nc);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
|
|
+ if (c == '"' || c == '\\')
|
|
|
|
+ buffer_append(text, '\\');
|
|
|
|
+ else if (c == '\n')
|
|
|
|
+ buffer_appends(text, "\\n");
|
|
|
|
|
|
- if (c == '"' || c == '\\')
|
|
|
|
- buffer_append(text, '\\');
|
|
|
|
- else if (c == '\n')
|
|
|
|
- buffer_appends(text, "\\n");
|
|
|
|
|
|
+ buffer_append(text, c);
|
|
|
|
+ }
|
|
|
|
|
|
- buffer_append(text, c);
|
|
|
|
- }
|
|
|
|
|
|
+ (*pos)++;
|
|
|
|
+
|
|
|
|
+ return token(T_STRING, buffer_read(text));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+token_t *next_token(char *source, size_t *pos) {
|
|
|
|
+ if (!source[*pos])
|
|
|
|
+ return token(T_EOF, NULL);
|
|
|
|
|
|
|
|
+ if (source[*pos] == '"' || source[*pos] == '\'' || source[*pos] == '`')
|
|
|
|
+ return tokenize_string(source, pos);
|
|
|
|
+ else if (source[*pos] == 'f' && (source[(*pos)+1] == '"' || source[(*pos)+1] == '\'' || source[(*pos)+1] == '`')) {
|
|
(*pos)++;
|
|
(*pos)++;
|
|
|
|
|
|
- return token(T_STRING, buffer_read(text));
|
|
|
|
|
|
+ token_t *t = tokenize_string(source, pos);
|
|
|
|
+ t->tag = T_FSTRING;
|
|
|
|
+
|
|
|
|
+ return t;
|
|
} else if (source[*pos] == '0' && (source[(*pos)+1] == 'x' || source[(*pos)+1] == 'b' || source[(*pos)+1] == 'o')) {
|
|
} else if (source[*pos] == '0' && (source[(*pos)+1] == 'x' || source[(*pos)+1] == 'b' || source[(*pos)+1] == 'o')) {
|
|
buffer_t *number = buffer_new();
|
|
buffer_t *number = buffer_new();
|
|
buffer_append(number, source[(*pos)++]);
|
|
buffer_append(number, source[(*pos)++]);
|
|
@@ -632,6 +645,8 @@ token_t *next_token(char *source, size_t *pos) {
|
|
return TK(INLINE);
|
|
return TK(INLINE);
|
|
else if (strcmp(name, "header") == 0)
|
|
else if (strcmp(name, "header") == 0)
|
|
return TK(HEADER);
|
|
return TK(HEADER);
|
|
|
|
+ else if (strcmp(name, "include") == 0)
|
|
|
|
+ return TK(INCLUDE);
|
|
|
|
|
|
return token(T_NAME, name);
|
|
return token(T_NAME, name);
|
|
} else if (strncmp(&source[*pos], "==", 2) == 0 && ++(*pos) && ++(*pos))
|
|
} else if (strncmp(&source[*pos], "==", 2) == 0 && ++(*pos) && ++(*pos))
|
|
@@ -775,6 +790,7 @@ struct _node_t {
|
|
N_STAR,
|
|
N_STAR,
|
|
N_MEMBER,
|
|
N_MEMBER,
|
|
N_INDEX,
|
|
N_INDEX,
|
|
|
|
+ N_SLICE,
|
|
|
|
|
|
N_ADD,
|
|
N_ADD,
|
|
N_SUB,
|
|
N_SUB,
|
|
@@ -842,6 +858,7 @@ struct _node_t {
|
|
|
|
|
|
N_INLINE,
|
|
N_INLINE,
|
|
N_HEADER,
|
|
N_HEADER,
|
|
|
|
+ N_INCLUDE,
|
|
|
|
|
|
N_IFEXPR,
|
|
N_IFEXPR,
|
|
N_FUNCEXPR,
|
|
N_FUNCEXPR,
|
|
@@ -1087,6 +1104,8 @@ list_t *parse_sequence(list_t *tokens, size_t *pos, int term) {
|
|
|
|
|
|
node_t *parse_func(list_t *tokens, size_t *pos, int is_expr);
|
|
node_t *parse_func(list_t *tokens, size_t *pos, int is_expr);
|
|
|
|
|
|
|
|
+char *unescape(char *s);
|
|
|
|
+
|
|
node_t *parse_primary(list_t *tokens, size_t *pos) {
|
|
node_t *parse_primary(list_t *tokens, size_t *pos) {
|
|
if (MATCH(FUNC))
|
|
if (MATCH(FUNC))
|
|
return parse_func(tokens, pos, 1);
|
|
return parse_func(tokens, pos, 1);
|
|
@@ -1161,19 +1180,21 @@ node_t *parse_primary(list_t *tokens, size_t *pos) {
|
|
if (!AT(NAME) && !AT(STRING))
|
|
if (!AT(NAME) && !AT(STRING))
|
|
PARSE_ERROR("expected identifier or string");
|
|
PARSE_ERROR("expected identifier or string");
|
|
|
|
|
|
|
|
+ int is_str = AT(STRING);
|
|
|
|
+
|
|
char *key = ((token_t *)tokens->data[(*pos)++])->text;
|
|
char *key = ((token_t *)tokens->data[(*pos)++])->text;
|
|
|
|
|
|
EXPECT(COLON, ":");
|
|
EXPECT(COLON, ":");
|
|
|
|
|
|
node_t *val = parse_expr(tokens, pos);
|
|
node_t *val = parse_expr(tokens, pos);
|
|
|
|
|
|
- table_set(table, key, val);
|
|
|
|
|
|
+ table_set(table, is_str? unescape(key): key, val);
|
|
} while (MATCH(COMMA));
|
|
} while (MATCH(COMMA));
|
|
|
|
|
|
EXPECT(RCB, "}");
|
|
EXPECT(RCB, "}");
|
|
|
|
|
|
return NODEH(TABLE, table);
|
|
return NODEH(TABLE, table);
|
|
- } else if (MATCH(NUMBER) || MATCH(STRING) || MATCH(NAME))
|
|
|
|
|
|
+ } else if (MATCH(NUMBER) || MATCH(STRING) || MATCH(FSTRING) || MATCH(NAME))
|
|
return NODET(LITERAL, tokens->data[(*pos)-1]);
|
|
return NODET(LITERAL, tokens->data[(*pos)-1]);
|
|
|
|
|
|
PARSE_ERROR("expected expression");
|
|
PARSE_ERROR("expected expression");
|
|
@@ -1207,8 +1228,29 @@ node_t *parse_call(list_t *tokens, size_t *pos) {
|
|
|
|
|
|
continue;
|
|
continue;
|
|
} else if (!CLIFF && MATCH(LSB)) {
|
|
} else if (!CLIFF && MATCH(LSB)) {
|
|
|
|
+ if (MATCH(COLON)) {
|
|
|
|
+ a = NODE3(SLICE, a, NULL, parse_expr(tokens, pos));
|
|
|
|
+
|
|
|
|
+ EXPECT(RSB, "]");
|
|
|
|
+
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
node_t *b = parse_expr(tokens, pos);
|
|
node_t *b = parse_expr(tokens, pos);
|
|
|
|
|
|
|
|
+ if (MATCH(COLON)) {
|
|
|
|
+ node_t *c = NULL;
|
|
|
|
+
|
|
|
|
+ if (!AT(RSB))
|
|
|
|
+ c = parse_expr(tokens, pos);
|
|
|
|
+
|
|
|
|
+ EXPECT(RSB, "]");
|
|
|
|
+
|
|
|
|
+ a = NODE3(SLICE, a, b, c);
|
|
|
|
+
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
EXPECT(RSB, "]");
|
|
EXPECT(RSB, "]");
|
|
|
|
|
|
a = NODE2(INDEX, a, b);
|
|
a = NODE2(INDEX, a, b);
|
|
@@ -2112,6 +2154,16 @@ node_t *parse_program(list_t *tokens, size_t *pos) {
|
|
token_t *text = tokens->data[(*pos)++];
|
|
token_t *text = tokens->data[(*pos)++];
|
|
|
|
|
|
n = NODET(HEADER, text);
|
|
n = NODET(HEADER, text);
|
|
|
|
+ } else if (MATCH(INCLUDE)) {
|
|
|
|
+ if (flag)
|
|
|
|
+ PARSE_ERROR("misplaced include statement")
|
|
|
|
+
|
|
|
|
+ if (!AT(STRING))
|
|
|
|
+ PARSE_ERROR("expected string");
|
|
|
|
+
|
|
|
|
+ token_t *text = tokens->data[(*pos)++];
|
|
|
|
+
|
|
|
|
+ n = NODET(INCLUDE, text);
|
|
} else { n = parse_stmt(tokens, pos); flag = 1; }
|
|
} else { n = parse_stmt(tokens, pos); flag = 1; }
|
|
|
|
|
|
MATCH(SEMI);
|
|
MATCH(SEMI);
|
|
@@ -2671,6 +2723,7 @@ const char *STD[][2] = {
|
|
"set_pseudomethod(\"list.slice\", slice)\n"
|
|
"set_pseudomethod(\"list.slice\", slice)\n"
|
|
"set_pseudomethod(\"string.slice\", slice)\n"
|
|
"set_pseudomethod(\"string.slice\", slice)\n"
|
|
"set_pseudomethod(\"bytes.slice\", slice)\n"
|
|
"set_pseudomethod(\"bytes.slice\", slice)\n"
|
|
|
|
+ "let __slice = slice;\n"
|
|
"func str_startswith(s, p) {\n"
|
|
"func str_startswith(s, p) {\n"
|
|
" if type(s) != \"string\"\n"
|
|
" if type(s) != \"string\"\n"
|
|
" throw \"expected first argument to be: string, but got: \" + type(s)\n"
|
|
" throw \"expected first argument to be: string, but got: \" + type(s)\n"
|
|
@@ -3005,6 +3058,9 @@ const char *STD[][2] = {
|
|
" return str_rstrip(getline(), \"\\n\\r\")\n"
|
|
" return str_rstrip(getline(), \"\\n\\r\")\n"
|
|
"}\n"
|
|
"}\n"
|
|
"func open(path, mode=\"r\"): fopen(path, mode)\n"
|
|
"func open(path, mode=\"r\"): fopen(path, mode)\n"
|
|
|
|
+ "func assert(cond, msg=\"assertion failed\")\n"
|
|
|
|
+ " if !cond\n"
|
|
|
|
+ " throw msg\n"
|
|
},
|
|
},
|
|
|
|
|
|
{"utf8",
|
|
{"utf8",
|
|
@@ -3042,6 +3098,7 @@ const char *STD[][2] = {
|
|
},
|
|
},
|
|
|
|
|
|
{"thread",
|
|
{"thread",
|
|
|
|
+ "include `pthread.h`\n"
|
|
"func thread_create(fn, args=[]) {\n"
|
|
"func thread_create(fn, args=[]) {\n"
|
|
" if type(fn) != \"function\"\n"
|
|
" if type(fn) != \"function\"\n"
|
|
" throw \"expected first argument to be: function, but got: \" + type(fn)\n"
|
|
" throw \"expected first argument to be: function, but got: \" + type(fn)\n"
|
|
@@ -3149,7 +3206,11 @@ const char *STD[][2] = {
|
|
},
|
|
},
|
|
|
|
|
|
{"time",
|
|
{"time",
|
|
- "header `#include <time.h>`\n"
|
|
|
|
|
|
+ "include `time.h`\n"
|
|
|
|
+ "include `errno.h`\n"
|
|
|
|
+ "header `#ifdef _WIN32`\n"
|
|
|
|
+ "include `Windows.h`\n"
|
|
|
|
+ "header `#endif`\n"
|
|
"func time() {\n"
|
|
"func time() {\n"
|
|
" inline `unsigned long long ts = time(NULL)`\n"
|
|
" inline `unsigned long long ts = time(NULL)`\n"
|
|
" inline `return qi_make_number(state, ts)`\n"
|
|
" inline `return qi_make_number(state, ts)`\n"
|
|
@@ -3166,6 +3227,23 @@ const char *STD[][2] = {
|
|
" inline `strftime(buffer, sizeof(buffer), qi_get(state, \"f\")->value.string, <)`\n"
|
|
" inline `strftime(buffer, sizeof(buffer), qi_get(state, \"f\")->value.string, <)`\n"
|
|
" inline `return qi_make_string_copy(state, buffer)`\n"
|
|
" inline `return qi_make_string_copy(state, buffer)`\n"
|
|
"}\n"
|
|
"}\n"
|
|
|
|
+ "func usleep(t) {\n"
|
|
|
|
+ " if type(t) != \"number\"\n"
|
|
|
|
+ " throw \"expected first argument to be: number, but got: \" + type(t)\n"
|
|
|
|
+ " \n"
|
|
|
|
+ " inline `#ifdef _WIN32`\n"
|
|
|
|
+ " inline `Sleep((unsigned long)(qi_get(state, \"t\")->value.number))`\n"
|
|
|
|
+ " inline `#else`\n"
|
|
|
|
+ " inline `unsigned long ms = (unsigned long)(qi_get(state, \"t\")->value.number)`\n"
|
|
|
|
+ " inline `struct timespec ts`\n"
|
|
|
|
+ " inline `ts.tv_sec = ms / 1000`\n"
|
|
|
|
+ " inline `ts.tv_nsec = (ms % 1000) * 1000000`\n"
|
|
|
|
+ " inline `struct timespec r`\n"
|
|
|
|
+ " inline `while (nanosleep(&ts, &r) < 0) if (errno == EINTR) ts = r; else break`\n"
|
|
|
|
+ " inline `#endif`\n"
|
|
|
|
+ "}\n"
|
|
|
|
+ "func sleep(t)\n"
|
|
|
|
+ " usleep(t * 1000)\n"
|
|
},
|
|
},
|
|
|
|
|
|
{"random",
|
|
{"random",
|
|
@@ -3385,6 +3463,98 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
+ case T_FSTRING: {
|
|
|
|
+ char *text = node->t->text;
|
|
|
|
+
|
|
|
|
+ if (!*text) {
|
|
|
|
+ EMIT("state->empty_string");
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ list_t *parts = list_new();
|
|
|
|
+
|
|
|
|
+ buffer_t *tbuf = buffer_new();
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ for (size_t i = 0; i < strlen(text); i++) {
|
|
|
|
+ char c = text[i];
|
|
|
|
+ if (c == '$' && text[i+1] == '$') {
|
|
|
|
+ buffer_append(tbuf, '$');
|
|
|
|
+
|
|
|
|
+ i++;
|
|
|
|
+
|
|
|
|
+ continue;
|
|
|
|
+ } else if (c == '$' && text[i+1] == '{') {
|
|
|
|
+ i += 2;
|
|
|
|
+
|
|
|
|
+ buffer_t *tbuf2 = buffer_new();
|
|
|
|
+
|
|
|
|
+ while (text[i] && text[i] != '}')
|
|
|
|
+ buffer_append(tbuf2, text[i++]);
|
|
|
|
+
|
|
|
|
+ if (text[i] != '}') {
|
|
|
|
+ i--;
|
|
|
|
+
|
|
|
|
+ buffer_appends(tbuf, "${");
|
|
|
|
+ buffer_appendb(tbuf, tbuf2);
|
|
|
|
+
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (tbuf->size > 0)
|
|
|
|
+ list_push(parts, nodeb(tbuf));
|
|
|
|
+
|
|
|
|
+ tbuf = buffer_new();
|
|
|
|
+
|
|
|
|
+ char *source = buffer_read(tbuf2);
|
|
|
|
+
|
|
|
|
+ list_t *pair = list_new();
|
|
|
|
+ list_push(pair, "<fstring>");
|
|
|
|
+ list_push(pair, source);
|
|
|
|
+
|
|
|
|
+ list_push(FILES, pair);
|
|
|
|
+
|
|
|
|
+ size_t pos = 0;
|
|
|
|
+ node_t *n = parse_expr(tokenize(source), &pos);
|
|
|
|
+
|
|
|
|
+ list_push(parts, n);
|
|
|
|
+ } else buffer_append(tbuf, c);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (tbuf->size > 0)
|
|
|
|
+ list_push(parts, nodeb(tbuf));
|
|
|
|
+
|
|
|
|
+ tbuf = buffer_new();
|
|
|
|
+
|
|
|
|
+ NEWGID();
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, "inline static qi_value_t *__fstring%d(qi_state_t *state) {\n", gid);
|
|
|
|
+ buffer_fmt(tbuf, "qi_value_t *str = state->empty_string;\n");
|
|
|
|
+
|
|
|
|
+ for (size_t i = 0; i < parts->length; i++) {
|
|
|
|
+ node_t *part = parts->data[i];
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, "str = qi_add(state, str, ");
|
|
|
|
+
|
|
|
|
+ if (part->tag == N_BUFFER)
|
|
|
|
+ buffer_fmt(tbuf, "qi_make_string(state, \"%s\")", buffer_read(part->buf));
|
|
|
|
+ else {
|
|
|
|
+ buffer_fmt(tbuf, "qi_to_string(state, ");
|
|
|
|
+ compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, part);
|
|
|
|
+ buffer_fmt(tbuf, ")");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, ");\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, "return str;\n}\n");
|
|
|
|
+
|
|
|
|
+ buffer_appendb(gbuf, tbuf);
|
|
|
|
+
|
|
|
|
+ EMIT("__fstring%d(state)", gid);
|
|
|
|
+ } break;
|
|
|
|
+
|
|
case T_NAME: {
|
|
case T_NAME: {
|
|
char *name = node->t->text;
|
|
char *name = node->t->text;
|
|
node_t *n = table_get(CONSTANTS, name);
|
|
node_t *n = table_get(CONSTANTS, name);
|
|
@@ -3411,7 +3581,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
|
|
|
|
|
|
buffer_t *tbuf = buffer_new();
|
|
buffer_t *tbuf = buffer_new();
|
|
|
|
|
|
- buffer_fmt(tbuf, "qi_value_t *__listgen%d(qi_state_t *state) {\n", gid);
|
|
|
|
|
|
+ buffer_fmt(tbuf, "inline static qi_value_t *__listgen%d(qi_state_t *state) {\n", gid);
|
|
buffer_fmt(tbuf, "qi_list_t *list = qi_list_make();\n");
|
|
buffer_fmt(tbuf, "qi_list_t *list = qi_list_make();\n");
|
|
|
|
|
|
buffer_t *bbuf = buffer_new();
|
|
buffer_t *bbuf = buffer_new();
|
|
@@ -3469,6 +3639,56 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
|
|
EMIT(")");
|
|
EMIT(")");
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
+ case N_SLICE: {
|
|
|
|
+ NEWGID();
|
|
|
|
+
|
|
|
|
+ buffer_t *tbuf = buffer_new();
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, "inline static qi_value_t *__slice%d(qi_state_t *state) {\n", gid);
|
|
|
|
+
|
|
|
|
+ if (node->b && node->c) {
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_t *pargs = qi_list_make_n(3);\n");
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_data(pargs, 0) = ");
|
|
|
|
+ compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->a);
|
|
|
|
+ buffer_fmt(tbuf, ";\n");
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_data(pargs, 1) = ");
|
|
|
|
+ compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->b);
|
|
|
|
+ buffer_fmt(tbuf, ";\n");
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_data(pargs, 2) = ");
|
|
|
|
+ compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->c);
|
|
|
|
+ buffer_fmt(tbuf, ";\n");
|
|
|
|
+ } else if (node->b) {
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_t *pargs = qi_list_make_n(2);\n");
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_data(pargs, 0) = ");
|
|
|
|
+ compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->a);
|
|
|
|
+ buffer_fmt(tbuf, ";\n");
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_data(pargs, 1) = ");
|
|
|
|
+ compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->b);
|
|
|
|
+ buffer_fmt(tbuf, ";\n");
|
|
|
|
+ } else {
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_t *pargs = qi_list_make_n(3);\n");
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_data(pargs, 0) = ");
|
|
|
|
+ compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->a);
|
|
|
|
+ buffer_fmt(tbuf, ";\n");
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_data(pargs, 1) = state->zero;\n");
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, "qi_list_data(pargs, 2) = ");
|
|
|
|
+ compile_node(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->c);
|
|
|
|
+ buffer_fmt(tbuf, ";\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ buffer_fmt(tbuf, "return qi_call(state, qi_get(state, \"__slice\"), pargs);\n");
|
|
|
|
+ buffer_fmt(tbuf, "}\n");
|
|
|
|
+
|
|
|
|
+ buffer_appendb(gbuf, tbuf);
|
|
|
|
+
|
|
|
|
+ EMIT("__slice%d(state)", gid);
|
|
|
|
+ } break;
|
|
|
|
+
|
|
case N_ASSIGN:
|
|
case N_ASSIGN:
|
|
if (node->a->tag == N_LIST) {
|
|
if (node->a->tag == N_LIST) {
|
|
if (node->a->l->length < 2)
|
|
if (node->a->l->length < 2)
|
|
@@ -4020,8 +4240,17 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
|
|
UNOP("bnot");
|
|
UNOP("bnot");
|
|
break;
|
|
break;
|
|
|
|
|
|
- case N_INLINE: EMIT("%s;", unescape(node->t->text)); break;
|
|
|
|
|
|
+ case N_INLINE: {
|
|
|
|
+ char *text = unescape(node->t->text);
|
|
|
|
+
|
|
|
|
+ if (text[0] == '#') {
|
|
|
|
+ EMIT("%s", text);
|
|
|
|
+ } else {
|
|
|
|
+ EMIT("%s;", text);
|
|
|
|
+ }
|
|
|
|
+ } break;
|
|
case N_HEADER: buffer_fmt(HBUF, "%s\n", unescape(node->t->text)); break;
|
|
case N_HEADER: buffer_fmt(HBUF, "%s\n", unescape(node->t->text)); break;
|
|
|
|
+ case N_INCLUDE: buffer_fmt(HBUF, "#include <%s>\n", unescape(node->t->text)); break;
|
|
|
|
|
|
case N_BUFFER: buffer_appendb(buf, node->buf); break;
|
|
case N_BUFFER: buffer_appendb(buf, node->buf); break;
|
|
|
|
|