|
@@ -229,13 +229,7 @@ buffer_t *buffer_new(void) {
|
|
|
|
|
|
void buffer_append(buffer_t *buf, char c) {
|
|
|
buf->size++;
|
|
|
-
|
|
|
- void *p = malloc(sizeof(char) * buf->size);
|
|
|
- if (buf->str)
|
|
|
- memcpy(p, buf->str, buf->size - 1);
|
|
|
-
|
|
|
- buf->str = p;
|
|
|
-
|
|
|
+ buf->str = realloc(buf->str, sizeof(char) * buf->size);
|
|
|
buf->str[buf->size - 1] = c;
|
|
|
}
|
|
|
|
|
@@ -2203,11 +2197,11 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
if (pair->data[1]) {
|
|
|
optargc++;
|
|
|
|
|
|
- buffer_fmt(tbuf, "qi_set(state, false, \"%s\", pargc >= %d? qi_list_index(pargs, %d): ", entry.key, argc+1, argc);
|
|
|
+ buffer_fmt(tbuf, "qi_decl(state, \"%s\", pargc >= %d? qi_list_index(pargs, %d): ", entry.key, argc+1, argc);
|
|
|
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);
|
|
|
+ buffer_fmt(tbuf, "qi_decl(state, \"%s\", qi_list_index(pargs, %d));\n", entry.key, argc);
|
|
|
|
|
|
argc++;
|
|
|
});
|
|
@@ -2460,6 +2454,43 @@ const char *STD[][2] = {
|
|
|
" 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"
|
|
@@ -2488,6 +2519,221 @@ const char *STD[][2] = {
|
|
|
"set_pseudomethod(\"list.slice\", slice)\n"
|
|
|
"set_pseudomethod(\"string.slice\", slice)\n"
|
|
|
"set_pseudomethod(\"bytes.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\", reduce)\n"
|
|
|
+ "set_pseudomethod(\"tuple.reduce\", reduce)\n"
|
|
|
+ "set_pseudomethod(\"string.reduce\", reduce)\n"
|
|
|
+ "set_pseudomethod(\"bytes.reduce\", reduce)\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\", map)\n"
|
|
|
+ "set_pseudomethod(\"tuple.map\", map)\n"
|
|
|
+ "set_pseudomethod(\"string.map\", map)\n"
|
|
|
+ "set_pseudomethod(\"bytes.map\", map)\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\", filter)\n"
|
|
|
+ "set_pseudomethod(\"tuple.filter\", filter)\n"
|
|
|
+ "set_pseudomethod(\"string.filter\", filter)\n"
|
|
|
+ "set_pseudomethod(\"bytes.filter\", filter)\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 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 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 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): return Object({\n"
|
|
@@ -2515,6 +2761,13 @@ const char *STD[][2] = {
|
|
|
" return obj\n"
|
|
|
" }\n"
|
|
|
"})\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"
|
|
|
},
|
|
|
|
|
@@ -2976,6 +3229,8 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
CTXPUSH("for");
|
|
|
compile_node(gbuf, buf, ctx, lstk, lbl, node->d);
|
|
|
|
|
|
+ EMIT("__continue%d:;\n", gid);
|
|
|
+
|
|
|
if (node->c) {
|
|
|
compile_node(gbuf, buf, ctx, lstk, lbl, node->c);
|
|
|
|
|
@@ -2984,8 +3239,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
|
|
|
CTXPOP();
|
|
|
LPOP();
|
|
|
-
|
|
|
- EMIT("__continue%d:;\n", gid);
|
|
|
+
|
|
|
EMIT("}\n");
|
|
|
|
|
|
EMIT("__break%d:;\n", gid);
|