Quoting and Quasiquoting
Quoting an S-expression delays its evaluation. That is, normally in GDLisp, a symbol or proper list that appears in expression context will have special semantics, whether that involves expanding macros, applying functions, accessing local variables, or any number of other rules. However, if you actually intend to explicitly construct a list or symbol as-is and have access to that data structure as a runtime value, you must quote the S-expression.
This is done by calling the special form quote with one argument,
as (quote some-s-expression). This can be abbreviated to an
apostrophe followed by the expression: 'some-s-expression.
All literals evaluate to themselves when quoted. This includes
Booleans (#t and #f), integers, floats, strings, symbols, and
the null object. Aside from symbols (when are treated specially when
quoted), the quote operator is a no-op on literals. That is, the
following are all equivalent when evaluated.
'1 == 1
'1.0 == 1.0
'#t == #t
'#f == #f
'() == ()
'"abc" == "abc"
A list evaluates, likewise, to the list itself when quoted. So while
(foo bar) is a function call in expression context, '(foo bar)
(or equivalently (quote (foo bar))) is a proper list at runtime,
whose first element is the symbol foo and whose second is the
symbol bar. Note that this also highlights another property of
quoting, namely that quoting an expression is contagious on the inner
expressions. Since the outer list in '(foo bar) is quoted, the
names foo and bar are never evaluated as variable names
either.
You may also use dotted list notation to construct lists with
non-() endings. For instance, '(1 2 . 3) will return a runtime
cons object whose car is 1. The cdr of this object is another cons
object whose car is 2 and whose cdr is 3.
Quasiquoting
Often, fully quoting with quote is sufficient. However, there are
often situations, especially during macro expansion, where an
S-expression should be interpreted mostly literally but with a few
values interjected at runtime. This is where quasiquoting comes in.
An S-expression is quasiquoted with the quasiquote special form,
abbreviated with a single prefix backtick `. quasiquote
behaves like quote except that it interprets the forms unquote
and unquote-spliced in a special way.
An unquote form (or, equivalently, a prefix ,) inside of a
quasiquote effectively reverses the quasiquote. The expression
inside of the unquote is evaluated and interpolated into the
list or expression being constructed by quasiquote.
An unquote-spliced form (equivalently, a prefix ,.) works like
an unquote, except that it can only be used inside a list within
a quasiquote and will flatten itself inside the enclosing list.
Consider the following examples.
`(1 2 ,(list 3 4) 5)
This evaluates to (1 2 (3 4) 5). The unquote (written with a
comma) causes the inner expression to be evaluated using the usual
GDLisp rules, which produces a list that is then inserted, as a single
element, into the surrounding list. On the other hand,
`(1 2 ,.(list 3 4) 5)
This evaluates to (1 2 3 4 5), because unquote-spliced
(written as ,.) flattens the result of evaluating the inner
expression into the outer list.
The expression within an unquote-spliced can evaluate to a list or
a Godot array. If it evaluates to any other datatype, then a runtime
error will be issued when the offending expression is interpolated.
Nested Quasiquotes
Warning
Nested quasiquotes are an experimental feature, whose behavior may change in a future version of GDLisp. Use with caution.
Quasiquotes can be nested. If a quasiquote appears inside of
another quasiquote, then it effectively cancels off with one
unquote or unquote-spliced on the inner list. That is,
``,a
This expression will not evaluate a as an expression. It will
return the constant list (quasiquote (unquote a)). On the other
hand,
``,,a
This will evaluate the inner unquote but not the outer one, so
if a has value 1, then this will return (quasiquote (unquote
1)).