|
@@ -671,9 +671,12 @@ token_t *tokenize_string(char *source, size_t *pos) {
|
|
|
|
|
|
if (c == '"' || c == '\\' || c == '?')
|
|
|
buffer_append(text, '\\');
|
|
|
- else if (c == '\n')
|
|
|
+ else if (c == '\n') {
|
|
|
buffer_appends(text, "\\n");
|
|
|
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
buffer_append(text, c);
|
|
|
}
|
|
|
|
|
@@ -2496,9 +2499,21 @@ node_t *_parse_stmt(list_t *tokens, size_t *pos, int allow_comma) {
|
|
|
else if (MATCH(RETURN)) {
|
|
|
node_t *a = NULL;
|
|
|
|
|
|
- if (!AT(RCB) && !CLIFF)
|
|
|
+ if (!AT(EOF) && !AT(RCB) && !CLIFF) {
|
|
|
a = parse_expr(tokens, pos);
|
|
|
|
|
|
+ if (!CLIFF_AHEAD && MATCH(COMMA)) {
|
|
|
+ list_t *l = list_new();
|
|
|
+ list_push(l, a);
|
|
|
+
|
|
|
+ do {
|
|
|
+ list_push(l, parse_expr(tokens, pos));
|
|
|
+ } while (!CLIFF_AHEAD && MATCH(COMMA));
|
|
|
+
|
|
|
+ a = NODEL(TUPLE, l);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return NODE1(RETURN, a);
|
|
|
} else if (MATCH(DEFER)) {
|
|
|
node_t *a;
|
|
@@ -2574,48 +2589,50 @@ node_t *_parse_stmt(list_t *tokens, size_t *pos, int allow_comma) {
|
|
|
EXPECT(RPAR, ")");
|
|
|
}
|
|
|
|
|
|
- EXPECT(LCB, "{");
|
|
|
-
|
|
|
list_t *triples = list_new();
|
|
|
|
|
|
- for (;;) {
|
|
|
- int is_out = 0;
|
|
|
- int is_static = 0;
|
|
|
-
|
|
|
- if (AT(RCB))
|
|
|
- break;
|
|
|
-
|
|
|
- if (MATCH(LET))
|
|
|
- is_out = 1;
|
|
|
- else if (MATCH(CONST))
|
|
|
- is_static = 1;
|
|
|
-
|
|
|
- if (!AT(NAME))
|
|
|
- PARSE_ERROR("expected identifier");
|
|
|
-
|
|
|
- list_t *triple = list_new();
|
|
|
-
|
|
|
- token_t *t = tokens->data[(*pos)++];
|
|
|
- list_push(triple, t);
|
|
|
-
|
|
|
- int *flagp = malloc_checked(sizeof(int));
|
|
|
- int flag = is_static ? 2 : is_out ? 1 : 0;
|
|
|
-
|
|
|
- memcpy(flagp, &flag, sizeof(int));
|
|
|
-
|
|
|
- if (MATCH(ASSIGN)) {
|
|
|
- list_push(triple, flagp);
|
|
|
- list_push(triple, parse_expr(tokens, pos));
|
|
|
- } else {
|
|
|
- list_push(triple, flagp);
|
|
|
- list_push(triple, parse_func(tokens, pos, 1));
|
|
|
+ if (!CLIFF && !AT(EOF) && !AT(SEMI)) {
|
|
|
+ EXPECT(LCB, "{");
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ int is_out = 0;
|
|
|
+ int is_static = 0;
|
|
|
+
|
|
|
+ if (AT(RCB))
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (MATCH(LET))
|
|
|
+ is_out = 1;
|
|
|
+ else if (MATCH(CONST))
|
|
|
+ is_static = 1;
|
|
|
+
|
|
|
+ if (!AT(NAME))
|
|
|
+ PARSE_ERROR("expected identifier");
|
|
|
+
|
|
|
+ list_t *triple = list_new();
|
|
|
+
|
|
|
+ token_t *t = tokens->data[(*pos)++];
|
|
|
+ list_push(triple, t);
|
|
|
+
|
|
|
+ int *flagp = malloc_checked(sizeof(int));
|
|
|
+ int flag = is_static ? 2 : is_out ? 1 : 0;
|
|
|
+
|
|
|
+ memcpy(flagp, &flag, sizeof(int));
|
|
|
+
|
|
|
+ if (MATCH(ASSIGN)) {
|
|
|
+ list_push(triple, flagp);
|
|
|
+ list_push(triple, parse_expr(tokens, pos));
|
|
|
+ } else {
|
|
|
+ list_push(triple, flagp);
|
|
|
+ list_push(triple, parse_func(tokens, pos, 1));
|
|
|
+ }
|
|
|
+
|
|
|
+ list_push(triples, triple);
|
|
|
}
|
|
|
-
|
|
|
- list_push(triples, triple);
|
|
|
+
|
|
|
+ EXPECT(RCB, "}");
|
|
|
}
|
|
|
|
|
|
- EXPECT(RCB, "}");
|
|
|
-
|
|
|
list_t *pair = list_new();
|
|
|
list_push(pair, l);
|
|
|
list_push(pair, triples);
|
|
@@ -3081,7 +3098,7 @@ node_t *parse(char *source) {
|
|
|
}
|
|
|
|
|
|
void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
- int_stack_t *lstk, int_stack_t *sstk, list_t *lbl,
|
|
|
+ list_t *lstk, list_t *sstk, list_t *lbl,
|
|
|
node_t *node);
|
|
|
|
|
|
char *tempvar() {
|
|
@@ -3094,7 +3111,7 @@ char *tempvar() {
|
|
|
}
|
|
|
|
|
|
void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
- int_stack_t *lstk, int_stack_t *sstk, list_t *lbl,
|
|
|
+ list_t *lstk, list_t *sstk, list_t *lbl,
|
|
|
list_t *seq) {
|
|
|
if (!seq || seq->length < 1) {
|
|
|
EMIT("NULL");
|
|
@@ -3162,7 +3179,7 @@ void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
}
|
|
|
|
|
|
void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
- int_stack_t *lstk, int_stack_t *sstk, list_t *lbl,
|
|
|
+ list_t *lstk, list_t *sstk, list_t *lbl,
|
|
|
table_t *table) {
|
|
|
if (!table || table->used < 1) {
|
|
|
EMIT("NULL");
|
|
@@ -3201,12 +3218,11 @@ int in_context(list_t *ctx, char *s) {
|
|
|
if (!ctx->length)
|
|
|
return 0;
|
|
|
|
|
|
- for (ssize_t i = ctx->length - 1; i >= 0; i--) {
|
|
|
+ for (ssize_t i = ctx->length - 1; i >= 0; i--)
|
|
|
if (strcmp(ctx->data[i], "gap") == 0)
|
|
|
break;
|
|
|
else if (strcmp(ctx->data[i], s) == 0)
|
|
|
return 1;
|
|
|
- }
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -3215,12 +3231,11 @@ int in_switch(list_t *ctx) {
|
|
|
if (!ctx->length)
|
|
|
return 0;
|
|
|
|
|
|
- for (ssize_t i = ctx->length - 1; i >= 0; i--) {
|
|
|
+ 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;
|
|
|
}
|
|
@@ -3231,12 +3246,11 @@ size_t count_ctxs(list_t *ctx, char *s) {
|
|
|
|
|
|
size_t k = 0;
|
|
|
|
|
|
- for (ssize_t i = ctx->length - 1; i >= 0; i--) {
|
|
|
+ for (ssize_t i = ctx->length - 1; i >= 0; i--)
|
|
|
if (strcmp(ctx->data[i], "gap") == 0)
|
|
|
break;
|
|
|
else if (strcmp(ctx->data[i], s) == 0)
|
|
|
k++;
|
|
|
- }
|
|
|
|
|
|
return k;
|
|
|
}
|
|
@@ -3247,13 +3261,23 @@ list_t *CONSTANTS;
|
|
|
#define SCOPESK (count_ctxs(ctx, "scope"))
|
|
|
#define TRAPSK (count_ctxs(ctx, "trap"))
|
|
|
|
|
|
-#define LPUSH(i) stack_push(lstk, (i))
|
|
|
-#define LPOP() stack_pop(lstk)
|
|
|
-#define LID (lstk->data[lstk->length - 1])
|
|
|
+#define LPUSH(i) {\
|
|
|
+ int_stack_t *pair = stack_new();\
|
|
|
+ stack_push(pair, (i));\
|
|
|
+ stack_push(pair, scope_index(ctx));\
|
|
|
+ list_push(lstk, pair);\
|
|
|
+}
|
|
|
+#define LPOP() list_pop(lstk)
|
|
|
+#define LID (((int_stack_t *)lstk->data[lstk->length - 1])->data[0])
|
|
|
|
|
|
-#define SPUSH(i) stack_push(sstk, (i))
|
|
|
-#define SPOP() stack_pop(sstk)
|
|
|
-#define SID (sstk->data[sstk->length - 1])
|
|
|
+#define SPUSH(i) {\
|
|
|
+ int_stack_t *pair = stack_new();\
|
|
|
+ stack_push(pair, (i));\
|
|
|
+ stack_push(pair, scope_index(ctx));\
|
|
|
+ list_push(sstk, pair);\
|
|
|
+}
|
|
|
+#define SPOP() list_pop(sstk)
|
|
|
+#define SID (sstk->data[sstk->length - 1]->data[0])
|
|
|
|
|
|
#define LBPUSH() list_push(lbl, table_new())
|
|
|
#define LBPOP() list_pop(lbl)
|
|
@@ -3279,7 +3303,7 @@ void emit_debug(buffer_t *buf, node_t *node) {
|
|
|
}
|
|
|
|
|
|
void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
- int_stack_t *lstk, int_stack_t *sstk, list_t *lbl,
|
|
|
+ list_t *lstk, list_t *sstk, list_t *lbl,
|
|
|
node_t *node, char *name) {
|
|
|
NEWGID();
|
|
|
|
|
@@ -3327,7 +3351,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- compile_node(gbuf, tbuf, ctx, table_new(), stack_new(), stack_new(), lbl,
|
|
|
+ compile_node(gbuf, tbuf, ctx, table_new(), list_new(), list_new(), lbl,
|
|
|
node->a);
|
|
|
|
|
|
list_pop(FUNCNAMES);
|
|
@@ -3381,8 +3405,36 @@ node_t *const_get(char *name) {
|
|
|
return val;
|
|
|
}
|
|
|
|
|
|
+size_t count_scopes(list_t *ctx, size_t offset) {
|
|
|
+ if (ctx->length < 2 || offset >= ctx->length)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ size_t k = 0;
|
|
|
+
|
|
|
+ for (ssize_t i = ctx->length - 1; i >= 0 && i > offset; i--)
|
|
|
+ if (strcmp(ctx->data[i], "gap") == 0)
|
|
|
+ break;
|
|
|
+ else if (strcmp(ctx->data[i], "scope") == 0)
|
|
|
+ k++;
|
|
|
+
|
|
|
+ return k;
|
|
|
+}
|
|
|
+
|
|
|
+size_t scope_index(list_t *ctx) {
|
|
|
+ if (ctx->length < 2)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ for (ssize_t i = ctx->length - 1; i >= 0; i--)
|
|
|
+ if (strcmp(ctx->data[i], "gap") == 0)
|
|
|
+ break;
|
|
|
+ else if (strcmp(ctx->data[i], "scope") == 0)
|
|
|
+ return i;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
- int_stack_t *lstk, int_stack_t *sstk, list_t *lbl,
|
|
|
+ list_t *lstk, list_t *sstk, list_t *lbl,
|
|
|
list_t *block) {
|
|
|
for (size_t i = 0; i < block->length; i++) {
|
|
|
node_t *node = block->data[i];
|
|
@@ -3481,10 +3533,11 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
|
|
|
NEWGID();
|
|
|
|
|
|
- size_t *n = malloc_checked(sizeof(size_t));
|
|
|
- memcpy(n, &gid, sizeof(size_t));
|
|
|
+ int_stack_t *pair = stack_new();
|
|
|
+ stack_push(pair, gid);
|
|
|
+ stack_push(pair, scope_index(ctx));
|
|
|
|
|
|
- table_set(list_index(lbl, -1), label, n);
|
|
|
+ table_set(list_index(lbl, -1), label, pair);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -3504,6 +3557,198 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
}
|
|
|
|
|
|
const char *STD[][2] = {
|
|
|
+ {"json",
|
|
|
+ "require \"string\"\n"
|
|
|
+ "class JSONError(Error)\n"
|
|
|
+ "func json_tokenize(s) {\n"
|
|
|
+ " let toks = []\n"
|
|
|
+ " for var i = 0; i < len(s); i++ {\n"
|
|
|
+ " if isws(s[i]) {\n"
|
|
|
+ " continue\n"
|
|
|
+ " }\n"
|
|
|
+ " if s[i] in \"[]{}:,\"\n"
|
|
|
+ " toks.push((s[i], nil))\n"
|
|
|
+ " elif isalpha(s[i]) {\n"
|
|
|
+ " var text = \"\"\n"
|
|
|
+ " for i < len(s) && isalpha(s[i])\n"
|
|
|
+ " text += s[i++]\n"
|
|
|
+ " toks.push((\"name\", text))\n"
|
|
|
+ " i--\n"
|
|
|
+ " } elif s[i] == '-' || isdigit(s[i]) {\n"
|
|
|
+ " var text = \"\"\n"
|
|
|
+ " if s[i] == '-'\n"
|
|
|
+ " text += s[i++]\n"
|
|
|
+ " if i >= len(s) || !isdigit(s[i])\n"
|
|
|
+ " throw JSONError(f\"${i}: malformed number literal\")\n"
|
|
|
+ " for i < len(s) && isdigit(s[i]) {\n"
|
|
|
+ " text += s[i++]\n"
|
|
|
+ " if i < len(s) && s[i] == \".\" && \".\" !in text\n"
|
|
|
+ " text += s[i++]\n"
|
|
|
+ " }\n"
|
|
|
+ " i--\n"
|
|
|
+ " toks.push((\"number\", text))\n"
|
|
|
+ " } elif s[i] == '\"' {\n"
|
|
|
+ " var text = \"\"\n"
|
|
|
+ " i++\n"
|
|
|
+ " for i < len(s) && s[i] != '\"'\n"
|
|
|
+ " text += s[i++]\n"
|
|
|
+ " if i >= len(s) || s[i] != '\"'\n"
|
|
|
+ " throw JSONError(f\"#${i}: unterminated string literal\")\n"
|
|
|
+ " toks.push((\"string\", text))\n"
|
|
|
+ " } else\n"
|
|
|
+ " throw JSONError(f\"#${i}: unknown input\")\n"
|
|
|
+ " }\n"
|
|
|
+ " return toks\n"
|
|
|
+ "}\n"
|
|
|
+ "func json_parse(toks) {\n"
|
|
|
+ " func parse_array(toks) {\n"
|
|
|
+ " let r = []\n"
|
|
|
+ " if toks && toks[0][0] == ']'\n"
|
|
|
+ " return r, toks[1:]\n"
|
|
|
+ " for {\n"
|
|
|
+ " var e\n"
|
|
|
+ " [e, toks] = parse_expression(toks)\n"
|
|
|
+ " r.push(e)\n"
|
|
|
+ " if !toks || toks[0][0] != ','\n"
|
|
|
+ " break\n"
|
|
|
+ " if toks[0][0] == \",\"\n"
|
|
|
+ " toks = toks[1:]\n"
|
|
|
+ " }\n"
|
|
|
+ " if !toks || toks[0][0] != ']'\n"
|
|
|
+ " throw JSONError(\"missing ]\")\n"
|
|
|
+ " return r, toks[1:]\n"
|
|
|
+ " }\n"
|
|
|
+ " func parse_object(toks) {\n"
|
|
|
+ " let r = {}\n"
|
|
|
+ " for {\n"
|
|
|
+ " var k, e\n"
|
|
|
+ " if !toks || toks[0][0] != \"string\"\n"
|
|
|
+ " throw JSONError(\"expected string\")\n"
|
|
|
+ " k = toks[0][1]\n"
|
|
|
+ " toks = toks[1:]\n"
|
|
|
+ " if !toks || toks[0][0] != \":\"\n"
|
|
|
+ " throw JSONError(\"expected :\")\n"
|
|
|
+ " toks = toks[1:]\n"
|
|
|
+ " [e, toks] = parse_expression(toks)\n"
|
|
|
+ " r[k] = e\n"
|
|
|
+ " if !toks || toks[0][0] != \",\"\n"
|
|
|
+ " break\n"
|
|
|
+ " if toks[0][0] == \",\"\n"
|
|
|
+ " toks = toks[1:]\n"
|
|
|
+ " }\n"
|
|
|
+ " if !toks || toks[0][0] != \"}\"\n"
|
|
|
+ " throw JSONError(\"missing }\")\n"
|
|
|
+ " return r, toks[1:]\n"
|
|
|
+ " }\n"
|
|
|
+ " func parse_expression(toks) {\n"
|
|
|
+ " if toks\n"
|
|
|
+ " switch toks[0][0] {\n"
|
|
|
+ " case \"{\":\n"
|
|
|
+ " return parse_object(toks[1:])\n"
|
|
|
+ " case \"[\":\n"
|
|
|
+ " return parse_array(toks[1:])\n"
|
|
|
+ " case \"name\":\n"
|
|
|
+ " switch toks[0][1] {\n"
|
|
|
+ " case \"true\":\n"
|
|
|
+ " return true, toks[1:]\n"
|
|
|
+ " case \"false\":\n"
|
|
|
+ " return false, toks[1:]\n"
|
|
|
+ " case \"null\":\n"
|
|
|
+ " return nil, toks[1:]\n"
|
|
|
+ " }\n"
|
|
|
+ " throw JSONError(f\"illegal name: ${toks[0][1]}\")\n"
|
|
|
+ " case \"number\":\n"
|
|
|
+ " return num(toks[0][1]), toks[1:]\n"
|
|
|
+ " case \"string\":\n"
|
|
|
+ " return toks[0][1], toks[1:]\n"
|
|
|
+ " }\n"
|
|
|
+ " throw JSONError(\"expected expression\")\n"
|
|
|
+ " }\n"
|
|
|
+ " if !toks\n"
|
|
|
+ " throw JSONError(\"empty document\")\n"
|
|
|
+ " if toks[0][0] !in \"{[\"\n"
|
|
|
+ " throw JSONError(\"expected { or [\")\n"
|
|
|
+ " let [r, unconsumed] = parse_expression(toks)\n"
|
|
|
+ " if unconsumed\n"
|
|
|
+ " throw JSONError(\"unconsumed input\")\n"
|
|
|
+ " return r\n"
|
|
|
+ "}\n"
|
|
|
+ "func json_read(s)\n"
|
|
|
+ " return json_parse(json_tokenize(s))\n"
|
|
|
+ "func json_dump(d) {\n"
|
|
|
+ " func escape(s) {\n"
|
|
|
+ " var r = \"\"\n"
|
|
|
+ " var skip = false\n"
|
|
|
+ " for var c of s {\n"
|
|
|
+ " if skip {\n"
|
|
|
+ " switch c {\n"
|
|
|
+ " case \"n\":\n"
|
|
|
+ " r += \"\\n\"\n"
|
|
|
+ " break\n"
|
|
|
+ " case \"r\":\n"
|
|
|
+ " r += \"\\r\"\n"
|
|
|
+ " break\n"
|
|
|
+ " case \"t\":\n"
|
|
|
+ " r += \"\\t\"\n"
|
|
|
+ " break\n"
|
|
|
+ " case '\"':\n"
|
|
|
+ " r += `\\\"`\n"
|
|
|
+ " break\n"
|
|
|
+ " case `\\`:\n"
|
|
|
+ " r += `\\\\`\n"
|
|
|
+ " break\n"
|
|
|
+ " default:\n"
|
|
|
+ " r += c\n"
|
|
|
+ " }\n"
|
|
|
+ " skip = false\n"
|
|
|
+ " continue\n"
|
|
|
+ " }\n"
|
|
|
+ " if c == `\\` {\n"
|
|
|
+ " skip = true\n"
|
|
|
+ " continue\n"
|
|
|
+ " }\n"
|
|
|
+ " r += c\n"
|
|
|
+ " }\n"
|
|
|
+ " return r\n"
|
|
|
+ " }\n"
|
|
|
+ " switch type(d) {\n"
|
|
|
+ " case \"nil\":\n"
|
|
|
+ " return \"null\"\n"
|
|
|
+ " case \"boolean\":\n"
|
|
|
+ " return d? \"true\": \"false\"\n"
|
|
|
+ " case \"number\":\n"
|
|
|
+ " return str(d)\n"
|
|
|
+ " case \"string\":\n"
|
|
|
+ " return \"\\\"\" + escape(d) + \"\\\"\"\n"
|
|
|
+ " case \"list\":\n"
|
|
|
+ " var f = true\n"
|
|
|
+ " var buf = \"[\"\n"
|
|
|
+ " for var el of d {\n"
|
|
|
+ " if f\n"
|
|
|
+ " f = false\n"
|
|
|
+ " else\n"
|
|
|
+ " buf += \", \"\n"
|
|
|
+ " buf += json_dump(el) \n"
|
|
|
+ " }\n"
|
|
|
+ " buf += \"]\"\n"
|
|
|
+ " return buf\n"
|
|
|
+ " case \"table\":\n"
|
|
|
+ " var f = true\n"
|
|
|
+ " var buf = \"{\"\n"
|
|
|
+ " for var [k, v] of enumerate(d) {\n"
|
|
|
+ " if f\n"
|
|
|
+ " f = false\n"
|
|
|
+ " else\n"
|
|
|
+ " buf += \", \"\n"
|
|
|
+ " buf += f`\"${escape(k)}\": ${json_dump(v)}`\n"
|
|
|
+ " }\n"
|
|
|
+ " buf += \"}\"\n"
|
|
|
+ " return buf\n"
|
|
|
+ " }\n"
|
|
|
+ " throw JSONError(f\"cannot serialize ${type(d)} into a JSON\")\n"
|
|
|
+ "}\n"
|
|
|
+ },
|
|
|
+
|
|
|
{"utf8", "func utf8_chrlen(s) {\n"
|
|
|
" s = bytes(s)\n"
|
|
|
" var z = len(s)\n"
|
|
@@ -3900,11 +4145,11 @@ char *unescape(char *s) {
|
|
|
}
|
|
|
|
|
|
void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx,
|
|
|
- table_t *ltab, int_stack_t *lstk, int_stack_t *sstk,
|
|
|
+ table_t *ltab, list_t *lstk, list_t *sstk,
|
|
|
list_t *lbl);
|
|
|
|
|
|
int require_once(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
- int_stack_t *lstk, int_stack_t *sstk, list_t *lbl,
|
|
|
+ list_t *lstk, list_t *sstk, list_t *lbl,
|
|
|
char *path) {
|
|
|
char *source = NULL;
|
|
|
|
|
@@ -4758,7 +5003,7 @@ node_t *expand_mvars(node_t *node, node_t *_node, int expr) {
|
|
|
}
|
|
|
|
|
|
void compile_macro_call(buffer_t *gbuf, buffer_t *buf, list_t *ctx,
|
|
|
- table_t *ltab, int_stack_t *lstk, int_stack_t *sstk,
|
|
|
+ table_t *ltab, list_t *lstk, list_t *sstk,
|
|
|
list_t *lbl, node_t *node, int expr) {
|
|
|
size_t argc = node->l->length;
|
|
|
char *name = node->t->text;
|
|
@@ -4815,7 +5060,7 @@ void compile_macro_call(buffer_t *gbuf, buffer_t *buf, list_t *ctx,
|
|
|
}
|
|
|
|
|
|
void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
- int_stack_t *lstk, int_stack_t *sstk, list_t *lbl,
|
|
|
+ list_t *lstk, list_t *sstk, list_t *lbl,
|
|
|
node_t *node) {
|
|
|
switch (node->tag) {
|
|
|
case N_TOPLEVEL:
|
|
@@ -5196,7 +5441,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
ASSIGNIN(tbuf, (node_t *)node->a->l->data[i],
|
|
|
buffer_fmt(tbuf,
|
|
|
"qi_index(state, %s, qi_make_number(state, %d))",
|
|
|
- varname, i), falss);
|
|
|
+ varname, i), false);
|
|
|
buffer_fmt(tbuf, ";\n");
|
|
|
}
|
|
|
|
|
@@ -5355,6 +5600,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
|
|
|
case N_IF:
|
|
|
CTXPUSH("scope");
|
|
|
+
|
|
|
EMIT("qi_new_scope(state);\n");
|
|
|
EMIT("if (_qi_truthy(state, ");
|
|
|
compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node->a);
|
|
@@ -5373,16 +5619,21 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
case N_SWITCH: {
|
|
|
NEWGID();
|
|
|
|
|
|
+ CTXPUSH("scope");
|
|
|
+
|
|
|
+ EMIT("qi_new_scope(state);\n");
|
|
|
+
|
|
|
if (node->t2) {
|
|
|
if (table_get(ltab, node->t2->text))
|
|
|
COMPILE_ERROR("redeclaration of loop label: '%s'", node->t2->text);
|
|
|
|
|
|
- int_stack_t *pair = stack_new();
|
|
|
+ int_stack_t *triple = stack_new();
|
|
|
|
|
|
- stack_push(pair, 1);
|
|
|
- stack_push(pair, gid);
|
|
|
+ stack_push(triple, 1);
|
|
|
+ stack_push(triple, gid);
|
|
|
+ stack_push(triple, scope_index(ctx));
|
|
|
|
|
|
- table_set(ltab, node->t2->text, pair);
|
|
|
+ table_set(ltab, node->t2->text, triple);
|
|
|
}
|
|
|
|
|
|
char *varname = tempvar();
|
|
@@ -5410,6 +5661,8 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
SPUSH(gid);
|
|
|
CTXPUSH("switch");
|
|
|
|
|
|
+ int has_default = 0;
|
|
|
+
|
|
|
for (size_t i = 0; i < node->l->length; i++) {
|
|
|
list_t *pair = node->l->data[i];
|
|
|
char *label = pair->data[0];
|
|
@@ -5417,6 +5670,8 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
|
|
|
if (!label) {
|
|
|
EMIT("__default%d:;\n", gid);
|
|
|
+
|
|
|
+ has_default = 1;
|
|
|
} else {
|
|
|
EMIT("%s:;\n", label);
|
|
|
}
|
|
@@ -5424,30 +5679,38 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, block);
|
|
|
}
|
|
|
|
|
|
+ CTXPOP();
|
|
|
CTXPOP();
|
|
|
SPOP();
|
|
|
|
|
|
+ if (!has_default) {
|
|
|
+ EMIT("__default%d:;\n", gid);
|
|
|
+ }
|
|
|
+
|
|
|
EMIT("__break%d:;\n", gid);
|
|
|
+
|
|
|
+ EMIT("qi_old_scope(state);\n");
|
|
|
} break;
|
|
|
|
|
|
case N_FOR: {
|
|
|
NEWGID();
|
|
|
|
|
|
+ CTXPUSH("scope");
|
|
|
+ EMIT("qi_new_scope(state);\n");
|
|
|
+
|
|
|
if (node->t2) {
|
|
|
if (table_get(ltab, node->t2->text))
|
|
|
COMPILE_ERROR("redeclaration of loop label: '%s'", node->t2->text);
|
|
|
|
|
|
- int_stack_t *pair = stack_new();
|
|
|
+ int_stack_t *triple = stack_new();
|
|
|
|
|
|
- stack_push(pair, 0);
|
|
|
- stack_push(pair, gid);
|
|
|
+ stack_push(triple, 0);
|
|
|
+ stack_push(triple, gid);
|
|
|
+ stack_push(triple, scope_index(ctx));
|
|
|
|
|
|
- table_set(ltab, node->t2->text, pair);
|
|
|
+ table_set(ltab, node->t2->text, triple);
|
|
|
}
|
|
|
|
|
|
- CTXPUSH("scope");
|
|
|
- EMIT("qi_new_scope(state);\n");
|
|
|
-
|
|
|
if (!node->a) {
|
|
|
EMIT("for (;;) {\n");
|
|
|
} else if (node->a && !node->b) {
|
|
@@ -5504,21 +5767,22 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
case N_FOROFVARUNPACK: {
|
|
|
NEWGID();
|
|
|
|
|
|
+ CTXPUSH("scope");
|
|
|
+ EMIT("qi_new_scope(state);\n");
|
|
|
+
|
|
|
if (node->t2) {
|
|
|
if (table_get(ltab, node->t2->text))
|
|
|
COMPILE_ERROR("redeclaration of loop label: '%s'", node->t2->text);
|
|
|
|
|
|
- int_stack_t *pair = stack_new();
|
|
|
+ int_stack_t *triple = stack_new();
|
|
|
|
|
|
- stack_push(pair, 0);
|
|
|
- stack_push(pair, gid);
|
|
|
+ stack_push(triple, 0);
|
|
|
+ stack_push(triple, gid);
|
|
|
+ stack_push(triple, scope_index(ctx));
|
|
|
|
|
|
- table_set(ltab, node->t2->text, pair);
|
|
|
+ table_set(ltab, node->t2->text, triple);
|
|
|
}
|
|
|
|
|
|
- CTXPUSH("scope");
|
|
|
- EMIT("qi_new_scope(state);\n");
|
|
|
-
|
|
|
char *varname = tempvar();
|
|
|
|
|
|
EMIT("qi_value_t *%s = qi_iter(state, ", varname);
|
|
@@ -5571,7 +5835,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
EMIT("qi_old_scope(state);\n");
|
|
|
} break;
|
|
|
|
|
|
- case N_BREAK:
|
|
|
+ case N_BREAK: {
|
|
|
if (!INCTX("for") && !INCTX("switch"))
|
|
|
COMPILE_ERROR("break outside of a loop or a switch");
|
|
|
|
|
@@ -5582,25 +5846,55 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
if (offset < 2 || offset > lstk->length)
|
|
|
COMPILE_ERROR("%d is not a valid break loop offset", offset - 1);
|
|
|
|
|
|
- EMIT("goto __break%d;", lstk->data[lstk->length - offset]);
|
|
|
+ int_stack_t *pair = lstk->data[lstk->length - offset];
|
|
|
+ size_t scopes_k = count_scopes(ctx, pair->data[1]);
|
|
|
+
|
|
|
+ for (size_t i = 0; i < scopes_k; i++) {
|
|
|
+ EMIT("qi_old_scope(state);\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ EMIT("goto __break%d;", pair->data[0]);
|
|
|
} else {
|
|
|
char *label = node->t->text;
|
|
|
|
|
|
- int_stack_t *pair = table_get(ltab, label);
|
|
|
+ int_stack_t *triple = table_get(ltab, label);
|
|
|
|
|
|
- if (!pair)
|
|
|
+ if (!triple)
|
|
|
COMPILE_ERROR("undefined loop label: '%s'", label);
|
|
|
|
|
|
- EMIT("goto __break%d;", pair->data[1]);
|
|
|
+ size_t scopes_k = count_scopes(ctx, triple->data[2]);
|
|
|
+
|
|
|
+ for (size_t i = 0; i < scopes_k; i++) {
|
|
|
+ EMIT("qi_old_scope(state);\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ EMIT("goto __break%d;", triple->data[1]);
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- EMIT("goto __break%d;", in_switch(ctx) ? SID : LID);
|
|
|
- break;
|
|
|
+ size_t gid;
|
|
|
+ int_stack_t *pair;
|
|
|
+
|
|
|
+ if (in_switch(ctx)) {
|
|
|
+ pair = sstk->data[sstk->length - 1];
|
|
|
+ gid = pair->data[0];
|
|
|
+ } else {
|
|
|
+ pair = lstk->data[lstk->length - 1];
|
|
|
+ gid = pair->data[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ size_t scopes_k = count_scopes(ctx, pair->data[1]);
|
|
|
+
|
|
|
+ for (size_t i = 0; i < scopes_k; i++) {
|
|
|
+ EMIT("qi_old_scope(state);\n");
|
|
|
+ }
|
|
|
|
|
|
- case N_CONTINUE:
|
|
|
+ EMIT("goto __break%d;", gid);
|
|
|
+ } break;
|
|
|
+
|
|
|
+ case N_CONTINUE: {
|
|
|
if (!INCTX("for"))
|
|
|
COMPILE_ERROR("continue outside of a loop");
|
|
|
|
|
@@ -5611,26 +5905,48 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
if (offset < 2 || offset > lstk->length)
|
|
|
COMPILE_ERROR("%d is not a valid break loop offset", offset - 1);
|
|
|
|
|
|
- EMIT("goto __continue%d;", lstk->data[lstk->length - offset]);
|
|
|
+ int_stack_t *pair = lstk->data[lstk->length - offset];
|
|
|
+ size_t scopes_k = count_scopes(ctx, pair->data[1]);
|
|
|
+
|
|
|
+ for (size_t i = 0; i < scopes_k; i++) {
|
|
|
+ EMIT("qi_old_scope(state);\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ EMIT("goto __continue%d;", pair->data[0]);
|
|
|
} else {
|
|
|
char *label = node->t->text;
|
|
|
|
|
|
- int_stack_t *pair = table_get(ltab, label);
|
|
|
+ int_stack_t *triple = table_get(ltab, label);
|
|
|
|
|
|
- if (pair->data[1])
|
|
|
+ if (!triple)
|
|
|
+ COMPILE_ERROR("undefined loop label: '%s'", label);
|
|
|
+
|
|
|
+ if (triple->data[0])
|
|
|
COMPILE_ERROR("continue on a switch loop label: '%s'", label);
|
|
|
|
|
|
- if (!pair)
|
|
|
- COMPILE_ERROR("undefined loop label: '%s'", label);
|
|
|
+ size_t scopes_k = count_scopes(ctx, triple->data[2]);
|
|
|
+
|
|
|
+ for (size_t i = 0; i < scopes_k; i++) {
|
|
|
+ EMIT("qi_old_scope(state);\n");
|
|
|
+ }
|
|
|
|
|
|
- EMIT("goto __continue%d;", pair->data[1]);
|
|
|
+ EMIT("goto __continue%d;", triple->data[1]);
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ int_stack_t *pair = lstk->data[lstk->length - 1];
|
|
|
+ size_t gid = pair->data[0];
|
|
|
+
|
|
|
+ size_t scopes_k = count_scopes(ctx, pair->data[1]);
|
|
|
|
|
|
- EMIT("goto __continue%d;", LID);
|
|
|
- break;
|
|
|
+ for (size_t i = 0; i < scopes_k; i++) {
|
|
|
+ EMIT("qi_old_scope(state);\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ EMIT("goto __continue%d;", gid);
|
|
|
+ } break;
|
|
|
|
|
|
case N_DEFER: {
|
|
|
NEWGID();
|
|
@@ -5643,7 +5959,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
CTXPUSH("gap");
|
|
|
list_push(CONSTANTS, table_new());
|
|
|
list_push(MACROS, table_new());
|
|
|
- compile_node(gbuf, tbuf, ctx, table_new(), stack_new(), stack_new(), lbl,
|
|
|
+ compile_node(gbuf, tbuf, ctx, table_new(), list_new(), list_new(), lbl,
|
|
|
node->a);
|
|
|
list_pop(MACROS);
|
|
|
list_pop(CONSTANTS);
|
|
@@ -5657,25 +5973,28 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
EMIT("qi_add_defer(state, -1, __%s%d);", PREFIX, gid);
|
|
|
} break;
|
|
|
|
|
|
- case N_RETURN:
|
|
|
+ case N_RETURN: {
|
|
|
if (!INCTX("func"))
|
|
|
COMPILE_ERROR("return outside of a function");
|
|
|
|
|
|
+ char *varname = NULL;
|
|
|
+
|
|
|
+ if (node->a) {
|
|
|
+ varname = tempvar();
|
|
|
+
|
|
|
+ EMIT("qi_value_t *%s = ", varname);
|
|
|
+ compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node->a);
|
|
|
+ EMIT(";\n");
|
|
|
+ }
|
|
|
+
|
|
|
for (size_t i = 0; i < SCOPESK; i++)
|
|
|
EMIT("qi_old_scope(state);\n");
|
|
|
|
|
|
for (size_t i = 0; i < TRAPSK; i++)
|
|
|
EMIT("qi_unset_trap(state, trap);\n");
|
|
|
|
|
|
- EMIT("return ");
|
|
|
-
|
|
|
- if (node->a)
|
|
|
- compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node->a);
|
|
|
- else
|
|
|
- EMIT("state->nil");
|
|
|
-
|
|
|
- EMIT(";");
|
|
|
- break;
|
|
|
+ EMIT("return %s;", varname? varname: "state->nil");
|
|
|
+ } break;
|
|
|
|
|
|
case N_FUNCDEF:
|
|
|
break;
|
|
@@ -5737,7 +6056,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
LBPUSH();
|
|
|
CTXPUSH("gap");
|
|
|
CTXPUSH("trap");
|
|
|
- compile_node(gbuf, buf, ctx, table_new(), stack_new(), stack_new(), lbl,
|
|
|
+ compile_node(gbuf, buf, ctx, table_new(), list_new(), list_new(), lbl,
|
|
|
node->a);
|
|
|
CTXPOP();
|
|
|
CTXPOP();
|
|
@@ -5747,7 +6066,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
EMIT("qi_decl(state, \"%s\", trap->value);\n", node->t->text);
|
|
|
LBPUSH();
|
|
|
CTXPUSH("gap");
|
|
|
- compile_node(gbuf, buf, ctx, table_new(), stack_new(), stack_new(), lbl,
|
|
|
+ compile_node(gbuf, buf, ctx, table_new(), list_new(), list_new(), lbl,
|
|
|
node->b);
|
|
|
CTXPOP();
|
|
|
LBPOP();
|
|
@@ -5760,7 +6079,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
buffer_fmt(tbuf, "void __%s%d(qi_state_t *state) {\n", PREFIX, gid);
|
|
|
LBPUSH();
|
|
|
CTXPUSH("gap");
|
|
|
- compile_node(gbuf, tbuf, ctx, table_new(), stack_new(), stack_new(), lbl,
|
|
|
+ compile_node(gbuf, tbuf, ctx, table_new(), list_new(), list_new(), lbl,
|
|
|
node->c);
|
|
|
CTXPOP();
|
|
|
LBPOP();
|
|
@@ -5796,18 +6115,29 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
break;
|
|
|
|
|
|
case N_LABEL: {
|
|
|
- size_t *gid = table_get(list_index(lbl, -1), node->t->text);
|
|
|
+ int_stack_t *pair = table_get(list_index(lbl, -1), node->t->text);
|
|
|
|
|
|
- EMIT("__label%d:;", *gid);
|
|
|
+ EMIT("__label%d:;", pair->data[0]);
|
|
|
} break;
|
|
|
|
|
|
case N_GOTO: {
|
|
|
char *label = node->t->text;
|
|
|
- size_t *gid = table_get(list_index(lbl, -1), label);
|
|
|
- if (!gid)
|
|
|
+ int_stack_t *pair = table_get(list_index(lbl, -1), label);
|
|
|
+ if (!pair)
|
|
|
COMPILE_ERROR("undefined label: '%s'", label);
|
|
|
|
|
|
- EMIT("goto __label%d;", *gid);
|
|
|
+ size_t offset = pair->data[1];
|
|
|
+
|
|
|
+ if (offset >= ctx->length)
|
|
|
+ COMPILE_ERROR("cannot goto inwards");
|
|
|
+
|
|
|
+ size_t scopes_k = count_scopes(ctx, offset);
|
|
|
+
|
|
|
+ for (size_t i = 0; i < scopes_k; i++) {
|
|
|
+ EMIT("qi_old_scope(state);\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ EMIT("goto __label%d;", pair->data[0]);
|
|
|
} break;
|
|
|
|
|
|
case N_REQUIRE:
|
|
@@ -5979,7 +6309,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
|
|
|
}
|
|
|
|
|
|
void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx,
|
|
|
- table_t *ltab, int_stack_t *lstk, int_stack_t *sstk,
|
|
|
+ table_t *ltab, list_t *lstk, list_t *sstk,
|
|
|
list_t *lbl) {
|
|
|
node_t *n = parse(source);
|
|
|
if (NEEDS_UTF8 && !is_required("utf8")) {
|
|
@@ -6006,9 +6336,11 @@ char *escape(char *s) {
|
|
|
|
|
|
char *compile(char *source, list_t *required) {
|
|
|
list_t *ctx = list_new();
|
|
|
+ list_push(ctx, "top");
|
|
|
+
|
|
|
table_t *ltab = table_new();
|
|
|
- int_stack_t *lstk = stack_new();
|
|
|
- int_stack_t *sstk = stack_new();
|
|
|
+ list_t *lstk = list_new();
|
|
|
+ list_t *sstk = list_new();
|
|
|
list_t *lbl = list_new();
|
|
|
LBPUSH();
|
|
|
|