txlyre 1 dzień temu
rodzic
commit
ac2e1824f3
1 zmienionych plików z 293 dodań i 275 usunięć
  1. 293 275
      qic.c

+ 293 - 275
qic.c

@@ -703,8 +703,8 @@ token_t *next_token(char *source, size_t *pos) {
 
     return t;
   } else if (source[*pos] == 'u' &&
-            (source[(*pos) + 1] == '"' || source[(*pos) + 1] == '\'' ||
-             source[(*pos) + 1] == '`')) {
+             (source[(*pos) + 1] == '"' || source[(*pos) + 1] == '\'' ||
+              source[(*pos) + 1] == '`')) {
     (*pos)++;
 
     token_t *t = tokenize_string(source, pos);
@@ -1583,7 +1583,9 @@ node_t *parse_primary(list_t *tokens, size_t *pos) {
     EXPECT(RCB, "}");
 
     return NODEH(TABLE, table);
-  } else if (MATCH(NUMBER) || MATCH(STRING) || MATCH(FSTRING) || MATCH(USTRING) || MATCH(NAME) || MATCH(TRUE) || MATCH(FALSE) || MATCH(NIL))
+  } else if (MATCH(NUMBER) || MATCH(STRING) || MATCH(FSTRING) ||
+             MATCH(USTRING) || MATCH(NAME) || MATCH(TRUE) || MATCH(FALSE) ||
+             MATCH(NIL))
     return NODET(LITERAL, tokens->data[(*pos) - 1]);
 
   if (MATCH(RPAR)) {
@@ -2593,32 +2595,32 @@ node_t *_parse_stmt(list_t *tokens, size_t *pos, int allow_comma) {
 
     if (!CLIFF && !AT(EOF) && !AT(SEMI)) {
       EXPECT(LCB, "{");
-  
+
       for (;;) {
         int is_out = 0;
         int is_static = 0;
-  
+
         if (AT(RCB))
           break;
-  
+
         if (MATCH(LET))
           is_out = 1;
         else if (MATCH(CONST))
           is_static = 1;
-  
+
         if (!AT(NAME))
           PARSE_ERROR("expected identifier");
-  
+
         list_t *triple = list_new();
-  
+
         token_t *t = tokens->data[(*pos)++];
         list_push(triple, t);
-  
+
         int *flagp = malloc_checked(sizeof(int));
         int flag = is_static ? 2 : is_out ? 1 : 0;
-  
+
         memcpy(flagp, &flag, sizeof(int));
-  
+
         if (MATCH(ASSIGN)) {
           list_push(triple, flagp);
           list_push(triple, parse_expr(tokens, pos));
@@ -2626,10 +2628,10 @@ node_t *_parse_stmt(list_t *tokens, size_t *pos, int allow_comma) {
           list_push(triple, flagp);
           list_push(triple, parse_func(tokens, pos, 1));
         }
-  
+
         list_push(triples, triple);
       }
-  
+
       EXPECT(RCB, "}");
     }
 
@@ -2663,7 +2665,8 @@ node_t *_parse_stmt(list_t *tokens, size_t *pos, int allow_comma) {
     return NODET(INLINE, t);
   }
 
-  return NODE1(EXPRSTMT, allow_comma? parse_comma_expr(tokens, pos): parse_expr(tokens, pos));
+  return NODE1(EXPRSTMT, allow_comma ? parse_comma_expr(tokens, pos)
+                                     : parse_expr(tokens, pos));
 }
 
 #define ATM(t)                                                                 \
@@ -3041,14 +3044,14 @@ node_t *parse(char *source) {
     compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node->a);              \
     EMIT(")");                                                                 \
   }
-#define ASSIGNIN(buf, lhs, rhs, prefix)                                                \
+#define ASSIGNIN(buf, lhs, rhs, prefix)                                        \
   {                                                                            \
     if ((lhs)->tag == N_LITERAL && (lhs)->t->tag == T_NAME) {                  \
-      buffer_fmt(buf, "qi_set(state, " #prefix  ", \"%s\", ", (lhs)->t->text);        \
+      buffer_fmt(buf, "qi_set(state, " #prefix ", \"%s\", ", (lhs)->t->text);  \
       rhs;                                                                     \
       buffer_fmt(buf, ")");                                                    \
     } else if ((lhs)->tag == N_INDEX) {                                        \
-      buffer_fmt(buf, "qi_index_set(state, " #prefix ", ");                          \
+      buffer_fmt(buf, "qi_index_set(state, " #prefix ", ");                    \
       compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, (lhs)->a);           \
       buffer_fmt(buf, ", ");                                                   \
       compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, (lhs)->b);           \
@@ -3056,7 +3059,7 @@ node_t *parse(char *source) {
       rhs;                                                                     \
       buffer_fmt(buf, ")");                                                    \
     } else if ((lhs)->tag == N_MEMBER) {                                       \
-      buffer_fmt(buf, "qi_index_set(state, " #prefix ", ");                          \
+      buffer_fmt(buf, "qi_index_set(state, " #prefix ", ");                    \
       compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, (lhs)->a);           \
       buffer_fmt(buf, ", qi_make_string(state, \"%s\"), ", (lhs)->t->text);    \
       rhs;                                                                     \
@@ -3075,15 +3078,18 @@ node_t *parse(char *source) {
       EMIT(")");                                                               \
     });                                                                        \
   }
-#define COMPASSIGNP(lhs, s, rhs)                                                \
+#define COMPASSIGNP(lhs, s, rhs)                                               \
   {                                                                            \
-    ASSIGNIN(buf, node->a, {                                                          \
-      EMIT("qi_%s(state, ", s);                                                \
-      compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, (lhs));              \
-      EMIT(", ");                                                              \
-      rhs;                                                                     \
-      EMIT(")");                                                               \
-    }, true);                                                                        \
+    ASSIGNIN(                                                                  \
+        buf, node->a,                                                          \
+        {                                                                      \
+          EMIT("qi_%s(state, ", s);                                            \
+          compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, (lhs));          \
+          EMIT(", ");                                                          \
+          rhs;                                                                 \
+          EMIT(")");                                                           \
+        },                                                                     \
+        true);                                                                 \
   }
 #define COMPILE_ERROR(fmt, ...)                                                \
   {                                                                            \
@@ -3098,8 +3104,7 @@ node_t *parse(char *source) {
   }
 
 void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
-                  list_t *lstk, list_t *sstk, list_t *lbl,
-                  node_t *node);
+                  list_t *lstk, list_t *sstk, list_t *lbl, node_t *node);
 
 char *tempvar() {
   NEWGID();
@@ -3111,8 +3116,7 @@ char *tempvar() {
 }
 
 void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
-                  list_t *lstk, list_t *sstk, list_t *lbl,
-                  list_t *seq) {
+                  list_t *lstk, list_t *sstk, list_t *lbl, list_t *seq) {
   if (!seq || seq->length < 1) {
     EMIT("NULL");
 
@@ -3179,8 +3183,7 @@ void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
 }
 
 void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
-                   list_t *lstk, list_t *sstk, list_t *lbl,
-                   table_t *table) {
+                   list_t *lstk, list_t *sstk, list_t *lbl, table_t *table) {
   if (!table || table->used < 1) {
     EMIT("NULL");
 
@@ -3218,7 +3221,7 @@ int in_context(list_t *ctx, char *s) {
   if (!ctx->length)
     return 0;
 
-  for (ssize_t i = ctx->length - 1; i >= 0; i--) 
+  for (ssize_t i = ctx->length - 1; i >= 0; i--)
     if (strcmp(ctx->data[i], "gap") == 0)
       break;
     else if (strcmp(ctx->data[i], s) == 0)
@@ -3261,21 +3264,23 @@ list_t *CONSTANTS;
 #define SCOPESK (count_ctxs(ctx, "scope"))
 #define TRAPSK (count_ctxs(ctx, "trap"))
 
-#define LPUSH(i) {\
-  int_stack_t *pair = stack_new();\
-  stack_push(pair, (i));\
-  stack_push(pair, scope_index(ctx));\
-  list_push(lstk, pair);\
-}
+#define LPUSH(i)                                                               \
+  {                                                                            \
+    int_stack_t *pair = stack_new();                                           \
+    stack_push(pair, (i));                                                     \
+    stack_push(pair, scope_index(ctx));                                        \
+    list_push(lstk, pair);                                                     \
+  }
 #define LPOP() list_pop(lstk)
 #define LID (((int_stack_t *)lstk->data[lstk->length - 1])->data[0])
 
-#define SPUSH(i) {\
-  int_stack_t *pair = stack_new();\
-  stack_push(pair, (i));\
-  stack_push(pair, scope_index(ctx));\
-  list_push(sstk, pair);\
-}
+#define SPUSH(i)                                                               \
+  {                                                                            \
+    int_stack_t *pair = stack_new();                                           \
+    stack_push(pair, (i));                                                     \
+    stack_push(pair, scope_index(ctx));                                        \
+    list_push(sstk, pair);                                                     \
+  }
 #define SPOP() list_pop(sstk)
 #define SID (sstk->data[sstk->length - 1]->data[0])
 
@@ -3303,8 +3308,8 @@ void emit_debug(buffer_t *buf, node_t *node) {
 }
 
 void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
-                  list_t *lstk, list_t *sstk, list_t *lbl,
-                  node_t *node, char *name) {
+                  list_t *lstk, list_t *sstk, list_t *lbl, node_t *node,
+                  char *name) {
   NEWGID();
 
   char *funname = name ? name : node->t ? node->t->text : "<anon>";
@@ -3434,8 +3439,7 @@ size_t scope_index(list_t *ctx) {
 }
 
 void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
-                   list_t *lstk, list_t *sstk, list_t *lbl,
-                   list_t *block) {
+                   list_t *lstk, list_t *sstk, list_t *lbl, list_t *block) {
   for (size_t i = 0; i < block->length; i++) {
     node_t *node = block->data[i];
 
@@ -3558,196 +3562,195 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
 
 const char *STD[][2] = {
     {"json",
-        "require \"string\"\n"
-    "class JSONError(Error)\n"
-    "func json_tokenize(s) {\n"
-    "  let toks = []\n"
-    "  for var i = 0; i < len(s); i++ {\n"
-    "    if isws(s[i])\n"
-    "      continue\n"
-    "    if s[i] in \"[]{}:,\"\n"
-    "      toks.push((s[i], nil))\n"
-    "    elif isalpha(s[i]) {\n"
-    "      var text = \"\"\n"
-    "      for i < len(s) && isalpha(s[i])\n"
-    "        text += s[i++]\n"
-    "      i--\n"
-    "      toks.push((\"name\", text))\n"
-    "    } elif s[i] == '-' || isdigit(s[i]) {\n"
-    "      var text = \"\"\n"
-    "      if s[i] == '-'\n"
-    "        text += s[i++]\n"
-    "      if i >= len(s) || !isdigit(s[i])\n"
-    "        throw JSONError(f\"${i}: malformed number literal\")\n"
-    "      for i < len(s) && isdigit(s[i]) {\n"
-    "        text += s[i++]\n"
-    "        if i < len(s) && s[i] == \".\" && \".\" !in text\n"
-    "          text += s[i++]\n"
-    "      }\n"
-    "      i--\n"
-    "      toks.push((\"number\", text))\n"
-    "    } elif s[i] == '\"' {\n"
-    "      var text = \"\"\n"
-    "      i++\n"
-    "      for i < len(s) && s[i] != '\"' {\n"
-    "        var c = s[i++]\n"
-    "        if c == `\\` {\n"
-    "          if i >= len(s)\n"
-    "            throw JSONError(f\"#${i}: unterminated string literal\")\n"
-    "          switch s[i] {\n"
-    "            case \"n\":\n"
-    "              c = \"\\n\"\n"
-    "              break\n"
-    "            case \"r\":\n"
-    "              c = \"\\r\"\n"
-    "              break\n"
-    "            case \"t\":\n"
-    "              c = \"\\t\"\n"
-    "              break\n"
-    "          }\n"
-    "          i++\n"
-    "        }\n"
-    "        text += c\n"
-    "      }\n"
-    "      if i >= len(s) || s[i] != '\"'\n"
-    "        throw JSONError(f\"#${i}: unterminated string literal\")\n"
-    "      toks.push((\"string\", text))\n"
-    "    } else\n"
-    "      throw JSONError(f\"#${i}: unknown input\")\n"
-    "  }\n"
-    "  return toks\n"
-    "}\n"
-    "func json_parse(toks) {\n"
-    "  func parse_array(toks) {\n"
-    "    let r = []\n"
-    "    if toks && toks[0][0] == ']'\n"
-    "      return r, toks[1:]\n"
-    "    for {\n"
-    "      var e\n"
-    "      [e, toks] = parse_expression(toks)\n"
-    "      r.push(e)\n"
-    "      if !toks || toks[0][0] != ','\n"
-    "        break\n"
-    "      if toks[0][0] == \",\"\n"
-    "        toks = toks[1:]\n"
-    "    }\n"
-    "    if !toks || toks[0][0] != ']'\n"
-    "      throw JSONError(\"missing ]\")\n"
-    "    return r, toks[1:]\n"
-    "  }\n"
-    "  func parse_object(toks) {\n"
-    "    let r = {}\n"
-    "    for {\n"
-    "      var k, e\n"
-    "      if !toks || toks[0][0] != \"string\"\n"
-    "        throw JSONError(\"expected string\")\n"
-    "      k = toks[0][1]\n"
-    "      toks = toks[1:]\n"
-    "      if !toks || toks[0][0] != \":\"\n"
-    "        throw JSONError(\"expected :\")\n"
-    "      toks = toks[1:]\n"
-    "      [e, toks] = parse_expression(toks)\n"
-    "      r[k] = e\n"
-    "      if !toks || toks[0][0] != \",\"\n"
-    "        break\n"
-    "      if toks[0][0] == \",\"\n"
-    "        toks = toks[1:]\n"
-    "    }\n"
-    "    if !toks || toks[0][0] != \"}\"\n"
-    "      throw JSONError(\"missing }\")\n"
-    "    return r, toks[1:]\n"
-    "  }\n"
-    "  func parse_expression(toks) {\n"
-    "    if toks\n"
-    "      switch toks[0][0] {\n"
-    "        case \"{\":\n"
-    "          return parse_object(toks[1:])\n"
-    "        case \"[\":\n"
-    "          return parse_array(toks[1:])\n"
-    "        case \"name\":\n"
-    "          switch toks[0][1] {\n"
-    "            case \"true\":\n"
-    "              return true, toks[1:]\n"
-    "            case \"false\":\n"
-    "              return false, toks[1:]\n"
-    "            case \"null\":\n"
-    "              return nil, toks[1:]\n"
-    "          }\n"
-    "          throw JSONError(f\"illegal name: ${toks[0][1]}\")\n"
-    "        case \"number\":\n"
-    "          return num(toks[0][1]), toks[1:]\n"
-    "        case \"string\":\n"
-    "          return toks[0][1], toks[1:]\n"
-    "      }\n"
-    "    throw JSONError(\"expected expression\")\n"
-    "  }\n"
-    "  if !toks\n"
-    "    throw JSONError(\"empty document\")\n"
-    "  if toks[0][0] !in \"{[\"\n"
-    "    throw JSONError(\"expected { or [\")\n"
-    "  let [r, unconsumed] = parse_expression(toks)\n"
-    "  if unconsumed\n"
-    "    throw JSONError(\"unconsumed input\")\n"
-    "  return r\n"
-    "}\n"
-    "func json_read(s)\n"
-    "  return json_parse(json_tokenize(s))\n"
-    "func json_dump(d) {\n"
-    "  func escape(s) {\n"
-    "    var r = \"\"\n"
-    "    \n"
-    "    for var c of s {\n"
-    "      if c == `\\`\n"
-    "        r += `\\\\`\n"
-    "      elif c == '\"'\n"
-    "        r += `\\\"`\n"
-    "      elif c == \"\\n\"\n"
-    "        r += `\\n`\n"
-    "      elif c == \"\\r\"\n"
-    "        r += `\\r`\n"
-    "      elif c == \"\\t\"\n"
-    "        r += `\\t`\n"
-    "      else r += c\n"
-    "    }\n"
-    "    return r\n"
-    "  }\n"
-    "  switch type(d) {\n"
-    "    case \"nil\":\n"
-    "      return \"null\"\n"
-    "    case \"bool\":\n"
-    "      return d? \"true\": \"false\"\n"
-    "    case \"number\":\n"
-    "      return str(d)\n"
-    "    case \"string\":\n"
-    "      return \"\\\"\" + escape(d) + \"\\\"\"\n"
-    "    case \"list\":\n"
-    "      var f = true\n"
-    "      var buf = \"[\"\n"
-    "      for var el of d {\n"
-    "        if f\n"
-    "          f = false\n"
-    "        else\n"
-    "          buf += \", \"\n"
-    "        buf += json_dump(el)   \n"
-    "      }\n"
-    "      buf += \"]\"\n"
-    "      return buf\n"
-    "    case \"table\":\n"
-    "      var f = true\n"
-    "      var buf = \"{\"\n"
-    "      for var [k, v] of enumerate(d) {\n"
-    "        if f\n"
-    "          f = false\n"
-    "        else\n"
-    "          buf += \", \"\n"
-    "        buf += f`\"${escape(k)}\": ${json_dump(v)}`\n"
-    "      }\n"
-    "      buf += \"}\"\n"
-    "      return buf\n"
-    "  }\n"
-    "  throw JSONError(f\"cannot serialize ${type(d)} into a JSON\")\n"
-    "}\n"
-    },
+     "require \"string\"\n"
+     "class JSONError(Error)\n"
+     "func json_tokenize(s) {\n"
+     "  let toks = []\n"
+     "  for var i = 0; i < len(s); i++ {\n"
+     "    if isws(s[i])\n"
+     "      continue\n"
+     "    if s[i] in \"[]{}:,\"\n"
+     "      toks.push((s[i], nil))\n"
+     "    elif isalpha(s[i]) {\n"
+     "      var text = \"\"\n"
+     "      for i < len(s) && isalpha(s[i])\n"
+     "        text += s[i++]\n"
+     "      i--\n"
+     "      toks.push((\"name\", text))\n"
+     "    } elif s[i] == '-' || isdigit(s[i]) {\n"
+     "      var text = \"\"\n"
+     "      if s[i] == '-'\n"
+     "        text += s[i++]\n"
+     "      if i >= len(s) || !isdigit(s[i])\n"
+     "        throw JSONError(f\"${i}: malformed number literal\")\n"
+     "      for i < len(s) && isdigit(s[i]) {\n"
+     "        text += s[i++]\n"
+     "        if i < len(s) && s[i] == \".\" && \".\" !in text\n"
+     "          text += s[i++]\n"
+     "      }\n"
+     "      i--\n"
+     "      toks.push((\"number\", text))\n"
+     "    } elif s[i] == '\"' {\n"
+     "      var text = \"\"\n"
+     "      i++\n"
+     "      for i < len(s) && s[i] != '\"' {\n"
+     "        var c = s[i++]\n"
+     "        if c == `\\` {\n"
+     "          if i >= len(s)\n"
+     "            throw JSONError(f\"#${i}: unterminated string literal\")\n"
+     "          switch s[i] {\n"
+     "            case \"n\":\n"
+     "              c = \"\\n\"\n"
+     "              break\n"
+     "            case \"r\":\n"
+     "              c = \"\\r\"\n"
+     "              break\n"
+     "            case \"t\":\n"
+     "              c = \"\\t\"\n"
+     "              break\n"
+     "          }\n"
+     "          i++\n"
+     "        }\n"
+     "        text += c\n"
+     "      }\n"
+     "      if i >= len(s) || s[i] != '\"'\n"
+     "        throw JSONError(f\"#${i}: unterminated string literal\")\n"
+     "      toks.push((\"string\", text))\n"
+     "    } else\n"
+     "      throw JSONError(f\"#${i}: unknown input\")\n"
+     "  }\n"
+     "  return toks\n"
+     "}\n"
+     "func json_parse(toks) {\n"
+     "  func parse_array(toks) {\n"
+     "    let r = []\n"
+     "    if toks && toks[0][0] == ']'\n"
+     "      return r, toks[1:]\n"
+     "    for {\n"
+     "      var e\n"
+     "      [e, toks] = parse_expression(toks)\n"
+     "      r.push(e)\n"
+     "      if !toks || toks[0][0] != ','\n"
+     "        break\n"
+     "      if toks[0][0] == \",\"\n"
+     "        toks = toks[1:]\n"
+     "    }\n"
+     "    if !toks || toks[0][0] != ']'\n"
+     "      throw JSONError(\"missing ]\")\n"
+     "    return r, toks[1:]\n"
+     "  }\n"
+     "  func parse_object(toks) {\n"
+     "    let r = {}\n"
+     "    for {\n"
+     "      var k, e\n"
+     "      if !toks || toks[0][0] != \"string\"\n"
+     "        throw JSONError(\"expected string\")\n"
+     "      k = toks[0][1]\n"
+     "      toks = toks[1:]\n"
+     "      if !toks || toks[0][0] != \":\"\n"
+     "        throw JSONError(\"expected :\")\n"
+     "      toks = toks[1:]\n"
+     "      [e, toks] = parse_expression(toks)\n"
+     "      r[k] = e\n"
+     "      if !toks || toks[0][0] != \",\"\n"
+     "        break\n"
+     "      if toks[0][0] == \",\"\n"
+     "        toks = toks[1:]\n"
+     "    }\n"
+     "    if !toks || toks[0][0] != \"}\"\n"
+     "      throw JSONError(\"missing }\")\n"
+     "    return r, toks[1:]\n"
+     "  }\n"
+     "  func parse_expression(toks) {\n"
+     "    if toks\n"
+     "      switch toks[0][0] {\n"
+     "        case \"{\":\n"
+     "          return parse_object(toks[1:])\n"
+     "        case \"[\":\n"
+     "          return parse_array(toks[1:])\n"
+     "        case \"name\":\n"
+     "          switch toks[0][1] {\n"
+     "            case \"true\":\n"
+     "              return true, toks[1:]\n"
+     "            case \"false\":\n"
+     "              return false, toks[1:]\n"
+     "            case \"null\":\n"
+     "              return nil, toks[1:]\n"
+     "          }\n"
+     "          throw JSONError(f\"illegal name: ${toks[0][1]}\")\n"
+     "        case \"number\":\n"
+     "          return num(toks[0][1]), toks[1:]\n"
+     "        case \"string\":\n"
+     "          return toks[0][1], toks[1:]\n"
+     "      }\n"
+     "    throw JSONError(\"expected expression\")\n"
+     "  }\n"
+     "  if !toks\n"
+     "    throw JSONError(\"empty document\")\n"
+     "  if toks[0][0] !in \"{[\"\n"
+     "    throw JSONError(\"expected { or [\")\n"
+     "  let [r, unconsumed] = parse_expression(toks)\n"
+     "  if unconsumed\n"
+     "    throw JSONError(\"unconsumed input\")\n"
+     "  return r\n"
+     "}\n"
+     "func json_read(s)\n"
+     "  return json_parse(json_tokenize(s))\n"
+     "func json_dump(d) {\n"
+     "  func escape(s) {\n"
+     "    var r = \"\"\n"
+     "    \n"
+     "    for var c of s {\n"
+     "      if c == `\\`\n"
+     "        r += `\\\\`\n"
+     "      elif c == '\"'\n"
+     "        r += `\\\"`\n"
+     "      elif c == \"\\n\"\n"
+     "        r += `\\n`\n"
+     "      elif c == \"\\r\"\n"
+     "        r += `\\r`\n"
+     "      elif c == \"\\t\"\n"
+     "        r += `\\t`\n"
+     "      else r += c\n"
+     "    }\n"
+     "    return r\n"
+     "  }\n"
+     "  switch type(d) {\n"
+     "    case \"nil\":\n"
+     "      return \"null\"\n"
+     "    case \"bool\":\n"
+     "      return d? \"true\": \"false\"\n"
+     "    case \"number\":\n"
+     "      return str(d)\n"
+     "    case \"string\":\n"
+     "      return \"\\\"\" + escape(d) + \"\\\"\"\n"
+     "    case \"list\":\n"
+     "      var f = true\n"
+     "      var buf = \"[\"\n"
+     "      for var el of d {\n"
+     "        if f\n"
+     "          f = false\n"
+     "        else\n"
+     "          buf += \", \"\n"
+     "        buf += json_dump(el)   \n"
+     "      }\n"
+     "      buf += \"]\"\n"
+     "      return buf\n"
+     "    case \"table\":\n"
+     "      var f = true\n"
+     "      var buf = \"{\"\n"
+     "      for var [k, v] of enumerate(d) {\n"
+     "        if f\n"
+     "          f = false\n"
+     "        else\n"
+     "          buf += \", \"\n"
+     "        buf += f`\"${escape(k)}\": ${json_dump(v)}`\n"
+     "      }\n"
+     "      buf += \"}\"\n"
+     "      return buf\n"
+     "  }\n"
+     "  throw JSONError(f\"cannot serialize ${type(d)} into a JSON\")\n"
+     "}\n"},
 
     {"utf8", "func utf8_chrlen(s) {\n"
              "  s = bytes(s)\n"
@@ -3785,7 +3788,8 @@ const char *STD[][2] = {
              "class ustr {\n"
              "  _ucs = nil\n"
              "  constructor (this, s=\"\") {\n"
-             "    if type(s) == \"list\" && all(map(func (x): type(x) == \"number\", s)) {\n"
+             "    if type(s) == \"list\" && all(map(func (x): type(x) == "
+             "\"number\", s)) {\n"
              "      this._ucs = s\n"
              "      return\n"
              "    }\n"
@@ -4145,12 +4149,10 @@ char *unescape(char *s) {
 }
 
 void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx,
-                  table_t *ltab, list_t *lstk, list_t *sstk,
-                  list_t *lbl);
+                  table_t *ltab, list_t *lstk, list_t *sstk, list_t *lbl);
 
 int require_once(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
-                 list_t *lstk, list_t *sstk, list_t *lbl,
-                 char *path) {
+                 list_t *lstk, list_t *sstk, list_t *lbl, char *path) {
   char *source = NULL;
 
   for (size_t i = 0; STD[i][0]; i++) {
@@ -4390,13 +4392,15 @@ node_t *mexpr_eval(node_t *n) {
       return mexpr_eval(n->c);
     }
 
-    case N_TUPLE: case N_LIST: {
+    case N_TUPLE:
+    case N_LIST: {
       list_t *l = list_new();
 
       for (size_t i = 0; i < n->l->length; i++) {
         node_t *a = mexpr_eval(n->l->data[i]);
 
-        if (!IS_EXPR(a)) return NULL;
+        if (!IS_EXPR(a))
+          return NULL;
 
         list_push(l, a);
       }
@@ -4896,7 +4900,8 @@ node_t *_expand_mvars(node_t *node, int expr, mvar_expand_err_t *err) {
 
     return node;
   } else if (node->tag == N_PROGRAM || node->tag == N_BLOCK ||
-             node->tag == N_LIST || node->tag == N_TUPLE || node->tag == N_COMMA) {
+             node->tag == N_LIST || node->tag == N_TUPLE ||
+             node->tag == N_COMMA) {
     node = node_copy(node);
     node->l = list_copy(node->l);
 
@@ -4958,7 +4963,8 @@ node_t *_expand_mvars(node_t *node, int expr, mvar_expand_err_t *err) {
     }
 
     return node;
-  } else if (node->tag == N_INC || node->tag == N_DEC || node->tag == N_PINC || node->tag == N_PDEC) {
+  } else if (node->tag == N_INC || node->tag == N_DEC || node->tag == N_PINC ||
+             node->tag == N_PDEC) {
     node = node_copy(node);
 
     node->a = _expand_mvars(node->a, 1, err);
@@ -5003,8 +5009,8 @@ node_t *expand_mvars(node_t *node, node_t *_node, int expr) {
 }
 
 void compile_macro_call(buffer_t *gbuf, buffer_t *buf, list_t *ctx,
-                        table_t *ltab, list_t *lstk, list_t *sstk,
-                        list_t *lbl, node_t *node, int expr) {
+                        table_t *ltab, list_t *lstk, list_t *sstk, list_t *lbl,
+                        node_t *node, int expr) {
   size_t argc = node->l->length;
   char *name = node->t->text;
 
@@ -5060,8 +5066,7 @@ void compile_macro_call(buffer_t *gbuf, buffer_t *buf, list_t *ctx,
 }
 
 void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
-                  list_t *lstk, list_t *sstk, list_t *lbl,
-                  node_t *node) {
+                  list_t *lstk, list_t *sstk, list_t *lbl, node_t *node) {
   switch (node->tag) {
   case N_TOPLEVEL:
   case N_PROGRAM:
@@ -5238,8 +5243,10 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
       EMIT("__%s%d(state)", PREFIX, gid);
     } break;
 
-    case T_USTRING:      
-      EMIT("qi_call(state, qi_get(state, \"ustr\"), qi_list_push(qi_list_make(), qi_make_string(state, \"%s\")))", node->t->text);
+    case T_USTRING:
+      EMIT("qi_call(state, qi_get(state, \"ustr\"), "
+           "qi_list_push(qi_list_make(), qi_make_string(state, \"%s\")))",
+           node->t->text);
       break;
 
     case T_NAME: {
@@ -5252,9 +5259,15 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
         EMIT("qi_get(state, \"%s\")", name);
     } break;
 
-    case T_TRUE: EMIT("state->_true"); break;
-    case T_FALSE: EMIT("state->_false"); break;
-    case T_NIL: EMIT("state->nil"); break;
+    case T_TRUE:
+      EMIT("state->_true");
+      break;
+    case T_FALSE:
+      EMIT("state->_false");
+      break;
+    case T_NIL:
+      EMIT("state->nil");
+      break;
 
     default:
       COMPILE_ERROR("not yet implemented");
@@ -5441,7 +5454,8 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
         ASSIGNIN(tbuf, (node_t *)node->a->l->data[i],
                  buffer_fmt(tbuf,
                             "qi_index(state, %s, qi_make_number(state, %d))",
-                            varname, i), false);
+                            varname, i),
+                 false);
         buffer_fmt(tbuf, ";\n");
       }
 
@@ -5697,7 +5711,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
 
     CTXPUSH("scope");
     EMIT("qi_new_scope(state);\n");
- 
+
     if (node->t2) {
       if (table_get(ltab, node->t2->text))
         COMPILE_ERROR("redeclaration of loop label: '%s'", node->t2->text);
@@ -5884,7 +5898,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
       pair = lstk->data[lstk->length - 1];
       gid = pair->data[0];
     }
-   
+
     size_t scopes_k = count_scopes(ctx, pair->data[1]);
 
     for (size_t i = 0; i < scopes_k; i++) {
@@ -5892,7 +5906,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
     }
 
     EMIT("goto __break%d;", gid);
-    } break;
+  } break;
 
   case N_CONTINUE: {
     if (!INCTX("for"))
@@ -5935,10 +5949,10 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
 
       break;
     }
-    
+
     int_stack_t *pair = lstk->data[lstk->length - 1];
     size_t gid = pair->data[0];
-   
+
     size_t scopes_k = count_scopes(ctx, pair->data[1]);
 
     for (size_t i = 0; i < scopes_k; i++) {
@@ -5946,7 +5960,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
     }
 
     EMIT("goto __continue%d;", gid);
-    } break;
+  } break;
 
   case N_DEFER: {
     NEWGID();
@@ -5986,15 +6000,15 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
       compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node->a);
       EMIT(";\n");
     }
-   
+
     for (size_t i = 0; i < SCOPESK; i++)
       EMIT("qi_old_scope(state);\n");
 
     for (size_t i = 0; i < TRAPSK; i++)
       EMIT("qi_unset_trap(state, trap);\n");
 
-    EMIT("return %s;", varname? varname: "state->nil");
-    } break;
+    EMIT("return %s;", varname ? varname : "state->nil");
+  } break;
 
   case N_FUNCDEF:
     break;
@@ -6027,7 +6041,10 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
 
     buffer_t *tbuf = buffer_new();
     buffer_fmt(tbuf, "void __%s%d(qi_state_t *state) {\n", PREFIX, gid);
-    buffer_fmt(tbuf, "qi_call(state, qi_index(state, %s, qi_make_string(state, \"__leave\")), qi_list_push(qi_list_make(), %s));\n", varname, varname);
+    buffer_fmt(tbuf,
+               "qi_call(state, qi_index(state, %s, qi_make_string(state, "
+               "\"__leave\")), qi_list_push(qi_list_make(), %s));\n",
+               varname, varname);
     buffer_fmt(tbuf, "}\n");
 
     buffer_appendb(gbuf, tbuf);
@@ -6036,8 +6053,10 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
     compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node->a);
     EMIT(";\n");
 
-    EMIT("qi_call(state, qi_index(state, %s, qi_make_string(state, \"__enter\")), qi_list_push(qi_list_make(), %s));\n", varname, varname);
-    
+    EMIT("qi_call(state, qi_index(state, %s, qi_make_string(state, "
+         "\"__enter\")), qi_list_push(qi_list_make(), %s));\n",
+         varname, varname);
+
     CTXPUSH("scope");
     EMIT("qi_new_scope(state);\n");
 
@@ -6046,10 +6065,10 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
     EMIT("qi_decl(state, \"%s\", %s);\n", node->t->text, varname);
 
     compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node->b);
-    
+
     CTXPOP();
     EMIT("qi_old_scope(state);\n");
-    } break;
+  } break;
 
   case N_TRY:
     EMIT("qi_try(state, {\n");
@@ -6309,8 +6328,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab,
 }
 
 void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx,
-                  table_t *ltab, list_t *lstk, list_t *sstk,
-                  list_t *lbl) {
+                  table_t *ltab, list_t *lstk, list_t *sstk, list_t *lbl) {
   node_t *n = parse(source);
   if (NEEDS_UTF8 && !is_required("utf8")) {
     NEEDS_UTF8 = 0;