binders.lisp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. (import core/base (defmacro if not when car and or cdr and print /= get-idx defun = n
  2. >= error progn gensym for list + else ..))
  3. (import core/base b)
  4. (import core/type (list? empty?))
  5. (import core/list (cars cadrs caar cadar map cadr cdar cddr caddar snoc push!
  6. nth))
  7. (import lua/basic (getmetatable))
  8. (defun make-vars (x) :hidden
  9. (if (list? x) x (list x)))
  10. (defun make-var (x) :hidden
  11. (if (list? x) (car x) x))
  12. (defun make-binding (xs) :hidden
  13. (if (= (n xs) 1)
  14. (car xs)
  15. (if (>= (n xs) 2)
  16. `(lambda ,(car xs) ,@(cdr xs))
  17. (error "Expected binding, got nil."))))
  18. (defun make-let-binding (xs) :hidden
  19. (if (= (n xs) 2)
  20. (cadr xs)
  21. (if (>= (n xs) 3)
  22. `(lambda ,(cadr xs) ,@(cddr xs))
  23. (error "Expected binding, got nil."))))
  24. (defmacro let* (vars &body)
  25. "Bind several variables (given in VARS), then evaluate BODY.
  26. Variables bound with [[let*]] can refer to variables bound
  27. previously, as they are evaluated in order.
  28. ### Example
  29. ```cl
  30. > (let* [(foo 1)
  31. . (bar (+ foo 1))]
  32. . bar)
  33. out = 2
  34. ```"
  35. (b/with (len (n vars))
  36. (cond
  37. [(= len 0) `((lambda () ,@body))]
  38. [(= len 1) `((lambda ,(make-vars (caar vars)) ,@body) ,(make-binding (cdar vars)))]
  39. [else
  40. `((lambda ,(make-vars (caar vars))
  41. (let* ,(cdr vars) ,@body))
  42. ,(make-binding (cdar vars)))])))
  43. (defmacro with (var &body)
  44. "Bind the single variable VAR, then evaluate BODY."
  45. `(let* [,var] ,@body))
  46. (defmacro let (vars &body)
  47. "Bind several variables (given in VARS), then evaluate BODY.
  48. In contrast to [[let*]], variables bound with [[let]] can not refer
  49. to each other.
  50. ### Example
  51. ```cl
  52. > (let [(foo 1)
  53. . (bar 2)]
  54. . (+ foo bar))
  55. out = 3
  56. ```"
  57. `((lambda ,(cars vars)
  58. ,@body)
  59. ,@(map make-let-binding vars)))
  60. (defmacro when-let (vars &body)
  61. "Bind VARS, as with [[let]], and check they are all truthy before
  62. evaluating BODY.
  63. ```cl
  64. > (when-let [(foo 1)
  65. . (bar nil)]
  66. . foo)
  67. out = nil
  68. ```
  69. Does not evaluate `foo`, while
  70. ```
  71. > (when-let [(foo 1)
  72. . (bar 2)]
  73. . (+ foo bar))
  74. out = 3
  75. ```
  76. does."
  77. `((lambda ,(cars vars)
  78. (when (and ,@(cars vars)) ,@body))
  79. ,@(map make-let-binding vars)))
  80. (defmacro when-let* (vars &body)
  81. "Bind each pair of `(name value)` of VARS, checking if the value is
  82. truthy before binding the next, and finally evaluating BODY. As with
  83. [[let*]], bindings inside [[when-let*]] can refer to previously bound
  84. names.
  85. ### Example
  86. ```cl
  87. > (when-let* [(foo 1)
  88. . (bar nil)
  89. . (baz 2)]
  90. . (+ foo baz))
  91. out = nil
  92. ```
  93. Since `1` is truthy, it is evaluated and bound to `foo`, however,
  94. since `nil` is falsey, evaluation does not continue."
  95. (cond
  96. [(empty? vars) `((lambda () ,@body))]
  97. [else `((lambda ,(make-vars (caar vars))
  98. (cond
  99. [,(make-var (caar vars)) (when-let* ,(cdr vars) ,@body)]
  100. [else nil]))
  101. ,(make-binding (cdar vars)))]))
  102. (defmacro when-with (var &body)
  103. "Bind the PAIR var of the form `(name value)`, only evaluating BODY if
  104. the value is truthy
  105. ### Example
  106. ```cl
  107. > (when-with (foo (.> { :baz \"foo\" } :baz))
  108. . (print! foo))
  109. foo
  110. out = nil
  111. ```
  112. When `bar` has an index `baz`, it will be bound to `foo` and
  113. printed. If not, the print statement will not be executed."
  114. `((lambda ,(make-vars (car var)) (when ,(make-var (car var)) ,@body)) ,(cadr var)))
  115. (defmacro if-let (vars then else)
  116. "Evaluate THEN or ELSE, depending on the truthiness of all variables
  117. bound (as per [[let]]) in VARS.
  118. ### Example
  119. ```cl
  120. > (if-let [(a 1)
  121. . (b false)]
  122. . b
  123. . a)
  124. out = 1
  125. ```"
  126. `((lambda ,(cars vars)
  127. (if (and ,@(cars vars))
  128. ,then
  129. ,else))
  130. ,@(map make-let-binding vars)))
  131. (defmacro if-with (var then else)
  132. "Bind the pair VAR of the form `(name value)`, evaluating THEN if the
  133. value is truthy or ELSE if not.
  134. ### Example
  135. ```cl
  136. > (if-with ((a b c) (values-list false 1 2))
  137. . a
  138. . (+ b c))
  139. out = 3
  140. ```"
  141. `((lambda ,(make-vars (car var))
  142. (if ,(make-var (car var))
  143. ,then
  144. ,else))
  145. ,(cadr var)))
  146. (defun make-setting (var) :hidden
  147. (if (= (n var) 2)
  148. `(set! ,(car var) ,(cadr var))
  149. (if (>= (n var) 3)
  150. `(set! ,(car var) (lambda ,(cadr var) ,@(cddr var)))
  151. (error "Expected binding, got nil."))))
  152. ;; Pre-declare variable and define it, allowing recursive functions to exist
  153. (defmacro letrec (vars &body)
  154. "Bind several variables (given in VARS), which may be recursive.
  155. ### Example
  156. ```cl
  157. > (letrec [(is-even? (lambda (n)
  158. . (or (= 0 n)
  159. . (is-odd? (pred n)))))
  160. . (is-odd? (lambda (n)
  161. . (and (not (= 0 n))
  162. . (is-even? (pred n)))))]
  163. . (is-odd? 11))
  164. out = true
  165. ```"
  166. `((lambda ,(cars vars)
  167. ,@(map make-setting vars)
  168. ,@body)))
  169. (defun finaliser-for (x) :hidden
  170. `((or (and (getmetatable ,x)
  171. (get-idx (getmetatable ,x) :--finalise))
  172. (get-idx ,x :close)
  173. (lambda ())), x))
  174. (defmacro use (var &body)
  175. "Bind each variable in VAR, checking for truthyness between bindings,
  176. execute BODY, then run a finaliser for all the variables bound by
  177. VAR.
  178. Potential finalisers might be:
  179. - `(get-idx (getmetatable FOO) :--finalise)`, where FOO is the
  180. variable.
  181. - `(get-idx FOO :close)` where FOO is the variable.
  182. If there is no finaliser for VAR, then nothing is done for it.
  183. ### Example:
  184. ```cl
  185. > (use [(file (io/open \"tests/data/hello.txt\"))]
  186. . (print! (self file :read \"*a\")))
  187. Hello, world!
  188. out = true
  189. ```"
  190. `(when-let* ,var
  191. ,@body
  192. ,@(map finaliser-for
  193. (cars var))))
  194. (defmacro loop (vs test &body)
  195. "A general iteration helper.
  196. ```cl :no-test
  197. > (loop [(var0 val0)
  198. . (var1 val1)
  199. . ...]
  200. . [test test-body ...]
  201. . body ...)
  202. ```
  203. Bind all the variables given in VS. Each iteration begins by
  204. evaluating TEST. If it evaluates to a truthy value, TEST-BODY
  205. is evaluated and the final expression in TEST-BODY is returned.
  206. In the case that TEST is falsey, the set of expressions BODY is
  207. evaluated. BODY may contain the \"magic\" form
  208. `(recur val0 val1 ...)`, which rebinds the respective variables
  209. in VS and reiterates.
  210. ### Examples:
  211. ```cl
  212. > (loop [(o '())
  213. . (l '(1 2 3))]
  214. . [(empty? l) o]
  215. . (recur (cons (car l) o) (cdr l)))
  216. out = (3 2 1)
  217. ```"
  218. (when (not vs)
  219. (error "expected variables, got nil"))
  220. (when (empty? test)
  221. (set! test '(false)))
  222. (let* [(recur-args (map car vs))
  223. (recur `(lambda ,recur-args
  224. (if ,(car test)
  225. (progn ,@(cdr test))
  226. (progn ,@body))))]
  227. `(letrec [(,'recur ,recur)]
  228. (,'recur ,@(map cadr vs)))))