racket/collects/scheme/require-transform.ss

129 lines
5.3 KiB
Scheme

(module require-transform '#%kernel
(#%require "private/stxcase-scheme.ss"
"private/qqstx.ss"
"private/stx.ss"
"private/define-struct.ss"
"private/more-scheme.ss"
"private/small-scheme.ss"
"private/define.ss"
(for-template (only '#%kernel quote)))
(#%provide expand-import
make-require-transformer prop:require-transformer require-transformer?
;; the import struct type:
import struct:import make-import import?
import-local-id import-src-sym import-src-mod-path import-orig-stx import-mode import-req-mode
;; the import-source struct type:
import-source struct:import-source make-import-source import-source?
import-source-mod-path-stx import-source-mode)
(define-struct* import (local-id src-sym src-mod-path mode req-mode orig-stx)
#:guard (lambda (i s path mode req-mode stx info)
(unless (identifier? i)
(raise-type-error 'make-import "identifier" i))
(unless (symbol? s)
(raise-type-error 'make-import "symbol" s))
(unless (module-path? path)
(raise-type-error 'make-import "module-path" path))
(unless (memq mode '(run syntax template label))
(raise-type-error 'make-import "'run, 'syntax, 'template, or 'label" mode))
(unless (memq req-mode '(run syntax template label))
(raise-type-error 'make-import "'run, 'syntax, 'template, or 'label" req-mode))
(unless (syntax? stx)
(raise-type-error 'make-import "syntax" stx))
(values i s path mode req-mode stx)))
(define-struct* import-source (mod-path-stx mode)
#:guard (lambda (path mode info)
(unless (and (syntax? path)
(module-path? (syntax->datum path)))
(raise-type-error 'make-import-source "syntax module-path" path))
(unless (memq mode '(run syntax template label))
(raise-type-error 'make-import-source "'run, 'syntax, 'template, or 'label" mode))
(values path mode)))
(define-values (prop:require-transformer require-transformer? require-transformer-get-proc)
(make-struct-type-property 'require-transformer))
(define-struct* rt (proc)
#:property prop:require-transformer (lambda (t) (rt-proc t)))
(define (make-require-transformer proc)
(make-rt proc))
;; expand-import : stx bool -> (listof import)
(define (expand-import stx)
(syntax-case stx ()
[simple
(or (identifier? #'simple)
(string? (syntax-e #'simple))
(syntax-case stx (quote)
[(quote s) #t]
[_ #f]))
(let ([mod-path
(if (pair? (syntax-e #'simple))
`(quote . ,(cdr (syntax->datum #'simple)))
(syntax->datum #'simple))])
(unless (module-path? mod-path)
(raise-syntax-error
#f
"invalid module-path form"
stx))
(let-values ([(names et-names lt-names) (syntax-local-module-exports stx)])
(values
(apply
append
(map (lambda (names mode)
(map (lambda (name)
(make-import (datum->syntax
stx
name
stx)
name
mod-path
mode
'run
stx))
names))
(list names et-names lt-names)
(list 'run 'syntax 'label)))
(list (make-import-source #'simple 'run)))))]
[(id . rest)
(identifier? #'id)
(let ([t (syntax-local-value #'id (lambda () #f))])
(if (require-transformer? t)
(call-with-values
(lambda ()
(((require-transformer-get-proc t) t) stx))
(case-lambda
[(v mods)
(unless (and (list? v)
(andmap import? v))
(raise-syntax-error
#f
"first result from require transformer is not a list of imports"
stx))
(unless (and (list? mods)
(andmap import-source? mods))
(raise-syntax-error
#f
"second result from require transformer is not a list of import-sources"
stx))
(values v mods)]
[args
(raise-syntax-error
#f
(format "require transformer did not produced ~a result~s instead of 2"
(length args)
(if (= 1 (length args)) "" "s"))
stx)]))
(raise-syntax-error
#f
"not a require sub-form"
stx)))]
[_
(raise-syntax-error
#f
"bad syntax for require sub-form"
stx)])))