require-provide.ss
#lang scheme

(require (for-syntax scheme/require-transform))

(define-syntax-rule (require/provide mod-path ...)
  (begin
    (require mod-path ...)
    (provide (all-from-out mod-path ...))))

(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 (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 ...))))]))

(provide require/provide
         quote-require
         define-planet-package)