Implement pub support for enums, and also anonymous enums declared in-place. Also give the cdr of a `pub' form the form's own location, so a error about what follows `pub' can say where it was written
99 lines
3.2 KiB
Scheme
99 lines
3.2 KiB
Scheme
(import
|
|
scheme
|
|
brev-separate
|
|
(chicken base)
|
|
(chicken file)
|
|
(chicken load)
|
|
(chicken pathname)
|
|
(chicken process-context)
|
|
(chicken string)
|
|
fmt
|
|
reader
|
|
srfi-1
|
|
utils)
|
|
|
|
(define +persistent-module-paths+ (list))
|
|
|
|
;;; for guarding against multiple imports (sort of mandatory #pragma
|
|
;;; once)
|
|
(define +imported-modules+ (list))
|
|
|
|
(define (get-modules-public-forms module-list)
|
|
;; Module list is a list of symbols
|
|
;; How Sex handles modules:
|
|
;; For each module in a list, construct path, find module by path in
|
|
;; module path directories, extract public definitions from the
|
|
;; module, paste them in current one in emulation of C include
|
|
;; directives.
|
|
(fold-right append (list)
|
|
(map (fn (import-module (symbol->string x)))
|
|
module-list)))
|
|
|
|
(define (import-module name)
|
|
(let ((module-path (locate-module name)))
|
|
(assert module-path (fmt #f "Failed to find module " name " in "
|
|
(get-module-paths)))
|
|
(if (member module-path +imported-modules+)
|
|
(list)
|
|
(begin
|
|
(set! +imported-modules+ (cons module-path +imported-modules+))
|
|
(read-public-interface module-path)))))
|
|
|
|
(define (get-module-paths)
|
|
(cons (current-directory)
|
|
+persistent-module-paths+))
|
|
|
|
(define (locate-module name)
|
|
;; Module locations: relative to file being compiled, or in what was
|
|
;; in SEX_MODULE_PATH env var at the start of the process (see
|
|
;; load-persistent-module-paths function)
|
|
|
|
(let ((search-paths (get-module-paths)))
|
|
(let loop ((paths search-paths))
|
|
(if (null? paths)
|
|
#f
|
|
(or (module-exists? name (car paths))
|
|
(loop (cdr paths)))))))
|
|
|
|
(define (module-exists? name module-dir)
|
|
;; returns absolute path to module, if it exists
|
|
(and (directory-exists? module-dir)
|
|
(let ((module-path (make-absolute-pathname module-dir name "sex")))
|
|
(and (file-exists? module-path)
|
|
(file-readable? module-path)
|
|
module-path))))
|
|
|
|
(define (read-public-interface module-path)
|
|
;; pub fns are reduced to prototypes, other pub forms are just pasted
|
|
(let ((raw-forms (read-from-file module-path)))
|
|
(fold
|
|
process-public-interface-form
|
|
(list)
|
|
raw-forms)))
|
|
|
|
;;; TODO: use semen facilities to analyze modules
|
|
(define (process-public-interface-form form acc)
|
|
(case (car form)
|
|
((pub)
|
|
(case (cadr form)
|
|
;; A function is reduced to a prototype and keeps its `pub', so
|
|
;; the importing unit declares it with external linkage
|
|
((fn)
|
|
(cons (copy-form-source! form (take form 5)) acc))
|
|
;; A variable becomes an `extern' declaration
|
|
((var)
|
|
(cons (copy-form-source! form (cons 'extern (take (cdr form) 3))) acc))
|
|
((define defmacro enum import include struct typedef union)
|
|
(cons (copy-form-source! form (cdr form)) acc))
|
|
(else (sex-error form "pub must be followed by a definition" form))))
|
|
(else acc)))
|
|
|
|
(define (load-persistent-module-paths)
|
|
(let ((sex-module-path-env-var
|
|
(get-env-var "SEX_MODULE_PATH")))
|
|
(when sex-module-path-env-var
|
|
(set! +persistent-module-paths+
|
|
(map (lambda (p)
|
|
(make-absolute-pathname p #f #f))
|
|
(string-split sex-module-path-env-var ":"))))))
|