[racket] Playing with module resolvers

From: Danny Yoo (dyoo at hashcollision.org)
Date: Tue Apr 9 18:29:35 EDT 2013

I thought the following example might tickle people:

#lang racket/base

(require net/url

;; Experiments with module-name-resolvers.
(define old-module-name-resolver (current-module-name-resolver))

(struct module-provider-record (name     ;; symbol
                                src      ;; string
                                provides ;; (listof string)

;; wescheme-module-provider: symbol -> (U module-provider-record #f)
;; A module provider using WeScheme.  Uses the getModuleProviderRecord servlet,
;; which generates JSON output that we parse into a module provider
;; record.
(define (make-wescheme-module-provider
         #:servlet-path [servlet-path "http://www.wescheme.org/loadProject"])
  (define (module-provider name)
    (define maybe-match
      (regexp-match #px"wescheme/([-\\w]+)$" (symbol->string name)))
      (define publicId (cadr maybe-match))
      (define url
         (string-append servlet-path "?"
                        (alist->form-urlencoded `((publicId . ,publicId))))))
      (define cust (make-custodian))
      (define a-module-provider-record
        (parameterize ([current-custodian cust])
          (with-handlers ([exn:fail? (lambda (exn) #f)])
            (define port (get-pure-port url))
            (define ht (read-json port))
            (cond [(hash? ht)
                    (hash-ref (hash-ref ht 'source (make-hash))
                    (hash-ref ht 'provides '()))]
                  [else #f]))))
      (custodian-shutdown-all cust)

(define wescheme-module-provider (make-wescheme-module-provider))

;; matches-wescheme-path?: module-path -> (U #f stx)
;; Returns source of the program if this is a path that we care about
for wescheme.
(define (matches-wescheme-path? module-path)
    [(and (symbol? module-path)
          (regexp-match #px"^wescheme/[-\\w]+$" (symbol->string module-path)))
     (define record (wescheme-module-provider module-path))
       [(and record (module-provider-record-src record))
        (parameterize ([read-accept-reader #t])
          (define stx (read-syntax module-path (open-input-string
                                                (string-append "#lang racket\n"

(module-provider-record-src record)))))
          (syntax-case stx ()
            [(m _ l body ...)
             #`(m #,(datum->syntax #f module-path) l body ...)]))]

(define wescheme-module-name-resolver
  (case-lambda [(resolved-path ns)
                (old-module-name-resolver resolved-path ns)]
               [(module-path source-resolved-path stx load?)
                  [(matches-wescheme-path? module-path)
                   => (lambda (src)
                        (when load?
                          (eval src))
                        (make-resolved-module-path module-path))]
                   (old-module-name-resolver module-path
source-resolved-path stx load?)])]))

;; Showing Racket how to evaluate WeScheme code:
(parameterize ([current-namespace (make-base-namespace)]
               [current-module-name-resolver wescheme-module-name-resolver])
  ;; http://www.wescheme.org/openEditor?publicId=0X8C8Np156
  (eval '(require wescheme/0X8C8Np156))
  ;; http://www.wescheme.org/openEditor?publicId=juicy-fever-plain-depth-relax
  (eval '(require wescheme/juicy-fever-plain-depth-relax)))

Posted on the users mailing list.