forked from alex-eg/sex
Introducing Sex SEMantic ENgine: the semen. Also split reader to other file (it can be replaced in the future). Macro expansion inside Sex code doesn't work yet, and it must be done in semen, not during fmt-c generation as before.
89 lines
2.9 KiB
Scheme
89 lines
2.9 KiB
Scheme
; Why `sex-modules`? Probably `modules` unit is reserved by chicken,
|
|
; things start to break.
|
|
(declare (unit sex-modules)
|
|
(uses sex-reader
|
|
utils))
|
|
|
|
(import brev-separate
|
|
(chicken file)
|
|
(chicken load)
|
|
(chicken pathname)
|
|
(chicken process-context)
|
|
(chicken string)
|
|
fmt
|
|
srfi-1)
|
|
|
|
(define +persistent-module-paths+ (list))
|
|
|
|
(define (get-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)))
|
|
(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)
|
|
((fn) ; replace with prototype
|
|
;; fn type name (arg-list) (body)
|
|
;; 1 2 3 4 - we need first 4
|
|
(cons (take (cdr form) 4) acc))
|
|
((define defmacro import include struct typedef union var)
|
|
(cons (cdr form) acc))
|
|
(else (error "Pub what? " (cadr 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 ":"))))))
|