Built-in Macros
All of the global macros available in GDLisp are documented here.
->
(defmacro -> (arg &rest forms)
...)
First-argument threading. Evaluates arg. Then, for each form in
forms, passes the accumulated argument as the first argument to
the given list (shifting the other arguments over). Any argument which
is a symbol is treated as a one-element list.
Examples:
(-> a b c) ; Expands to (c (b a))
(-> a (b 1) c (d 2 3)) ; Expands to (d (c (b a 1)) 2 3)
->>
(defmacro ->> (arg &rest forms)
...)
Last-argument threading. Evaluates arg. Then, for each form in
forms, passes the accumulated argument as the last argument to the
given list. Any argument which is a symbol is treated as a one-element
list.
Examples:
(->> a b c) ; Expands to (c (b a))
(->> a (b 1) c (d 2 3)) ; Expands to (d 2 3 (c (b 1 a)))
and
(defmacro and (&rest args)
...)
Short-circuiting conjunction operator. Returns the first falsy value
out of its arguments, evaluating as few arguments as necessary to do
so. Returns #t if given no arguments.
as->
(defmacro as-> (arg var &rest forms)
...)
Arbitrary threading macro. Evaluates arg. Then evaluates the first
of forms with var bound to arg. The next form in forms
is evaluated with the result of the prior bound to var, and so on.
The result of the final form is returned.
Example:
;; Equivalent:
(as-> (foo) v (bar 2 v 3) (baz 1 v 4 5))
(baz 1 (bar 2 (foo) 3) 4 5)
contextual-load
(defmacro contextual-load (filename)
...)
Expands to a load call to the file with the name filename.
However, unlike a plain load call, contextual-load will be
understood during macro expansion and translated to an appropriate
virtual filename. Thus, load should not be used directly in macro
bodies, as it will fail when run during macro expansion.
Caution
While the GDLisp macro engine understands how to
translate names into virtual filenames inside a
contextual-load, it will NOT attempt to trace
dependencies into the corresponding file. So
contextual-load is only safe to use on a filename
which has already been loaded in the current scope. For
instance, (contextual-load (this-true-filename)) is
always safe, since the current file is always (trivially)
loaded.
deflazy
(defmacro deflazy (name value &rest modifiers)
...)
deflazy defines the name name in the value namespace of the
current scope. That name, when it is evaluated for the first time,
will evaluate value and return it. The value will then be cached
and returned when name is evaluated in the future.
The only valid modifiers are public and private, which set the
visibility of the defined name. New modifiers may be added in the
future.
defobject
(defmacro defobject (name parent &opt visibility &rest body)
...)
Defines a new subclass of parent, whose visibility is
visibility (or public, if not provided) and whose class body is
body. This subclass only has one instance, which is lazily
initialized to the name name. The first time name is
evaluated, the instance is constructed and returned. On future
evaluations of name, the same instance will be returned.
defvars
(defmacro defvars (&rest args)
...)
defvars expands into multiple defvar blocks with no
initializers. That is, (defvars a b c) is equivalent to
(defvar a)
(defvar b)
(defvar c)
There is no way to include initializers or onready modifiers with
this macro. For such use cases, call defvar directly.
if
(defmacro if (cond true-case &opt false-case)
...)
Evaluates cond. If it’s true, then evalautes and returns
true-case. If cond is false, then evaluates and returns
false-case. If not provided, false-case defaults to ().
let*
(defmacro let* (vars &rest body)
...)
let* is equivalent to let except that each variable clause in
a let* is evaluated in sequence and has access to the variables
declared before it in the same let* block. That is,
(let* ((a 1)
(b (+ a 1)))
b)
is equivalent to
(let ((a 1))
(let ((b (+ a 1)))
b))
and will return 2. Attempting to do the same with a single let
block will result in the a variable not being in scope during
initialization of b.
list/for
(defmacro list/for (var list &rest body)
...)
Equivalent to the for special form, but works on lists rather than
arrays.
var is a symbol name and list is an expression that evaluates
to a list. list is evaluated, and then body is run once per
list element in a local scope where var is defined to be the
current list element. Always returns ().
or
(defmacro or (&rest args)
...)
Short-circuiting disjunction operator. Returns the first truthy value
out of its arguments, evaluating as few arguments as necessary to do
so. Returns #f if given no arguments.
quit
(defmacro quit ()
...)
Expands to a call to the quit method on the scene tree. This is
most commonly used in the REPL, where (quit) will quickly and
easily exit the REPL.
this-file
(defmacro this-file ()
...)
(this-file) is an expression which will load the current file.
this-file can be used in macro contexts to dynamically load the
current file. Equivalent to (load (this-filename)).
this-filename
(defmacro this-filename ()
...)
(this-filename) evaluates to a string consisting of the path to
the current file being compiled (as a .gd file). In macro
expansion, (this-filename) will expand to the virtual filename of
the file, suitable to be used during macro expansion.
this-true-filename
(defmacro this-true-filename ()
...)
(this-true-filename) evaluates to a string consisting of the path
to the current file being compiled (as a .gd file). In macro
expansion, (this-true-filename) will expand to the real runtime
filename of the file. This filename is not suitable to load during
macro expansion but it should be used in situations where a macro is
attempting to expand into a load call which will happen at
runtime.
unless
(defmacro unless (cond &rest body)
...)
Shorthand syntax for an if block which only has an else
part. If cond is false, evaluates and returns the body. If
cond is true, returns ().
update
(defmacro update (field updater)
...)
Convenient shorthand for updating a field. (update x (foo y z))
expands to (set x (foo x y z)). That is, the value field is
taken and passed as the first argument to the updater (with the
other arguments, if any, shifted one to the right), and then the
result is put back into the place x. x can be anything that is
valid on the left-hand side of a set. See set Forms for more
details on the valid argument forms.
If updater is a symbol rather than a proper list, then it is
wrapped in a one-element list before expanding.
Examples:
(update a (+ 1)) ; Adds 1 to the variable a
(update b -) ; Sets b equal to its negative
(update player:position (* 2)) ; Multiplies the position field on player by 2
(update (elt x 0) (/ 2)) ; Divides the first element of the array x by 2
when
(defmacro when (cond &rest body)
...)
Shorthand syntax for an if block which has no else part. If
cond is true, evaluates and returns the body. If cond is
false, returns ().
yield*
(defmacro yield* (arg)
...)
If arg is a function call which yields and produces a
GDScriptFunctionState object, then this macro yields the current
function as well. When the current function is resumed, then so too
shall the inner function. When the inner function terminates and
returns normally, the result of the inner function is returned from
yield*. Effectively, yield* propagates a yield from
arg to the caller.
Example:
(defn foo ()
(print 2)
(yield)
(print 4)
(yield)
(print 6))
(defn bar ()
(print 1)
(yield* (foo))
(print 7))
(let ((x (bar)))
(print 3)
(set x (x:resume))
(print 5)
(x:resume)
(print 8))
This code will print the numbers from 1 to 8 in order. Note that the
actual “yielding” is done in foo, but when we resume from our
let block, we resume through the bar function.
Warning
yield* should only be used to yield from functions
that used the 0-argument form of yield. If a function
uses the 2-argument yield and then is resumed by a
signal, the intermediate yield* object will be left
in an un-resumable state.