txlyre 1 miesiąc temu
rodzic
commit
44358974f5
1 zmienionych plików z 113 dodań i 4 usunięć
  1. 113 4
      qic.c

+ 113 - 4
qic.c

@@ -283,6 +283,7 @@ typedef struct {
     T_ELSE,
     T_ELIF,
     T_FOR,
+    T_OF,
     T_BREAK,
     T_CONTINUE,
     T_PASS,
@@ -333,6 +334,8 @@ typedef struct {
     T_DOT,
     T_BANG,
 
+    T_INLINE,
+
     T_ASSIGN,
     T_SEMI
   } tag;
@@ -562,6 +565,10 @@ token_t *next_token(char *source, size_t *pos) {
       return TK(IS);
     else if (strcmp(name, "in") == 0)
       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);
   } else if (strncmp(&source[*pos], "==", 2) == 0 && ++(*pos) && ++(*pos))
@@ -702,6 +709,7 @@ struct _node_t {
     N_LET,
     N_IF,
     N_FOR,
+    N_FOROF,
     N_BREAK,
     N_CONTINUE,
     N_FUNCDEF,
@@ -714,6 +722,8 @@ struct _node_t {
     N_LABEL,
     N_GOTO,
 
+    N_INLINE,
+
     N_IFEXPR,
     N_FUNCEXPR,
 
@@ -1471,6 +1481,17 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
 
     if (!AT(LCB) && !AT(COLON)) {
       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);
         EXPECT(SEMI, ";");
         b = parse_expr(tokens, pos);
@@ -1538,6 +1559,13 @@ node_t *parse_stmt(list_t *tokens, size_t *pos) {
     EXPECT(COLON, ":");
 
     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);
@@ -1725,6 +1753,15 @@ size_t count_ctxs(list_t *ctx, char *s) {
 #define LBPUSH() list_push(lbl, table_new())
 #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) {
   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] = {
-  {"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}
 };
 
+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_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();
       LPOP();
 
-      EMIT("__continue%d:;\n", gid);
-
       if (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("__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: {
       char *source = NULL;
 
-      char *path = node->t->text;
+      char *path = unescape(node->t->text);
       for (size_t i = 0; STD[i][0]; i++) {
         if (strcmp(path, STD[i][0]) == 0) {
           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");
       break;
 
+    case N_INLINE: EMIT("%s;", unescape(node->t->text)); break;
+
     default:
       COMPILE_ERROR("not yet implemented");
   }