|  | @@ -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();
 | 
	
		
			
				|  |  |  
 |