3
\$\begingroup\$

I'm working on FFI wrapper for SDL2 library in Racket. The library includes several variadic functions (e.g. SDL_SetError, SDL_LogMessage etc); Racket FFI does not have straight way for importing those, but there's a workaround showcased here. Despite having little experience with Racket macros, I've decided to create one from the linked code to avoid excess code duplication. Here's my code:

#lang racket

(require (for-syntax racket/syntax)
         (for-syntax racket/format)
         ffi/unsafe)

(define sdl-lib (ffi-lib "libSDL2-2.0" '("0" #f)))

(define-syntax (define-vararg-func stx)
    (syntax-case stx ()
        [(_ name (arg-types ...) ret-type)
         (with-syntax*
             ([name-str (~a (syntax->datum #'name))]
              [arglist
               (map
                (lambda (arg)
                    (gensym (syntax->datum arg)))
                (syntax->list #'(arg-types ...)))]
              [full-arglist (append (syntax->list #'arglist) 'args)]
              [final-call (append '(apply fun) (syntax->list #'arglist) '(args))])
             #'(define name
                   (let ([interfaces (make-hash)])
                       (lambda full-arglist
                           (define itypes
                               (append (list arg-types ...)
                                       (map (lambda (x)
                                                (cond
                                                    [(and (integer? x) (exact? x)) _int]
                                                    [(and (number? x) (real? x))   _double*]
                                                    [(string? x)  _string]
                                                    [(bytes? x)   _bytes]
                                                    [(symbol? x)  _symbol]
                                                    [else
                                                     (error
                                                      "don't know how to deal with ~e" x)]))
                                            args)))
                           (let ([fun (hash-ref
                                       interfaces itypes
                                       (lambda ()
                                           (let ([i (get-ffi-obj
                                                     name-str sdl-lib
                                                     (_cprocedure itypes ret-type))])
                                               (hash-set! interfaces itypes i)
                                               i)))])
                               final-call)))))]))


;; macro usage
(define-vararg-func SDL_SetError (_string) _int)
(SDL_SetError "test %s %d" "test" 42)

(define SDL_GetError (get-ffi-obj "SDL_GetError" sdl-lib (_cprocedure '() _string)))
(displayln (SDL_GetError))

I'd love any feedback on the macro and suggestions on how to improve its readability.

\$\endgroup\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.