txlyre vor 1 Monat
Ursprung
Commit
dd4dbbfb74
1 geänderte Dateien mit 147 neuen und 66 gelöschten Zeilen
  1. 147 66
      qic.c

+ 147 - 66
qic.c

@@ -199,7 +199,7 @@ table_t *table_set(table_t *table, char *key, void *value) {
 
 #define table_iterate(table, code)                                             \
   {                                                                            \
-    if (table->used) {                                                         \
+    if ((table)->used) {                                                         \
       size_t i = 0;                                                            \
       while (i < (table)->capacity) {                                          \
         entry_t entry = (table)->entries[i];                             \
@@ -278,6 +278,7 @@ typedef struct {
     T_NAME,
 
     T_VAR,
+    T_LET,
     T_IF,
     T_ELSE,
     T_ELIF,
@@ -293,6 +294,7 @@ typedef struct {
     T_TRY,
     T_CATCH,
     T_THROW,
+    T_GOTO,
 
     T_LPAR,
     T_RPAR,
@@ -517,6 +519,8 @@ token_t *next_token(char *source, size_t *pos) {
 
     if (strcmp(name, "var") == 0)
       return TK(VAR);
+    else if (strcmp(name, "let") == 0)
+      return TK(LET);
     else if (strcmp(name, "if") == 0)
       return TK(IF);
     else if (strcmp(name, "else") == 0)
@@ -547,6 +551,8 @@ token_t *next_token(char *source, size_t *pos) {
       return TK(CATCH);
     else if (strcmp(name, "throw") == 0)
       return TK(THROW);
+    else if (strcmp(name, "goto") == 0)
+      return TK(GOTO);
 
     return token(T_NAME, name);
   } else if (strncmp(&source[*pos], "==", 2) == 0 && ++(*pos) && ++(*pos))
@@ -664,6 +670,7 @@ struct _node_t {
     N_DEC,
 
     N_VAR,
+    N_LET,
     N_IF,
     N_FOR,
     N_BREAK,
@@ -675,6 +682,8 @@ struct _node_t {
     N_REQUIRE,
     N_TRY,
     N_THROW,
+    N_LABEL,
+    N_GOTO,
 
     N_IFEXPR,
     N_FUNCEXPR,
@@ -852,6 +861,7 @@ node_t *nodef(int tag, token_t *name, table_t *params, table_t *captured, node_t
 #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 ATP(tk, p) ((*pos)+p < tokens->length && ((token_t *)tokens->data[(*pos)+p])->tag == T_##tk)
 #define MATCH(tk) (AT(tk) && ++(*pos))
 #define PARSE_ERROR(fmt, ...) { format_error(GETFNAME(((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi), GETSRC(((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->fi), ((token_t *)tokens->data[(*pos)>0?(*pos)-1:(*pos)])->pos, fmt, ##__VA_ARGS__); exit(1); }
 #define EXPECT(tk, s) { if (!MATCH(tk)) PARSE_ERROR("expected %s", (s)); }
@@ -1235,7 +1245,7 @@ node_t *parse_if(list_t *tokens, size_t *pos) {
   return NODE3(IF, a, b, c);
 }
 
-node_t *parse_var(list_t *tokens, size_t *pos) {
+node_t *parse_var(list_t *tokens, size_t *pos, int is_let) {
   table_t *h = table_new();
 
   do {
@@ -1245,12 +1255,19 @@ node_t *parse_var(list_t *tokens, size_t *pos) {
     char *k = ((token_t *)tokens->data[(*pos)++])->text;
     node_t *v = NULL;
 
-    if (MATCH(ASSIGN))
+    if (is_let) {
+      EXPECT(ASSIGN, "=");
+
+      v = parse_expr(tokens, pos);
+    } else if (MATCH(ASSIGN))
       v = parse_expr(tokens, pos);
 
     table_set(h, k, v);
   } while (MATCH(COMMA));
 
+  if (is_let)
+    return NODEH(LET, h);
+
   return NODEH(VAR, h);
 }
 
@@ -1350,7 +1367,9 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
 
     return NODEL(BLOCK, stmts);
   } else if (MATCH(VAR))
-    return parse_var(tokens, pos);
+    return parse_var(tokens, pos, 0);
+  else if (MATCH(LET))
+    return parse_var(tokens, pos, 1);
   else if (MATCH(IF))
     return parse_if(tokens, pos);
   else if (MATCH(FOR)) {
@@ -1360,7 +1379,7 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
 
     if (!AT(LCB) && !AT(COLON)) {
       if (MATCH(VAR)) {
-        a = parse_var(tokens, pos);
+        a = parse_var(tokens, pos, 0);
         EXPECT(SEMI, ";");
         b = parse_expr(tokens, pos);
         EXPECT(SEMI, ";");
@@ -1414,6 +1433,19 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
       a = parse_expr(tokens, pos);
 
     return NODE1(THROW, a);
+  } else if (MATCH(GOTO)) {
+    if(!AT(NAME))
+      PARSE_ERROR("expected identifier");
+
+    token_t *t = tokens->data[(*pos)++];
+
+    return NODET(GOTO, t);
+  } else if (AT(NAME) && ATP(COLON, 1) && !CLIFF) {
+    token_t *t = tokens->data[(*pos)++];
+
+    EXPECT(COLON, ":");
+
+    return NODET(LABEL, t);
   }
 
   node_t *n = parse_expr(tokens, pos);
@@ -1461,8 +1493,8 @@ node_t *parse(char *source) {
 #define NEWGID() size_t gid = GID++
  
 #define EMIT(fmt, ...) buffer_fmt(buf, (fmt), ##__VA_ARGS__);
-#define BINOP(s) { EMIT("qi_" s "(state, "); compile_node(gbuf, buf, ctx, lstk, node->a); EMIT(", "); compile_node(gbuf, buf, ctx, lstk, node->b); EMIT(")"); }
-#define UNOP(s) { EMIT("qi_" s "(state, "); compile_node(gbuf, buf, ctx, lstk, node->a); EMIT(")"); }
+#define BINOP(s) { EMIT("qi_" s "(state, "); compile_node(gbuf, buf, ctx, lstk, lbl, node->a); EMIT(", "); compile_node(gbuf, buf, ctx, lstk, lbl, node->b); EMIT(")"); }
+#define UNOP(s) { EMIT("qi_" s "(state, "); compile_node(gbuf, buf, ctx, lstk, lbl, node->a); EMIT(")"); }
 #define ASSIGN(lhs, rhs) {\
   if ((lhs)->tag == N_LITERAL && (lhs)->t->tag == T_NAME) {\
     EMIT("qi_set(state, false, \"%s\", ", (lhs)->t->text);\
@@ -1470,15 +1502,15 @@ node_t *parse(char *source) {
     EMIT(")");\
   } else if ((lhs)->tag == N_INDEX) {\
     EMIT("qi_index_set(state, false, ");\
-    compile_node(gbuf, buf, ctx, lstk, (lhs)->a);\
+    compile_node(gbuf, buf, ctx, lstk, lbl, (lhs)->a);\
     EMIT(", ");\
-    compile_node(gbuf, buf, ctx, lstk, (lhs)->b);\
+    compile_node(gbuf, buf, ctx, lstk, lbl, (lhs)->b);\
     EMIT(", ");\
     rhs;\
     EMIT(")");\
   } else if ((lhs)->tag == N_MEMBER) {\
     EMIT("qi_index_set(state, false, ");\
-    compile_node(gbuf, buf, ctx, lstk, (lhs)->a);\
+    compile_node(gbuf, buf, ctx, lstk, lbl, (lhs)->a);\
     EMIT(", qi_make_string(state, \"%s\"), ", (lhs)->t->text);\
     rhs;\
     EMIT(")");\
@@ -1487,7 +1519,7 @@ node_t *parse(char *source) {
 #define COMPASSIGN(lhs, s, rhs) {\
   ASSIGN(node->a, {\
     EMIT("qi_%s(state, ", s);\
-    compile_node(gbuf, buf, ctx, lstk, (lhs));\
+    compile_node(gbuf, buf, ctx, lstk, lbl, (lhs));\
     EMIT(", ");\
     rhs;\
     EMIT(")");\
@@ -1495,9 +1527,9 @@ node_t *parse(char *source) {
 }
 #define COMPILE_ERROR(fmt, ...) { format_error(GETFNAME(node->fi), GETSRC(node->fi), node->pos, fmt, ##__VA_ARGS__); exit(1); }
 
-void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, node_t *node);
+void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node);
 
-void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *seq) {
+void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, list_t *seq) {
   if (!seq || seq->length < 1) {
     EMIT("NULL");
 
@@ -1514,7 +1546,7 @@ void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
   for (size_t i = 0; i < seq->length; i++) {
     buffer_fmt(tbuf, "qi_list_push(list, ");
 
-    compile_node(gbuf, tbuf, ctx, lstk, seq->data[i]);
+    compile_node(gbuf, tbuf, ctx, lstk, lbl, seq->data[i]);
 
     buffer_fmt(tbuf, ");\n");
   }
@@ -1527,7 +1559,7 @@ void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
   EMIT("__list%d(state)", gid);
 }
 
-void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, table_t *table) {
+void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, table_t *table) {
   if (!table || table->used < 1) {
     EMIT("NULL");
 
@@ -1544,7 +1576,7 @@ void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, ta
   table_iterate(table, {
     buffer_fmt(tbuf, "qi_table_set(table, \"%s\", ", entry.key);
 
-    compile_node(gbuf, tbuf, ctx, lstk, entry.value);
+    compile_node(gbuf, tbuf, ctx, lstk, lbl, entry.value);
 
     buffer_fmt(tbuf, ");\n");
   });
@@ -1598,13 +1630,17 @@ size_t count_ctxs(list_t *ctx, char *s) {
 #define LPOP() stack_pop(lstk)
 #define LID (lstk->data[lstk->length-1])
 
-void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, node_t *node) {
+#define LBPUSH() list_push(lbl, table_new())
+#define LBPOP() list_pop(lbl)
+
+void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node) {
   NEWGID();
 
   buffer_t *tbuf = buffer_new();
 
   buffer_fmt(tbuf, "qi_value_t *__func%d(qi_state_t *state, qi_size_t pargc, qi_list_t *pargs) {\n", gid);
 
+  LBPUSH();
   CTXPUSH("gap");
   CTXPUSH("func");
 
@@ -1620,7 +1656,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
         optargc++;
 
         buffer_fmt(tbuf, "qi_set(state, false, \"%s\", pargc >= %d? qi_list_index(pargs, %d): ", entry.key, argc+1, argc);
-        compile_node(gbuf, tbuf, ctx, lstk, pair->data[1]);
+        compile_node(gbuf, tbuf, ctx, lstk, lbl, pair->data[1]);
         buffer_fmt(tbuf, ");\n");
       } else
         buffer_fmt(tbuf, "qi_set(state, false, \"%s\", qi_list_index(pargs, %d));\n", entry.key, argc);
@@ -1629,10 +1665,11 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
     });
   }
 
-  compile_node(gbuf, tbuf, ctx, lstk, node->a);
+  compile_node(gbuf, tbuf, ctx, lstk, lbl, node->a);
 
   CTXPOP();
   CTXPOP();
+  LBPOP();
 
   buffer_fmt(tbuf, "return state->nil;\n");
   buffer_fmt(tbuf, "}\n");
@@ -1642,7 +1679,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
   tbuf = buffer_new();
 
   buffer_fmt(tbuf, "qi_make_function(state, \"%s\", %d, __func%d, ", node->t? node->t->text: "<anon>", !node->h? 0: (node->h->used - optargc), gid);
-  compile_table(gbuf, tbuf, ctx, lstk, node->h2);
+  compile_table(gbuf, tbuf, ctx, lstk, lbl, node->h2);
   buffer_fmt(tbuf, ")");
 
   if (node->tag == N_FUNCEXPR) {
@@ -1656,20 +1693,20 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
   EMIT(");");
 }
 
-void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *block) {
+void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, list_t *block) {
   for (size_t i = 0; i < block->length; i++) {
     node_t *n = block->data[i];
 
     if (n->tag == N_FUNCDEF) {
-      compile_func(gbuf, buf, ctx, lstk, n);
+      compile_func(gbuf, buf, ctx, lstk, lbl, n);
 
       EMIT("\n");
-    } else if (n->tag == N_VAR) {
+    } else if (n->tag == N_VAR || n->tag == N_LET) {
       table_iterate(n->h, {
-        EMIT("qi_decl(state, \"%s\", ", entry.key);
+        EMIT("qi_%s(state, \"%s\", ", n->tag == N_LET? "decl_const": "decl", entry.key);
         
         if (entry.value)
-          compile_node(gbuf, buf, ctx, lstk, entry.value);
+          compile_node(gbuf, buf, ctx, lstk, lbl, entry.value);
         else EMIT("state->nil");
 
         EMIT(");\n");
@@ -1678,37 +1715,40 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, li
   }
 
   for (size_t i = 0; i < block->length; i++) {
-    compile_node(gbuf, buf, ctx, lstk, block->data[i]);
+    compile_node(gbuf, buf, ctx, lstk, lbl, block->data[i]);
 
     EMIT("\n");
   }
 }
 
-#define STD_SIZE 1
-const char *STD[STD_SIZE][2] = {
+const char *STD[][2] = {
   {"std", "func head(l): return l[0]"},
+
+  {NULL, NULL}
 };
 
-void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctk, stack_t *lstk);
+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, node_t *node) {
+void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, node_t *node) {
   switch (node->tag) {
     case N_PROGRAM:
-      compile_block(gbuf, buf, ctx, lstk, node->l);
+      compile_block(gbuf, buf, ctx, lstk, lbl, node->l);
       break;
 
     case N_EXPRSTMT:
       EMIT("(void)(");
-      compile_node(gbuf, buf, ctx, lstk, node->a);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
       EMIT(");");
       break;
 
     case N_BLOCK:
+      LBPUSH();
       CTXPUSH("scope");
       EMIT("qi_new_scope(state);\n");
-      compile_block(gbuf, buf, ctx, lstk, node->l);
+      compile_block(gbuf, buf, ctx, lstk, lbl, node->l);
       EMIT("qi_old_scope(state);");
       CTXPOP();
+      LBPOP();
       break;
 
     case N_LITERAL:
@@ -1736,13 +1776,13 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
 
     case N_LIST:
       EMIT("qi_make_list(state, ");
-      compile_list(gbuf, buf, ctx, lstk, node->l);
+      compile_list(gbuf, buf, ctx, lstk, lbl, node->l);
       EMIT(")");
       break;
 
     case N_TUPLE:
       EMIT("qi_make_tuple(state, ");
-      compile_list(gbuf, buf, ctx, lstk, node->l);
+      compile_list(gbuf, buf, ctx, lstk, lbl, node->l);
       EMIT(")");
       break;
 
@@ -1750,35 +1790,35 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
 
     case N_TABLE:
       EMIT("qi_make_table(state, ");
-      compile_table(gbuf, buf, ctx, lstk, node->h);
+      compile_table(gbuf, buf, ctx, lstk, lbl, node->h);
       EMIT(")");
       break;
 
     case N_CALL:
       EMIT("qi_call(state, ");
-      compile_node(gbuf, buf, ctx, lstk, node->a);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
       EMIT(", ");
-      compile_list(gbuf, buf, ctx, lstk, node->l);
+      compile_list(gbuf, buf, ctx, lstk, lbl, node->l);
       EMIT(")");
       break;
 
     case N_MEMBER:
       EMIT("qi_index(state, ");
-      compile_node(gbuf, buf, ctx, lstk, node->a);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
       EMIT(", qi_make_string(state, \"%s\"))", node->t->text);
       break;
 
     case N_INDEX:
       EMIT("qi_index(state, ");
-      compile_node(gbuf, buf, ctx, lstk, node->a);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
       EMIT(", ");
-      compile_node(gbuf, buf, ctx, lstk, node->b);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
       EMIT(")");
       break;
 
-    case N_ASSIGN: ASSIGN(node->a, compile_node(gbuf, buf, ctx, lstk, node->b)); break;
+    case N_ASSIGN: ASSIGN(node->a, compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
 
-    case N_ASSIGN_ADD: COMPASSIGN(node->a, "add", compile_node(gbuf, buf, ctx, lstk, node->b)); break;
+    case N_ASSIGN_ADD: COMPASSIGN(node->a, "add", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
 
     case N_INC: 
       COMPASSIGN(node->a, "add", EMIT("state->one"));
@@ -1792,18 +1832,18 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
 
     case N_IF:
       EMIT("if (_qi_truthy(state, ");
-      compile_node(gbuf, buf, ctx, lstk, node->a);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
       EMIT(")) {\n");
       CTXPUSH("scope");
       EMIT("qi_new_scope(state);\n");
-      compile_node(gbuf, buf, ctx, lstk, node->b);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
       EMIT("qi_old_scope(state);\n");
       CTXPOP();
       if (node->c) {
         EMIT("} else {\n");
         CTXPUSH("scope");
         EMIT("qi_new_scope(state);\n");
-        compile_node(gbuf, buf, ctx, lstk, node->c);
+        compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
         EMIT("qi_old_scope(state);\n");
         CTXPOP();
       }
@@ -1820,25 +1860,25 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
         EMIT("for (;;) {\n");
       } else if (node->a && !node->b) {
         EMIT("while (_qi_truthy(state, ");
-        compile_node(gbuf, buf, ctx, lstk, node->a);
+        compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
         EMIT(")) {\n");
       } else {
-        compile_node(gbuf, buf, ctx, lstk, node->a);
+        compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
         EMIT("while (_qi_truthy(state, ");
-        compile_node(gbuf, buf, ctx, lstk, node->b);
+        compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
         EMIT(")) {\n");
       }
 
       LPUSH(gid);
       CTXPUSH("for");
-      compile_node(gbuf, buf, ctx, lstk, node->d);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->d);
       CTXPOP();
       LPOP();
 
       EMIT("__continue%d:;\n", gid);
 
       if (node->c)
-        compile_node(gbuf, buf, ctx, lstk, node->c);
+        compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
 
       EMIT("}\n");
 
@@ -1869,9 +1909,11 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
 
       buffer_fmt(tbuf, "void __defer%d(qi_state_t *state) {\n", gid);
 
+      LBPUSH();
       CTXPUSH("gap");
-      compile_node(gbuf, tbuf, ctx, lstk, node->a);
+      compile_node(gbuf, tbuf, ctx, lstk, lbl, node->a);
       CTXPOP();
+      LBPOP();
 
       buffer_fmt(tbuf, "\n");
       buffer_fmt(tbuf, "}\n");
@@ -1894,7 +1936,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
       EMIT("return ");
 
       if (node->a)
-        compile_node(gbuf, buf, ctx, lstk, node->a);
+        compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
       else EMIT("state->nil");
 
       EMIT(";");
@@ -1907,12 +1949,12 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
       CTXPUSH("scope");
       EMIT("qi_new_scope(state);\n");
       EMIT("qi_try(state, {\n");
-      compile_node(gbuf, buf, ctx, lstk, node->a);
+      compile_node(gbuf, buf, ctx, lstk, lbl, 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);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
       CTXPOP();
       EMIT("}, NULL);\n");
       EMIT("qi_new_scope(state);");
@@ -1922,18 +1964,55 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
     case N_THROW:
       EMIT("qi_throw(state, ");
       if (node->a)
-        compile_node(gbuf, buf, ctx, lstk, node->a);
+        compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
       else {
         EMIT("state->nil");
       }
       EMIT(");");
       break;
 
+    case N_LABEL: {
+      char *label = node->t->text;
+
+      table_iterate((table_t *)list_index(lbl, -1), {
+        if (strcmp(entry.key, label) == 0) {
+          COMPILE_ERROR("duplicated label: '%s'", label);
+        }
+      });
+
+      NEWGID();
+
+      EMIT("__label%d:;", gid);
+
+      size_t *n = malloc(sizeof(size_t));
+      memcpy(n, &gid, sizeof(size_t));
+
+      table_set(list_index(lbl, -1), label, n);
+      } break;
+
+    case N_GOTO: {
+      ssize_t gid = -1;
+      char *label = node->t->text;
+
+      table_iterate((table_t *)list_index(lbl, -1), {
+        if (strcmp(entry.key, label) == 0) {
+          gid = *(size_t *)entry.value;
+
+          break;
+        }
+      });
+
+      if (gid < 0)
+        COMPILE_ERROR("undefined label: '%s'", label);
+
+      EMIT("goto __label%d;", gid);
+      } break;
+
     case N_REQUIRE: {
       char *source = NULL;
 
       char *path = node->t->text;
-      for (size_t i = 0; i < STD_SIZE; i++) {
+      for (size_t i = 0; STD[i][0]; i++) {
         if (strcmp(path, STD[i][0]) == 0) {
           source = (char *)STD[i][1];
 
@@ -1947,7 +2026,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
       if (!source) {
         FILE *fd = fopen(path, "rb");
         if (!fd)
-          COMPILE_ERROR("failed to open: `%s'", path);
+          COMPILE_ERROR("'%s' is not a valid file path or a builtin library name", path);
 
         buffer_t *fbuf = buffer_new();
 
@@ -1970,7 +2049,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
 
       list_push(FILES, pair);
 
-      compile_into(source, gbuf, buf, ctx, lstk);
+      compile_into(source, gbuf, buf, ctx, lstk, lbl);
 
       list_pop(FILES);
       list_push(REQUIRED, path);
@@ -1978,16 +2057,16 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
 
     case N_IFEXPR:
       EMIT("(_qi_truthy(state, ");
-      compile_node(gbuf, buf, ctx, lstk, node->a);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
       EMIT(")? ");
-      compile_node(gbuf, buf, ctx, lstk, node->b);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
       EMIT(": ");
-      compile_node(gbuf, buf, ctx, lstk, node->c);
+      compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
       EMIT(")");
       break;
 
     case N_FUNCEXPR:
-      compile_func(gbuf, buf, ctx, lstk, node);
+      compile_func(gbuf, buf, ctx, lstk, lbl, node);
       break;
 
     case N_EQUALS:
@@ -2035,15 +2114,17 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, nod
   }
 }
 
-void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk) {
+void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl) {
   node_t *n = parse(source);
 
-  compile_node(gbuf, buf, ctx, lstk, n);
+  compile_node(gbuf, buf, ctx, lstk, lbl, n);
 }
 
 char *compile(char *source) {
   list_t *ctx = list_new();
   stack_t *lstk = stack_new();
+  list_t *lbl = list_new();
+  LBPUSH();
   
   buffer_t *gbuf = buffer_new();
 
@@ -2051,7 +2132,7 @@ char *compile(char *source) {
 
   buffer_t *buf = buffer_new();
 
-  compile_into(source, gbuf, buf, ctx, lstk);
+  compile_into(source, gbuf, buf, ctx, lstk, lbl);
 
   buffer_t *rbuf = buffer_new();