std.qi 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. func head(l): return l[0]
  2. func tail(l): return slice(l, 1)
  3. func min(x, y): x < y? x: y
  4. func max(x, y): x > y? x: y
  5. func reverse(x) {
  6. if type(x) !in ("list", "string", "bytes")
  7. throw "expected first argument to be: list, string or bytes, but got: " + type(x)
  8. var r = []
  9. for var i = len(x)-1; i >= 0; i--
  10. list_push(r, x[i])
  11. if type(x) == "string"
  12. return list_join(r)
  13. elif type(x) == "bytes"
  14. return bytes(r)
  15. return r
  16. }
  17. set_pseudomethod("list.reverse", reverse)
  18. set_pseudomethod("string.reverse", reverse)
  19. set_pseudomethod("bytes.reverse", reverse)
  20. func range(f) {
  21. var t, s
  22. if len(arguments) >= 3 {
  23. t = arguments[1]
  24. s = arguments[2]
  25. } elif len(arguments) >= 2 {
  26. t = arguments[1]
  27. s = 1
  28. } else {
  29. t = f
  30. f = 0
  31. s = 1
  32. }
  33. if type(f) != "number"
  34. throw "expected first argument to be: number, but got: " + type(f)
  35. if type(t) != "number"
  36. throw "expected second argument to be: number, but got: " + type(t)
  37. if type(s) != "number"
  38. throw "expected third argument to be: number, but got: " + type(s)
  39. if f > t
  40. return reverse(range(t, f, s))
  41. var r = []
  42. for var i = f; i < t; i += s
  43. list_push(r, i)
  44. return r
  45. }
  46. let SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2
  47. func frewind(file)
  48. return file.rewind()
  49. func file_read(filename) {
  50. let file = fopen(filename, "r")
  51. defer fclose(file)
  52. return str(fread(file, -1))
  53. }
  54. func file_write(filename, data) {
  55. let file = fopen(filename, "w")
  56. defer fclose(file)
  57. fwrite(file, bytes(data))
  58. }
  59. func is_defined(name) {
  60. if type(name) != "string"
  61. throw "expected first argument to be: string, but got: " + type(name)
  62. inline `qi_bool b = qi_find(state, qi_get(state, "name")->value.string) != NULL`
  63. inline `return qi_make_boolean(state, b)`
  64. }
  65. func list_remove(l, x, first=false) {
  66. if type(l) != "list"
  67. throw "expected first argument to be: list, but got: " + type(l)
  68. repeat:
  69. for var i = 0; i < len(l); i++
  70. if l[i] == x {
  71. list_delete(l, i)
  72. if first
  73. break
  74. goto repeat
  75. }
  76. }
  77. set_pseudomethod("list.remove", list_remove)
  78. func list_join(l) {
  79. if type(l) != "list"
  80. throw "expected first argumient to be: list, but got: " + type(l)
  81. var r = ""
  82. var s
  83. if len(arguments) == 1
  84. s = ""
  85. else
  86. s = arguments[1]
  87. if type(s) != "string"
  88. throw "expected second argument to be: string, but got: " + type(s)
  89. var first = true
  90. for var x of l {
  91. if type(x) != "string"
  92. throw "expected sequence item to be: string, but got: " + type(x)
  93. if s != "" && !first
  94. r += s
  95. r += x
  96. first = false
  97. }
  98. return r
  99. }
  100. set_pseudomethod("list.join", list_join)
  101. func list_pop_at(l, i) {
  102. if type(l) != "list"
  103. throw "expected first argument to be: list, but got: " + type(l)
  104. if type(i) != "number"
  105. throw "expected second argument to be: number, but got: " + type(i)
  106. var x = l[i]
  107. list_delete(l, i)
  108. return x
  109. }
  110. set_pseudomethod("list.popAt", list_pop_at)
  111. func __cmp(x, y): x > y? 1: x < y? -1: 0
  112. func list_sort(l, cmp=__cmp) {
  113. if type(l) != "list"
  114. throw "expected first argument to be: list, but got: " + type(l)
  115. if type(cmp) != "function"
  116. throw "expected second argument to be: function, but got: " + type(cmp)
  117. if len(l) == 0
  118. return l
  119. var z = len(l)
  120. for var i = 0; i < z - 1; i++
  121. for var j = 0; j < z - 1 - i; j++
  122. if cmp(l[j], l[j+1]) > 0 {
  123. let tmp = l[j]
  124. l[j] = l[j+1]
  125. l[j+1] = tmp
  126. }
  127. return l
  128. }
  129. func list_sorted(l, cmp=__cmp) {
  130. l = list_copy(l)
  131. return list_sort(l, cmp)
  132. }
  133. set_pseudomethod("list.sort", list_sort)
  134. set_pseudomethod("list.sorted", list_sorted)
  135. func list_shift(l) {
  136. if type(l) != "list"
  137. throw "expected first argument to be: list, but got: " + type(l)
  138. if is_empty(l)
  139. throw "shift from empty list"
  140. var a = l[0]
  141. list_delete(l, 0)
  142. return a
  143. }
  144. func list_unshift(l, x) {
  145. list_insert(l, 0, x)
  146. }
  147. set_pseudomethod("list.shift", list_shift)
  148. set_pseudomethod("list.unshift", list_unshift)
  149. func slice(l) {
  150. if type(l) !in ("list", "string", "bytes", "ustr")
  151. throw "expected first argument to be: list, string, bytes or ustr, but got: " + type(l)
  152. var r = []
  153. if len(arguments) == 2 {
  154. var f = arguments[1]
  155. if type(f) != "number"
  156. throw "expected second argument to be: number, but got: " + type(f)
  157. if f < 0
  158. f += len(l)
  159. for var i = f; i < len(l); i++
  160. list_push(r, l[i])
  161. } elif len(arguments) == 3 {
  162. var f = arguments[1], t = arguments[2]
  163. if type(f) != "number"
  164. throw "expected second argument to be: number, but got: " + type(f)
  165. if type(t) != "number"
  166. throw "expected third argument to be: number, but got: " + type(t)
  167. if f < 0
  168. f += len(l)
  169. if t < 0
  170. t += len(l)
  171. for var i = f; i < len(l) && i <= t; i++
  172. list_push(r, l[i])
  173. }
  174. if type(l) == "string"
  175. return list_join(r)
  176. elif type(l) == "bytes"
  177. return bytes(r)
  178. elif type(l) == "ustr"
  179. return ustr(r)
  180. return r
  181. }
  182. set_pseudomethod("list.slice", slice)
  183. set_pseudomethod("string.slice", slice)
  184. set_pseudomethod("bytes.slice", slice)
  185. let __slice = slice;
  186. func str_startswith(s, p) {
  187. if type(s) != "string"
  188. throw "expected first argument to be: string, but got: " + type(s)
  189. if len(s) < len(p)
  190. return false
  191. return slice(s, 0, len(p)-1) == p
  192. }
  193. set_pseudomethod("string.startsWith", str_startswith)
  194. func str_endswith(s, p) {
  195. if type(s) != "string"
  196. throw "expected first argument to be: string, but got: " + type(s)
  197. if len(s) < len(p)
  198. return false
  199. return slice(s, len(s) - len(p)) == p
  200. }
  201. set_pseudomethod("string.endsWith", str_endswith)
  202. func str_split(s) {
  203. if len(arguments) == 1 || arguments[1] == ""
  204. return list(s)
  205. if type(s) != "string"
  206. throw "expected first argument to be:!string, but got: " + type(s)
  207. var r = []
  208. var d = arguments[1]
  209. if type(d) != "string"
  210. throw "expected second argument to be: string, but got: " + type(s)
  211. var t = ""
  212. for var i = 0; i < len(s); i++ {
  213. if slice(s, i, i+len(d)-1) == d {
  214. list_push(r, t)
  215. t = ""
  216. i += len(d)-1
  217. continue
  218. }
  219. t += s[i]
  220. }
  221. if t != ""
  222. list_push(r, t)
  223. return r
  224. }
  225. set_pseudomethod("string.split", str_split)
  226. func str_replace(s, w, b) {
  227. if type(s) != "string"
  228. throw "expected first argument to be: string, but got: " + type(s)
  229. if type(w) != "string"
  230. throw "expected second argument to be: string, but got: " + type(w)
  231. if type(b) != "string"
  232. throw "expected third argument to be: string, but got: " + type(b)
  233. var r = ""
  234. for var i = 0; i < len(s); i++ {
  235. if slice(s, i, i+len(w)-1) == w {
  236. r += b
  237. i += len(w)-1
  238. continue
  239. }
  240. r += s[i]
  241. }
  242. return r
  243. }
  244. set_pseudomethod("string.replace", str_replace)
  245. func table_keys(t) {
  246. if type(t) != "table"
  247. throw "expected first argument to be: table, but got: " + type(t)
  248. var r = []
  249. for var k of t
  250. list_push(r, k)
  251. return r
  252. }
  253. set_pseudomethod("table.keys", table_keys)
  254. func table_values(t) {
  255. if type(t) != "table"
  256. throw "expected first argument to be: table, but got: " + type(t)
  257. var r = []
  258. for var k of t
  259. list_push(r, t[k])
  260. return r
  261. }
  262. set_pseudomethod("table.values", table_values)
  263. func reduce(f, xs) {
  264. if type(f) != "function"
  265. throw "expected first argument to be: function, but got: " + type(f)
  266. if type(xs) !in ("list", "tuple", "string", "bytes")
  267. throw "expected second argument to be: list, tuple, string or bytes, but got: " + type(xs)
  268. if len(xs) == 0
  269. throw "cannot reduce empty list"
  270. r = xs[0]
  271. for var x of slice(xs, 1)
  272. r = f(r, x)
  273. if type(xs) == "tuple"
  274. return tuple(r)
  275. elif type(xs) == "string"
  276. return list_join(r)
  277. elif type(xs) == "bytes"
  278. return bytes(r)
  279. return r
  280. }
  281. set_pseudomethod("list.reduce", func (xs, f): reduce(f, xs))
  282. set_pseudomethod("tuple.reduce", func (xs, f): reduce(f, xs))
  283. set_pseudomethod("string.reduce", func (xs, f): reduce(f, xs))
  284. set_pseudomethod("bytes.reduce", func (xs, f): reduce(f, xs))
  285. func sum(xs)
  286. return reduce(func (x, y): x + y, xs)
  287. set_pseudomethod("list.sum", sum)
  288. set_pseudomethod("tuple.sum", sum)
  289. func product(xs)
  290. return reduce(func (x, y): x * y, xs)
  291. set_pseudomethod("list.product", product)
  292. set_pseudomethod("tuple.product", product)
  293. func all(l): reduce(func (x, y): x && y, l)
  294. set_pseudomethod("list.all", all)
  295. set_pseudomethod("tuple.all", all)
  296. func any(l): reduce(func (x, y): x || y, l)
  297. set_pseudomethod("list.any", any)
  298. set_pseudomethod("tuple.any", any)
  299. func map(f, xs) {
  300. if type(f) != "function"
  301. throw "expected first argument to be: function, but got: " + type(f)
  302. if type(xs) !in ("list", "tuple", "string", "bytes")
  303. throw "expected second argument to be: list, tuple, string or bytes, but got: " + type(xs)
  304. if len(xs) == 0
  305. return xs
  306. var r = []
  307. for var x of xs
  308. list_push(r, f(x))
  309. if type(xs) == "tuple"
  310. return tuple(r)
  311. elif type(xs) == "string"
  312. return list_join(r)
  313. elif type(xs) == "bytes"
  314. return bytes(r)
  315. return r
  316. }
  317. set_pseudomethod("list.map", func (xs, f): map(f, xs))
  318. set_pseudomethod("tuple.map", func (xs, f): map(f, xs))
  319. set_pseudomethod("string.map", func (xs, f): map(f, xs))
  320. set_pseudomethod("bytes.map", func (xs, f): map(f, xs))
  321. func filter(f, xs) {
  322. if type(f) != "function"
  323. throw "expected first argument to be: function, but got: " + type(f)
  324. if type(xs) !in ("list", "tuple", "string", "bytes")
  325. throw "expected second argument to be: list, tuple, string or bytes, but got: " + type(xs)
  326. if len(xs) == 0
  327. return xs
  328. var r = []
  329. for var x of xs
  330. if f(x)
  331. list_push(r, x)
  332. if type(xs) == "tuple"
  333. return tuple(r)
  334. elif type(xs) == "string"
  335. return list_join(r)
  336. elif type(xs) == "bytes"
  337. return bytes(r)
  338. return r
  339. }
  340. set_pseudomethod("list.filter", func (xs, f): filter(f, xs))
  341. set_pseudomethod("tuple.filter", func (xs, f): filter(f, xs))
  342. set_pseudomethod("string.filter", func (xs, f): filter(f, xs))
  343. set_pseudomethod("bytes.filter", func (xs, f): filter(f, xs))
  344. func str_index(s, w) {
  345. if s == "" || w == ""
  346. return -1
  347. if type(s) != "string"
  348. throw "expected first argument to be: string, but got: " + type(s)
  349. if type(w) != "string"
  350. throw "expected second argument to be: string, but got: " + type(w)
  351. for var i = 0; i < len(s); i++
  352. if len(w) == 1 && s[i] == w
  353. return i
  354. elif slice(s, i, i+len(w)-1) == w
  355. return i
  356. return -1
  357. }
  358. set_pseudomethod("string.index", str_index)
  359. func str_lstrip(s, cs=" \t\n\r\x0b\x0c") {
  360. if type(s) != "string"
  361. throw "expected first argument to be: string, but got: " + type(s)
  362. if type(cs) != "string"
  363. throw "expected second argument to be: string, but got: " + type(cs)
  364. if s == ""
  365. return s
  366. var i
  367. for i = 0; s[i] in cs && i < len(s); i++
  368. pass
  369. return slice(s, i)
  370. }
  371. set_pseudomethod("string.lstrip", str_lstrip)
  372. func str_rstrip(s, cs=" \t\n\r\x0b\x0c") {
  373. if type(s) != "string"
  374. throw "expected first argument to be: string, but got: " + type(s)
  375. if type(cs) != "string"
  376. throw "expected second argument to be: string, but got: " + type(cs)
  377. if s == ""
  378. return s
  379. var k, i
  380. for k = 0, i = len(s)-1; s[i] in cs && i >= 0; k++
  381. i--
  382. return slice(s, 0, len(s)-k-1)
  383. }
  384. set_pseudomethod("string.rstrip", str_rstrip)
  385. func str_strip(s, cs=" \t\n\r\x0b\x0c") {
  386. if type(s) != "string"
  387. throw "expected first argument to be: string, but got: " + type(s)
  388. if type(cs) != "string"
  389. throw "expected second argument to be: string, but got: " + type(cs)
  390. return str_lstrip(str_rstrip(s, cs), cs)
  391. }
  392. set_pseudomethod("string.strip", str_strip)
  393. func zip() {
  394. if !arguments
  395. return []
  396. var l = map(len, arguments)
  397. l = reduce(min, l)
  398. var r = []
  399. for var i = 0; i < l; i++ {
  400. var t = []
  401. for var xs of arguments
  402. list_push(t, xs[i])
  403. list_push(r, t)
  404. }
  405. return r
  406. }
  407. func enumerate(l)
  408. if type(l) == "table"
  409. return zip(table_keys(l), table_values(l))
  410. else
  411. return zip(range(len(l)), l)
  412. func str_toupper(s) {
  413. if type(s) != "string"
  414. throw "expected first argument to be: string, but got: " + type(c)
  415. return map(func (c): c >= 'a' && c <= 'z'? chr(ord(c) - 32): c, s)
  416. }
  417. set_pseudomethod("string.toupper", str_toupper)
  418. func str_tolower(s) {
  419. if type(s) != "string"
  420. throw "expected first argument to be: string, but got: " + type(c)
  421. return map(func (c): c >= 'A' && c <= 'Z'? chr(ord(c) + 32): c, s)
  422. }
  423. set_pseudomethod("string.tolower", str_tolower)
  424. func Object(t, p=nil): return p !is nil? set_meta_table(p, get_meta_table(p) + t): set_meta_table({}, t)
  425. func is_object(o): return has_meta_table(o)
  426. func __class_wrapper(n, p, t, mt, st): return Object(st + {
  427. "t": t,
  428. "mt": mt,
  429. "super": p,
  430. "__type": func (this) use (n): return n,
  431. "__str": func (this) use (n): return "<class " + n + ">",
  432. "__call": func (this, pargs) use (n, p) {
  433. var t = {}
  434. var mt = { "__type": func (this) use (n): n }
  435. for var other of p {
  436. t += other.t
  437. mt += other.mt
  438. }
  439. t += this.t
  440. mt += this.mt
  441. mt.super = this.super
  442. obj = set_meta_table(t, mt)
  443. if "constructor" in mt
  444. func_call(mt.constructor, [obj] + pargs)
  445. return obj
  446. }
  447. })
  448. func format(s) {
  449. if type(s) != "string"
  450. throw "expected first argument to be: string, but got: " + type(s)
  451. var r = ""
  452. var n = 1
  453. for var i = 0; i < len(s); i++
  454. switch s[i] {
  455. case '_'
  456. if i+1 < len(s) && s[i+1] == '_' {
  457. r += '_'
  458. i++
  459. continue
  460. }
  461. r += repr(arguments[n++])
  462. break
  463. default
  464. r += s[i]
  465. }
  466. return r
  467. }
  468. set_pseudomethod("string.format", format)
  469. func formatl(s, l) {
  470. if type(s) != "string"
  471. throw "expected first argument to be: string, but got: " + type(s)
  472. if type(l) != "list"
  473. throw "expected second argument to be: list, but got: " + type(l)
  474. return func_call(str_format, [s] + l)
  475. }
  476. set_pseudomethod("string.formatl", formatl)
  477. func formatd(s, t) {
  478. if type(s) != "string"
  479. throw "expected first argument to be: string, but got: " + type(s)
  480. var r = ""
  481. var n = 1
  482. for var i = 0; i < len(s); i++
  483. switch s[i] {
  484. case '{'
  485. if i+1 < len(s) && s[i+1] == '{' {
  486. r += '{'
  487. i++
  488. continue
  489. }
  490. var k = ''
  491. i++
  492. for i < len(s) && s[i] != '}'
  493. k += s[i++]
  494. if i >= len(s) || s[i] != '}'
  495. throw "unmatched { in format specifier"
  496. if !k
  497. throw "empty format key"
  498. r += repr(t[k])
  499. break
  500. default
  501. r += s[i]
  502. }
  503. return r
  504. }
  505. set_pseudomethod("string.formatd", formatd)
  506. func getch() return chr(fgetc(STDIN))
  507. func putch(c) fputc(STDOUT, c)
  508. func getline()
  509. return fgets(STDIN, 256)
  510. func input() {
  511. if len(arguments) > 0
  512. func_call(print, arguments)
  513. return str_rstrip(getline(), "\n\r")
  514. }
  515. func open(path, mode="r"): fopen(path, mode)
  516. set_pseudomethod("file.__enter", func () {})
  517. set_pseudomethod("file.__leave", func (f): fclose(f))
  518. set_pseudomethod("file.close", fclose)
  519. func assert(cond, msg="assertion failed")
  520. if !cond
  521. throw msg
  522. class Error {
  523. msg = nil
  524. constructor (this, msg) {
  525. this.msg = msg
  526. }
  527. __str (this): type(this) + ": " + this.msg
  528. }