|
@@ -290,6 +290,9 @@ typedef struct {
|
|
|
T_RETURN,
|
|
|
T_DEFER,
|
|
|
T_REQUIRE,
|
|
|
+ T_TRY,
|
|
|
+ T_CATCH,
|
|
|
+ T_THROW,
|
|
|
|
|
|
T_LPAR,
|
|
|
T_RPAR,
|
|
@@ -305,6 +308,7 @@ typedef struct {
|
|
|
T_STARSTAR,
|
|
|
T_PLUSPLUS,
|
|
|
T_MINUSMINUS,
|
|
|
+ T_SLASHSLASH,
|
|
|
|
|
|
T_PLUS,
|
|
|
T_MINUS,
|
|
@@ -537,6 +541,12 @@ token_t *next_token(char *source, size_t *pos) {
|
|
|
return TK(PASS);
|
|
|
else if (strcmp(name, "require") == 0)
|
|
|
return TK(REQUIRE);
|
|
|
+ else if (strcmp(name, "try") == 0)
|
|
|
+ return TK(TRY);
|
|
|
+ else if (strcmp(name, "catch") == 0)
|
|
|
+ return TK(CATCH);
|
|
|
+ else if (strcmp(name, "throw") == 0)
|
|
|
+ return TK(THROW);
|
|
|
|
|
|
return token(T_NAME, name);
|
|
|
} else if (strncmp(&source[*pos], "==", 2) == 0 && ++(*pos) && ++(*pos))
|
|
@@ -551,6 +561,10 @@ token_t *next_token(char *source, size_t *pos) {
|
|
|
return TK(PLUSPLUS);
|
|
|
else if (strncmp(&source[*pos], "--", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
return TK(MINUSMINUS);
|
|
|
+ else if (strncmp(&source[*pos], "//", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
+ return TK(SLASHSLASH);
|
|
|
+ else if (strncmp(&source[*pos], "**", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
+ return TK(STARSTAR);
|
|
|
else if (source[*pos] == '(' && ++(*pos))
|
|
|
return TK(LPAR);
|
|
|
else if (source[*pos] == ')' && ++(*pos))
|
|
@@ -604,10 +618,10 @@ list_t *tokenize(char *source) {
|
|
|
tok->fi = FILES->length-1;
|
|
|
tok->pos = tok_pos;
|
|
|
|
|
|
+ list_push(toks, tok);
|
|
|
+
|
|
|
if (tok->tag == T_EOF)
|
|
|
break;
|
|
|
-
|
|
|
- list_push(toks, tok);
|
|
|
} while (1);
|
|
|
|
|
|
return toks;
|
|
@@ -636,6 +650,8 @@ struct _node_t {
|
|
|
N_SUB,
|
|
|
N_MUL,
|
|
|
N_DIV,
|
|
|
+ N_IDIV,
|
|
|
+ N_POW,
|
|
|
|
|
|
N_ASSIGN,
|
|
|
N_ASSIGN_ADD,
|
|
@@ -657,6 +673,8 @@ struct _node_t {
|
|
|
N_DEFER,
|
|
|
N_PASS,
|
|
|
N_REQUIRE,
|
|
|
+ N_TRY,
|
|
|
+ N_THROW,
|
|
|
|
|
|
N_IFEXPR,
|
|
|
N_FUNCEXPR,
|
|
@@ -698,7 +716,7 @@ node_t *nodet(int tag, token_t *t) {
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODET(n, a) (node_pos(nodet(N_##n, (a)), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#define NODET(n, a) (node_pos(nodet(N_##n, (a)), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
|
|
|
node_t *nodel(int tag, list_t *l) {
|
|
|
node_t *node = malloc(sizeof(node_t));
|
|
@@ -709,7 +727,7 @@ node_t *nodel(int tag, list_t *l) {
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODEL(n, a) (node_pos(nodel(N_##n, (a)), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#define NODEL(n, a) (node_pos(nodel(N_##n, (a)), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
|
|
|
node_t *nodeh(int tag, table_t *h) {
|
|
|
node_t *node = malloc(sizeof(node_t));
|
|
@@ -720,7 +738,7 @@ node_t *nodeh(int tag, table_t *h) {
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODEH(n, a) (node_pos(nodeh(N_##n, (a)), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#define NODEH(n, a) (node_pos(nodeh(N_##n, (a)), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
|
|
|
node_t *node0(int tag) {
|
|
|
node_t *node = malloc(sizeof(node_t));
|
|
@@ -730,7 +748,7 @@ node_t *node0(int tag) {
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODE0(n) (node_pos(node0(N_##n), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#define NODE0(n) (node_pos(node0(N_##n), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
|
|
|
node_t *node1(int tag, node_t *a) {
|
|
|
node_t *node = malloc(sizeof(node_t));
|
|
@@ -741,7 +759,7 @@ node_t *node1(int tag, node_t *a) {
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODE1(n, a) (node_pos(node1(N_##n, (a)), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#define NODE1(n, a) (node_pos(node1(N_##n, (a)), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
|
|
|
node_t *node1l(int tag, node_t *a, list_t *l) {
|
|
|
node_t *node = malloc(sizeof(node_t));
|
|
@@ -753,7 +771,7 @@ node_t *node1l(int tag, node_t *a, list_t *l) {
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODE1l(n, a, l) (node_pos(node1l(N_##n, (a), (l)), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#define NODE1l(n, a, l) (node_pos(node1l(N_##n, (a), (l)), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
|
|
|
node_t *node1t(int tag, node_t *a, token_t *t) {
|
|
|
node_t *node = malloc(sizeof(node_t));
|
|
@@ -765,7 +783,7 @@ node_t *node1t(int tag, node_t *a, token_t *t) {
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODE1t(n, a, t) (node_pos(node1t(N_##n, (a), (t)), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#define NODE1t(n, a, t) (node_pos(node1t(N_##n, (a), (t)), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
|
|
|
node_t *node2(int tag, node_t *a, node_t *b) {
|
|
|
node_t *node = malloc(sizeof(node_t));
|
|
@@ -777,7 +795,20 @@ node_t *node2(int tag, node_t *a, node_t *b) {
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODE2(n, a, b) (node_pos(node2(N_##n, (a), (b)), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#define NODE2(n, a, b) (node_pos(node2(N_##n, (a), (b)), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
+
|
|
|
+node_t *node2t(int tag, node_t *a, node_t *b, token_t *t) {
|
|
|
+ node_t *node = malloc(sizeof(node_t));
|
|
|
+
|
|
|
+ node->tag = tag;
|
|
|
+ node->a = a;
|
|
|
+ node->b = b;
|
|
|
+ node->t = t;
|
|
|
+
|
|
|
+ return node;
|
|
|
+}
|
|
|
+
|
|
|
+#define NODE2t(n, a, b, c) (node_pos(node2t(N_##n, (a), (b), (c)), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
|
|
|
node_t *node3(int tag, node_t *a, node_t *b, node_t *c) {
|
|
|
node_t *node = malloc(sizeof(node_t));
|
|
@@ -790,7 +821,7 @@ node_t *node3(int tag, node_t *a, node_t *b, node_t *c) {
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODE3(n, a, b, c) (node_pos(node3(N_##n, (a), (b), (c)), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#define NODE3(n, a, b, c) (node_pos(node3(N_##n, (a), (b), (c)), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi, ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos))
|
|
|
|
|
|
node_t *node4(int tag, node_t *a, node_t *b, node_t *c, node_t *d) {
|
|
|
node_t *node = malloc(sizeof(node_t));
|
|
@@ -804,7 +835,7 @@ node_t *node4(int tag, node_t *a, node_t *b, node_t *c, node_t *d) {
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODE4(n, a, b, c, d) (node_pos(node4(N_##n, (a), (b), (c), (d)), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#define NODE4(n, a, b, c, d) (node_pos(node4(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))
|
|
|
|
|
|
node_t *nodef(int tag, token_t *name, table_t *params, table_t *captured, node_t *body) {
|
|
|
node_t *node = malloc(sizeof(node_t));
|
|
@@ -818,7 +849,7 @@ node_t *nodef(int tag, token_t *name, table_t *params, table_t *captured, node_t
|
|
|
return node;
|
|
|
}
|
|
|
|
|
|
-#define NODEF(n, a, b, c, d) (node_pos(nodef(N_##n, (a), (b), (c), (d)), ((token_t *)tokens->data[(*pos)-1])->fi, ((token_t *)tokens->data[(*pos)-1])->pos))
|
|
|
+#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 MATCH(tk) (AT(tk) && ++(*pos))
|
|
@@ -978,6 +1009,18 @@ node_t *parse_unary(list_t *tokens, size_t *pos) {
|
|
|
node_t *parse_pow(list_t *tokens, size_t *pos) {
|
|
|
node_t *a = parse_unary(tokens, pos);
|
|
|
|
|
|
+ do {
|
|
|
+ if (MATCH(STARSTAR)) {
|
|
|
+ node_t *b = parse_unary(tokens, pos);
|
|
|
+
|
|
|
+ a = NODE2(POW, a, b);
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ } while (1);
|
|
|
+
|
|
|
return a;
|
|
|
}
|
|
|
|
|
@@ -996,6 +1039,12 @@ node_t *parse_mul(list_t *tokens, size_t *pos) {
|
|
|
|
|
|
a = NODE2(DIV, a, b);
|
|
|
|
|
|
+ continue;
|
|
|
+ } else if (MATCH(SLASHSLASH)) {
|
|
|
+ node_t *b = parse_pow(tokens, pos);
|
|
|
+
|
|
|
+ a = NODE2(IDIV, a, b);
|
|
|
+
|
|
|
continue;
|
|
|
}
|
|
|
|
|
@@ -1342,13 +1391,29 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
|
|
|
return NODE1(DEFER, a);
|
|
|
} else if (MATCH(PASS)) return NODE0(PASS);
|
|
|
- else if (MATCH(REQUIRE)) {
|
|
|
- if (!AT(STRING))
|
|
|
- PARSE_ERROR("expected string");
|
|
|
+ else if (MATCH(TRY)) {
|
|
|
+ node_t *a = BLOCK();
|
|
|
+ token_t *t = NULL;
|
|
|
+
|
|
|
+ EXPECT(CATCH, "catch");
|
|
|
|
|
|
- token_t *path = tokens->data[(*pos)++];
|
|
|
+ if (!AT(COLON) && !AT(LCB)) {
|
|
|
+ if (!AT(NAME))
|
|
|
+ PARSE_ERROR("expected identifier");
|
|
|
+
|
|
|
+ t = tokens->data[(*pos)++];
|
|
|
+ }
|
|
|
+
|
|
|
+ node_t *b = BLOCK();
|
|
|
+
|
|
|
+ return NODE2t(TRY, a, b, t);
|
|
|
+ } else if (MATCH(THROW)) {
|
|
|
+ node_t *a = NULL;
|
|
|
+
|
|
|
+ if (!CLIFF)
|
|
|
+ a = parse_expr(tokens, pos);
|
|
|
|
|
|
- return NODET(REQUIRE, path);
|
|
|
+ return NODE1(THROW, a);
|
|
|
}
|
|
|
|
|
|
node_t *n = parse_expr(tokens, pos);
|
|
@@ -1357,10 +1422,27 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
}
|
|
|
|
|
|
node_t *parse_program(list_t *tokens, size_t *pos) {
|
|
|
+ if (AT(EOF))
|
|
|
+ PARSE_ERROR("empty program");
|
|
|
+
|
|
|
list_t *stmts = list_new();
|
|
|
|
|
|
- while (*pos < tokens->length) {
|
|
|
- node_t *n = parse_stmt(tokens, pos);
|
|
|
+ int flag = 0;
|
|
|
+
|
|
|
+ while (!AT(EOF) && *pos < tokens->length) {
|
|
|
+ node_t *n;
|
|
|
+
|
|
|
+ if (MATCH(REQUIRE)) {
|
|
|
+ if (flag)
|
|
|
+ PARSE_ERROR("misplaced require statement")
|
|
|
+
|
|
|
+ if (!AT(STRING))
|
|
|
+ PARSE_ERROR("expected string");
|
|
|
+
|
|
|
+ token_t *path = tokens->data[(*pos)++];
|
|
|
+
|
|
|
+ n = NODET(REQUIRE, path);
|
|
|
+ } else { n = parse_stmt(tokens, pos); flag = 1; }
|
|
|
|
|
|
MATCH(SEMI);
|
|
|
|
|
@@ -1492,7 +1574,7 @@ int in_context(list_t *ctx, char *s) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-size_t scopes_count(list_t *ctx) {
|
|
|
+size_t count_ctxs(list_t *ctx, char *s) {
|
|
|
if (!ctx->length)
|
|
|
return 0;
|
|
|
|
|
@@ -1501,7 +1583,7 @@ size_t scopes_count(list_t *ctx) {
|
|
|
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)
|
|
|
+ else if (strcmp(ctx->data[i], s) == 0)
|
|
|
k++;
|
|
|
}
|
|
|
|
|
@@ -1509,7 +1591,8 @@ size_t scopes_count(list_t *ctx) {
|
|
|
}
|
|
|
|
|
|
#define INCTX(s) (in_context(ctx, (s)))
|
|
|
-#define SCOPESK (scopes_count(ctx))
|
|
|
+#define SCOPESK (count_ctxs(ctx, "scope"))
|
|
|
+#define TRAPSK (count_ctxs(ctx, "trap"))
|
|
|
|
|
|
#define LPUSH(i) stack_push(lstk, (i))
|
|
|
#define LPOP() stack_pop(lstk)
|
|
@@ -1601,6 +1684,11 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, li
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#define STD_SIZE 1
|
|
|
+const char *STD[STD_SIZE][2] = {
|
|
|
+ {"std", "func head(l): return l[0]"},
|
|
|
+};
|
|
|
+
|
|
|
void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctk, stack_t *lstk);
|
|
|
|
|
|
void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, node_t *node) {
|
|
@@ -1800,6 +1888,9 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
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)
|
|
@@ -1812,28 +1903,66 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
case N_FUNCDEF: break;
|
|
|
case N_PASS: break;
|
|
|
|
|
|
+ case N_TRY:
|
|
|
+ CTXPUSH("scope");
|
|
|
+ EMIT("qi_new_scope(state);\n");
|
|
|
+ EMIT("qi_try(state, {\n");
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, 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);
|
|
|
+ CTXPOP();
|
|
|
+ EMIT("}, NULL);\n");
|
|
|
+ EMIT("qi_new_scope(state);");
|
|
|
+ CTXPOP();
|
|
|
+ break;
|
|
|
+
|
|
|
+ case N_THROW:
|
|
|
+ EMIT("qi_throw(state, ");
|
|
|
+ if (node->a)
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ else {
|
|
|
+ EMIT("state->nil");
|
|
|
+ }
|
|
|
+ EMIT(");");
|
|
|
+ break;
|
|
|
+
|
|
|
case N_REQUIRE: {
|
|
|
+ char *source = NULL;
|
|
|
+
|
|
|
char *path = node->t->text;
|
|
|
+ for (size_t i = 0; i < STD_SIZE; i++) {
|
|
|
+ if (strcmp(path, STD[i][0]) == 0) {
|
|
|
+ source = (char *)STD[i][1];
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
if (is_required(path))
|
|
|
break;
|
|
|
|
|
|
- FILE *fd = fopen(path, "rb");
|
|
|
- if (!fd)
|
|
|
- COMPILE_ERROR("failed to open: `%s'", path);
|
|
|
+ if (!source) {
|
|
|
+ FILE *fd = fopen(path, "rb");
|
|
|
+ if (!fd)
|
|
|
+ COMPILE_ERROR("failed to open: `%s'", path);
|
|
|
|
|
|
- buffer_t *fbuf = buffer_new();
|
|
|
+ buffer_t *fbuf = buffer_new();
|
|
|
|
|
|
- for (;;) {
|
|
|
- char line[512];
|
|
|
+ for (;;) {
|
|
|
+ char line[512];
|
|
|
|
|
|
- if (!fgets(line, sizeof(line), fd))
|
|
|
- break;
|
|
|
+ if (!fgets(line, sizeof(line), fd))
|
|
|
+ break;
|
|
|
|
|
|
- buffer_appends(fbuf, line);
|
|
|
- }
|
|
|
+ buffer_appends(fbuf, line);
|
|
|
+ }
|
|
|
|
|
|
- char *source = buffer_read(fbuf);
|
|
|
+ source = buffer_read(fbuf);
|
|
|
+ path = realpath(path, NULL);
|
|
|
+ }
|
|
|
|
|
|
list_t *pair = list_new();
|
|
|
list_push(pair, path);
|
|
@@ -1889,6 +2018,14 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
BINOP("div");
|
|
|
break;
|
|
|
|
|
|
+ case N_IDIV:
|
|
|
+ BINOP("idiv");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case N_POW:
|
|
|
+ BINOP("pow");
|
|
|
+ break;
|
|
|
+
|
|
|
case N_NEGATE:
|
|
|
UNOP("negate");
|
|
|
break;
|