Carp/core/Quasiquote.carp
2021-01-24 22:49:51 +01:00

82 lines
2.4 KiB
Plaintext

(doc Quasiquote "is a mechanism for quotation with code interspersed. See
the documentation of [`quasiquote`](#quasiquote) or the [high level
overview](https://github.com/carp-lang/Carp/blob/master/docs/Quasiquotation.md)
for details.")
(defmodule Quasiquote
(doc unquote "unquotes (i.e. evaluates) an expression `form` inside a
quasiquote. It will generate an error message when used outside a
`quasiquote` form.
Example:
```
(defdynamic x 2)
(quasiquote (+ (unquote x) 1)) ; => (+ 2 1)
```")
(defmacro unquote [form]
(macro-error "unquotes need to be wrapped inside quasiquotes."))
(doc unquote-splicing "unquotes (i.e. evaluates) an expression `form` inside a
quasiquote and splices it in, i.e. flattens the expression. It will
generate an error message when used outside a `quasiquote` form.
Example:
```
(defdynamic x '(1 2)
(quasiquote (+ (unquote-splicing x))) ; => (+ 1 2)
```")
(defmacro unquote-splicing [form]
(macro-error "unquotes need to be wrapped inside quasiquotes."))
(hidden quasiquote-list)
(defndynamic quasiquote-list [form]
(let [app (car form)]
(cond
(= app 'quasiquote) form
(and (= app 'unquote) (= (length form) 2))
(cadr form)
(= app 'unquote)
(macro-error "unquote takes exactly one argument.")
(and (= app 'unquote-splicing) (= (length form) 2))
(macro-error "unquote-splicing needs an enclosing list.")
(= app 'unquote-splicing)
(macro-error "unquote-splicing takes exactly one argument.")
(reduce
(fn [acc elem]
(if (and* (list? elem)
(= (length elem) 2)
(= (car elem) 'unquote-splicing))
(list 'append acc (cadr elem))
(list 'cons-last (quasiquote- elem) acc)))
'()
form))))
(hidden quasiquote-)
(defndynamic quasiquote- [form]
(cond
(and (list? form) (> (length form) 0))
(quasiquote-list form)
(array? form)
(collect-into (map quasiquote- form) array)
(list 'quote form)))
(doc quasiquote "is a quotation that may have expressions inside it in the
form of [`unquote`](#unquote) and [`unquote-splicing`](#unquote-splicing).
Example:
```
(defdynamic x 1)
(defdynamic y '(2 3 4))
(quasiquote (1 (unquote x) (unquote-splicing y))) ; => (1 1 2 3 4)
; using the reader macros
`(1 %x %@y)) ; => (1 1 2 3 4)
```")
(defmacro quasiquote [form]
(quasiquote- form)))
(use Quasiquote)