#lang scheme
(require (for-syntax scheme/match
scheme/require-transform
scheme/provide-transform
"syntax.ss")
"define.ss")
(define-syntax (define-planet-package stx)
(syntax-case stx ()
[(_ name pkg)
(begin
(unless (identifier? #'name)
(raise-syntax-error #f "expected an identifier" stx #'name))
(unless (identifier? #'pkg)
(raise-syntax-error #f "expected an identifier" stx #'pkg))
(syntax/loc stx
(define-syntax name
(make-require-transformer
(lambda (stx*)
(syntax-case stx* ()
[(_) (expand-import (datum->syntax stx* (list #'planet #'pkg)))]
[(_ file)
(begin
(unless (identifier? #'file)
(raise-syntax-error
#f "expected an identifier" stx* #'file))
(let* ([prefix (symbol->string (syntax-e #'pkg))]
[suffix (symbol->string (syntax-e #'file))]
[sym
(string->symbol (string-append prefix "/" suffix))]
[spec (datum->syntax stx* (list #'planet sym))])
(expand-import spec)))]))))))]))
(define-syntax this-package-in
(make-require-transformer
(lambda (stx)
(syntax-case stx ()
[(_ file)
(expand-import (make-planet-path stx #'file))]))))
(define-syntax this-package-out
(make-provide-transformer
(lambda (stx modes)
(syntax-case stx ()
[(_ file)
(expand-export
(datum->syntax
stx
(list #'all-from-out (make-planet-path stx #'file)))
modes)]))))
(define-for-syntax (import->export i)
(make-export (import-local-id i)
(syntax-e (import-local-id i))
(import-mode i)
#f
(import-orig-stx i)))
(define-syntax box-require
(make-require-transformer
(lambda (stx)
(syntax-case stx []
[(_ ibox spec)
(let-values ([(imports sources) (expand-import #'spec)])
(set-box! (syntax-local-value #'ibox) imports)
(values imports sources))]))))
(define-syntax box-provide
(make-provide-transformer
(lambda (stx modes)
(syntax-case stx []
[(_ ibox)
(map import->export (unbox (syntax-local-value #'ibox)))]))))
(define-syntax-rule (require/provide spec ...)
(begin
(define-syntax imports (box #f))
(require (box-require imports (combine-in spec ...)))
(provide (box-provide imports))))
(define-syntax (quote-require stx)
(syntax-case stx ()
[(_ spec ...)
(let*-values ([(imports sources)
(expand-import (syntax/loc stx (combine-in spec ...)))])
(with-syntax ([(name ...) (map import-local-id imports)])
(syntax/loc stx '(name ...))))]))
(define-for-syntax (rename-import i id)
(struct-copy import i [local-id id]))
(define-for-syntax (import->raw-require-spec i)
(match i
[(struct import [local-id
src-sym
src-mod-path
mode
req-mode
orig-mode
orig-stx])
(datum->syntax
orig-stx
(list #'just-meta
req-mode
(list #'for-meta
mode
(list #'rename
src-mod-path
(syntax-local-introduce local-id)
src-sym)))
orig-stx)]))
(define-syntax (do-local-require stx)
(syntax-case stx []
[(_ rename spec ...)
(let*-values ([(imports sources)
(expand-import
(datum->syntax
stx
(list* #'only-meta-in 0 (syntax->list #'(spec ...)))
stx))]
[(names) (map import-local-id imports)]
[(reqd-names)
(let ([ctx (syntax-local-get-shadower (datum->syntax #f (gensym)))])
(map (lambda (n) (datum->syntax ctx (syntax-e n) n)) names))]
[(renamed-imports) (map rename-import imports reqd-names)]
[(raw-specs) (map import->raw-require-spec renamed-imports)]
[(lifts) (map syntax-local-lift-require raw-specs reqd-names)])
(with-syntax ([(name ...) names]
[(lifted ...) lifts])
(syntax/loc stx (rename [name lifted] ...))))]))
(define-syntax-rule (local-require spec ...)
(do-local-require define-renamings spec ...))
(provide require/provide
do-local-require
local-require
quote-require
define-planet-package
this-package-in)