txlyre il y a 1 jour
Parent
commit
de087b04be
1 fichiers modifiés avec 70 ajouts et 564 suppressions
  1. 70 564
      qic.c

+ 70 - 564
qic.c

@@ -1,3 +1,4 @@
+#include <time.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -7,6 +8,7 @@
 #define QIC_VERSION "qic v01 " __DATE__
 
 size_t GID = 0;
+char *PREFIX = NULL;
 
 typedef struct {
   void **data;
@@ -67,24 +69,24 @@ typedef struct {
   size_t *data;
 
   size_t length;
-} stack_t;
+} int_stack_t;
 
-stack_t *stack_new(void) {
-  stack_t *stack = malloc(sizeof(list_t));
+int_stack_t *stack_new(void) {
+  int_stack_t *stack = malloc(sizeof(list_t));
   stack->data = NULL;
   stack->length = 0;
 
   return stack;
 }
 
-void stack_push(stack_t *l, size_t v) {
+void stack_push(int_stack_t *l, size_t v) {
   size_t i = l->length++;
 
   l->data = realloc(l->data, l->length * sizeof(size_t));
   l->data[i] = v;
 }
 
-size_t stack_pop(stack_t *l) {
+size_t stack_pop(int_stack_t *l) {
   if (!l->length)
     return 0;
 
@@ -2382,18 +2384,18 @@ 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, table_t *ltab, stack_t *lstk, stack_t *sstk, list_t *lbl, node_t *node);
+void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, int_stack_t *lstk, int_stack_t *sstk, list_t *lbl, node_t *node);
 
 char *tempvar() {
   NEWGID();
 
-  char *s = malloc(sizeof(char) * 64);
-  snprintf(s, 64, "__temp%zu", gid);
+  char *s = malloc(sizeof(char) * (64 + strlen(PREFIX)));
+  snprintf(s, 64 + strlen(PREFIX), "__%s%zu", PREFIX, gid);
 
   return s;
 }
 
-void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, stack_t *lstk, stack_t *sstk, list_t *lbl, list_t *seq) {
+void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, int_stack_t *lstk, int_stack_t *sstk, list_t *lbl, list_t *seq) {
   if (!seq || seq->length < 1) {
     EMIT("NULL");
 
@@ -2411,7 +2413,7 @@ void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
   NEWGID();
 
-  buffer_fmt(tbuf, "inline static qi_list_t *__list%d(qi_state_t *state) {\n", gid);
+  buffer_fmt(tbuf, "inline static qi_list_t *__%s%d(qi_state_t *state) {\n", PREFIX, gid);
   if (has_star)
     buffer_fmt(tbuf, "qi_list_t *list = qi_list_make();\n");
   else
@@ -2449,10 +2451,10 @@ void compile_list(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
   buffer_appendb(gbuf, tbuf);
 
-  EMIT("__list%d(state)", gid);
+  EMIT("__%s%d(state)", PREFIX, gid);
 }
 
-void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, stack_t *lstk, stack_t *sstk, list_t *lbl, table_t *table) {
+void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, int_stack_t *lstk, int_stack_t *sstk, list_t *lbl, table_t *table) {
   if (!table || table->used < 1) {
     EMIT("NULL");
 
@@ -2463,7 +2465,7 @@ void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, st
 
   NEWGID();
 
-  buffer_fmt(tbuf, "inline static qi_table_t *__table%d(qi_state_t *state) {\n", gid);
+  buffer_fmt(tbuf, "inline static qi_table_t *__%s%d(qi_state_t *state) {\n", PREFIX, gid);
   buffer_fmt(tbuf, "qi_table_t *table = qi_table_make();\n");
 
   table_iterate(table, {
@@ -2479,7 +2481,7 @@ void compile_table(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, st
 
   buffer_appendb(gbuf, tbuf);
 
-  EMIT("__table%d(state)", gid);
+  EMIT("__%s%d(state)", PREFIX, gid);
 }
 
 #define CTXPUSH(s) list_push(ctx, (s))
@@ -2565,14 +2567,14 @@ void emit_debug(buffer_t *buf, node_t *node) {
   buffer_fmt(buf, "state->_debug_data = __debugData[%d];\n", insert_debug(node)); 
 }
 
-void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, stack_t *lstk, stack_t *sstk, list_t *lbl, node_t *node, char *name) {
+void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, int_stack_t *lstk, int_stack_t *sstk, list_t *lbl, node_t *node, char *name) {
   NEWGID();
 
   char *funname = name? name: node->t? node->t->text: "<anon>";
 
   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);
+  buffer_fmt(tbuf, "qi_value_t *__%s%d(qi_state_t *state, qi_size_t pargc, qi_list_t *pargs) {\n", PREFIX, gid);
 
   LBPUSH();
   CTXPUSH("gap");
@@ -2618,7 +2620,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
   tbuf = buffer_new();
 
-  buffer_fmt(tbuf, "qi_make_function(state, \"%s\", %d, __func%d, ", funname, !node->h? 0: (node->h->used - optargc), gid);
+  buffer_fmt(tbuf, "qi_make_function(state, \"%s\", %d, __%s%d, ", funname, !node->h? 0: (node->h->used - optargc), PREFIX, gid);
   compile_table(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->h2);
   buffer_fmt(tbuf, ")");
 
@@ -2654,7 +2656,7 @@ node_t *const_get(char *name) {
   return val;
 }
 
-void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, stack_t *lstk, stack_t *sstk, list_t *lbl, list_t *block) {
+void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, int_stack_t *lstk, int_stack_t *sstk, list_t *lbl, list_t *block) {
   for (size_t i = 0; i < block->length; i++) {
     node_t *node = block->data[i];
 
@@ -2678,7 +2680,7 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, st
 
       buffer_t *tbuf = buffer_new();
 
-      buffer_fmt(tbuf, "qi_value_t *__class%d(qi_state_t *state) {\n", gid);
+      buffer_fmt(tbuf, "qi_value_t *__%s%d(qi_state_t *state) {\n", PREFIX, gid);
       buffer_fmt(tbuf, "qi_list_t *supers = qi_list_make_n(%d);\n", !supers? 0: supers->length);
 
       if (supers)
@@ -2727,7 +2729,7 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, st
 
       buffer_appendb(gbuf, tbuf);
 
-      EMIT("qi_set(state, false, \"%s\", __class%d(state));", name, gid);
+      EMIT("qi_set(state, false, \"%s\", __%s%d(state));", name, PREFIX, gid);
     } else if (node->tag == N_LABEL) {
       char *label = node->t->text;
 
@@ -2757,522 +2759,6 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, st
 }
 
 const char *STD[][2] = {
-  {"std",
-    "func head(l): return l[0]\n"
-    "func tail(l): return slice(l, 1)\n"   
-    "func min(x, y): x < y? x: y\n"
-    "func max(x, y): x > y? x: y\n"
-    "func reverse(x) {\n"
-    "  if type(x) !in (\"list\", \"string\", \"bytes\")\n"
-    "    throw \"expected first argument to be: list, string or bytes, but got: \" + type(x)\n"
-    "  var r = []\n"
-    "  for var i = len(x)-1; i >= 0; i--\n"
-    "    list_push(r, x[i])\n"
-    "  if type(x) == \"string\"\n"
-    "    return list_join(r)\n"
-    "  elif type(x) == \"bytes\"\n"
-    "    return bytes(r)\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"list.reverse\", reverse)\n"
-    "set_pseudomethod(\"string.reverse\", reverse)\n"
-    "set_pseudomethod(\"bytes.reverse\", reverse)\n"
-    "func range(f) {\n"
-    "  var t, s\n"
-    "  if len(arguments) >= 3 {\n"
-    "    t = arguments[1]\n"
-    "    s = arguments[2]\n"
-    "  } elif len(arguments) >= 2 {\n"
-    "    t = arguments[1]\n"
-    "    s = 1\n"
-    "  } else {\n"
-    "    t = f\n"
-    "    f = 0\n"
-    "    s = 1\n"
-    "  }\n"
-    "  if type(f) != \"number\"\n"
-    "    throw \"expected first argument to be: number, but got: \" + type(f)\n"
-    "  if type(t) != \"number\"\n"
-    "    throw \"expected second argument to be: number, but got: \" + type(t)\n"
-    "  if type(s) != \"number\"\n"
-    "    throw \"expected third argument to be: number, but got: \" + type(s)\n"
-    "  if f > t\n"
-    "    return reverse(range(t, f, s))\n"
-    "  var r = []\n"
-    "  for var i = f; i < t; i += s\n"
-    "    list_push(r, i)\n"
-    "  return r\n"
-    "}\n"
-    "const SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2\n"
-    "func frewind(file)\n"
-    "  return file.rewind()\n"
-    "func file_read(filename) {\n"
-    "  let file = fopen(filename, \"r\")\n"
-    "  defer fclose(file)\n"
-    "  return str(fread(file, -1))\n"
-    "}\n"
-    "func file_write(filename, data) {\n"
-    "  let file = fopen(filename, \"w\")\n"
-    "  defer fclose(file)\n"
-    "  fwrite(file, bytes(data))\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"
-    "func list_remove(l, x, first=false) {\n"
-    "  if type(l) != \"list\"\n"
-    "    throw \"expected first argument to be: list, but got: \" + type(l)\n"
-    "  repeat:\n"
-    "  for var i = 0; i < len(l); i++\n"
-    "    if l[i] == x {\n"
-    "      list_delete(l, i)\n"
-    "      if first\n"
-    "        break\n"
-    "      goto repeat\n"
-    "    }\n"
-    "}\n"
-    "set_pseudomethod(\"list.remove\", list_remove)\n"
-    "func list_join(l) {\n"
-    "  if type(l) != \"list\"\n"
-    "    throw \"expected first argument to be: list, but got: \" + type(l)\n"
-    "  var r = \"\"\n"
-    "  var s\n"
-    "  if len(arguments) == 1\n"
-    "    s = \"\"\n"
-    "  else\n"
-    "    s = arguments[1]\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected second argument to be: string, but got: \" + type(s)\n"
-    "  var first = true\n"
-    "  for var x of l {\n"
-    "    if type(x) != \"string\"\n"
-    "      throw \"expected sequence item to be: string, but got: \" + type(x)\n"
-    "    if s != \"\" && !first\n"
-    "      r += s\n"
-    "    r += x\n"
-    "    first = false\n"
-    "  }\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"list.join\", list_join)\n"
-    "func list_pop_at(l, i) {\n"
-    "  if type(l) != \"list\"\n"
-    "    throw \"expected first argument to be: list, but got: \" + type(l)\n"
-    "  if type(i) != \"number\"\n"
-    "    throw \"expected second argument to be: number, but got: \" + type(i)\n"
-    "  var x = l[i]\n"
-    "  list_delete(l, i)\n"
-    "  return x\n"
-    "}\n"
-    "set_pseudomethod(\"list.popAt\", list_pop_at)\n"
-    "func list_sort(l, cmp=func (x, y): x > y) {\n"
-    "  if type(l) != \"list\"\n"
-    "    throw \"expected first argument to be: list, but got: \" + type(l)\n"
-    "  if type(cmp) != \"function\"\n"
-    "    throw \"expected second argument to be: function, but got: \" + type(cmp)\n"
-    "  if len(l) == 0\n"
-    "    return l\n"
-    "  var z = len(l)\n"
-    "  for var i = 0; i < z - 1; i++\n"
-    "    for var j = 0; j < z - 1 - i; j++\n"
-    "      if cmp(l[j], l[j+1]) {\n"
-    "        let tmp = l[j]\n"
-    "        l[j] = l[j+1]\n"
-    "        l[j+1] = tmp\n"
-    "      }\n"
-    "  return l\n"
-    "}\n"
-    "func list_sorted(l, cmp=func (x, y): x > y) {\n"
-    "  l = list_copy(l)\n"
-    "  return list_sort(l, cmp)\n"
-    "}\n"
-    "set_pseudomethod(\"list.sort\", list_sort)\n"
-    "set_pseudomethod(\"list.sorted\", list_sorted)\n"
-    "func list_shift(l) {\n"
-    "  if type(l) != \"list\"\n"
-    "    throw \"expected first argument to be: list, but got: \" + type(l)\n"
-    "  if is_empty(l)\n"
-    "    throw \"shift from empty list\"\n"
-    "  var a = l[0]\n"
-    "  list_delete(l, 0)\n"
-    "  return a\n"
-    "}\n"
-    "func list_unshift(l, x) {\n"
-    "  list_insert(l, 0, x)\n"
-    "}\n"
-    "set_pseudomethod(\"list.shift\", list_shift)\n"
-    "set_pseudomethod(\"list.unshift\", list_unshift)\n"
-    "func slice(l) {\n"
-    "  if type(l) !in (\"list\", \"string\", \"bytes\")\n"
-    "    throw \"expected first argument to be: list, string or bytes, but got: \" + type(l)\n"
-    "  var r = []\n"
-    "  if len(arguments) == 2 {\n"
-    "    var f = arguments[1]\n"
-    "    if type(f) != \"number\"\n"
-    "      throw \"expected second argument to be: number, but got: \" + type(f)\n"
-    "    for var i = f; i < len(l); i++\n"
-    "      list_push(r, l[i])\n"
-    "  } elif len(arguments) == 3 {\n"
-    "    var f = arguments[1], t = arguments[2]\n"
-    "    if type(f) != \"number\"\n"
-    "      throw \"expected second argument to be: number, but got: \" + type(f)\n"
-    "    if type(t) != \"number\"\n"
-    "      throw \"expected third argument to be: number, but got: \" + type(t)\n"
-    "    for var i = f; i < len(l) && i <= t; i++\n"
-    "      list_push(r, l[i])\n"
-    "  }\n"
-    "  if type(l) == \"string\"\n"
-    "    return list_join(r)\n"
-    "  elif type(l) == \"bytes\"\n"
-    "    return bytes(r)\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"list.slice\", slice)\n"
-    "set_pseudomethod(\"string.slice\", slice)\n"
-    "set_pseudomethod(\"bytes.slice\", slice)\n"
-    "let __slice = slice;\n"
-    "func str_startswith(s, p) {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(s)\n"
-    "  if len(s) < len(p)\n"
-    "    return false\n"
-    "  return slice(s, 0, len(p)-1) == p\n"
-    "}\n"
-    "set_pseudomethod(\"string.startsWith\", str_startswith)\n"
-    "func str_endswith(s, p) {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(s)\n"
-    "  if len(s) < len(p)\n"
-    "    return false\n"
-    "  return slice(s, len(s) - len(p)) == p\n"
-    "}\n"
-    "set_pseudomethod(\"string.endsWith\", str_endswith)\n"
-    "func str_split(s) {\n"
-    "  if len(arguments) == 1 || arguments[1] == \"\"\n"
-    "    return list(s)\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be:!string, but got: \" + type(s)\n"
-    "  var r = []\n"
-    "  var d = arguments[1]\n"
-    "  if type(d) != \"string\"\n"
-    "    throw \"expected second argument to be: string, but got: \" + type(s)\n"
-    "  var t = \"\"\n"
-    "  for var i = 0; i < len(s); i++ {\n"
-    "    if slice(s, i, i+len(d)-1) == d {\n"
-    "      list_push(r, t)\n"
-    "      t = \"\"\n"
-    "      i += len(d)-1\n"
-    "      continue\n"
-    "    }\n"
-    "    t += s[i]\n"
-    "  }\n"
-    "  if t != \"\"\n"
-    "    list_push(r, t)\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"string.split\", str_split)\n"
-    "func str_replace(s, w, b) {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(s)\n"
-    "  if type(w) != \"string\"\n"
-    "    throw \"expected second argument to be: string, but got: \" + type(w)\n"
-    "  if type(b) != \"string\"\n"
-    "    throw \"expected third argument to be: string, but got: \" + type(b)\n"
-    "  var r = \"\"\n"
-    "  for var i = 0; i < len(s); i++ {\n"
-    "    if slice(s, i, i+len(w)-1) == w {\n"
-    "      r += b\n"
-    "      i += len(w)-1\n"
-    "      continue\n"
-    "    }\n"
-    "    r += s[i]\n"
-    "  }\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"string.replace\", str_replace)\n"
-    "func table_keys(t) {\n"
-    "  if type(t) != \"table\"\n"
-    "    throw \"expected first argument to be: table, but got: \" + type(t)\n"
-    "  var r = []\n"
-    "  for var k of t\n"
-    "    list_push(r, k)\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"table.keys\", table_keys)\n"
-    "func table_values(t) {\n"
-    "  if type(t) != \"table\"\n"
-    "    throw \"expected first argument to be: table, but got: \" + type(t)\n"
-    "  var r = []\n"
-    "  for var k of t\n"
-    "    list_push(r, t[k])\n"                                                                          "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"table.values\", table_values)\n"
-    "func reduce(f, xs) {\n"
-    "  if type(f) != \"function\"\n"
-    "    throw \"expected first argument to be: function, but got: \" + type(f)\n"
-    "  if type(xs) !in (\"list\", \"tuple\", \"string\", \"bytes\")\n"
-    "    throw \"expected second argument to be: list, tuple, string or bytes, but got: \" + type(xs)\n"
-    "  if len(xs) == 0\n"
-    "    throw \"cannot reduce empty list\"\n"
-    "  r = xs[0]\n"
-    "  for var x of slice(xs, 1)\n"
-    "    r = f(r, x)\n"
-    "  if type(xs) == \"tuple\"\n"
-    "    return tuple(r)\n"
-    "  elif type(xs) == \"string\"\n"
-    "    return list_join(r)\n"
-    "  elif type(xs) == \"bytes\"\n"
-    "    return bytes(r)\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"list.reduce\", func (xs, f): reduce(f, xs))\n"
-    "set_pseudomethod(\"tuple.reduce\", func (xs, f): reduce(f, xs))\n"
-    "set_pseudomethod(\"string.reduce\", func (xs, f): reduce(f, xs))\n"
-    "set_pseudomethod(\"bytes.reduce\", func (xs, f): reduce(f, xs))\n"
-    "func sum(xs)\n"
-    "  return reduce(func (x, y): x + y, xs)\n"
-    "set_pseudomethod(\"list.sum\", sum)\n"
-    "set_pseudomethod(\"tuple.sum\", sum)\n"
-    "func product(xs)\n"
-    "  return reduce(func (x, y): x * y, xs)\n"
-    "set_pseudomethod(\"list.product\", product)\n"
-    "set_pseudomethod(\"tuple.product\", product)\n"
-    "func map(f, xs) {\n"
-    "  if type(f) != \"function\"\n"
-    "    throw \"expected first argument to be: function, but got: \" + type(f)\n"
-    "  if type(xs) !in (\"list\", \"tuple\", \"string\", \"bytes\")\n"
-    "    throw \"expected second argument to be: list, tuple, string or bytes, but got: \" + type(xs)\n"
-    "  if len(xs) == 0\n"
-    "    return xs\n"
-    "  var r = []\n"
-    "  for var x of xs\n"
-    "    list_push(r, f(x))\n"
-    "  if type(xs) == \"tuple\"\n"
-    "    return tuple(r)\n"
-    "  elif type(xs) == \"string\"\n"
-    "    return list_join(r)\n"
-    "  elif type(xs) == \"bytes\"\n"
-    "    return bytes(r)\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"list.map\", func (xs, f): map(f, xs))\n"
-    "set_pseudomethod(\"tuple.map\", func (xs, f): map(f, xs))\n"
-    "set_pseudomethod(\"string.map\", func (xs, f): map(f, xs))\n"
-    "set_pseudomethod(\"bytes.map\", func (xs, f): map(f, xs))\n"
-    "func filter(f, xs) {\n"
-    "  if type(f) != \"function\"\n"
-    "    throw \"expected first argument to be: function, but got: \" + type(f)\n"
-    "  if type(xs) !in (\"list\", \"tuple\", \"string\", \"bytes\")\n"
-    "    throw \"expected second argument to be: list, tuple, string or bytes, but got: \" + type(xs)\n"
-    "  if len(xs) == 0\n"
-    "    return xs\n"
-    "  var r = []\n"
-    "  for var x of xs\n"
-    "    if f(x)\n"
-    "      list_push(r, x)\n"
-    "  if type(xs) == \"tuple\"\n"
-    "    return tuple(r)\n"
-    "  elif type(xs) == \"string\"\n"
-    "    return list_join(r)\n"
-    "  elif type(xs) == \"bytes\"\n"
-    "    return bytes(r)\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"list.filter\", func (xs, f): filter(f, xs))\n"
-    "set_pseudomethod(\"tuple.filter\", func (xs, f): filter(f, xs))\n"
-    "set_pseudomethod(\"string.filter\", func (xs, f): filter(f, xs))\n"
-    "set_pseudomethod(\"bytes.filter\", func (xs, f): filter(f, xs))\n"
-    "func str_index(s, w) {\n"
-    "  if s == \"\" || w == \"\"\n"
-    "    return -1\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(s)\n"
-    "  if type(w) != \"string\"\n"
-    "    throw \"expected second argument to be: string, but got: \" + type(w)\n"
-    "  for var i = 0; i < len(s); i++\n"
-    "    if len(w) == 1 && s[i] == w\n"
-    "      return i\n"
-    "    elif slice(s, i, i+len(w)-1) == w\n"
-    "      return i\n"
-    "  return -1\n"
-    "}\n"
-    "set_pseudomethod(\"string.index\", str_index)\n"
-    "func str_lstrip(s, cs=\" \\t\\n\\r\\x0b\\x0c\") {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(s)\n"
-    "  if type(cs) != \"string\"\n"
-    "    throw \"expected second argument to be: string, but got: \" + type(cs)\n"
-    "  if s == \"\"\n"
-    "    return s\n"
-    "  for var i = 0; s[i] in cs && i < len(s); i++\n"
-    "    pass\n"
-    "  return slice(s, i)\n"
-    "}\n"
-    "set_pseudomethod(\"string.lstrip\", str_lstrip)\n"
-    "func str_rstrip(s, cs=\" \\t\\n\\r\\x0b\\x0c\") {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(s)\n"
-    "  if type(cs) != \"string\"\n"
-    "    throw \"expected second argument to be: string, but got: \" + type(cs)\n"
-    "  if s == \"\"\n"
-    "    return s\n"
-    "  for var k = 0, i = len(s)-1; s[i] in cs && i >= 0; k++\n"
-    "    i--\n"
-    "  return slice(s, 0, len(s)-k-1)\n"
-    "}\n"
-    "set_pseudomethod(\"string.rstrip\", str_rstrip)\n"
-    "func str_strip(s, cs=\" \\t\\n\\r\\x0b\\x0c\") {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(s)\n"
-    "  if type(cs) != \"string\"\n"
-    "    throw \"expected second argument to be: string, but got: \" + type(cs)\n"
-    "  return str_lstrip(str_rstrip(s, cs), cs)\n"
-    "}\n"
-    "set_pseudomethod(\"string.strip\", str_strip)\n"
-    "func table_get(t, k, d=nil) {\n"
-    "  if type(t) != \"table\"\n"
-    "    throw \"expected first argument to be: table, but got: \" + type(t)\n"
-    "  if type(k) != \"string\"\n"
-    "    throw \"expected second argument to be: string, but got: \" + type(k)\n"
-    "  if k !in t\n"
-    "    return d\n"
-    "  return t[k]\n"
-    "}\n"
-    "set_pseudomethod(\"table.get\", table_get)\n"
-    "func zip() {\n"
-    "  if !arguments\n"
-    "    return []\n"
-    "  var l = map(len, arguments)\n"
-    "  l = reduce(min, l)\n"
-    "  var r = []\n"
-    "  for var i = 0; i < l; i++ {\n"
-    "    var t = []\n"
-    "    for var xs of arguments\n"
-    "      list_push(t, xs[i])\n"
-    "    list_push(r, t)\n"
-    "  }\n"
-    "  return r\n"
-    "}\n"
-    "func enumerate(l)\n"
-    "  if type(l) == \"table\"\n"
-    "    return zip(table_keys(l), table_values(l))\n"
-    "  else\n"
-    "    return zip(range(len(l)), l)\n"
-    "func str_toupper(s) {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(c)\n"
-    "  return map(func (c): c >= 'a' && c <= 'z'? chr(ord(c) - 32): c, s)\n"
-    "}\n"
-    "set_pseudomethod(\"string.toupper\", str_toupper)\n"
-    "func str_tolower(s) {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(c)\n"
-    "  return map(func (c): c >= 'A' && c <= 'Z'? chr(ord(c) + 32): c, s)\n"
-    "}\n"
-    "set_pseudomethod(\"string.tolower\", str_tolower)\n"
-    "func Object(t, p=nil): return p !is nil? set_meta_table(p, get_meta_table(p) + t): set_meta_table({}, t)\n"
-    "func is_object(o): return has_meta_table(o)\n"
-    "func __class_wrapper(n, p, t, mt, st): return Object(st + {\n"
-    "    t: t,\n"
-    "    mt: mt,\n"
-    "    super: [],\n"
-    "    __type: func (this) use (n): return n,\n"
-    "    __str: func (this) use (n): return \"<class \" + n + \">\",\n"
-    "    __call: func (this, pargs) use (p) {\n"
-    "        var t = {}\n"
-    "        var mt = {}\n"
-    "        for var other of p {\n"
-    "            t += other.t\n"
-    "            mt += other.mt\n"
-    "            list_push(this.super, other)\n"
-    "        }\n"
-    "        if len(this.super) == 1\n"
-    "          this.super = this.super[0]\n"
-    "        t += this.t\n"
-    "        mt += this.mt\n"
-    "        t.super = this.super\n"
-    "        obj = set_meta_table(t, mt)\n"
-    "        if \"constructor\" in mt\n"
-    "          func_call(mt.constructor, [obj] + pargs)\n"
-    "        return obj\n"
-    "    }\n"
-    "})\n"
-    "func format(s) {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(s)\n"
-    "  var r = \"\"\n"
-    "  var n = 1\n"
-    "  for var i = 0; i < len(s); i++\n"
-    "    switch s[i] {\n"
-    "      case '_'\n"
-    "        if i+1 < len(s) && s[i+1] == '_' {\n"
-    "          r += '_'\n"
-    "          i++\n"
-    "          continue\n"
-    "        }\n"
-    "        r += repr(arguments[n++])\n"
-    "        break\n"
-    "      default\n"
-    "        r += s[i]\n"
-    "    }\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"string.format\", format)\n"
-    "func formatl(s, l) {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(s)\n"
-    "  if type(l) != \"list\"\n"
-    "    throw \"expected second argument to be: list, but got: \" + type(l)\n"
-    "  return func_call(str_format, [s] + l)\n"
-    "}\n"
-    "set_pseudomethod(\"string.formatl\", formatl)\n"
-    "func formatd(s, t) {\n"
-    "  if type(s) != \"string\"\n"
-    "    throw \"expected first argument to be: string, but got: \" + type(s)\n"
-    "  var r = \"\"\n"
-    "  var n = 1\n"
-    "  for var i = 0; i < len(s); i++\n"
-    "    switch s[i] {\n"
-    "      case '{'\n"
-    "        if i+1 < len(s) && s[i+1] == '{' {\n"
-    "          r += '{'\n"
-    "          i++\n"
-    "          continue\n"
-    "        }\n"
-    "        var k = ''\n"
-    "        i++\n"
-    "        for i < len(s) && s[i] != '}'\n"
-    "          k += s[i++]\n"
-    "        if i >= len(s) || s[i] != '}'\n"
-    "          throw \"unmatched { in format specifier\"\n"
-    "        if !k\n"
-    "          throw \"empty format key\"\n"
-    "        r += repr(t[k])\n"
-    "        break\n"
-    "      default\n"
-    "        r += s[i]\n"
-    "    }\n"
-    "  return r\n"
-    "}\n"
-    "set_pseudomethod(\"string.formatd\", formatd)\n"
-    "func getch() return chr(fgetc(STDIN))\n"
-    "func putch(c) fputc(STDOUT, c)\n"
-    "func getline()\n"
-    "  return fgets(STDIN, 256)\n"
-    "func input() {\n"
-    "  if len(arguments) > 0\n"
-    "    func_call(print, arguments)\n"
-    "  return str_rstrip(getline(), \"\\n\\r\")\n"
-    "}\n"
-    "func open(path, mode=\"r\"): fopen(path, mode)\n"
-    "func assert(cond, msg=\"assertion failed\")\n"
-    "  if !cond\n"
-    "    throw msg\n"
-  },
-
   {"utf8",
     "func utf8_chrlen(s) {\n"
     "  s = bytes(s)\n"
@@ -3603,9 +3089,9 @@ char *unescape(char *s) {
   return buffer_read(buf);
 }
 
-void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, stack_t *lstk, stack_t *sstk, list_t *lbl);
+void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, int_stack_t *lstk, int_stack_t *sstk, list_t *lbl);
 
-int require_once(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, stack_t *lstk, stack_t *sstk, list_t *lbl, char *path) {
+int require_once(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, int_stack_t *lstk, int_stack_t *sstk, list_t *lbl, char *path) {
   char *source = NULL;
 
   for (size_t i = 0; STD[i][0]; i++) {
@@ -3655,7 +3141,7 @@ int require_once(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, stac
 
 buffer_t *HBUF;
 
-void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, stack_t *lstk, stack_t *sstk, list_t *lbl, node_t *node) {
+void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, int_stack_t *lstk, int_stack_t *sstk, list_t *lbl, node_t *node) {
   switch (node->tag) {
     case N_TOPLEVEL: case N_PROGRAM:
       compile_block(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node->l);
@@ -3790,7 +3276,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
           NEWGID();
 
-          buffer_fmt(tbuf, "inline static qi_value_t *__fstring%d(qi_state_t *state) {\n", gid);
+          buffer_fmt(tbuf, "inline static qi_value_t *__%s%d(qi_state_t *state) {\n", PREFIX, gid);
           buffer_fmt(tbuf, "qi_value_t *str = state->empty_string;\n");
 
           for (size_t i = 0; i < parts->length; i++) {
@@ -3813,7 +3299,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
           buffer_appendb(gbuf, tbuf);
 
-          EMIT("__fstring%d(state)", gid);
+          EMIT("__%s%d(state)", PREFIX, gid);
           } break;
 
         case T_NAME: {
@@ -3842,7 +3328,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
       buffer_t *tbuf = buffer_new();
 
-      buffer_fmt(tbuf, "inline static qi_value_t *__listgen%d(qi_state_t *state) {\n", gid);
+      buffer_fmt(tbuf, "inline static qi_value_t *__%s%d(qi_state_t *state) {\n", PREFIX, gid);
       buffer_fmt(tbuf, "qi_list_t *list = qi_list_make();\n");
 
       buffer_t *bbuf = buffer_new();
@@ -3871,7 +3357,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
       buffer_appendb(gbuf, tbuf);
 
-      EMIT("__listgen%d(state)", gid);
+      EMIT("__%s%d(state)", PREFIX, gid);
       } break;
 
     case N_TUPLE:
@@ -3924,7 +3410,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
       buffer_t *tbuf = buffer_new();
 
-      buffer_fmt(tbuf, "inline static qi_value_t *__slice%d(qi_state_t *state) {\n", gid);
+      buffer_fmt(tbuf, "inline static qi_value_t *__%s%d(qi_state_t *state) {\n", PREFIX, gid);
 
       if (node->b && node->c) {
         buffer_fmt(tbuf, "qi_list_t *pargs = qi_list_make_n(3);\n");
@@ -3966,7 +3452,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
       buffer_appendb(gbuf, tbuf);
 
-      EMIT("__slice%d(state)", gid);
+      EMIT("__%s%d(state)", PREFIX, gid);
       } break;
 
     case N_ASSIGN:
@@ -3978,7 +3464,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
         buffer_t *tbuf = buffer_new();
 
-        buffer_fmt(tbuf, "inline static qi_value_t *__assign%d(qi_state_t *state) {\n", gid);
+        buffer_fmt(tbuf, "inline static qi_value_t *__%s%d(qi_state_t *state) {\n", PREFIX, gid);
    
         char *varname = tempvar();
 
@@ -3995,7 +3481,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
         buffer_appendb(gbuf, tbuf);
 
-        EMIT("__assign%d(state)", gid);
+        EMIT("__%s%d(state)", PREFIX, gid);
 
         break;
       } else if (node->a->tag == N_TUPLE) {
@@ -4009,7 +3495,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
         buffer_t *tbuf = buffer_new();
 
-        buffer_fmt(tbuf, "qi_value_t *__assign%d(qi_state_t *state) {\n", gid);
+        buffer_fmt(tbuf, "qi_value_t *__%s%d(qi_state_t *state) {\n", PREFIX, gid);
 
         list_t *vals = list_new();
         for (size_t i = 0; i < node->b->l->length; i++) {
@@ -4033,7 +3519,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
         buffer_appendb(gbuf, tbuf);
 
-        EMIT("__assign%d(state)", gid);
+        EMIT("__%s%d(state)", PREFIX, gid);
 
         break;
       }
@@ -4106,7 +3592,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
         if (table_get(ltab, node->t2->text))
           COMPILE_ERROR("redeclaration of loop label: '%s'", node->t2->text);
 
-        stack_t *pair = stack_new();
+        int_stack_t *pair = stack_new();
 
         stack_push(pair, 1);
         stack_push(pair, gid);
@@ -4163,7 +3649,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
         if (table_get(ltab, node->t2->text))
           COMPILE_ERROR("redeclaration of loop label: '%s'", node->t2->text);
 
-        stack_t *pair = stack_new();
+        int_stack_t *pair = stack_new();
 
         stack_push(pair, 0);
         stack_push(pair, gid);
@@ -4211,7 +3697,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
         if (table_get(ltab, node->t2->text))
           COMPILE_ERROR("redeclaration of loop label: '%s'", node->t2->text);
 
-        stack_t *pair = stack_new();
+        int_stack_t *pair = stack_new();
 
         stack_push(pair, 0);
         stack_push(pair, gid);
@@ -4267,7 +3753,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
         } else {
           char *label = node->t->text;
 
-          stack_t *pair = table_get(ltab, label);
+          int_stack_t *pair = table_get(ltab, label);
 
           if (!pair)
             COMPILE_ERROR("undefined loop label: '%s'", label);
@@ -4296,7 +3782,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
         } else {
           char *label = node->t->text;
 
-          stack_t *pair = table_get(ltab, label);
+          int_stack_t *pair = table_get(ltab, label);
 
           if (pair->data[1])
             COMPILE_ERROR("continue on a switch loop label: '%s'", label);
@@ -4318,7 +3804,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
       buffer_t *tbuf = buffer_new();
 
-      buffer_fmt(tbuf, "void __defer%d(qi_state_t *state) {\n", gid);
+      buffer_fmt(tbuf, "void __%s%d(qi_state_t *state) {\n", PREFIX, gid);
 
       LBPUSH();
       CTXPUSH("gap");
@@ -4332,7 +3818,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
       buffer_appendb(gbuf, tbuf);
 
-      EMIT("qi_add_defer(state, -1, __defer%d);", gid);
+      EMIT("qi_add_defer(state, -1, __%s%d);", PREFIX, gid);
       } break;
 
     case N_RETURN:
@@ -4396,7 +3882,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
         buffer_t *tbuf = buffer_new();
 
-        buffer_fmt(tbuf, "void __finally%d(qi_state_t *state) {\n", gid);
+        buffer_fmt(tbuf, "void __%s%d(qi_state_t *state) {\n", PREFIX, gid);
         LBPUSH();
         CTXPUSH("gap");
         compile_node(gbuf, tbuf, ctx, table_new(), stack_new(), stack_new(), lbl, node->c);
@@ -4407,7 +3893,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
 
         buffer_appendb(gbuf, tbuf);
 
-        EMIT("}, __finally%d);\n", gid);
+        EMIT("}, __%s%d);\n", PREFIX, gid);
       } else {
         EMIT("}, NULL);\n");
       }
@@ -4593,7 +4079,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
   }
 }
 
-void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, stack_t *lstk, stack_t *sstk, list_t *lbl) {
+void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, int_stack_t *lstk, int_stack_t *sstk, list_t *lbl) {
   node_t *n = parse(source);
 
   compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, n);
@@ -4615,8 +4101,8 @@ char *escape(char *s) {
 char *compile(char *source, list_t *required) {
   list_t *ctx = list_new();
   table_t *ltab = table_new();
-  stack_t *lstk = stack_new();
-  stack_t *sstk = stack_new();
+  int_stack_t *lstk = stack_new();
+  int_stack_t *sstk = stack_new();
   list_t *lbl = list_new();
   LBPUSH();
   
@@ -4726,7 +4212,15 @@ int main(int argc, char **argv) {
         DEBUG = 1;
       else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--stdin") == 0)
         readstdin = 1;
-      else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) {
+      else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--prefix") == 0) {
+        if (i+1 >= argc) {
+          fprintf(stderr, "fatal: missing argument after '-p/--prefix' parameter\n");
+
+          return 1;
+        }
+
+        PREFIX = argv[++i];
+      } else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) {
         if (i+1 >= argc) {
           fprintf(stderr, "fatal: missing argument after '-o/--output' parameter\n");
 
@@ -4740,7 +4234,7 @@ int main(int argc, char **argv) {
         fprintf(stderr, "-h --help\tprint this message and exit\n");
         fprintf(stderr, "-d --debug\tenable debug mode\n");
         fprintf(stderr, "-s --stdin\tread stdin as input\n");
-        fprintf(stderr, "-o --outout path\toutput generated C code to 'path'\n");
+        fprintf(stderr, "-o --output\toutput generated C code to the specified file\n");
 
         return 0;
       } else {
@@ -4761,6 +4255,18 @@ int main(int argc, char **argv) {
     }
   }
 
+  if (!PREFIX) {
+    const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    srand(time(NULL));
+ 
+    PREFIX = malloc(sizeof(char) * 9);
+    PREFIX[8] = 0;
+
+    for (size_t i = 0; i < 8; i++)
+      PREFIX[i] = chars[(size_t)((double) rand() / RAND_MAX * (sizeof(chars) - 1))];
+  }
+
   if (readstdin || !main)
     out = compile_file("<stdin>", stdin, required);
   else {
@@ -4778,7 +4284,7 @@ int main(int argc, char **argv) {
     fclose(fd);
   }
 
-  if (outf) {
+  if (outf && strcmp(outf, "-") != 0) {
     FILE *fd = fopen(outf, "wb");
     if (!fd) {
       fprintf(stderr, "fatal: unable to open output file: '%s'\n", outf);