|
@@ -347,6 +347,7 @@ typedef struct {
|
|
|
T_TILDE,
|
|
|
|
|
|
T_INLINE,
|
|
|
+ T_HEADER,
|
|
|
|
|
|
T_ASSIGN,
|
|
|
T_SEMI
|
|
@@ -628,6 +629,8 @@ token_t *next_token(char *source, size_t *pos) {
|
|
|
return TK(OF);
|
|
|
else if (strcmp(name, "inline") == 0)
|
|
|
return TK(INLINE);
|
|
|
+ else if (strcmp(name, "header") == 0)
|
|
|
+ return TK(HEADER);
|
|
|
|
|
|
return token(T_NAME, name);
|
|
|
} else if (strncmp(&source[*pos], "==", 2) == 0 && ++(*pos) && ++(*pos))
|
|
@@ -834,6 +837,7 @@ struct _node_t {
|
|
|
N_CLASS,
|
|
|
|
|
|
N_INLINE,
|
|
|
+ N_HEADER,
|
|
|
|
|
|
N_IFEXPR,
|
|
|
N_FUNCEXPR,
|
|
@@ -1674,7 +1678,7 @@ node_t *parse_func(list_t *tokens, size_t *pos, int is_expr) {
|
|
|
|
|
|
int colon = AT(COLON);
|
|
|
|
|
|
- node_t *body = BLOCK();
|
|
|
+ node_t *body = !colon && !AT(LCB)? parse_stmt(tokens, pos): BLOCK();
|
|
|
|
|
|
if (colon && body->tag == N_EXPRSTMT)
|
|
|
body = NODE1(RETURN, body->a);
|
|
@@ -1901,7 +1905,7 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
} else if (MATCH(THROW)) {
|
|
|
node_t *a = NULL;
|
|
|
|
|
|
- if (!CLIFF)
|
|
|
+ if (!CLIFF && !AT(COMMA) && !AT(RPAR) && !AT(RCB))
|
|
|
a = parse_expr(tokens, pos);
|
|
|
|
|
|
return NODE1(THROW, a);
|
|
@@ -2007,6 +2011,16 @@ node_t *parse_program(list_t *tokens, size_t *pos) {
|
|
|
token_t *path = tokens->data[(*pos)++];
|
|
|
|
|
|
n = NODET(REQUIRE, path);
|
|
|
+ } else if (MATCH(HEADER)) {
|
|
|
+ if (flag)
|
|
|
+ PARSE_ERROR("misplaced header statement")
|
|
|
+
|
|
|
+ if (!AT(STRING))
|
|
|
+ PARSE_ERROR("expected string");
|
|
|
+
|
|
|
+ token_t *text = tokens->data[(*pos)++];
|
|
|
+
|
|
|
+ n = NODET(HEADER, text);
|
|
|
} else { n = parse_stmt(tokens, pos); flag = 1; }
|
|
|
|
|
|
MATCH(SEMI);
|
|
@@ -2026,8 +2040,8 @@ node_t *parse(char *source) {
|
|
|
#define NEWGID() size_t gid = GID++
|
|
|
|
|
|
#define EMIT(fmt, ...) buffer_fmt(buf, (fmt), ##__VA_ARGS__);
|
|
|
-#define BINOP(s) { EMIT("qi_" s "(state, "); compile_node(gbuf, buf, ctx, lstk, lbl, node->a); EMIT(", "); compile_node(gbuf, buf, ctx, lstk, lbl, node->b); EMIT(")"); }
|
|
|
-#define UNOP(s) { EMIT("qi_" s "(state, "); compile_node(gbuf, buf, ctx, lstk, lbl, node->a); EMIT(")"); }
|
|
|
+#define BINOP(s) { EMIT("qi_" s "(state, "); compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a); EMIT(", "); compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b); EMIT(")"); }
|
|
|
+#define UNOP(s) { EMIT("qi_" s "(state, "); compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a); EMIT(")"); }
|
|
|
#define ASSIGN(lhs, rhs) {\
|
|
|
if ((lhs)->tag == N_LITERAL && (lhs)->t->tag == T_NAME) {\
|
|
|
EMIT("qi_set(state, false, \"%s\", ", (lhs)->t->text);\
|
|
@@ -2035,15 +2049,15 @@ node_t *parse(char *source) {
|
|
|
EMIT(")");\
|
|
|
} else if ((lhs)->tag == N_INDEX) {\
|
|
|
EMIT("qi_index_set(state, false, ");\
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, (lhs)->a);\
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, (lhs)->a);\
|
|
|
EMIT(", ");\
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, (lhs)->b);\
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, (lhs)->b);\
|
|
|
EMIT(", ");\
|
|
|
rhs;\
|
|
|
EMIT(")");\
|
|
|
} else if ((lhs)->tag == N_MEMBER) {\
|
|
|
EMIT("qi_index_set(state, false, ");\
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, (lhs)->a);\
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, (lhs)->a);\
|
|
|
EMIT(", qi_make_string(state, \"%s\"), ", (lhs)->t->text);\
|
|
|
rhs;\
|
|
|
EMIT(")");\
|
|
@@ -2052,7 +2066,7 @@ node_t *parse(char *source) {
|
|
|
#define COMPASSIGN(lhs, s, rhs) {\
|
|
|
ASSIGN(node->a, {\
|
|
|
EMIT("qi_%s(state, ", s);\
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, (lhs));\
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, (lhs));\
|
|
|
EMIT(", ");\
|
|
|
rhs;\
|
|
|
EMIT(")");\
|
|
@@ -2060,9 +2074,9 @@ node_t *parse(char *source) {
|
|
|
}
|
|
|
#define COMPILE_ERROR(fmt, ...) { format_error(GETFNAME(node->fi), GETSRC(node->fi), node->pos, fmt, ##__VA_ARGS__); exit(1); }
|
|
|
|
|
|
-void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node);
|
|
|
+void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, stack_t *sstk, list_t *lbl, node_t *node);
|
|
|
|
|
|
-void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, list_t *seq) {
|
|
|
+void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, stack_t *sstk, list_t *lbl, list_t *seq) {
|
|
|
if (!seq || seq->length < 1) {
|
|
|
EMIT("NULL");
|
|
|
|
|
@@ -2079,7 +2093,7 @@ void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
for (size_t i = 0; i < seq->length; i++) {
|
|
|
buffer_fmt(tbuf, "qi_list_data(list, %d) = ", i);
|
|
|
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, lbl, seq->data[i]);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, sstk, lbl, seq->data[i]);
|
|
|
|
|
|
buffer_fmt(tbuf, ";\n");
|
|
|
}
|
|
@@ -2092,7 +2106,7 @@ void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
EMIT("__list%d(state)", gid);
|
|
|
}
|
|
|
|
|
|
-void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, table_t *table) {
|
|
|
+void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, stack_t *sstk, list_t *lbl, table_t *table) {
|
|
|
if (!table || table->used < 1) {
|
|
|
EMIT("NULL");
|
|
|
|
|
@@ -2109,7 +2123,7 @@ void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, li
|
|
|
table_iterate(table, {
|
|
|
buffer_fmt(tbuf, "qi_table_set(table, \"%s\", ", entry.key);
|
|
|
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, lbl, entry.value);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, sstk, lbl, entry.value);
|
|
|
|
|
|
buffer_fmt(tbuf, ");\n");
|
|
|
});
|
|
@@ -2139,6 +2153,20 @@ int in_context(list_t *ctx, char *s) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int in_switch(list_t *ctx) {
|
|
|
+ if (!ctx->length)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ for (ssize_t i = ctx->length - 1; i >= 0; i--) {
|
|
|
+ if (strcmp(ctx->data[i], "gap") == 0 || strcmp(ctx->data[i], "for") == 0)
|
|
|
+ break;
|
|
|
+ else if (strcmp(ctx->data[i], "switch") == 0)
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
size_t count_ctxs(list_t *ctx, char *s) {
|
|
|
if (!ctx->length)
|
|
|
return 0;
|
|
@@ -2163,6 +2191,10 @@ size_t count_ctxs(list_t *ctx, char *s) {
|
|
|
#define LPOP() stack_pop(lstk)
|
|
|
#define LID (lstk->data[lstk->length-1])
|
|
|
|
|
|
+#define SPUSH(i) stack_push(sstk, (i))
|
|
|
+#define SPOP() stack_pop(sstk)
|
|
|
+#define SID (sstk->data[sstk->length-1])
|
|
|
+
|
|
|
#define LBPUSH() list_push(lbl, table_new())
|
|
|
#define LBPOP() list_pop(lbl)
|
|
|
|
|
@@ -2175,7 +2207,7 @@ char *tempvar() {
|
|
|
return s;
|
|
|
}
|
|
|
|
|
|
-void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node, char *name) {
|
|
|
+void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, stack_t *sstk, list_t *lbl, node_t *node, char *name) {
|
|
|
NEWGID();
|
|
|
|
|
|
buffer_t *tbuf = buffer_new();
|
|
@@ -2198,7 +2230,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
optargc++;
|
|
|
|
|
|
buffer_fmt(tbuf, "qi_decl(state, \"%s\", pargc >= %d? qi_list_index(pargs, %d): ", entry.key, argc+1, argc);
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, lbl, pair->data[1]);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, sstk, lbl, pair->data[1]);
|
|
|
buffer_fmt(tbuf, ");\n");
|
|
|
} else
|
|
|
buffer_fmt(tbuf, "qi_decl(state, \"%s\", qi_list_index(pargs, %d));\n", entry.key, argc);
|
|
@@ -2207,7 +2239,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, sstk, lbl, node->a);
|
|
|
|
|
|
CTXPOP();
|
|
|
CTXPOP();
|
|
@@ -2221,7 +2253,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
tbuf = buffer_new();
|
|
|
|
|
|
buffer_fmt(tbuf, "qi_make_function(state, \"%s\", %d, __func%d, ", name? name: node->t? node->t->text: "<anon>", !node->h? 0: (node->h->used - optargc), gid);
|
|
|
- compile_table(gbuf, tbuf, ctx, lstk, lbl, node->h2);
|
|
|
+ compile_table(gbuf, tbuf, ctx, lstk, sstk, lbl, node->h2);
|
|
|
buffer_fmt(tbuf, ")");
|
|
|
|
|
|
if (node->tag == N_FUNCEXPR) {
|
|
@@ -2237,7 +2269,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
|
|
|
table_t *CONSTANTS;
|
|
|
|
|
|
-void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, list_t *block, int toplevel) {
|
|
|
+void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, stack_t *sstk, list_t *lbl, list_t *block, int toplevel) {
|
|
|
for (size_t i = 0; i < block->length; i++) {
|
|
|
node_t *node = block->data[i];
|
|
|
|
|
@@ -2254,7 +2286,7 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, li
|
|
|
table_set(CONSTANTS, name, entry.value);
|
|
|
});
|
|
|
} else if (node->tag == N_FUNCDEF) {
|
|
|
- compile_func(gbuf, buf, ctx, lstk, lbl, node, NULL);
|
|
|
+ compile_func(gbuf, buf, ctx, lstk, sstk, lbl, node, NULL);
|
|
|
|
|
|
EMIT("\n");
|
|
|
} else if (node->tag == N_CLASS) {
|
|
@@ -2288,9 +2320,9 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, li
|
|
|
|
|
|
buffer_fmt(tbuf, "qi_table_set(%s, \"%s\", ", triple->data[1] != NULL? "table": "metatable", t->text);
|
|
|
if (triple->data[1] == NULL)
|
|
|
- compile_func(gbuf, tbuf, ctx, lstk, lbl, triple->data[2], buffer_read(methodname));
|
|
|
+ compile_func(gbuf, tbuf, ctx, lstk, sstk, lbl, triple->data[2], buffer_read(methodname));
|
|
|
else
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, lbl, triple->data[2]);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, sstk, lbl, triple->data[2]);
|
|
|
buffer_fmt(tbuf, ");\n");
|
|
|
}
|
|
|
|
|
@@ -2326,7 +2358,7 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, li
|
|
|
if (n->tag == N_FUNCDEF)
|
|
|
continue;
|
|
|
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, n);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, n);
|
|
|
|
|
|
EMIT("\n");
|
|
|
}
|
|
@@ -2613,10 +2645,10 @@ const char *STD[][2] = {
|
|
|
" return bytes(r)\n"
|
|
|
" return r\n"
|
|
|
"}\n"
|
|
|
- "set_pseudomethod(\"list.reduce\", reduce)\n"
|
|
|
- "set_pseudomethod(\"tuple.reduce\", reduce)\n"
|
|
|
- "set_pseudomethod(\"string.reduce\", reduce)\n"
|
|
|
- "set_pseudomethod(\"bytes.reduce\", reduce)\n"
|
|
|
+ "set_pseudomethod(\"list.reduce\", func (xs, f): reduce(f, xs))\n"
|
|
|
+ "set_pseudomethod(\"tuple.reduce\", func (xs, f): reduce(f, xs))\n"
|
|
|
+ "set_pseudomethod(\"string.reduce\", func (xs, f): reduce(f, xs))\n"
|
|
|
+ "set_pseudomethod(\"bytes.reduce\", func (xs, f): reduce(f, xs))\n"
|
|
|
"func sum(xs)\n"
|
|
|
" return reduce(func (x, y): x + y, xs)\n"
|
|
|
"set_pseudomethod(\"list.sum\", sum)\n"
|
|
@@ -2643,10 +2675,10 @@ const char *STD[][2] = {
|
|
|
" return bytes(r)\n"
|
|
|
" return r\n"
|
|
|
"}\n"
|
|
|
- "set_pseudomethod(\"list.map\", map)\n"
|
|
|
- "set_pseudomethod(\"tuple.map\", map)\n"
|
|
|
- "set_pseudomethod(\"string.map\", map)\n"
|
|
|
- "set_pseudomethod(\"bytes.map\", map)\n"
|
|
|
+ "set_pseudomethod(\"list.map\", func (xs, f): map(f, xs))\n"
|
|
|
+ "set_pseudomethod(\"tuple.map\", func (xs, f): map(f, xs))\n"
|
|
|
+ "set_pseudomethod(\"string.map\", func (xs, f): map(f, xs))\n"
|
|
|
+ "set_pseudomethod(\"bytes.map\", func (xs, f): map(f, xs))\n"
|
|
|
"func filter(f, xs) {\n"
|
|
|
" if type(f) != \"function\"\n"
|
|
|
" throw \"expected first argument to be: function, but got: \" + type(f)\n"
|
|
@@ -2666,10 +2698,10 @@ const char *STD[][2] = {
|
|
|
" return bytes(r)\n"
|
|
|
" return r\n"
|
|
|
"}\n"
|
|
|
- "set_pseudomethod(\"list.filter\", filter)\n"
|
|
|
- "set_pseudomethod(\"tuple.filter\", filter)\n"
|
|
|
- "set_pseudomethod(\"string.filter\", filter)\n"
|
|
|
- "set_pseudomethod(\"bytes.filter\", filter)\n"
|
|
|
+ "set_pseudomethod(\"list.filter\", func (xs, f): filter(f, xs))\n"
|
|
|
+ "set_pseudomethod(\"tuple.filter\", func (xs, f): filter(f, xs))\n"
|
|
|
+ "set_pseudomethod(\"string.filter\", func (xs, f): filter(f, xs))\n"
|
|
|
+ "set_pseudomethod(\"bytes.filter\", func (xs, f): filter(f, xs))\n"
|
|
|
"func str_index(s, w) {\n"
|
|
|
" if s == \"\" || w == \"\"\n"
|
|
|
" return -1\n"
|
|
@@ -2715,6 +2747,16 @@ const char *STD[][2] = {
|
|
|
" return str_lstrip(str_rstrip(s, cs), cs)\n"
|
|
|
"}\n"
|
|
|
"set_pseudomethod(\"string.strip\", str_strip)\n"
|
|
|
+ "func table_get(t, k, d=nil) {\n"
|
|
|
+ " if type(t) != \"table\"\n"
|
|
|
+ " throw \"expected first argument to be: table, but got: \" + type(t)\n"
|
|
|
+ " if type(k) != \"string\"\n"
|
|
|
+ " throw \"expected second argument to be: string, but got: \" + type(k)\n"
|
|
|
+ " if k !in t\n"
|
|
|
+ " return d\n"
|
|
|
+ " return t[k]\n"
|
|
|
+ "}\n"
|
|
|
+ "set_pseudomethod(\"table.get\", table_get)\n"
|
|
|
"func zip() {\n"
|
|
|
" if !arguments\n"
|
|
|
" return []\n"
|
|
@@ -2734,6 +2776,18 @@ const char *STD[][2] = {
|
|
|
" return zip(table_keys(l), table_values(l))\n"
|
|
|
" else\n"
|
|
|
" return zip(range(len(l)), l)\n"
|
|
|
+ "func str_toupper(s) {\n"
|
|
|
+ " if type(s) != \"string\"\n"
|
|
|
+ " throw \"expected first argument to be: string, but got: \" + type(c)\n"
|
|
|
+ " return map(func (c): c >= 'a' && c <= 'z'? chr(ord(c) - 32): c, s)\n"
|
|
|
+ "}\n"
|
|
|
+ "set_pseudomethod(\"string.toupper\", str_toupper)\n"
|
|
|
+ "func str_tolower(s) {\n"
|
|
|
+ " if type(s) != \"string\"\n"
|
|
|
+ " throw \"expected first argument to be: string, but got: \" + type(c)\n"
|
|
|
+ " return map(func (c): c >= 'A' && c <= 'Z'? chr(ord(c) + 32): c, s)\n"
|
|
|
+ "}\n"
|
|
|
+ "set_pseudomethod(\"string.tolower\", str_tolower)\n"
|
|
|
"func Object(t, p=nil): return p !is nil? set_meta_table(p, get_meta_table(p) + t): set_meta_table({}, t)\n"
|
|
|
"func is_object(o): return has_meta_table(o)\n"
|
|
|
"func __class_wrapper(n, p, t, mt): return Object({\n"
|
|
@@ -2761,6 +2815,66 @@ const char *STD[][2] = {
|
|
|
" return obj\n"
|
|
|
" }\n"
|
|
|
"})\n"
|
|
|
+ "func format(s) {\n"
|
|
|
+ " if type(s) != \"string\"\n"
|
|
|
+ " throw \"expected first argument to be: string, but got: \" + type(s)\n"
|
|
|
+ " var r = \"\"\n"
|
|
|
+ " var n = 1\n"
|
|
|
+ " for var i = 0; i < len(s); i++\n"
|
|
|
+ " switch s[i] {\n"
|
|
|
+ " case '_'\n"
|
|
|
+ " if i+1 < len(s) && s[i+1] == '_' {\n"
|
|
|
+ " r += '_'\n"
|
|
|
+ " i++\n"
|
|
|
+ " continue\n"
|
|
|
+ " }\n"
|
|
|
+ " r += repr(arguments[n++])\n"
|
|
|
+ " break\n"
|
|
|
+ " default\n"
|
|
|
+ " r += s[i]\n"
|
|
|
+ " }\n"
|
|
|
+ " return r\n"
|
|
|
+ "}\n"
|
|
|
+ "set_pseudomethod(\"string.format\", format)\n"
|
|
|
+ "func formatl(s, l) {\n"
|
|
|
+ " if type(s) != \"string\"\n"
|
|
|
+ " throw \"expected first argument to be: string, but got: \" + type(s)\n"
|
|
|
+ " if type(l) != \"list\"\n"
|
|
|
+ " throw \"expected second argument to be: list, but got: \" + type(l)\n"
|
|
|
+ " return func_call(str_format, [s] + l)\n"
|
|
|
+ "}\n"
|
|
|
+ "set_pseudomethod(\"string.formatl\", formatl)\n"
|
|
|
+ "func formatd(s, t) {\n"
|
|
|
+ " if type(s) != \"string\"\n"
|
|
|
+ " throw \"expected first argument to be: string, but got: \" + type(s)\n"
|
|
|
+ " var r = \"\"\n"
|
|
|
+ " var n = 1\n"
|
|
|
+ " for var i = 0; i < len(s); i++\n"
|
|
|
+ " switch s[i] {\n"
|
|
|
+ " case '{'\n"
|
|
|
+ " if i+1 < len(s) && s[i+1] == '{' {\n"
|
|
|
+ " r += '{'\n"
|
|
|
+ " i++\n"
|
|
|
+ " continue\n"
|
|
|
+ " }\n"
|
|
|
+ " var k = ''\n"
|
|
|
+ " i++\n"
|
|
|
+ " for i < len(s) && s[i] != '}'\n"
|
|
|
+ " k += s[i++]\n"
|
|
|
+ " if i >= len(s) || s[i] != '}'\n"
|
|
|
+ " throw \"unmatched { in format specifier\"\n"
|
|
|
+ " if !k\n"
|
|
|
+ " throw \"empty format key\"\n"
|
|
|
+ " r += repr(t[k])\n"
|
|
|
+ " break\n"
|
|
|
+ " default\n"
|
|
|
+ " r += s[i]\n"
|
|
|
+ " }\n"
|
|
|
+ " return r\n"
|
|
|
+ "}\n"
|
|
|
+ "set_pseudomethod(\"string.formatd\", formatd)\n"
|
|
|
+ "func getch() return chr(fgetc(STDIN))\n"
|
|
|
+ "func putch(c) fputc(STDOUT, c)\n"
|
|
|
"func getline()\n"
|
|
|
" return fgets(STDIN, 256)\n"
|
|
|
"func input() {\n"
|
|
@@ -2805,6 +2919,85 @@ const char *STD[][2] = {
|
|
|
"}\n"
|
|
|
},
|
|
|
|
|
|
+ {"thread",
|
|
|
+ "func thread_create(fn, args=[]) {\n"
|
|
|
+ " if type(fn) != \"function\"\n"
|
|
|
+ " throw \"expected first argument to be: function, but got: \" + type(fn)\n"
|
|
|
+ " if type(args) != \"list\"\n"
|
|
|
+ " throw \"expected second argument to be: list, but got: \" + type(args)\n"
|
|
|
+ " inline `qi_value_t *args = qi_get(state, \"args\")`\n"
|
|
|
+ " inline `qi_list_t *list`\n"
|
|
|
+ " inline `LOCKED(args, {list = qi_list_copy(args->value.list);})`\n"
|
|
|
+ " inline `void *td = qi_thread_create(state, qi_get(state, \"fn\"), list)`\n"
|
|
|
+ " inline `qi_decl(state, \"td\", qi_make_data(state, 'T', td))`\n"
|
|
|
+ " return Object({\n"
|
|
|
+ " __str: func (this): \"<Thread>\",\n"
|
|
|
+ " _td: td,\n"
|
|
|
+ " joined: false,\n"
|
|
|
+ " join: func (this) {\n"
|
|
|
+ " if this.joined\n"
|
|
|
+ " return\n"
|
|
|
+ " var td = this._td\n"
|
|
|
+ " inline `qi_value_t *ret = qi_thread_join(state, qi_get_data(state, 'T', qi_get(state, \"td\")))`\n"
|
|
|
+ " this.joined = true\n"
|
|
|
+ " inline `return ret`\n"
|
|
|
+ " }\n"
|
|
|
+ " })\n"
|
|
|
+ "}\n"
|
|
|
+ "func Thread(fn, args=[]): Object({\n"
|
|
|
+ " __str: func (this) use (fn, args): format(\"<Thread _ _>\", fn, args),\n"
|
|
|
+ " _thread: nil,\n"
|
|
|
+ " start: func (this) use (fn, args) {\n"
|
|
|
+ " if this._thread !is nil\n"
|
|
|
+ " return\n"
|
|
|
+ " this._thread = thread_create(fn, args)\n"
|
|
|
+ " return this\n"
|
|
|
+ " },\n"
|
|
|
+ " join: func (this) {\n"
|
|
|
+ " if this._thread !is nil\n"
|
|
|
+ " return this._thread.join()\n"
|
|
|
+ " },\n"
|
|
|
+ " is_joined: func (this): this._thread.joined\n"
|
|
|
+ "})\n"
|
|
|
+ "func Lock(acquired=false) {\n"
|
|
|
+ " inline `void *lock = qi_lock_create()`\n"
|
|
|
+ " inline `if (!lock) qi_throw_format(state, \"lock init failed\")`\n"
|
|
|
+ " inline `qi_decl(state, \"lock\", qi_make_data(state, 'L', lock))`\n"
|
|
|
+ " var l = Object({\n"
|
|
|
+ " __fin: func (this) {\n"
|
|
|
+ " var lock = this._lock\n"
|
|
|
+ " this._lock = nil\n"
|
|
|
+ " inline `qi_lock_destroy(qi_get_data(state, 'L', qi_get(state, \"lock\")))`\n"
|
|
|
+ " },\n"
|
|
|
+ " __str: func (this): \"<Lock>\",\n"
|
|
|
+ " _lock: lock,\n"
|
|
|
+ " acquired: func (this) {\n"
|
|
|
+ " var lock = this._lock\n"
|
|
|
+ " inline `return qi_make_boolean(state, qi_lock_acquired(qi_get_data(state, 'L', qi_get(state, \"lock\"))))`\n"
|
|
|
+ " },\n"
|
|
|
+ " acquire: func (this) {\n"
|
|
|
+ " var lock = this._lock\n"
|
|
|
+ " inline `qi_lock_acquire(qi_get_data(state, 'L', qi_get(state, \"lock\")))`\n"
|
|
|
+ " },\n"
|
|
|
+ " tryacquire: func (this) {\n"
|
|
|
+ " var lock = this._lock\n"
|
|
|
+ " inline `return qi_make_boolean(state, qi_lock_tryacquire(qi_get_data(state, 'L', qi_get(state, \"lock\"))))`\n"
|
|
|
+ " },\n"
|
|
|
+ " release: func (this) {\n"
|
|
|
+ " var lock = this._lock\n"
|
|
|
+ " inline `qi_lock_release(qi_get_data(state, 'L', qi_get(state, \"lock\")))`\n"
|
|
|
+ " }\n"
|
|
|
+ " })\n"
|
|
|
+ " if acquired\n"
|
|
|
+ " l.acquire()\n"
|
|
|
+ " return l\n"
|
|
|
+ "}\n"
|
|
|
+ "func thread_exit(ret=nil)\n"
|
|
|
+ " inline `qi_thread_exit(state, qi_get(state, \"ret\"))`\n"
|
|
|
+ "func is_main_thread()\n"
|
|
|
+ " inline `return qi_make_boolean(state, qi_thread_main())`\n"
|
|
|
+ },
|
|
|
+
|
|
|
{"str",
|
|
|
"let STR_LETTERS = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n"
|
|
|
"let STR_ASCII_LC = \"abcdefghijklmnopqrstuvwxyz\"\n"
|
|
@@ -2941,9 +3134,9 @@ char *unescape(char *s) {
|
|
|
return buffer_read(buf);
|
|
|
}
|
|
|
|
|
|
-void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl);
|
|
|
+void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, stack_t *sstk, list_t *lbl);
|
|
|
|
|
|
-int require_once(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, char *path) {
|
|
|
+int require_once(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, stack_t *sstk, list_t *lbl, char *path) {
|
|
|
char *source = NULL;
|
|
|
|
|
|
for (size_t i = 0; STD[i][0]; i++) {
|
|
@@ -2983,7 +3176,7 @@ int require_once(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list
|
|
|
|
|
|
list_push(FILES, pair);
|
|
|
|
|
|
- compile_into(source, gbuf, buf, ctx, lstk, lbl);
|
|
|
+ compile_into(source, gbuf, buf, ctx, lstk, sstk, lbl);
|
|
|
|
|
|
list_pop(FILES);
|
|
|
list_push(REQUIRED, path);
|
|
@@ -2991,15 +3184,17 @@ int require_once(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node) {
|
|
|
+buffer_t *HBUF;
|
|
|
+
|
|
|
+void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, stack_t *sstk, list_t *lbl, node_t *node) {
|
|
|
switch (node->tag) {
|
|
|
case N_TOPLEVEL: case N_PROGRAM:
|
|
|
- compile_block(gbuf, buf, ctx, lstk, lbl, node->l, node->tag == N_TOPLEVEL);
|
|
|
+ compile_block(gbuf, buf, ctx, lstk, sstk, lbl, node->l, node->tag == N_TOPLEVEL);
|
|
|
break;
|
|
|
|
|
|
case N_EXPRSTMT:
|
|
|
EMIT("(void)(");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT(");");
|
|
|
break;
|
|
|
|
|
@@ -3007,7 +3202,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
LBPUSH();
|
|
|
CTXPUSH("scope");
|
|
|
EMIT("qi_new_scope(state);\n");
|
|
|
- compile_block(gbuf, buf, ctx, lstk, lbl, node->l, 0);
|
|
|
+ compile_block(gbuf, buf, ctx, lstk, sstk, lbl, node->l, 0);
|
|
|
EMIT("qi_old_scope(state);");
|
|
|
CTXPOP();
|
|
|
LBPOP();
|
|
@@ -3052,7 +3247,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
node_t *n = table_get(CONSTANTS, name);
|
|
|
|
|
|
if (n)
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, n);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, n);
|
|
|
else
|
|
|
EMIT("qi_get(state, \"%s\")", name);
|
|
|
} break;
|
|
@@ -3064,13 +3259,13 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
|
|
|
case N_LIST:
|
|
|
EMIT("qi_make_list(state, ");
|
|
|
- compile_list(gbuf, buf, ctx, lstk, lbl, node->l);
|
|
|
+ compile_list(gbuf, buf, ctx, lstk, sstk, lbl, node->l);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
|
case N_TUPLE:
|
|
|
EMIT("qi_make_tuple(state, ");
|
|
|
- compile_list(gbuf, buf, ctx, lstk, lbl, node->l);
|
|
|
+ compile_list(gbuf, buf, ctx, lstk, sstk, lbl, node->l);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
@@ -3078,43 +3273,43 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
|
|
|
case N_TABLE:
|
|
|
EMIT("qi_make_table(state, ");
|
|
|
- compile_table(gbuf, buf, ctx, lstk, lbl, node->h);
|
|
|
+ compile_table(gbuf, buf, ctx, lstk, sstk, lbl, node->h);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
|
case N_CALL:
|
|
|
EMIT("qi_call(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT(", ");
|
|
|
- compile_list(gbuf, buf, ctx, lstk, lbl, node->l);
|
|
|
+ compile_list(gbuf, buf, ctx, lstk, sstk, lbl, node->l);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
|
case N_MEMBER:
|
|
|
EMIT("qi_index(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT(", qi_make_string(state, \"%s\"))", node->t->text);
|
|
|
break;
|
|
|
|
|
|
case N_INDEX:
|
|
|
EMIT("qi_index(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT(", ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
|
- case N_ASSIGN: ASSIGN(node->a, compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN: ASSIGN(node->a, compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b)); break;
|
|
|
|
|
|
- case N_ASSIGN_ADD: COMPASSIGN(node->a, "add", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
- case N_ASSIGN_SUB: COMPASSIGN(node->a, "sub", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
- case N_ASSIGN_MUL: COMPASSIGN(node->a, "mul", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
- case N_ASSIGN_DIV: COMPASSIGN(node->a, "div", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
- case N_ASSIGN_IDIV: COMPASSIGN(node->a, "idiv", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
- case N_ASSIGN_MOD: COMPASSIGN(node->a, "mod", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
- case N_ASSIGN_POW: COMPASSIGN(node->a, "pow", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
- case N_ASSIGN_BOR: COMPASSIGN(node->a, "bor", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
- case N_ASSIGN_BAND: COMPASSIGN(node->a, "band", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_ADD: COMPASSIGN(node->a, "add", compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_SUB: COMPASSIGN(node->a, "sub", compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_MUL: COMPASSIGN(node->a, "mul", compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_DIV: COMPASSIGN(node->a, "div", compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_IDIV: COMPASSIGN(node->a, "idiv", compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_MOD: COMPASSIGN(node->a, "mod", compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_POW: COMPASSIGN(node->a, "pow", compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_BOR: COMPASSIGN(node->a, "bor", compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b)); break;
|
|
|
+ case N_ASSIGN_BAND: COMPASSIGN(node->a, "band", compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b)); break;
|
|
|
|
|
|
case N_INC:
|
|
|
COMPASSIGN(node->a, "add", EMIT("state->one"));
|
|
@@ -3129,7 +3324,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
EMIT("qi_%s(state, \"%s\", ", node->tag == N_LET? "decl_const": "decl", entry.key);
|
|
|
|
|
|
if (entry.value)
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, entry.value);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, entry.value);
|
|
|
else EMIT("state->nil");
|
|
|
|
|
|
EMIT(");\n");
|
|
@@ -3140,7 +3335,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
char *varname = tempvar();
|
|
|
|
|
|
EMIT("qi_value_t *%s = ", varname);
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT(";\n");
|
|
|
|
|
|
for (size_t i = 0; i < node->l->length; i++)
|
|
@@ -3155,12 +3350,12 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
|
|
|
case N_IF:
|
|
|
EMIT("if (_qi_truthy(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT(")) {\n");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b);
|
|
|
if (node->c) {
|
|
|
EMIT("} else {\n");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->c);
|
|
|
}
|
|
|
EMIT("}");
|
|
|
break;
|
|
@@ -3170,7 +3365,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
char *varname = tempvar();
|
|
|
|
|
|
EMIT("qi_value_t *%s = ", varname);
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT(";\n");
|
|
|
|
|
|
for (size_t i = 0; i < node->l->length; i++) {
|
|
@@ -3178,7 +3373,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
char *label = tempvar();
|
|
|
|
|
|
EMIT("if (_qi_equals(state, %s, ", varname);
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, pair->data[0]);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, pair->data[0]);
|
|
|
EMIT(")) goto %s;\n", label);
|
|
|
|
|
|
pair->data[0] = label;
|
|
@@ -3186,7 +3381,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
|
|
|
EMIT("goto __default%d;\n", gid);
|
|
|
|
|
|
- LPUSH(gid);
|
|
|
+ SPUSH(gid);
|
|
|
CTXPUSH("switch");
|
|
|
|
|
|
for (size_t i = 0; i < node->l->length; i++) {
|
|
@@ -3195,16 +3390,16 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
node_t *block = pair->data[1];
|
|
|
|
|
|
EMIT("%s:;\n", label);
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, block);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, block);
|
|
|
}
|
|
|
|
|
|
EMIT("__default%d:;\n", gid);
|
|
|
|
|
|
if (node->b)
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b);
|
|
|
|
|
|
CTXPOP();
|
|
|
- LPOP();
|
|
|
+ SPOP();
|
|
|
|
|
|
EMIT("__break%d:;\n", gid);
|
|
|
} break;
|
|
@@ -3216,23 +3411,23 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
EMIT("for (;;) {\n");
|
|
|
} else if (node->a && !node->b) {
|
|
|
EMIT("while (_qi_truthy(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT(")) {\n");
|
|
|
} else {
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT("while (_qi_truthy(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b);
|
|
|
EMIT(")) {\n");
|
|
|
}
|
|
|
|
|
|
LPUSH(gid);
|
|
|
CTXPUSH("for");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->d);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->d);
|
|
|
|
|
|
EMIT("__continue%d:;\n", gid);
|
|
|
|
|
|
if (node->c) {
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->c);
|
|
|
|
|
|
EMIT(";\n");
|
|
|
}
|
|
@@ -3250,7 +3445,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
char *varname = tempvar();
|
|
|
|
|
|
EMIT("qi_value_t *%s = qi_iter(state, ", varname);
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT(");\n");
|
|
|
|
|
|
if (node->tag == N_FOROFVAR) {
|
|
@@ -3270,7 +3465,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
|
|
|
LPUSH(gid);
|
|
|
CTXPUSH("for");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b);
|
|
|
CTXPOP();
|
|
|
LPOP();
|
|
|
|
|
@@ -3284,7 +3479,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
if (!INCTX("for") && !INCTX("switch"))
|
|
|
COMPILE_ERROR("break outside of a loop or a switch");
|
|
|
|
|
|
- EMIT("goto __break%d;", LID);
|
|
|
+ EMIT("goto __break%d;", in_switch(ctx)? SID: LID);
|
|
|
break;
|
|
|
|
|
|
case N_CONTINUE:
|
|
@@ -3303,7 +3498,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
|
|
|
LBPUSH();
|
|
|
CTXPUSH("gap");
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, sstk, lbl, node->a);
|
|
|
CTXPOP();
|
|
|
LBPOP();
|
|
|
|
|
@@ -3328,7 +3523,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
EMIT("return ");
|
|
|
|
|
|
if (node->a)
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
else EMIT("state->nil");
|
|
|
|
|
|
EMIT(";");
|
|
@@ -3340,12 +3535,12 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
|
|
|
case N_TRY:
|
|
|
EMIT("qi_try(state, {\n");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT("}, {\n");
|
|
|
if (node->t)
|
|
|
EMIT("qi_decl(state, \"%s\", trap->value);\n", node->t->text);
|
|
|
CTXPUSH("trap");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b);
|
|
|
CTXPOP();
|
|
|
EMIT("}, NULL);\n");
|
|
|
break;
|
|
@@ -3353,7 +3548,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
case N_THROW:
|
|
|
EMIT("qi_throw(state, ");
|
|
|
if (node->a)
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
else {
|
|
|
EMIT("state->nil");
|
|
|
}
|
|
@@ -3378,22 +3573,22 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
case N_REQUIRE: {
|
|
|
char *path = unescape(node->t->text);
|
|
|
|
|
|
- if (require_once(gbuf, buf, ctx, lstk, lbl, path) < 0)
|
|
|
+ if (require_once(gbuf, buf, ctx, lstk, sstk, lbl, path) < 0)
|
|
|
COMPILE_ERROR("'%s' is not a valid file path or a builtin library name", path);
|
|
|
} break;
|
|
|
|
|
|
case N_IFEXPR:
|
|
|
EMIT("(_qi_truthy(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->a);
|
|
|
EMIT(")? ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->b);
|
|
|
EMIT(": ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, node->c);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
|
case N_FUNCEXPR:
|
|
|
- compile_func(gbuf, buf, ctx, lstk, lbl, node, NULL);
|
|
|
+ compile_func(gbuf, buf, ctx, lstk, sstk, lbl, node, NULL);
|
|
|
break;
|
|
|
|
|
|
case N_EQUALS:
|
|
@@ -3505,35 +3700,38 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
break;
|
|
|
|
|
|
case N_INLINE: EMIT("%s;", unescape(node->t->text)); break;
|
|
|
+ case N_HEADER: buffer_fmt(HBUF, "%s\n", unescape(node->t->text)); break;
|
|
|
|
|
|
default:
|
|
|
COMPILE_ERROR("not yet implemented");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl) {
|
|
|
+void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, stack_t *sstk, list_t *lbl) {
|
|
|
node_t *n = parse(source);
|
|
|
|
|
|
- compile_node(gbuf, buf, ctx, lstk, lbl, n);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, sstk, lbl, n);
|
|
|
}
|
|
|
|
|
|
char *compile(char *source) {
|
|
|
list_t *ctx = list_new();
|
|
|
stack_t *lstk = stack_new();
|
|
|
+ stack_t *sstk = stack_new();
|
|
|
list_t *lbl = list_new();
|
|
|
LBPUSH();
|
|
|
|
|
|
buffer_t *gbuf = buffer_new();
|
|
|
|
|
|
- buffer_appends(gbuf, "#include <qirt.h>\n");
|
|
|
-
|
|
|
buffer_t *buf = buffer_new();
|
|
|
|
|
|
- require_once(gbuf, buf, ctx, lstk, lbl, "std");
|
|
|
- compile_into(source, gbuf, buf, ctx, lstk, lbl);
|
|
|
+ require_once(gbuf, buf, ctx, lstk, sstk, lbl, "std");
|
|
|
+ compile_into(source, gbuf, buf, ctx, lstk, sstk, lbl);
|
|
|
|
|
|
buffer_t *rbuf = buffer_new();
|
|
|
|
|
|
+ buffer_appends(rbuf, "#include <qirt.h>\n");
|
|
|
+ buffer_appendb(rbuf, HBUF);
|
|
|
+
|
|
|
buffer_appendb(rbuf, gbuf);
|
|
|
|
|
|
buffer_appends(rbuf, "int main(int argc, char **argv) {\n");
|
|
@@ -3579,6 +3777,7 @@ int main(int argc, char **argv) {
|
|
|
FILES = list_new();
|
|
|
REQUIRED = list_new();
|
|
|
CONSTANTS = table_new();
|
|
|
+ HBUF = buffer_new();
|
|
|
|
|
|
genmathlib();
|
|
|
|