module-utils.ss
(module module-utils mzscheme

  (require (lib "contract.ss"))

  ;; A ModuleHandle is (make-module-handle path namespace)
  ;; where path is a require-spec s-expression
  ;; and namespace is a namespace to which the module is attached
  (define-struct module-handle (path namespace))

  (provide/contract
   [module-handle? (-> any/c boolean?)]
   [get-module (-> any/c module-handle?)]
   [module-path (-> module-handle? any/c)]
   [module->external-namespace (-> module-handle? namespace?)]
   [module->internal-namespace (-> module-handle? namespace?)]
   [module-exported-names (-> module-handle? (listof symbol?))]
   [module->eval (-> module-handle? (-> any/c any))])

  (define (get-module path)
    (define attach-namespace (make-namespace 'initial))
    (parameterize ([current-namespace attach-namespace])
      (namespace-require path))
    (make-module-handle path attach-namespace))

  (define (module-path mod)
    (module-handle-path mod))

  (define (module->external-namespace mod)
    (define external-namespace (make-namespace 'empty))
    (parameterize ([current-namespace external-namespace])
      (namespace-attach-module (module-handle-namespace mod)
                               (module-handle-path mod))
      (namespace-require (module-handle-path mod)))
    external-namespace)

  (define (module->internal-namespace mod)
    (parameterize ([current-namespace (module-handle-namespace mod)])
      (module->namespace (module-handle-path mod))))

  (define (module-exported-names mod)
    (namespace-mapped-symbols (module->external-namespace mod)))

  (define (module->eval mod)
    (let* ([ns (module->external-namespace mod)])
      (lambda (expr)
        (parameterize ([current-namespace ns])
          (eval expr)))))

  )