Racket: use EOT token for internal communications
[geiser.git] / scheme / racket / geiser / modules.rkt
blob0591a9235235b00cfac8cabf73fe3baba4913bc9
1 ;;; modules.rkt -- module metadata
3 ;; Copyright (C) 2009, 2010 Jose Antonio Ortega Ruiz
5 ;; This program is free software; you can redistribute it and/or
6 ;; modify it under the terms of the Modified BSD License. You should
7 ;; have received a copy of the license along with this program. If
8 ;; not, see <http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5>.
10 ;; Start date: Wed May 06, 2009 02:35
12 #lang racket
14 (provide load-module
15          ensure-module-spec
16          module-spec->namespace
17          namespace->module-name
18          namespace->module-path-name
19          module-path-name->name
20          module-spec->path-name
21          module-list
22          module-exports)
24 (require srfi/13 syntax/modresolve syntax/modcode geiser/enter)
26 (define (ensure-module-spec spec)
27   (cond [(symbol? spec) spec]
28         [(not (string? spec)) #f]
29         [else `(file ,spec)]))
31 (define (module-spec->namespace spec (lang #f) (current #t))
32   (define (try-lang)
33     (and lang
34          (with-handlers ([exn? (const #f)])
35            (load-module lang #f (current-namespace))
36            (module->namespace lang))))
37   (or (get-namespace spec)
38       (try-lang)
39       (and current (current-namespace))))
41 (define nowhere (open-output-nowhere))
43 (define (load-module spec (port #f) (ns #f))
44   (parameterize ([current-error-port (or port nowhere)])
45     (enter-module (ensure-module-spec spec))
46     (when (namespace? ns)
47       (current-namespace ns))))
49 (define (namespace->module-path-name ns)
50   (let ([rmp (variable-reference->resolved-module-path
51               (eval '(#%variable-reference) ns))])
52     (and (resolved-module-path? rmp)
53          (resolved-module-path-name rmp))))
55 (define (module-spec->path-name spec)
56   (and (symbol? spec)
57        (or (get-path spec)
58            (register-path spec
59                           (namespace->module-path-name
60                            (module-spec->namespace spec) #f #f)))))
62 (define (module-path-name->name path)
63   (cond [(path? path)
64          (let* ([path (path->string path)]
65                 [cpaths (map (compose path->string path->directory-path)
66                              (current-library-collection-paths))]
67                 [prefix-len (lambda (p)
68                               (let ((pl (string-length p)))
69                                 (if (= pl (string-prefix-length p path))
70                                     pl
71                                     0)))]
72                 [lens (map prefix-len cpaths)]
73                 [real-path (substring path (apply max lens))])
74            (if (absolute-path? real-path)
75                (call-with-values (lambda () (split-path path))
76                  (lambda (_ basename __) (path->string basename)))
77                (regexp-replace "\\.[^./]*$" real-path "")))]
78         ;; [(eq? path '#%kernel) "(kernel)"]
79         [(string? path) path]
80         [(symbol? path) (symbol->string path)]
81         [else ""]))
83 (define namespace->module-name
84   (compose module-path-name->name namespace->module-path-name))
86 (define (skippable-dir? path)
87   (call-with-values (lambda () (split-path path))
88     (lambda (_ basename __)
89       (member (path->string basename) '(".svn" "compiled")))))
91 (define path->symbol (compose string->symbol path->string))
93 (define (path->entry path)
94   (let ([ext (filename-extension path)])
95     (and ext
96          (or (bytes=? ext #"rkt") (bytes=? ext #"ss"))
97          (not (bytes=? (bytes-append #"main" ext) (path->bytes path)))
98          (let* ([path (path->string path)]
99                 [len (- (string-length path) (bytes-length ext) 1)])
100            (substring path 0 len)))))
102 (define (visit-module-path path kind acc)
103   (define (register e p)
104     (register-path (string->symbol e) (build-path (current-directory) p))
105     (cons e acc))
106   (define (find-main ext)
107     (let ([m (build-path path (string-append "main." ext))])
108       (and (file-exists? m) m)))
109   (case kind
110     [(file) (let ([entry (path->entry path)])
111               (if (not entry) acc (register entry path)))]
112     [(dir) (cond [(skippable-dir? path) (values acc #f)]
113                  [(or (find-main "rkt") (find-main "ss")) =>
114                   (curry register (path->string path))]
115                  [else acc])]
116     [else acc]))
118 (define (find-modules path acc)
119   (if (directory-exists? path)
120       (parameterize ([current-directory path])
121         (fold-files visit-module-path acc))
122       acc))
124 (define (known-modules)
125   (sort (foldl find-modules '() (current-library-collection-paths)) string<?))
127 (define registered (make-hash))
129 (define (get-path mod) (hash-ref registered mod #f))
131 (define (register-path mod path)
132   (hash-set! registered mod path)
133   path)
135 (define module-cache #f)
137 (define (update-module-cache)
138   (when (not module-cache) (set! module-cache (known-modules))))
140 (define (module-list)
141   (update-module-cache)
142   module-cache)
144 (define (module-exports mod)
145   (define (value id)
146     (with-handlers ([exn? (const #f)])
147       (dynamic-require mod id (const #f))))
148   (define (contracted id)
149     (let ([v (value id)])
150       (if (has-contract? v)
151           (cons id (contract-name (value-contract v)))
152           id)))
153   (define (extract-ids ls)
154     (append-map (lambda (idls)
155                   (map car (cdr idls)))
156                 ls))
157   (define (classify-ids ids)
158     (let loop ([ids ids] [procs '()] [vars '()])
159       (cond [(null? ids)
160              `((procs ,@(map contracted (reverse procs)))
161                (vars ,@(map contracted (reverse vars))))]
162             [(procedure? (value (car ids)))
163              (loop (cdr ids) (cons (car ids) procs) vars)]
164             [else (loop (cdr ids) procs (cons (car ids) vars))])))
165   (let-values ([(reg syn)
166                 (module-compiled-exports
167                  (get-module-code (resolve-module-path mod #f)))])
168     (let ([syn (map contracted (extract-ids syn))]
169           [reg (extract-ids reg)])
170       `((syntax ,@syn) ,@(classify-ids reg)))))
172 (define (startup)
173  (thread update-module-cache)
174  (void))
176 (startup)
178 ;;; modules.rkt ends here