match.lisp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. "A pattern matching library.
  2. Utilities for manipulating deeply-nested data and lists in general, as
  3. well as binding multiple values.
  4. ## Literal patterns
  5. A literal pattern matches only if the scrutinee (what's being matched)
  6. compares [[eql?]] to the literal. One can use any Urn atom here:
  7. strings, numbers, keys and symbols.
  8. Note that the `true`, `false` and `nil` symbols will match against their
  9. *values*, whilst other symbols will match against a symbol object. Note
  10. that using a quoted symbol will match against a list instead. For
  11. instance, `'x` will expand to a match against `(quote x)`.
  12. ### Example
  13. ```cl
  14. > (with (x 1)
  15. . (case x
  16. . [1 \"Is 1!\"]
  17. . [x \"Is symbol 'x'!\"]
  18. . [nil \"Is nil :/\"]))
  19. \"Is 1!\"
  20. ```
  21. ### Wildcards and captures
  22. If one does not require a value to take a particular form, you can use a
  23. wildcard (`_` or `else`). This will match anything, discarding its value. This
  24. is often useful as the last expression in a [[case]], where you need to
  25. handle any remaining forms.
  26. If you wish to use this value, you should use a capture, or
  27. metavariable. This is a symbol prefixed with `?`. This will declare a
  28. variable of the same name (though without the `?`), bound to the
  29. captured value.
  30. ```cl
  31. > (with (x 3)
  32. . (case x
  33. . [1 \"Is 1!\"]
  34. . [2 \"Is 2!\"]
  35. . [?y $\"Is ~{y}\"]))
  36. \"Is 3\"
  37. ```
  38. In the above example, neither of the first two arms match, so the value
  39. of `x` is bound to the `y` variable and the arm's body executed.
  40. One can also match against the captured value by using the `@`
  41. form. This is a list which takes a pattern, the `@` symbol and then a
  42. metavariable. It will attempt to match the value against the provided
  43. pattern and, if it matches, bind it to the given variable.
  44. ```cl
  45. > (with (x 3)
  46. . (case x
  47. . [1 \"Is 1!\"]
  48. . [2 \"Is 2!\"]
  49. . [(_ @ ?y) $\"Is ~{y}\"]))
  50. \"Is 3\"
  51. ```
  52. This example is equivalent to the previous one, as the wildcard will
  53. match anything. You can of course use a more complex pattern there.
  54. ## List patterns
  55. List patterns and _list with rest_, patterns match lists.
  56. A list pattern requires a value to be a list of a specific length,
  57. matching each element in the list with its corresponding pattern in the
  58. list pattern.
  59. List with rest patterns, or cons patterns, require a value to be at
  60. least the given length, bundling all remaining values into a separate
  61. list and matching that against a new pattern.
  62. Both these patterns allow variables to be bound by their \"inner\"
  63. patterns, allowing one to build up complex expressions.
  64. ```cl
  65. > (with (x '(1 2 (3 4 5)))
  66. . (case x
  67. . ;; Matching against a fixed list
  68. . [() \"Got an empty list\"]
  69. . [(?a ?b) $\"Got a pair ~{a} ~{b}\"]
  70. . ;; Using cons patterns, and capturing inside nested patterns
  71. . [(?a ?b (?c . ?d)) $\"Got a triplet with ~{d}\"])
  72. \"Got a triplet with (4 5)\"
  73. ```
  74. ## Struct patterns
  75. Not dissimilar to list patterns, struct patterns allow you do match
  76. against an arbitrary struct. However, the struct pattern only checks for
  77. the presence of keys, and does not verify no additional keys are
  78. present.
  79. ```cl
  80. > (with (x { :x 1 :y '(1 2 3) })
  81. . (case x
  82. . [{ :x 1 :y 1 } \"A struct of 1, 1\"]
  83. . [{ :x 1 :y (1 2 ?x) } x]))
  84. 3
  85. ```
  86. ## Additional expressions in patterns
  87. Sometimes the built-in patterns are not enough and you need a little bit
  88. more power. Thankfully, one can use any expression in patterns in several
  89. forms: predicates, guards and views.
  90. ### Predicates and guards
  91. Predicates are formed by a symbol ending in a `?`. This symbol is looked
  92. up in the current scope and called with the value to be matched. If it
  93. returns a truthy value, then the pattern is considered to be matched.
  94. Guards are not dissimilar to predicates. They match a pattern against a
  95. value, bind the patterns metavariables and evaluate the expression, only
  96. succeeding if the expression evaluates to a truthy value.
  97. ```cl
  98. > (with (x \"foo\")
  99. . (case x
  100. . [(string? @ ?x) x]
  101. . [?x (pretty x])))
  102. \"foo\"
  103. > (with (x \"foo\")
  104. . (case x
  105. . [(?x :when (string? ?x)) x]
  106. . [?x (pretty x)]))
  107. \"foo\"
  108. ```
  109. Note that the above expressions have the same functionality. Predicates
  110. are generally more concise, whilst guards are more powerful.
  111. ### Views
  112. Views are a way of implementing your own quasi-patterns. Simply put,
  113. they call an expression with the required value and match the returned
  114. value against a pattern.
  115. ```cl
  116. > ;; Declare a helper method for matching strings.
  117. > (defun matcher (ptrn)
  118. . \"Create a function which matches its input against PTRN, returning
  119. . `nil` or a list of captured groups.\"
  120. . (lambda (str)
  121. . (case (list (string/match str ptrn))
  122. . [(nil) nil]
  123. . [?x x])))
  124. > (with (x \"0x23\")
  125. . (case x
  126. . [((matcher \"0x(%d+)\") -> ?x) x]))
  127. (\"23\")
  128. ```
  129. You can see the view pattern in use on the last line: we create the view
  130. with `(matcher \"0x(%d+)\")`, apply it to `x` and then match the
  131. returned value (`(\"23\")`) against the `?x` pattern.
  132. ### The [[case]] expression
  133. Bodies in case may be either of the form `[pattern exps]` or
  134. `[pattern => exps]`. In the latter case, the form matched against is
  135. bound, in its entirety, to the variable `it`."
  136. (import core/base (defun defmacro if get-idx and gensym error for set-idx!
  137. quasiquote list or slice concat apply /= n = not - + / * >= <= mod ..
  138. else splice))
  139. (import core/binders (let*))
  140. (import core/list (car caddr cadr cdr cddr append for-each map filter
  141. push! range snoc nth last elem? flat-map cons))
  142. (import core/method (eq? eql? pretty))
  143. (import core/string (char-at sub))
  144. (import core/type (list? symbol? key? string? boolean? number? table?))
  145. (import lua/basic (pcall))
  146. (import lua/math (max))
  147. (defun cons-pattern? (pattern) :hidden
  148. (and (list? pattern)
  149. (symbol? (nth pattern (- (n pattern) 1)))
  150. (eq? (nth pattern (- (n pattern) 1)) '.)))
  151. (defun cons-pat-left-side (pattern) :hidden
  152. (slice pattern 1 (- (n pattern) 2)))
  153. (defun cons-pat-right-side (pattern) :hidden
  154. (last pattern))
  155. (defun meta? (symbol) :hidden
  156. (and (symbol? symbol)
  157. (eq? (char-at (get-idx symbol "contents") 1) "?")))
  158. (defun pattern-length (pattern correction) :hidden
  159. (let* [(len 0)]
  160. (cond
  161. [(list? pattern)
  162. (for i 1 (n pattern) 1
  163. (if (and (list? (nth pattern i))
  164. (eq? (car (nth pattern i)) 'optional))
  165. 0
  166. (set! len (+ len 1))))]
  167. [(meta? pattern) 1]
  168. [else 0])
  169. (+ len correction)))
  170. (defun pattern-# (pat) :hidden
  171. (cond
  172. [(cons-pattern? pat) (pattern-length pat -2)]
  173. [(and (list? pat)
  174. (eql? '$ (car pat)))
  175. (pattern-length pat -3)]
  176. [else (pattern-length pat 0)]))
  177. (defun predicate? (x) :hidden
  178. (let* [(x (get-idx x :contents))]
  179. (= (char-at x (n x)) "?")))
  180. (defun struct-pat? (x) :hidden
  181. (and (eql? (car x) 'struct-literal)
  182. (= (mod (n (cdr x)) 2) 0)))
  183. (defun assert-linearity! (pat seen) :hidden
  184. (cond
  185. [(not seen) (assert-linearity! pat {})]
  186. [(list? pat)
  187. (cond
  188. [(eql? (cadr pat) '@)
  189. (assert-linearity! (caddr pat) seen)]
  190. [(eql? (cadr pat) ':when)
  191. (assert-linearity! (car pat) seen)]
  192. [(eql? (cadr pat) '->)
  193. (assert-linearity! (caddr pat) seen)]
  194. [(eql? (car pat) 'optional)
  195. (assert-linearity! (cadr pat) seen)]
  196. [(eql? (car pat) '$)
  197. (assert-linearity! (cddr pat) seen)]
  198. [(struct-pat? pat)
  199. (for i 3 (n pat) 2
  200. (assert-linearity! (nth pat i) seen))]
  201. [(cons-pattern? pat)
  202. (let* [(seen '())]
  203. (for i 1 (pattern-# pat) 1
  204. (assert-linearity! (nth pat i) seen))
  205. (assert-linearity! (get-idx pat (n pat)) seen))]
  206. [else
  207. (let* [(seen '())]
  208. (for i 1 (n pat) 1
  209. (assert-linearity! (nth pat i) seen)))])]
  210. [(or (and (not (meta? pat)) (symbol? pat))
  211. (and (symbol? pat) (or (eq? pat '_)
  212. (eq? pat 'else)))
  213. (number? pat)
  214. (string? pat)
  215. (boolean? pat)
  216. (eq? pat 'nil))
  217. true]
  218. [(meta? pat)
  219. (if (get-idx seen (get-idx pat :contents))
  220. (error (.. "pattern is not linear: seen " (pretty pat) " more than once"))
  221. (set-idx! seen (get-idx pat :contents) true))]
  222. [else true]))
  223. (defun compile-pattern-test (pattern symb)
  224. :hidden
  225. (cond
  226. [(list? pattern)
  227. (cond
  228. [(eql? (cadr pattern) '@)
  229. (compile-pattern-test (car pattern) symb)]
  230. [(eql? (cadr pattern) '->)
  231. (compile-pattern-test (caddr pattern) `(,(car pattern) ,symb))]
  232. [(eql? (car pattern) '$)
  233. (let* [(sym (gensym))]
  234. `(and ((get-idx ,(cadr pattern) :test) ,symb)
  235. (let* [(,sym (,(cadr pattern) ,symb))]
  236. ,@(map (lambda (x k)
  237. (compile-pattern-test x `(nth ,sym ,k)))
  238. (cddr pattern)
  239. (range :from 1 :to (n (cddr pattern)))))))]
  240. [(eql? (cadr pattern) ':when)
  241. `(and ,(compile-pattern-test (car pattern) symb)
  242. (let* ,(cons (list 'it symb)
  243. (compile-pattern-bindings (car pattern) symb))
  244. ,(caddr pattern)))]
  245. [(eql? (car pattern) 'optional)
  246. `(if ,symb ,(compile-pattern-test (cadr pattern) symb) true)]
  247. [(struct-pat? pattern)
  248. `(and (table? ,symb)
  249. ,@(let* [(out '(true))]
  250. (for i 2 (n pattern) 2
  251. (push! out (compile-pattern-test
  252. (nth pattern (+ 1 i))
  253. `(get-idx ,symb ,(nth pattern i))))
  254. (push! out `(get-idx ,symb ,(nth pattern i))))
  255. out))]
  256. [(cons-pattern? pattern)
  257. (let* [(pattern-sym (gensym))
  258. (lhs (cons-pat-left-side pattern))
  259. (rhs (cons-pat-right-side pattern))
  260. (lhs-test '())]
  261. (for i 1 (n lhs) 1
  262. (push! lhs-test
  263. (compile-pattern-test (nth lhs i)
  264. `(nth ,pattern-sym ,i))))
  265. `(let* [(,pattern-sym ,symb)]
  266. (and (list? ,pattern-sym)
  267. (>= (n ,pattern-sym) ,(pattern-length pattern -2))
  268. ,@lhs-test
  269. ,(compile-pattern-test
  270. (last pattern) `(slice ,pattern-sym ,(+ 1 (n lhs)))))))]
  271. [else
  272. (let* [(out '())
  273. (sym (gensym))]
  274. (for i 1 (n pattern) 1
  275. (push! out (compile-pattern-test (nth pattern i)
  276. `(nth ,sym ,i))))
  277. `(let* [(,sym ,symb)]
  278. (and (list? ,sym)
  279. (>= (n ,sym) ,(pattern-length pattern 0))
  280. (<= (n ,sym) ,(n pattern))
  281. ,@out)))])]
  282. [(or (eq? 'else pattern) (eq? '_ pattern) (meta? pattern))
  283. `true]
  284. [(and (not (meta? pattern)) (symbol? pattern))
  285. (cond
  286. [(eq? pattern 'true) `(= ,symb true)]
  287. [(eq? pattern 'false) `(= ,symb false)]
  288. [(eq? pattern 'nil) `(= ,symb nil)]
  289. [(predicate? pattern) `(,pattern ,symb)]
  290. [else `(eq? ,symb ',pattern)])]
  291. [(key? pattern)
  292. `(eq? ,symb ,pattern)]
  293. [(or (number? pattern) (boolean? pattern) (string? pattern))
  294. `(= ,symb ,pattern)]
  295. [else (error (.. "unsupported pattern " (pretty pattern)))]))
  296. (defun compile-pattern-bindings (pattern symb) :hidden
  297. (filter (lambda (x) (/= (n x) 0))
  298. (cond
  299. [(list? pattern)
  300. (cond
  301. [(eql? (cadr pattern) '@)
  302. `(,@(compile-pattern-bindings (caddr pattern) symb) ,@(compile-pattern-bindings (car pattern) symb))]
  303. [(eql? (cadr pattern) ':when)
  304. (compile-pattern-bindings (car pattern) symb)]
  305. [(eql? (cadr pattern) '->)
  306. (compile-pattern-bindings (caddr pattern) `(,(car pattern) ,symb))]
  307. [(eql? (car pattern) '$)
  308. (let* [(sym (gensym))]
  309. (cons `(,sym (,(cadr pattern) ,symb))
  310. (compile-pattern-bindings (cddr pattern) sym)))]
  311. [(eql? (car pattern) 'optional)
  312. (compile-pattern-bindings (cadr pattern) symb)]
  313. [(struct-pat? pattern)
  314. (let* [(out '())]
  315. (for i 2 (n pattern) 2
  316. (for-each elem (compile-pattern-bindings (nth pattern (+ i 1))
  317. `(get-idx ,symb ,(nth pattern i)))
  318. (push! out elem)))
  319. out)]
  320. [(cons-pattern? pattern)
  321. (let* [(lhs (cons-pat-left-side pattern))
  322. (rhs (cons-pat-right-side pattern))
  323. (lhs-bindings '())]
  324. (for i 1 (n lhs) 1
  325. (for-each elem (compile-pattern-bindings (nth lhs i) `(nth ,symb ,i))
  326. (push! lhs-bindings elem)))
  327. (append lhs-bindings (compile-pattern-bindings rhs `(slice ,symb ,(+ 1 (n lhs))))))]
  328. [else
  329. (let* [(out '())]
  330. (for i 1 (n pattern) 1
  331. (for-each elem (compile-pattern-bindings (nth pattern i) `(nth ,symb ,i))
  332. (push! out elem)))
  333. out)])]
  334. [(meta? pattern)
  335. `((,{ :tag "symbol" :contents (sub (get-idx pattern "contents") 2) } ,symb))]
  336. [(or (number? pattern) (boolean? pattern) (string? pattern) (key? pattern) (eq? pattern '_) (and (not (meta? pattern)) (symbol? pattern)))
  337. '()]
  338. [else (error (.. "unsupported pattern " (pretty pattern)))])))
  339. (defun compile-pattern (pattern symb body) :hidden
  340. `(if ,(compile-pattern-test pattern symb)
  341. (let* ,(compile-pattern-bindings pattern symb)
  342. ,@body)
  343. (error (.. ,(.. "Pattern matching failure! Can not match the pattern `" (pretty pattern) "` against `") (pretty ,symb) "`."))))
  344. (defmacro destructuring-bind (pt &body)
  345. "Match a single pattern against a single value, then evaluate the BODY.
  346. The pattern is given as `(car PT)` and the value as `(cadr PT)`. If
  347. the pattern does not match, an error is thrown."
  348. (let* [(pattern (car pt))
  349. (value (cadr pt))
  350. (val-sym (gensym))]
  351. (assert-linearity! pattern)
  352. `(let* [(,val-sym ,value)]
  353. ,(compile-pattern pattern val-sym body))))
  354. (defun generate-case-error (arms val) :hidden
  355. (let* [(patterns (map (lambda (x) (pretty (car x))) arms))]
  356. `(error (.. "Pattern matching failure!\nTried to match the following patterns against " (pretty ,val) ", but none matched.\n"
  357. ,(concat (map (lambda (x) (.. " Tried: `" x "`")) patterns) "\n")))))
  358. (defmacro case (val &pts)
  359. "Match a single value against a series of patterns, evaluating the
  360. first body that matches, much like [[cond]]."
  361. (let* [(val-sym (gensym))
  362. (compile-arm
  363. (lambda (pt)
  364. (assert-linearity! (car pt))
  365. (cond
  366. [(eql? '=> (cadr pt))
  367. `(,(compile-pattern-test (car pt) val-sym)
  368. (let* ,(cons (list 'it val-sym)
  369. (compile-pattern-bindings (car pt) val-sym))
  370. ,@(cddr pt)))]
  371. [else
  372. `(,(compile-pattern-test (car pt) val-sym)
  373. (let* ,(compile-pattern-bindings (car pt) val-sym)
  374. ,@(cdr pt)))])))]
  375. `(let* [(,val-sym ,val)]
  376. (cond ,@(map compile-arm pts)
  377. [else ,(generate-case-error pts val-sym)]))))
  378. (defmacro matches? (pt x)
  379. "Test if the value X matches the pattern PT.
  380. Note that, since this does not bind anything, all metavariables may be
  381. replaced by `_` with no loss of meaning."
  382. (compile-pattern-test pt x))
  383. (defun ->meta (x) :hidden
  384. { :tag "symbol" :contents (.. "?" (get-idx x :contents)) })
  385. (defmacro handler-case (x &body)
  386. "Evaluate the form X, and if an error happened, match the series
  387. of `(?pattern . ?body)` arms given in BODY against the value of
  388. the error, executing the first that succeeeds.
  389. In the case that X does not throw an error, the value of that
  390. expression is returned by [[handler-case]].
  391. ### Example:
  392. ```cl
  393. > (handler-case
  394. . (fail! \"oh no!\")
  395. . [string?
  396. . => (print! it)])
  397. oh no!
  398. out = nil
  399. ```"
  400. (let* [(ok (gensym))
  401. (val (gensym))
  402. (err (gensym))
  403. (error-handler `(lambda (,err)
  404. (case ,err
  405. ,@body
  406. [else (error ,err 2)])))]
  407. `(let* [(,val (list (pcall (lambda () ,x))))
  408. (,ok (car ,val))]
  409. (if ,ok
  410. (splice (cdr ,val))
  411. (,error-handler (cadr ,val))))))
  412. (defmacro function (&arms)
  413. "Create a lambda which matches its arguments against the patterns
  414. defined in ARMS."
  415. (let* [(rest-sym (gensym "remaining-arguments"))
  416. (rest { :tag :symbol
  417. :display-name (get-idx rest-sym :display-name)
  418. :contents (.. "&" (get-idx rest-sym :contents)) })
  419. (param-n (apply max (map (lambda (x)
  420. (pattern-# (car x)))
  421. arms)))
  422. (param-nams (map gensym (range :from 1 :to param-n)))]
  423. `(lambda ,(snoc param-nams rest)
  424. (case (append (list ,@param-nams) ,rest-sym)
  425. ,@arms))))
  426. (defmacro if-match (cs t e)
  427. "Matches a pattern against a value defined in CS, evaluating T with the
  428. captured variables in scope if the pattern succeeded, otherwise
  429. evaluating E.
  430. [[if-match]] is to [[case]] what [[if]] is to `cond`."
  431. (let* [(x (gensym))]
  432. `(let* [(,x ,(cadr cs))]
  433. (if ,(compile-pattern-test (car cs) x)
  434. (let* ,(compile-pattern-bindings (car cs) x)
  435. ,t)
  436. ,e))))