File: define-fallbacks.rkt

package info (click to toggle)
racket-mode 20250501~git.2eec63c-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 2,020 kB
  • sloc: lisp: 17,236; makefile: 105
file content (39 lines) | stat: -rw-r--r-- 1,561 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
;; Copyright (c) 2024 by Greg Hendershott.
;; SPDX-License-Identifier: GPL-3.0-or-later

#lang racket/base

(require (for-syntax racket/base
                     (only-in "safe-dynamic-require.rkt"
                              safe-dynamic-require))
         syntax/parse/define)

(provide define-fallbacks)

;; safe-dynamic-require is most useful in scenarios where an entire
;; module might not be installed. Note that tools like
;; go-to-definition will always go to the safe-dynamic-require site,
;; because that is the binding site. Any binding from a normal
;; (non-dynamic) require is shadowed by the dynamic require.
;;
;; Another scenario is where a module is always installed, but over
;; time has added exports; therefore an older version might be
;; installed. In this case it can be nicer to do a plain, non-dynamic
;; require of the module, and use define-fallbacks to create
;; definitions /only/ for identifiers not supplied by the installed
;; version of the module. As a result, tools like go-to-definition
;; will handle normally imported bindings in the usual way (go to the
;; definition in that other module's source), which is very
;; convenient.

(define-syntax-parser define-fallback
  [(_ mod:id (id:id arg:expr ...) body:expr ...+)
   (if (safe-dynamic-require (syntax-e #'mod) (syntax-e #'id))
       #'(begin)
       #'(define (id arg ...)
           body ...))])

(define-syntax-parser define-fallbacks
  [(_ mod:id [(id:id arg:expr ...) body:expr ...+] ...+)
   #`(begin
       (define-fallback mod (id arg ...) body ...) ...)])