39 lines
1.4 KiB
Racket
39 lines
1.4 KiB
Racket
#lang racket/base
|
|
(require (for-syntax racket/base)
|
|
racket/runtime-path
|
|
racket/promise)
|
|
(provide define-lazy-require-definer)
|
|
|
|
(define-syntax (define-lazy-require-definer stx)
|
|
(syntax-case stx ()
|
|
[(_ name modpath)
|
|
(begin
|
|
(unless (identifier? #'name)
|
|
(raise-syntax-error #f "expected identifier" stx #'name))
|
|
#'(begin (define-runtime-module-path-index mpi-var modpath)
|
|
(define-syntax name (make-lazy-require-definer #'mpi-var))))]))
|
|
|
|
(define-for-syntax (make-lazy-require-definer mpi-var)
|
|
(lambda (stx)
|
|
(syntax-case stx ()
|
|
[(_ fun ...)
|
|
(begin
|
|
(for ([fun (in-list (syntax->list #'(fun ...)))])
|
|
(unless (identifier? fun)
|
|
(raise-syntax-error #f "expected identifier for function name" stx fun)))
|
|
(with-syntax ([(fun-p ...) (generate-temporaries #'(fun ...))]
|
|
[mpi-var mpi-var])
|
|
;; Use 'delay/sync' because 'delay' promise is not reentrant.
|
|
;; FIXME: OTOH, 'delay/sync' promise is not kill-safe.
|
|
#'(begin (define fun-p (delay/sync (dynamic-require mpi-var 'fun)))
|
|
...
|
|
(define fun (make-delayed-function 'fun fun-p))
|
|
...)))])))
|
|
|
|
(define (make-delayed-function name fun-p)
|
|
(procedure-rename
|
|
(make-keyword-procedure
|
|
(lambda (kws kwargs . args)
|
|
(keyword-apply (force fun-p) kws kwargs args)))
|
|
name))
|