func head(l): return l[0] func tail(l): return slice(l, 1) func min(x, y): x < y? x: y func max(x, y): x > y? x: y func reverse(x) { if type(x) !in ("list", "string", "bytes") throw "expected first argument to be: list, string or bytes, but got: " + type(x) var r = [] for var i = len(x)-1; i >= 0; i-- list_push(r, x[i]) if type(x) == "string" return list_join(r) elif type(x) == "bytes" return bytes(r) return r } set_pseudomethod("list.reverse", reverse) set_pseudomethod("string.reverse", reverse) set_pseudomethod("bytes.reverse", reverse) func range(f) { var t, s if len(arguments) >= 3 { t = arguments[1] s = arguments[2] } elif len(arguments) >= 2 { t = arguments[1] s = 1 } else { t = f f = 0 s = 1 } if type(f) != "number" throw "expected first argument to be: number, but got: " + type(f) if type(t) != "number" throw "expected second argument to be: number, but got: " + type(t) if type(s) != "number" throw "expected third argument to be: number, but got: " + type(s) if f > t return reverse(range(t, f, s)) var r = [] for var i = f; i < t; i += s list_push(r, i) return r } let SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2 func frewind(file) return file.rewind() func file_read(filename) { let file = fopen(filename, "r") defer fclose(file) return str(fread(file, -1)) } func file_write(filename, data) { let file = fopen(filename, "w") defer fclose(file) fwrite(file, bytes(data)) } func is_defined(name) { if type(name) != "string" throw "expected first argument to be: string, but got: " + type(name) inline `bool b = qi_find(state, qi_get(state, "name")->value.string) != NULL` inline `return qi_make_boolean(state, b)` } func list_remove(l, x, first=false) { if type(l) != "list" throw "expected first argument to be: list, but got: " + type(l) repeat: for var i = 0; i < len(l); i++ if l[i] == x { list_delete(l, i) if first break goto repeat } } set_pseudomethod("list.remove", list_remove) func list_join(l) { if type(l) != "list" throw "expected first argument to be: list, but got: " + type(l) var r = "" var s if len(arguments) == 1 s = "" else s = arguments[1] if type(s) != "string" throw "expected second argument to be: string, but got: " + type(s) var first = true for var x of l { if type(x) != "string" throw "expected sequence item to be: string, but got: " + type(x) if s != "" && !first r += s r += x first = false } return r } set_pseudomethod("list.join", list_join) func list_pop_at(l, i) { if type(l) != "list" throw "expected first argument to be: list, but got: " + type(l) if type(i) != "number" throw "expected second argument to be: number, but got: " + type(i) var x = l[i] list_delete(l, i) return x } set_pseudomethod("list.popAt", list_pop_at) func list_sort(l, cmp=func (x, y): x > y) { if type(l) != "list" throw "expected first argument to be: list, but got: " + type(l) if type(cmp) != "function" throw "expected second argument to be: function, but got: " + type(cmp) if len(l) == 0 return l var z = len(l) for var i = 0; i < z - 1; i++ for var j = 0; j < z - 1 - i; j++ if cmp(l[j], l[j+1]) { let tmp = l[j] l[j] = l[j+1] l[j+1] = tmp } return l } func list_sorted(l, cmp=func (x, y): x > y) { l = list_copy(l) return list_sort(l, cmp) } set_pseudomethod("list.sort", list_sort) set_pseudomethod("list.sorted", list_sorted) func list_shift(l) { if type(l) != "list" throw "expected first argument to be: list, but got: " + type(l) if is_empty(l) throw "shift from empty list" var a = l[0] list_delete(l, 0) return a } func list_unshift(l, x) { list_insert(l, 0, x) } set_pseudomethod("list.shift", list_shift) set_pseudomethod("list.unshift", list_unshift) func slice(l) { if type(l) !in ("list", "string", "bytes") throw "expected first argument to be: list, string or bytes, but got: " + type(l) var r = [] if len(arguments) == 2 { var f = arguments[1] if type(f) != "number" throw "expected second argument to be: number, but got: " + type(f) if f < 0 f += len(l) for var i = f; i < len(l); i++ list_push(r, l[i]) } elif len(arguments) == 3 { var f = arguments[1], t = arguments[2] if type(f) != "number" throw "expected second argument to be: number, but got: " + type(f) if type(t) != "number" throw "expected third argument to be: number, but got: " + type(t) if f < 0 f += len(l) if t < 0 t += len(l) for var i = f; i < len(l) && i <= t; i++ list_push(r, l[i]) } if type(l) == "string" return list_join(r) elif type(l) == "bytes" return bytes(r) return r } set_pseudomethod("list.slice", slice) set_pseudomethod("string.slice", slice) set_pseudomethod("bytes.slice", slice) let __slice = slice; func str_startswith(s, p) { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(s) if len(s) < len(p) return false return slice(s, 0, len(p)-1) == p } set_pseudomethod("string.startsWith", str_startswith) func str_endswith(s, p) { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(s) if len(s) < len(p) return false return slice(s, len(s) - len(p)) == p } set_pseudomethod("string.endsWith", str_endswith) func str_split(s) { if len(arguments) == 1 || arguments[1] == "" return list(s) if type(s) != "string" throw "expected first argument to be:!string, but got: " + type(s) var r = [] var d = arguments[1] if type(d) != "string" throw "expected second argument to be: string, but got: " + type(s) var t = "" for var i = 0; i < len(s); i++ { if slice(s, i, i+len(d)-1) == d { list_push(r, t) t = "" i += len(d)-1 continue } t += s[i] } if t != "" list_push(r, t) return r } set_pseudomethod("string.split", str_split) func str_replace(s, w, b) { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(s) if type(w) != "string" throw "expected second argument to be: string, but got: " + type(w) if type(b) != "string" throw "expected third argument to be: string, but got: " + type(b) var r = "" for var i = 0; i < len(s); i++ { if slice(s, i, i+len(w)-1) == w { r += b i += len(w)-1 continue } r += s[i] } return r } set_pseudomethod("string.replace", str_replace) func table_keys(t) { if type(t) != "table" throw "expected first argument to be: table, but got: " + type(t) var r = [] for var k of t list_push(r, k) return r } set_pseudomethod("table.keys", table_keys) func table_values(t) { if type(t) != "table" throw "expected first argument to be: table, but got: " + type(t) var r = [] for var k of t list_push(r, t[k]) return r } set_pseudomethod("table.values", table_values) func reduce(f, xs) { if type(f) != "function" throw "expected first argument to be: function, but got: " + type(f) if type(xs) !in ("list", "tuple", "string", "bytes") throw "expected second argument to be: list, tuple, string or bytes, but got: " + type(xs) if len(xs) == 0 throw "cannot reduce empty list" r = xs[0] for var x of slice(xs, 1) r = f(r, x) if type(xs) == "tuple" return tuple(r) elif type(xs) == "string" return list_join(r) elif type(xs) == "bytes" return bytes(r) return r } set_pseudomethod("list.reduce", func (xs, f): reduce(f, xs)) set_pseudomethod("tuple.reduce", func (xs, f): reduce(f, xs)) set_pseudomethod("string.reduce", func (xs, f): reduce(f, xs)) set_pseudomethod("bytes.reduce", func (xs, f): reduce(f, xs)) func sum(xs) return reduce(func (x, y): x + y, xs) set_pseudomethod("list.sum", sum) set_pseudomethod("tuple.sum", sum) func product(xs) return reduce(func (x, y): x * y, xs) set_pseudomethod("list.product", product) set_pseudomethod("tuple.product", product) func map(f, xs) { if type(f) != "function" throw "expected first argument to be: function, but got: " + type(f) if type(xs) !in ("list", "tuple", "string", "bytes") throw "expected second argument to be: list, tuple, string or bytes, but got: " + type(xs) if len(xs) == 0 return xs var r = [] for var x of xs list_push(r, f(x)) if type(xs) == "tuple" return tuple(r) elif type(xs) == "string" return list_join(r) elif type(xs) == "bytes" return bytes(r) return r } set_pseudomethod("list.map", func (xs, f): map(f, xs)) set_pseudomethod("tuple.map", func (xs, f): map(f, xs)) set_pseudomethod("string.map", func (xs, f): map(f, xs)) set_pseudomethod("bytes.map", func (xs, f): map(f, xs)) func filter(f, xs) { if type(f) != "function" throw "expected first argument to be: function, but got: " + type(f) if type(xs) !in ("list", "tuple", "string", "bytes") throw "expected second argument to be: list, tuple, string or bytes, but got: " + type(xs) if len(xs) == 0 return xs var r = [] for var x of xs if f(x) list_push(r, x) if type(xs) == "tuple" return tuple(r) elif type(xs) == "string" return list_join(r) elif type(xs) == "bytes" return bytes(r) return r } set_pseudomethod("list.filter", func (xs, f): filter(f, xs)) set_pseudomethod("tuple.filter", func (xs, f): filter(f, xs)) set_pseudomethod("string.filter", func (xs, f): filter(f, xs)) set_pseudomethod("bytes.filter", func (xs, f): filter(f, xs)) func str_index(s, w) { if s == "" || w == "" return -1 if type(s) != "string" throw "expected first argument to be: string, but got: " + type(s) if type(w) != "string" throw "expected second argument to be: string, but got: " + type(w) for var i = 0; i < len(s); i++ if len(w) == 1 && s[i] == w return i elif slice(s, i, i+len(w)-1) == w return i return -1 } set_pseudomethod("string.index", str_index) func str_lstrip(s, cs=" \t\n\r\x0b\x0c") { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(s) if type(cs) != "string" throw "expected second argument to be: string, but got: " + type(cs) if s == "" return s for var i = 0; s[i] in cs && i < len(s); i++ pass return slice(s, i) } set_pseudomethod("string.lstrip", str_lstrip) func str_rstrip(s, cs=" \t\n\r\x0b\x0c") { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(s) if type(cs) != "string" throw "expected second argument to be: string, but got: " + type(cs) if s == "" return s for var k = 0, i = len(s)-1; s[i] in cs && i >= 0; k++ i-- return slice(s, 0, len(s)-k-1) } set_pseudomethod("string.rstrip", str_rstrip) func str_strip(s, cs=" \t\n\r\x0b\x0c") { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(s) if type(cs) != "string" throw "expected second argument to be: string, but got: " + type(cs) return str_lstrip(str_rstrip(s, cs), cs) } set_pseudomethod("string.strip", str_strip) func table_get(t, k, d=nil) { if type(t) != "table" throw "expected first argument to be: table, but got: " + type(t) if type(k) != "string" throw "expected second argument to be: string, but got: " + type(k) if k !in t return d return t[k] } set_pseudomethod("table.get", table_get) func zip() { if !arguments return [] var l = map(len, arguments) l = reduce(min, l) var r = [] for var i = 0; i < l; i++ { var t = [] for var xs of arguments list_push(t, xs[i]) list_push(r, t) } return r } func enumerate(l) if type(l) == "table" return zip(table_keys(l), table_values(l)) else return zip(range(len(l)), l) func str_toupper(s) { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(c) return map(func (c): c >= 'a' && c <= 'z'? chr(ord(c) - 32): c, s) } set_pseudomethod("string.toupper", str_toupper) func str_tolower(s) { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(c) return map(func (c): c >= 'A' && c <= 'Z'? chr(ord(c) + 32): c, s) } set_pseudomethod("string.tolower", str_tolower) func Object(t, p=nil): return p !is nil? set_meta_table(p, get_meta_table(p) + t): set_meta_table({}, t) func is_object(o): return has_meta_table(o) func __class_wrapper(n, p, t, mt, st): return Object(st + { t: t, mt: mt, super: [], __type: func (this) use (n): return n, __str: func (this) use (n): return "", __call: func (this, pargs) use (p) { var t = {} var mt = {} for var other of p { t += other.t mt += other.mt list_push(this.super, other) } if len(this.super) == 1 this.super = this.super[0] t += this.t mt += this.mt t.super = this.super obj = set_meta_table(t, mt) if "constructor" in mt func_call(mt.constructor, [obj] + pargs) return obj } }) func format(s) { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(s) var r = "" var n = 1 for var i = 0; i < len(s); i++ switch s[i] { case '_' if i+1 < len(s) && s[i+1] == '_' { r += '_' i++ continue } r += repr(arguments[n++]) break default r += s[i] } return r } set_pseudomethod("string.format", format) func formatl(s, l) { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(s) if type(l) != "list" throw "expected second argument to be: list, but got: " + type(l) return func_call(str_format, [s] + l) } set_pseudomethod("string.formatl", formatl) func formatd(s, t) { if type(s) != "string" throw "expected first argument to be: string, but got: " + type(s) var r = "" var n = 1 for var i = 0; i < len(s); i++ switch s[i] { case '{' if i+1 < len(s) && s[i+1] == '{' { r += '{' i++ continue } var k = '' i++ for i < len(s) && s[i] != '}' k += s[i++] if i >= len(s) || s[i] != '}' throw "unmatched { in format specifier" if !k throw "empty format key" r += repr(t[k]) break default r += s[i] } return r } set_pseudomethod("string.formatd", formatd) func getch() return chr(fgetc(STDIN)) func putch(c) fputc(STDOUT, c) func getline() return fgets(STDIN, 256) func input() { if len(arguments) > 0 func_call(print, arguments) return str_rstrip(getline(), "\n\r") } func open(path, mode="r"): fopen(path, mode) func assert(cond, msg="assertion failed") if !cond throw msg