I'm writing an application (a simple game) using cl-sdl2. cl-sdl2 includes a macro called WITH-EVENT-LOOP
that can be used to start the SDL application with some event handlers.
Currently I use the macro like so:
(sdl2:with-event-loop (:method :poll)
(:idle () (on-idle :renderer renderer
:tick-func tick-func
:render-func render-func))
(:quit () t)
;; Input handlers below
(:keydown (:keysym keysym)
(funcall input-func :keydown :keysym keysym))
(:keyup (:keysym keysym)
(funcall input-func :keyup :keysym keysym)))
This code listing is small because I omitted several more input handlers. There are at least 6 more handlers defined following this same pattern, for handling mouse and game controller input events, so my actual code is longer and highly repetitive.
I can write a macro that generates these boilerplate forms:
(defmacro forward-evt-to (target evt &rest evt-args)
`(,evt ,evt-args
(funcall ,target ,evt ,@evt-args)))
This produces a list that can be understood by WITH-EVENT-LOOP
:
> (macroexpand-1 '(forward-evt-to input-func :keydown :keysym keysym))
(:KEYDOWN (:KEYSYM KEYSYM) (FUNCALL INPUT-FUNC :KEYDOWN :KEYSYM KEYSYM))
T
But when I try to use that macro, I get a compiler error. For example this fails:
(sdl2:with-event-loop (:method :poll)
(:idle () (on-idle :renderer renderer
:tick-func tick-func
:render-func render-func))
(:quit () t)
(forward-evt-to input-func :keydown :keysym keysym)
(forward-evt-to input-func :keyup :keysym keysym))
WITH-EVENT-LOOP
tries to compile the code without expanding it and gives the error
; The value
; INPUT-FUNC
; is not of type
; LIST
Is there any way I can use my FORWARD-EVT-TO
macro from inside the WITH-EVENT-LOOP
macro? I can't/don't want to modify WITH-EVENT-LOOP
directly.
One way would be to write a new macro, which expands into your target form.
Sketch of an example:
CL-USER 8 > (defmacro with-event-loop-1 (foo &body clauses &environment env)
`(with-event-loop ,foo
,(loop for clause in clauses
when (keywordp (first clause))
collect clause
else
collect (macroexpand-1 clause env))))
WITH-EVENT-LOOP-1
CL-USER 9 > (pprint
(macroexpand
'(with-event-loop-1 (:method :poll)
(:idle () (on-idle :renderer renderer
:tick-func tick-func
:render-func render-func))
(:quit () t)
(forward-evt-to input-func :keydown :keysym keysym)
(forward-evt-to input-func :keyup :keysym keysym))))
(WITH-EVENT-LOOP (:METHOD :POLL)
((:IDLE NIL (ON-IDLE :RENDERER RENDERER
:TICK-FUNC TICK-FUNC
:RENDER-FUNC RENDER-FUNC))
(:QUIT NIL T)
(:KEYDOWN (:KEYSYM KEYSYM) (FUNCALL INPUT-FUNC :KEYDOWN :KEYSYM KEYSYM))
(:KEYUP (:KEYSYM KEYSYM) (FUNCALL INPUT-FUNC :KEYUP :KEYSYM KEYSYM))))