|
@@ -199,7 +199,7 @@ table_t *table_set(table_t *table, char *key, void *value) {
|
|
|
|
|
|
#define table_iterate(table, code) \
|
|
|
{ \
|
|
|
- if (table->used) { \
|
|
|
+ if ((table)->used) { \
|
|
|
size_t i = 0; \
|
|
|
while (i < (table)->capacity) { \
|
|
|
entry_t entry = (table)->entries[i]; \
|
|
@@ -278,6 +278,7 @@ typedef struct {
|
|
|
T_NAME,
|
|
|
|
|
|
T_VAR,
|
|
|
+ T_LET,
|
|
|
T_IF,
|
|
|
T_ELSE,
|
|
|
T_ELIF,
|
|
@@ -293,6 +294,7 @@ typedef struct {
|
|
|
T_TRY,
|
|
|
T_CATCH,
|
|
|
T_THROW,
|
|
|
+ T_GOTO,
|
|
|
|
|
|
T_LPAR,
|
|
|
T_RPAR,
|
|
@@ -517,6 +519,8 @@ token_t *next_token(char *source, size_t *pos) {
|
|
|
|
|
|
if (strcmp(name, "var") == 0)
|
|
|
return TK(VAR);
|
|
|
+ else if (strcmp(name, "let") == 0)
|
|
|
+ return TK(LET);
|
|
|
else if (strcmp(name, "if") == 0)
|
|
|
return TK(IF);
|
|
|
else if (strcmp(name, "else") == 0)
|
|
@@ -547,6 +551,8 @@ token_t *next_token(char *source, size_t *pos) {
|
|
|
return TK(CATCH);
|
|
|
else if (strcmp(name, "throw") == 0)
|
|
|
return TK(THROW);
|
|
|
+ else if (strcmp(name, "goto") == 0)
|
|
|
+ return TK(GOTO);
|
|
|
|
|
|
return token(T_NAME, name);
|
|
|
} else if (strncmp(&source[*pos], "==", 2) == 0 && ++(*pos) && ++(*pos))
|
|
@@ -664,6 +670,7 @@ struct _node_t {
|
|
|
N_DEC,
|
|
|
|
|
|
N_VAR,
|
|
|
+ N_LET,
|
|
|
N_IF,
|
|
|
N_FOR,
|
|
|
N_BREAK,
|
|
@@ -675,6 +682,8 @@ struct _node_t {
|
|
|
N_REQUIRE,
|
|
|
N_TRY,
|
|
|
N_THROW,
|
|
|
+ N_LABEL,
|
|
|
+ N_GOTO,
|
|
|
|
|
|
N_IFEXPR,
|
|
|
N_FUNCEXPR,
|
|
@@ -852,6 +861,7 @@ node_t *nodef(int tag, token_t *name, table_t *params, table_t *captured, node_t
|
|
|
#define NODEF(n, a, b, c, d) (node_pos(nodef(N_##n, (a), (b), (c), (d)), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
|
|
|
#define AT(tk) (*pos < tokens->length && ((token_t *)tokens->data[*pos])->tag == T_##tk)
|
|
|
+#define ATP(tk, p) ((*pos)+p < tokens->length && ((token_t *)tokens->data[(*pos)+p])->tag == T_##tk)
|
|
|
#define MATCH(tk) (AT(tk) && ++(*pos))
|
|
|
#define PARSE_ERROR(fmt, ...) { format_error(GETFNAME(((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi), GETSRC(((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos, fmt, ##__VA_ARGS__); exit(1); }
|
|
|
#define EXPECT(tk, s) { if (!MATCH(tk)) PARSE_ERROR("expected %s", (s)); }
|
|
@@ -1235,7 +1245,7 @@ node_t *parse_if(list_t *tokens, size_t *pos) {
|
|
|
return NODE3(IF, a, b, c);
|
|
|
}
|
|
|
|
|
|
-node_t *parse_var(list_t *tokens, size_t *pos) {
|
|
|
+node_t *parse_var(list_t *tokens, size_t *pos, int is_let) {
|
|
|
table_t *h = table_new();
|
|
|
|
|
|
do {
|
|
@@ -1245,12 +1255,19 @@ node_t *parse_var(list_t *tokens, size_t *pos) {
|
|
|
char *k = ((token_t *)tokens->data[(*pos)++])->text;
|
|
|
node_t *v = NULL;
|
|
|
|
|
|
- if (MATCH(ASSIGN))
|
|
|
+ if (is_let) {
|
|
|
+ EXPECT(ASSIGN, "=");
|
|
|
+
|
|
|
+ v = parse_expr(tokens, pos);
|
|
|
+ } else if (MATCH(ASSIGN))
|
|
|
v = parse_expr(tokens, pos);
|
|
|
|
|
|
table_set(h, k, v);
|
|
|
} while (MATCH(COMMA));
|
|
|
|
|
|
+ if (is_let)
|
|
|
+ return NODEH(LET, h);
|
|
|
+
|
|
|
return NODEH(VAR, h);
|
|
|
}
|
|
|
|
|
@@ -1350,7 +1367,9 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
|
|
|
return NODEL(BLOCK, stmts);
|
|
|
} else if (MATCH(VAR))
|
|
|
- return parse_var(tokens, pos);
|
|
|
+ return parse_var(tokens, pos, 0);
|
|
|
+ else if (MATCH(LET))
|
|
|
+ return parse_var(tokens, pos, 1);
|
|
|
else if (MATCH(IF))
|
|
|
return parse_if(tokens, pos);
|
|
|
else if (MATCH(FOR)) {
|
|
@@ -1360,7 +1379,7 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
|
|
|
if (!AT(LCB) && !AT(COLON)) {
|
|
|
if (MATCH(VAR)) {
|
|
|
- a = parse_var(tokens, pos);
|
|
|
+ a = parse_var(tokens, pos, 0);
|
|
|
EXPECT(SEMI, ";");
|
|
|
b = parse_expr(tokens, pos);
|
|
|
EXPECT(SEMI, ";");
|
|
@@ -1414,6 +1433,19 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
a = parse_expr(tokens, pos);
|
|
|
|
|
|
return NODE1(THROW, a);
|
|
|
+ } else if (MATCH(GOTO)) {
|
|
|
+ if(!AT(NAME))
|
|
|
+ PARSE_ERROR("expected identifier");
|
|
|
+
|
|
|
+ token_t *t = tokens->data[(*pos)++];
|
|
|
+
|
|
|
+ return NODET(GOTO, t);
|
|
|
+ } else if (AT(NAME) && ATP(COLON, 1) && !CLIFF) {
|
|
|
+ token_t *t = tokens->data[(*pos)++];
|
|
|
+
|
|
|
+ EXPECT(COLON, ":");
|
|
|
+
|
|
|
+ return NODET(LABEL, t);
|
|
|
}
|
|
|
|
|
|
node_t *n = parse_expr(tokens, pos);
|
|
@@ -1461,8 +1493,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, node->a); EMIT(", "); compile_node(gbuf, buf, ctx, lstk, node->b); EMIT(")"); }
|
|
|
-#define UNOP(s) { EMIT("qi_" s "(state, "); compile_node(gbuf, buf, ctx, lstk, node->a); EMIT(")"); }
|
|
|
+#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 ASSIGN(lhs, rhs) {\
|
|
|
if ((lhs)->tag == N_LITERAL && (lhs)->t->tag == T_NAME) {\
|
|
|
EMIT("qi_set(state, false, \"%s\", ", (lhs)->t->text);\
|
|
@@ -1470,15 +1502,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, (lhs)->a);\
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, (lhs)->a);\
|
|
|
EMIT(", ");\
|
|
|
- compile_node(gbuf, buf, ctx, lstk, (lhs)->b);\
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, (lhs)->b);\
|
|
|
EMIT(", ");\
|
|
|
rhs;\
|
|
|
EMIT(")");\
|
|
|
} else if ((lhs)->tag == N_MEMBER) {\
|
|
|
EMIT("qi_index_set(state, false, ");\
|
|
|
- compile_node(gbuf, buf, ctx, lstk, (lhs)->a);\
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, (lhs)->a);\
|
|
|
EMIT(", qi_make_string(state, \"%s\"), ", (lhs)->t->text);\
|
|
|
rhs;\
|
|
|
EMIT(")");\
|
|
@@ -1487,7 +1519,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, (lhs));\
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, (lhs));\
|
|
|
EMIT(", ");\
|
|
|
rhs;\
|
|
|
EMIT(")");\
|
|
@@ -1495,9 +1527,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, node_t *node);
|
|
|
+void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node);
|
|
|
|
|
|
-void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *seq) {
|
|
|
+void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, list_t *seq) {
|
|
|
if (!seq || seq->length < 1) {
|
|
|
EMIT("NULL");
|
|
|
|
|
@@ -1514,7 +1546,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_push(list, ");
|
|
|
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, seq->data[i]);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, lbl, seq->data[i]);
|
|
|
|
|
|
buffer_fmt(tbuf, ");\n");
|
|
|
}
|
|
@@ -1527,7 +1559,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, table_t *table) {
|
|
|
+void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, table_t *table) {
|
|
|
if (!table || table->used < 1) {
|
|
|
EMIT("NULL");
|
|
|
|
|
@@ -1544,7 +1576,7 @@ void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, ta
|
|
|
table_iterate(table, {
|
|
|
buffer_fmt(tbuf, "qi_table_set(table, \"%s\", ", entry.key);
|
|
|
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, entry.value);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, lbl, entry.value);
|
|
|
|
|
|
buffer_fmt(tbuf, ");\n");
|
|
|
});
|
|
@@ -1598,13 +1630,17 @@ size_t count_ctxs(list_t *ctx, char *s) {
|
|
|
#define LPOP() stack_pop(lstk)
|
|
|
#define LID (lstk->data[lstk->length-1])
|
|
|
|
|
|
-void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, node_t *node) {
|
|
|
+#define LBPUSH() list_push(lbl, table_new())
|
|
|
+#define LBPOP() list_pop(lbl)
|
|
|
+
|
|
|
+void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node) {
|
|
|
NEWGID();
|
|
|
|
|
|
buffer_t *tbuf = buffer_new();
|
|
|
|
|
|
buffer_fmt(tbuf, "qi_value_t *__func%d(qi_state_t *state, qi_size_t pargc, qi_list_t *pargs) {\n", gid);
|
|
|
|
|
|
+ LBPUSH();
|
|
|
CTXPUSH("gap");
|
|
|
CTXPUSH("func");
|
|
|
|
|
@@ -1620,7 +1656,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
optargc++;
|
|
|
|
|
|
buffer_fmt(tbuf, "qi_set(state, false, \"%s\", pargc >= %d? qi_list_index(pargs, %d): ", entry.key, argc+1, argc);
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, pair->data[1]);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, lbl, pair->data[1]);
|
|
|
buffer_fmt(tbuf, ");\n");
|
|
|
} else
|
|
|
buffer_fmt(tbuf, "qi_set(state, false, \"%s\", qi_list_index(pargs, %d));\n", entry.key, argc);
|
|
@@ -1629,10 +1665,11 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, lbl, node->a);
|
|
|
|
|
|
CTXPOP();
|
|
|
CTXPOP();
|
|
|
+ LBPOP();
|
|
|
|
|
|
buffer_fmt(tbuf, "return state->nil;\n");
|
|
|
buffer_fmt(tbuf, "}\n");
|
|
@@ -1642,7 +1679,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
tbuf = buffer_new();
|
|
|
|
|
|
buffer_fmt(tbuf, "qi_make_function(state, \"%s\", %d, __func%d, ", node->t? node->t->text: "<anon>", !node->h? 0: (node->h->used - optargc), gid);
|
|
|
- compile_table(gbuf, tbuf, ctx, lstk, node->h2);
|
|
|
+ compile_table(gbuf, tbuf, ctx, lstk, lbl, node->h2);
|
|
|
buffer_fmt(tbuf, ")");
|
|
|
|
|
|
if (node->tag == N_FUNCEXPR) {
|
|
@@ -1656,20 +1693,20 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
EMIT(");");
|
|
|
}
|
|
|
|
|
|
-void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *block) {
|
|
|
+void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, list_t *block) {
|
|
|
for (size_t i = 0; i < block->length; i++) {
|
|
|
node_t *n = block->data[i];
|
|
|
|
|
|
if (n->tag == N_FUNCDEF) {
|
|
|
- compile_func(gbuf, buf, ctx, lstk, n);
|
|
|
+ compile_func(gbuf, buf, ctx, lstk, lbl, n);
|
|
|
|
|
|
EMIT("\n");
|
|
|
- } else if (n->tag == N_VAR) {
|
|
|
+ } else if (n->tag == N_VAR || n->tag == N_LET) {
|
|
|
table_iterate(n->h, {
|
|
|
- EMIT("qi_decl(state, \"%s\", ", entry.key);
|
|
|
+ EMIT("qi_%s(state, \"%s\", ", n->tag == N_LET? "decl_const": "decl", entry.key);
|
|
|
|
|
|
if (entry.value)
|
|
|
- compile_node(gbuf, buf, ctx, lstk, entry.value);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, entry.value);
|
|
|
else EMIT("state->nil");
|
|
|
|
|
|
EMIT(");\n");
|
|
@@ -1678,37 +1715,40 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, li
|
|
|
}
|
|
|
|
|
|
for (size_t i = 0; i < block->length; i++) {
|
|
|
- compile_node(gbuf, buf, ctx, lstk, block->data[i]);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, block->data[i]);
|
|
|
|
|
|
EMIT("\n");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#define STD_SIZE 1
|
|
|
-const char *STD[STD_SIZE][2] = {
|
|
|
+const char *STD[][2] = {
|
|
|
{"std", "func head(l): return l[0]"},
|
|
|
+
|
|
|
+ {NULL, NULL}
|
|
|
};
|
|
|
|
|
|
-void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctk, stack_t *lstk);
|
|
|
+void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl);
|
|
|
|
|
|
-void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, node_t *node) {
|
|
|
+void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node) {
|
|
|
switch (node->tag) {
|
|
|
case N_PROGRAM:
|
|
|
- compile_block(gbuf, buf, ctx, lstk, node->l);
|
|
|
+ compile_block(gbuf, buf, ctx, lstk, lbl, node->l);
|
|
|
break;
|
|
|
|
|
|
case N_EXPRSTMT:
|
|
|
EMIT("(void)(");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
EMIT(");");
|
|
|
break;
|
|
|
|
|
|
case N_BLOCK:
|
|
|
+ LBPUSH();
|
|
|
CTXPUSH("scope");
|
|
|
EMIT("qi_new_scope(state);\n");
|
|
|
- compile_block(gbuf, buf, ctx, lstk, node->l);
|
|
|
+ compile_block(gbuf, buf, ctx, lstk, lbl, node->l);
|
|
|
EMIT("qi_old_scope(state);");
|
|
|
CTXPOP();
|
|
|
+ LBPOP();
|
|
|
break;
|
|
|
|
|
|
case N_LITERAL:
|
|
@@ -1736,13 +1776,13 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
|
|
|
case N_LIST:
|
|
|
EMIT("qi_make_list(state, ");
|
|
|
- compile_list(gbuf, buf, ctx, lstk, node->l);
|
|
|
+ compile_list(gbuf, buf, ctx, lstk, lbl, node->l);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
|
case N_TUPLE:
|
|
|
EMIT("qi_make_tuple(state, ");
|
|
|
- compile_list(gbuf, buf, ctx, lstk, node->l);
|
|
|
+ compile_list(gbuf, buf, ctx, lstk, lbl, node->l);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
@@ -1750,35 +1790,35 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
|
|
|
case N_TABLE:
|
|
|
EMIT("qi_make_table(state, ");
|
|
|
- compile_table(gbuf, buf, ctx, lstk, node->h);
|
|
|
+ compile_table(gbuf, buf, ctx, lstk, lbl, node->h);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
|
case N_CALL:
|
|
|
EMIT("qi_call(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
EMIT(", ");
|
|
|
- compile_list(gbuf, buf, ctx, lstk, node->l);
|
|
|
+ compile_list(gbuf, buf, ctx, lstk, lbl, node->l);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
|
case N_MEMBER:
|
|
|
EMIT("qi_index(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, 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, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
EMIT(", ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
|
- case N_ASSIGN: ASSIGN(node->a, compile_node(gbuf, buf, ctx, lstk, node->b)); break;
|
|
|
+ case N_ASSIGN: ASSIGN(node->a, compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
|
|
|
- case N_ASSIGN_ADD: COMPASSIGN(node->a, "add", compile_node(gbuf, buf, ctx, lstk, node->b)); break;
|
|
|
+ case N_ASSIGN_ADD: COMPASSIGN(node->a, "add", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
|
|
|
case N_INC:
|
|
|
COMPASSIGN(node->a, "add", EMIT("state->one"));
|
|
@@ -1792,18 +1832,18 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
|
|
|
case N_IF:
|
|
|
EMIT("if (_qi_truthy(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
EMIT(")) {\n");
|
|
|
CTXPUSH("scope");
|
|
|
EMIT("qi_new_scope(state);\n");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
EMIT("qi_old_scope(state);\n");
|
|
|
CTXPOP();
|
|
|
if (node->c) {
|
|
|
EMIT("} else {\n");
|
|
|
CTXPUSH("scope");
|
|
|
EMIT("qi_new_scope(state);\n");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->c);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
|
|
|
EMIT("qi_old_scope(state);\n");
|
|
|
CTXPOP();
|
|
|
}
|
|
@@ -1820,25 +1860,25 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
EMIT("for (;;) {\n");
|
|
|
} else if (node->a && !node->b) {
|
|
|
EMIT("while (_qi_truthy(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
EMIT(")) {\n");
|
|
|
} else {
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
EMIT("while (_qi_truthy(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
EMIT(")) {\n");
|
|
|
}
|
|
|
|
|
|
LPUSH(gid);
|
|
|
CTXPUSH("for");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->d);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->d);
|
|
|
CTXPOP();
|
|
|
LPOP();
|
|
|
|
|
|
EMIT("__continue%d:;\n", gid);
|
|
|
|
|
|
if (node->c)
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->c);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
|
|
|
|
|
|
EMIT("}\n");
|
|
|
|
|
@@ -1869,9 +1909,11 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
|
|
|
buffer_fmt(tbuf, "void __defer%d(qi_state_t *state) {\n", gid);
|
|
|
|
|
|
+ LBPUSH();
|
|
|
CTXPUSH("gap");
|
|
|
- compile_node(gbuf, tbuf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, tbuf, ctx, lstk, lbl, node->a);
|
|
|
CTXPOP();
|
|
|
+ LBPOP();
|
|
|
|
|
|
buffer_fmt(tbuf, "\n");
|
|
|
buffer_fmt(tbuf, "}\n");
|
|
@@ -1894,7 +1936,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
EMIT("return ");
|
|
|
|
|
|
if (node->a)
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
else EMIT("state->nil");
|
|
|
|
|
|
EMIT(";");
|
|
@@ -1907,12 +1949,12 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
CTXPUSH("scope");
|
|
|
EMIT("qi_new_scope(state);\n");
|
|
|
EMIT("qi_try(state, {\n");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, 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, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
CTXPOP();
|
|
|
EMIT("}, NULL);\n");
|
|
|
EMIT("qi_new_scope(state);");
|
|
@@ -1922,18 +1964,55 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
case N_THROW:
|
|
|
EMIT("qi_throw(state, ");
|
|
|
if (node->a)
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
else {
|
|
|
EMIT("state->nil");
|
|
|
}
|
|
|
EMIT(");");
|
|
|
break;
|
|
|
|
|
|
+ case N_LABEL: {
|
|
|
+ char *label = node->t->text;
|
|
|
+
|
|
|
+ table_iterate((table_t *)list_index(lbl, -1), {
|
|
|
+ if (strcmp(entry.key, label) == 0) {
|
|
|
+ COMPILE_ERROR("duplicated label: '%s'", label);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ NEWGID();
|
|
|
+
|
|
|
+ EMIT("__label%d:;", gid);
|
|
|
+
|
|
|
+ size_t *n = malloc(sizeof(size_t));
|
|
|
+ memcpy(n, &gid, sizeof(size_t));
|
|
|
+
|
|
|
+ table_set(list_index(lbl, -1), label, n);
|
|
|
+ } break;
|
|
|
+
|
|
|
+ case N_GOTO: {
|
|
|
+ ssize_t gid = -1;
|
|
|
+ char *label = node->t->text;
|
|
|
+
|
|
|
+ table_iterate((table_t *)list_index(lbl, -1), {
|
|
|
+ if (strcmp(entry.key, label) == 0) {
|
|
|
+ gid = *(size_t *)entry.value;
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if (gid < 0)
|
|
|
+ COMPILE_ERROR("undefined label: '%s'", label);
|
|
|
+
|
|
|
+ EMIT("goto __label%d;", gid);
|
|
|
+ } break;
|
|
|
+
|
|
|
case N_REQUIRE: {
|
|
|
char *source = NULL;
|
|
|
|
|
|
char *path = node->t->text;
|
|
|
- for (size_t i = 0; i < STD_SIZE; i++) {
|
|
|
+ for (size_t i = 0; STD[i][0]; i++) {
|
|
|
if (strcmp(path, STD[i][0]) == 0) {
|
|
|
source = (char *)STD[i][1];
|
|
|
|
|
@@ -1947,7 +2026,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
if (!source) {
|
|
|
FILE *fd = fopen(path, "rb");
|
|
|
if (!fd)
|
|
|
- COMPILE_ERROR("failed to open: `%s'", path);
|
|
|
+ COMPILE_ERROR("'%s' is not a valid file path or a builtin library name", path);
|
|
|
|
|
|
buffer_t *fbuf = buffer_new();
|
|
|
|
|
@@ -1970,7 +2049,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
|
|
|
list_push(FILES, pair);
|
|
|
|
|
|
- compile_into(source, gbuf, buf, ctx, lstk);
|
|
|
+ compile_into(source, gbuf, buf, ctx, lstk, lbl);
|
|
|
|
|
|
list_pop(FILES);
|
|
|
list_push(REQUIRED, path);
|
|
@@ -1978,16 +2057,16 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
|
|
|
case N_IFEXPR:
|
|
|
EMIT("(_qi_truthy(state, ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
EMIT(")? ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->b);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
EMIT(": ");
|
|
|
- compile_node(gbuf, buf, ctx, lstk, node->c);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
|
case N_FUNCEXPR:
|
|
|
- compile_func(gbuf, buf, ctx, lstk, node);
|
|
|
+ compile_func(gbuf, buf, ctx, lstk, lbl, node);
|
|
|
break;
|
|
|
|
|
|
case N_EQUALS:
|
|
@@ -2035,15 +2114,17 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk) {
|
|
|
+void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl) {
|
|
|
node_t *n = parse(source);
|
|
|
|
|
|
- compile_node(gbuf, buf, ctx, lstk, n);
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, n);
|
|
|
}
|
|
|
|
|
|
char *compile(char *source) {
|
|
|
list_t *ctx = list_new();
|
|
|
stack_t *lstk = stack_new();
|
|
|
+ list_t *lbl = list_new();
|
|
|
+ LBPUSH();
|
|
|
|
|
|
buffer_t *gbuf = buffer_new();
|
|
|
|
|
@@ -2051,7 +2132,7 @@ char *compile(char *source) {
|
|
|
|
|
|
buffer_t *buf = buffer_new();
|
|
|
|
|
|
- compile_into(source, gbuf, buf, ctx, lstk);
|
|
|
+ compile_into(source, gbuf, buf, ctx, lstk, lbl);
|
|
|
|
|
|
buffer_t *rbuf = buffer_new();
|
|
|
|