|
@@ -283,6 +283,7 @@ typedef struct {
|
|
T_ELSE,
|
|
T_ELSE,
|
|
T_ELIF,
|
|
T_ELIF,
|
|
T_FOR,
|
|
T_FOR,
|
|
|
|
+ T_OF,
|
|
T_BREAK,
|
|
T_BREAK,
|
|
T_CONTINUE,
|
|
T_CONTINUE,
|
|
T_PASS,
|
|
T_PASS,
|
|
@@ -333,6 +334,8 @@ typedef struct {
|
|
T_DOT,
|
|
T_DOT,
|
|
T_BANG,
|
|
T_BANG,
|
|
|
|
|
|
|
|
+ T_INLINE,
|
|
|
|
+
|
|
T_ASSIGN,
|
|
T_ASSIGN,
|
|
T_SEMI
|
|
T_SEMI
|
|
} tag;
|
|
} tag;
|
|
@@ -562,6 +565,10 @@ token_t *next_token(char *source, size_t *pos) {
|
|
return TK(IS);
|
|
return TK(IS);
|
|
else if (strcmp(name, "in") == 0)
|
|
else if (strcmp(name, "in") == 0)
|
|
return TK(IN);
|
|
return TK(IN);
|
|
|
|
+ else if (strcmp(name, "of") == 0)
|
|
|
|
+ return TK(OF);
|
|
|
|
+ else if (strcmp(name, "inline") == 0)
|
|
|
|
+ return TK(INLINE);
|
|
|
|
|
|
return token(T_NAME, name);
|
|
return token(T_NAME, name);
|
|
} else if (strncmp(&source[*pos], "==", 2) == 0 && ++(*pos) && ++(*pos))
|
|
} else if (strncmp(&source[*pos], "==", 2) == 0 && ++(*pos) && ++(*pos))
|
|
@@ -702,6 +709,7 @@ struct _node_t {
|
|
N_LET,
|
|
N_LET,
|
|
N_IF,
|
|
N_IF,
|
|
N_FOR,
|
|
N_FOR,
|
|
|
|
+ N_FOROF,
|
|
N_BREAK,
|
|
N_BREAK,
|
|
N_CONTINUE,
|
|
N_CONTINUE,
|
|
N_FUNCDEF,
|
|
N_FUNCDEF,
|
|
@@ -714,6 +722,8 @@ struct _node_t {
|
|
N_LABEL,
|
|
N_LABEL,
|
|
N_GOTO,
|
|
N_GOTO,
|
|
|
|
|
|
|
|
+ N_INLINE,
|
|
|
|
+
|
|
N_IFEXPR,
|
|
N_IFEXPR,
|
|
N_FUNCEXPR,
|
|
N_FUNCEXPR,
|
|
|
|
|
|
@@ -1471,6 +1481,17 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
|
|
|
|
if (!AT(LCB) && !AT(COLON)) {
|
|
if (!AT(LCB) && !AT(COLON)) {
|
|
if (MATCH(VAR)) {
|
|
if (MATCH(VAR)) {
|
|
|
|
+ if (AT(NAME) && ATP(OF, 1)) {
|
|
|
|
+ token_t *t = tokens->data[(*pos)++];
|
|
|
|
+
|
|
|
|
+ EXPECT(OF, "of");
|
|
|
|
+
|
|
|
|
+ a = parse_expr(tokens, pos);
|
|
|
|
+ b = BLOCK();
|
|
|
|
+
|
|
|
|
+ return NODE2t(FOROF, a, b, t);
|
|
|
|
+ }
|
|
|
|
+
|
|
a = parse_var(tokens, pos, 0);
|
|
a = parse_var(tokens, pos, 0);
|
|
EXPECT(SEMI, ";");
|
|
EXPECT(SEMI, ";");
|
|
b = parse_expr(tokens, pos);
|
|
b = parse_expr(tokens, pos);
|
|
@@ -1538,6 +1559,13 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
|
|
EXPECT(COLON, ":");
|
|
EXPECT(COLON, ":");
|
|
|
|
|
|
return NODET(LABEL, t);
|
|
return NODET(LABEL, t);
|
|
|
|
+ } else if (MATCH(INLINE)) {
|
|
|
|
+ if (!AT(STRING))
|
|
|
|
+ PARSE_ERROR("expected string");
|
|
|
|
+
|
|
|
|
+ token_t *t = tokens->data[(*pos)++];
|
|
|
|
+
|
|
|
|
+ return NODET(INLINE, t);
|
|
}
|
|
}
|
|
|
|
|
|
node_t *n = parse_expr(tokens, pos);
|
|
node_t *n = parse_expr(tokens, pos);
|
|
@@ -1725,6 +1753,15 @@ size_t count_ctxs(list_t *ctx, char *s) {
|
|
#define LBPUSH() list_push(lbl, table_new())
|
|
#define LBPUSH() list_push(lbl, table_new())
|
|
#define LBPOP() list_pop(lbl)
|
|
#define LBPOP() list_pop(lbl)
|
|
|
|
|
|
|
|
+char *tempvar() {
|
|
|
|
+ NEWGID();
|
|
|
|
+
|
|
|
|
+ char *s = malloc(sizeof(char) * 64);
|
|
|
|
+ snprintf(s, 64, "__temp%zu", gid);
|
|
|
|
+
|
|
|
|
+ return s;
|
|
|
|
+}
|
|
|
|
+
|
|
void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node) {
|
|
void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node) {
|
|
NEWGID();
|
|
NEWGID();
|
|
|
|
|
|
@@ -1814,11 +1851,51 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, li
|
|
}
|
|
}
|
|
|
|
|
|
const char *STD[][2] = {
|
|
const char *STD[][2] = {
|
|
- {"std", "func head(l): return l[0]"},
|
|
|
|
|
|
+ {"std",
|
|
|
|
+ "func exit(c) {\n"
|
|
|
|
+ " if type(c) != \"number\":\n"
|
|
|
|
+ " throw \"expected first argument to be: number, but got: \" + type(c)\n"
|
|
|
|
+ " inline 'int code = qi_get(state, \"c\")->value.number'\n"
|
|
|
|
+ " inline 'exit(code)'\n"
|
|
|
|
+ "}\n"
|
|
|
|
+ "func head(l): return l[0]\n"
|
|
|
|
+ "func die(msg, c=1) {\n"
|
|
|
|
+ " println(msg)\n"
|
|
|
|
+ " exit(c)\n"
|
|
|
|
+ "}"
|
|
|
|
+ },
|
|
|
|
|
|
{NULL, NULL}
|
|
{NULL, NULL}
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+char *unescape(char *s) {
|
|
|
|
+ buffer_t *buf = buffer_new();
|
|
|
|
+
|
|
|
|
+ for (size_t i = 0; i < strlen(s); i++) {
|
|
|
|
+ char c = s[i];
|
|
|
|
+
|
|
|
|
+ if (c == '\\') {
|
|
|
|
+ char nc = s[i+1];
|
|
|
|
+ if (!nc)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ switch (nc) {
|
|
|
|
+ case 'n':
|
|
|
|
+ buffer_append(buf, '\n');
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ default:
|
|
|
|
+ buffer_append(buf, nc);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ i++;
|
|
|
|
+ } else buffer_append(buf, c);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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, list_t *lbl);
|
|
|
|
|
|
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, list_t *lbl, node_t *node) {
|
|
@@ -1967,11 +2044,41 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
CTXPOP();
|
|
CTXPOP();
|
|
LPOP();
|
|
LPOP();
|
|
|
|
|
|
- EMIT("__continue%d:;\n", gid);
|
|
|
|
-
|
|
|
|
if (node->c)
|
|
if (node->c)
|
|
compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
|
|
compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
|
|
|
|
|
|
|
|
+ EMIT("__continue%d:;\n", gid);
|
|
|
|
+ EMIT("}\n");
|
|
|
|
+
|
|
|
|
+ EMIT("__break%d:;\n", gid);
|
|
|
|
+
|
|
|
|
+ EMIT("qi_old_scope(state);\n");
|
|
|
|
+ CTXPOP();
|
|
|
|
+ } break;
|
|
|
|
+
|
|
|
|
+ case N_FOROF: {
|
|
|
|
+ NEWGID();
|
|
|
|
+ char *varname = tempvar();
|
|
|
|
+
|
|
|
|
+ CTXPUSH("scope");
|
|
|
|
+ EMIT("qi_new_scope(state);\n");
|
|
|
|
+
|
|
|
|
+ EMIT("qi_value_t *%s = qi_iter(state, ", varname);
|
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
|
|
|
|
+ EMIT(");\n");
|
|
|
|
+
|
|
|
|
+ EMIT("qi_decl(state, \"%s\", state->nil);\n", node->t->text);
|
|
|
|
+
|
|
|
|
+ EMIT("for (qi_size_t length = _qi_length(state, %s), i = 0; i < length; i++) {\n", varname);
|
|
|
|
+ EMIT("qi_set(state, false, \"%s\", qi_index(state, %s, qi_make_number(state, i)));\n", node->t->text, varname);
|
|
|
|
+
|
|
|
|
+ LPUSH(gid);
|
|
|
|
+ CTXPUSH("for");
|
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
|
|
|
|
+ CTXPOP();
|
|
|
|
+ LPOP();
|
|
|
|
+
|
|
|
|
+ EMIT("__continue%d:;\n", gid);
|
|
EMIT("}\n");
|
|
EMIT("}\n");
|
|
|
|
|
|
EMIT("__break%d:;\n", gid);
|
|
EMIT("__break%d:;\n", gid);
|
|
@@ -2103,7 +2210,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
case N_REQUIRE: {
|
|
case N_REQUIRE: {
|
|
char *source = NULL;
|
|
char *source = NULL;
|
|
|
|
|
|
- char *path = node->t->text;
|
|
|
|
|
|
+ char *path = unescape(node->t->text);
|
|
for (size_t i = 0; STD[i][0]; i++) {
|
|
for (size_t i = 0; STD[i][0]; i++) {
|
|
if (strcmp(path, STD[i][0]) == 0) {
|
|
if (strcmp(path, STD[i][0]) == 0) {
|
|
source = (char *)STD[i][1];
|
|
source = (char *)STD[i][1];
|
|
@@ -2237,6 +2344,8 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
UNOP("not");
|
|
UNOP("not");
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
+ case N_INLINE: EMIT("%s;", unescape(node->t->text)); break;
|
|
|
|
+
|
|
default:
|
|
default:
|
|
COMPILE_ERROR("not yet implemented");
|
|
COMPILE_ERROR("not yet implemented");
|
|
}
|
|
}
|