txlyre 1 gün önce
ebeveyn
işleme
d65c88f1d3
1 değiştirilmiş dosya ile 108 ekleme ve 74 silme
  1. 108 74
      qic.c

+ 108 - 74
qic.c

@@ -434,7 +434,7 @@ token_t *next_token(char *source, size_t *pos) {
   if (!source[*pos])
     return token(T_EOF, NULL);
 
-  if (source[*pos] == '"' || source[*pos] == '\'') {
+  if (source[*pos] == '"' || source[*pos] == '\'' || source[*pos] == '`') {
     char term = source[(*pos)++];
 
     buffer_t *text = buffer_new();
@@ -444,8 +444,10 @@ token_t *next_token(char *source, size_t *pos) {
         LEX_ERROR("unterminated string literal");
 
       char c = source[(*pos)++];
+      if (c == '\n' && term != '`')
+        LEX_ERROR("unterminated string literal");
 
-      if (c == '\\') {
+      if (term != '`' && c == '\\') {
         char nc = source[(*pos)++];
 
         if (!nc)
@@ -484,6 +486,10 @@ token_t *next_token(char *source, size_t *pos) {
             buffer_appends(text, "\\\\");
             break;
 
+          case '\n':
+            buffer_appends(text, "\\n");
+            break;
+
           default:
             buffer_append(text, nc);
             break;
@@ -494,6 +500,8 @@ token_t *next_token(char *source, size_t *pos) {
 
       if (c == '"' || c == '\\')
         buffer_append(text, '\\');
+      else if (c == '\n')
+        buffer_appends(text, "\\n");
 
       buffer_append(text, c);
     }
@@ -501,13 +509,22 @@ token_t *next_token(char *source, size_t *pos) {
     (*pos)++;
 
     return token(T_STRING, buffer_read(text));
-  } else if (isdigit(source[*pos])) {
+  } else if ((source[*pos] == '.' && isdigit(source[(*pos)+1])) || isdigit(source[*pos])) {
     buffer_t *number = buffer_new();
     int dot = 0;
     int sub = 0;
+    int skip = 0;
+
+    if (source[*pos] == '.') {
+      buffer_append(number, '0');
+
+      skip = 1;
+    }
 
     do {
-      buffer_append(number, source[(*pos)++]);
+      if (skip) skip = 0;
+      else
+        buffer_append(number, source[(*pos)++]);
 
       if (!dot && source[*pos] == '.') {
         buffer_append(number, source[(*pos)++]);
@@ -516,9 +533,12 @@ token_t *next_token(char *source, size_t *pos) {
           LEX_ERROR("illegal number literal (missing part after floating point)");
 
         dot = 1;
-      } else if (!sub && source[*pos] == '.') {
+      } else if (!sub && source[*pos] == '_') {
         (*pos)++;
 
+        if (!isdigit(source[*pos]))
+          LEX_ERROR("illegal number literal (missing part after underscore)");
+
         sub = 1;
       } else if (sub) sub = 0;
     } while (isdigit(source[*pos]));
@@ -1541,8 +1561,13 @@ node_t *parse_func(list_t *tokens, size_t *pos, int is_expr) {
     EXPECT(RPAR, ")");
   }
 
+  int colon = AT(COLON);
+
   node_t *body = BLOCK();
 
+  if (colon && body->tag == N_EXPRSTMT)
+    body = NODE1(RETURN, body->a);
+
   if (is_expr)
     return NODEF(FUNCEXPR, NULL, params, captured, body);
 
@@ -1940,7 +1965,11 @@ 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, lbl, block->data[i]);
+    node_t *n = block->data[i];
+    if (n->tag == N_FUNCDEF || n->tag == N_VAR || n->tag == N_LET)
+      continue;
+
+    compile_node(gbuf, buf, ctx, lstk, lbl, n);
 
     EMIT("\n");
   }
@@ -1949,10 +1978,10 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, li
 const char *STD[][2] = {
   {"std",
     "func exit(c) {\n"
-    "  if type(c) != \"number\":\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"
+    "  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"
@@ -1961,7 +1990,7 @@ const char *STD[][2] = {
     "}\n"
     "let SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2\n"
     "func frewind(file)\n"
-    "  fseek(file, 0, SEEK_SET)\n"
+    "  return fseek(file, 0, SEEK_SET)\n"
     "func file_read(filename) {\n"
     "  var file = fopen(filename, \"r\")\n"
     "  defer fclose(file)\n"
@@ -1970,6 +1999,20 @@ const char *STD[][2] = {
     "  frewind(file)\n"
     "  return str(fread(file, size))\n"
     "}\n"
+    "func is_defined(name) {\n"
+    "  if type(name) != \"string\"\n"
+    "    throw \"expected first argument to be: string, but got: \" + type(name)\n"
+    "  inline `bool b = qi_find(state, qi_get(state, \"name\")->value.string) != NULL`\n"
+    "  inline `return qi_make_boolean(state, b)`\n"
+    "}\n"
+  },
+
+  {"str",
+    "let STR_LETTERS = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n"
+    "let STR_ASCII_LC = \"abcdefghijklmnopqrstuvwxyz\"\n"
+    "let STR_ASCII_UC = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n"
+    "let STR_DIGITS = \"0123456789\"\n"
+    "func is_char(c): return type(c) == \"string\" && len(c) == 1\n"
   },
 
   {NULL, NULL}
@@ -2005,6 +2048,54 @@ char *unescape(char *s) {
 
 void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl);
 
+int require_once(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, list_t *lbl, char *path) {
+  char *source = NULL;
+
+  for (size_t i = 0; STD[i][0]; i++) {
+    if (strcmp(path, STD[i][0]) == 0) {
+      source = (char *)STD[i][1];
+
+      break;
+    }
+  }
+
+  if (is_required(path))
+    return 1;
+
+  if (!source) {
+    FILE *fd = fopen(path, "rb");
+    if (!fd)
+      return -1;
+
+    buffer_t *fbuf = buffer_new();
+
+    for (;;) {
+      char line[512];
+
+      if (!fgets(line, sizeof(line), fd))
+        break;
+
+      buffer_appends(fbuf, line);
+    }
+
+    source = buffer_read(fbuf);
+    path = realpath(path, NULL);
+  }
+
+  list_t *pair = list_new();
+  list_push(pair, path);
+  list_push(pair, source);
+
+  list_push(FILES, pair);
+
+  compile_into(source, gbuf, buf, ctx, lstk, lbl);
+
+  list_pop(FILES);
+  list_push(REQUIRED, path);
+
+  return 0;
+}
+
 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:
@@ -2117,18 +2208,10 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
       EMIT("if (_qi_truthy(state, ");
       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, 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, lbl, node->c);
-        EMIT("qi_old_scope(state);\n");
-        CTXPOP();
       }
       EMIT("}");
       break;
@@ -2136,9 +2219,6 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
     case N_FOR: {
       NEWGID();
 
-      CTXPUSH("scope");
-      EMIT("qi_new_scope(state);\n");
-
       if (!node->a) {
         EMIT("for (;;) {\n");
       } else if (node->a && !node->b) {
@@ -2165,22 +2245,19 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
       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");
 
+      CTXPUSH("scope");
+      EMIT("qi_new_scope(state);\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);
@@ -2197,7 +2274,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
 
       EMIT("__break%d:;\n", gid);
 
-      EMIT("qi_old_scope(state);\n");
+      EMIT("qi_old_scope(state);");
       CTXPOP();
       } break;
 
@@ -2259,8 +2336,6 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
     case N_PASS: break;
 
     case N_TRY:
-      CTXPUSH("scope");
-      EMIT("qi_new_scope(state);\n");
       EMIT("qi_try(state, {\n");
       compile_node(gbuf, buf, ctx, lstk, lbl, node->a);
       EMIT("}, {\n");
@@ -2270,8 +2345,6 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
       compile_node(gbuf, buf, ctx, lstk, lbl, node->b);
       CTXPOP();
       EMIT("}, NULL);\n");
-      EMIT("qi_new_scope(state);");
-      CTXPOP();
       break;
 
     case N_THROW:
@@ -2322,50 +2395,10 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
       } break;
 
     case N_REQUIRE: {
-      char *source = NULL;
-
       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];
-
-          break;
-        }
-      }
-
-      if (is_required(path))
-        break;
-
-      if (!source) {
-        FILE *fd = fopen(path, "rb");
-        if (!fd)
-          COMPILE_ERROR("'%s' is not a valid file path or a builtin library name", path);
-
-        buffer_t *fbuf = buffer_new();
-
-        for (;;) {
-          char line[512];
-
-          if (!fgets(line, sizeof(line), fd))
-            break;
-
-          buffer_appends(fbuf, line);
-        }
-
-        source = buffer_read(fbuf);
-        path = realpath(path, NULL);
-      }
-
-      list_t *pair = list_new();
-      list_push(pair, path);
-      list_push(pair, source);
-
-      list_push(FILES, pair);
-
-      compile_into(source, gbuf, buf, ctx, lstk, lbl);
 
-      list_pop(FILES);
-      list_push(REQUIRED, path);
+      if (require_once(gbuf, buf, ctx, lstk, lbl, path) < 0)
+        COMPILE_ERROR("'%s' is not a valid file path or a builtin library name", path);
       } break;
 
     case N_IFEXPR:
@@ -2507,6 +2540,7 @@ char *compile(char *source) {
 
   buffer_t *buf = buffer_new();
 
+  require_once(gbuf, buf, ctx, lstk, lbl, "std");
   compile_into(source, gbuf, buf, ctx, lstk, lbl);
 
   buffer_t *rbuf = buffer_new();