|
@@ -289,6 +289,7 @@ typedef struct {
|
|
|
T_USE,
|
|
|
T_RETURN,
|
|
|
T_DEFER,
|
|
|
+ T_REQUIRE,
|
|
|
|
|
|
T_LPAR,
|
|
|
T_RPAR,
|
|
@@ -367,6 +368,17 @@ void consume_ignored(char *source, size_t *pos) {
|
|
|
|
|
|
list_t *FILES;
|
|
|
|
|
|
+int is_required(char *path) {
|
|
|
+ for (size_t i = 0; i < FILES->length; i++) {
|
|
|
+ list_t *pair = FILES->data[i];
|
|
|
+
|
|
|
+ if (strcmp(pair->data[0], path) == 0)
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
void traverse(char *source, size_t pos, size_t *line, size_t *col) {
|
|
|
*line = 1;
|
|
|
*col = 1;
|
|
@@ -525,6 +537,8 @@ token_t *next_token(char *source, size_t *pos) {
|
|
|
return TK(DEFER);
|
|
|
else if (strcmp(name, "pass") == 0)
|
|
|
return TK(PASS);
|
|
|
+ else if (strcmp(name, "require") == 0)
|
|
|
+ return TK(REQUIRE);
|
|
|
|
|
|
return token(T_NAME, name);
|
|
|
} else if (strncmp(&source[*pos], "==", 2) == 0 && ++(*pos) && ++(*pos))
|
|
@@ -644,6 +658,7 @@ struct _node_t {
|
|
|
N_RETURN,
|
|
|
N_DEFER,
|
|
|
N_PASS,
|
|
|
+ N_REQUIRE,
|
|
|
|
|
|
N_IFEXPR,
|
|
|
N_FUNCEXPR,
|
|
@@ -1329,6 +1344,14 @@ 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");
|
|
|
+
|
|
|
+ token_t *path = tokens->data[(*pos)++];
|
|
|
+
|
|
|
+ return NODET(REQUIRE, path);
|
|
|
+ }
|
|
|
|
|
|
node_t *n = parse_expr(tokens, pos);
|
|
|
|
|
@@ -1580,6 +1603,8 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, li
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+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) {
|
|
|
switch (node->tag) {
|
|
|
case N_PROGRAM:
|
|
@@ -1781,6 +1806,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
|
|
|
if (node->a)
|
|
|
compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
|
+ else EMIT("state->nil");
|
|
|
|
|
|
EMIT(";");
|
|
|
break;
|
|
@@ -1788,6 +1814,40 @@ 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_REQUIRE: {
|
|
|
+ char *path = node->t->text;
|
|
|
+
|
|
|
+ if (is_required(path))
|
|
|
+ break;
|
|
|
+
|
|
|
+ FILE *fd = fopen(path, "rb");
|
|
|
+ if (!fd)
|
|
|
+ COMPILE_ERROR("failed to open: `%s'", path);
|
|
|
+
|
|
|
+ buffer_t *fbuf = buffer_new();
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ char line[512];
|
|
|
+
|
|
|
+ if (!fgets(line, sizeof(line), fd))
|
|
|
+ break;
|
|
|
+
|
|
|
+ buffer_appends(fbuf, line);
|
|
|
+ }
|
|
|
+
|
|
|
+ char *source = buffer_read(fbuf);
|
|
|
+
|
|
|
+ list_t *pair = list_new();
|
|
|
+ list_push(pair, path);
|
|
|
+ list_push(pair, source);
|
|
|
+
|
|
|
+ list_push(FILES, pair);
|
|
|
+
|
|
|
+ compile_into(source, gbuf, buf, ctx, lstk);
|
|
|
+
|
|
|
+ list_pop(FILES);
|
|
|
+ } break;
|
|
|
+
|
|
|
case N_IFEXPR:
|
|
|
EMIT("(_qi_truthy(state, ");
|
|
|
compile_node(gbuf, buf, ctx, lstk, node->a);
|
|
@@ -1839,9 +1899,13 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-char *compile(char *source) {
|
|
|
+void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk) {
|
|
|
node_t *n = parse(source);
|
|
|
|
|
|
+ compile_node(gbuf, buf, ctx, lstk, n);
|
|
|
+}
|
|
|
+
|
|
|
+char *compile(char *source) {
|
|
|
list_t *ctx = list_new();
|
|
|
stack_t *lstk = stack_new();
|
|
|
|
|
@@ -1851,7 +1915,7 @@ char *compile(char *source) {
|
|
|
|
|
|
buffer_t *buf = buffer_new();
|
|
|
|
|
|
- compile_node(gbuf, buf, ctx, lstk, n);
|
|
|
+ compile_into(source, gbuf, buf, ctx, lstk);
|
|
|
|
|
|
buffer_t *rbuf = buffer_new();
|
|
|
|