(define-library (csc compiler) (export *library-search-dirs* compile) (import (scheme base) (only (scheme file) call-with-input-file file-exists?) (only (scheme read) read) (only (csc codegen) ir2->ir3) (only (csc config) *standard-library-dir*) (only (csc cps) closure-convert ir1->ir2) (only (csc encoding) encode) (only (csc format) sprintf) (only (csc hash-map) compare-symbols hash-bytevector insert key-not-found-error? lookup make-comparer make-map merge) (only (csc ir1) %define-syntax %library-define %library-ref %sequence) (only (csc linker) link) (only (csc list) revappend) (only (csc loop) loop return) (only (csc macros) expand-body) (only (csc match) match) (only (csc strings) join)) (begin (define (normalize-library lib) (match lib (('define-library name . declarations) (loop for decl in declarations if (match decl (('export . _) #t) (_ #f)) collect (cdr decl) into exports else if (match decl (('import . _) #t) (_ #f)) collect (cdr decl) into imports else if (match decl (('begin . _) #t) (_ #f)) collect (cdr decl) into body else do (error "unexpected form in normalize-library" decl) finally (return (list 'define-library name (cons 'export exports) (cons 'import imports) (cons 'begin body))))) (_ (error "unexpected form in normalize-library" lib)))) (define compare-library-names (make-comparer (lambda (x) (hash-bytevector (string->utf8 (sprintf "{}" x)))) (lambda (x y) (cond ((equal? x y) 0) ((stringstring part) into path finally (return (join "/" (cons dir path)))) if (file-exists? file-path) return file-path else collect file-path into bad-paths finally (error "unable to find library" name bad-paths))) (define (ir1->bytecode expr) (ir2->ir3 (closure-convert (ir1->ir2 expr (lambda (x) *tail*))))) ; compile turns scheme code into bytecode. (define (compile program) (define library-symbols (make-map compare-library-names)) (define (make-import-map imports) (define env (make-map compare-symbols)) (loop for import in imports do (set! env (merge env (or (lookup library-symbols import #f) (call-with-input-file (find-library import) (lambda (f) (compile-library (read f))))))) finally (return env))) (define library-code '()) (define (compile-library lib) (match (normalize-library lib) (('define-library library-name ('export . exports) ('import . imports) ('begin . body)) (define expanded-body (expand-body library-name body env)) (define env (make-import-map imports)) (let loop ((expr expanded-body)) (match expr ((% %library-define (% %library-ref name _) val) (set! env (insert env name val))) ((% %define-syntax name val) (set! env (insert env name val))) ((% %sequence head tail) (loop head) (loop tail)))) (define exported-symbols (make-map compare-symbols)) (loop for sym in exports do (set! exported-symbols (insert exported-symbols sym (guard (e ((key-not-found-error? e) (error "exported symbol was not defined in the library" sym))) (lookup env sym))))) (set! library-symbols (insert library-symbols library-name exported-symbols)) (set! library-code (cons (ir1->bytecode expanded-body) library-code))) (_ (error "unexpected form in compile-library" lib)))) (match program ((('import . imports1) ('import . imports2) . rest) (compile (cons (list 'import (append imports1 imports2)) rest))) ((('import . imports) . body) (define compiled-body (ir1->bytecode (expand-body 'main body (make-import-map imports)))) (encode (link (revappend library-code (list compiled-body))))) (_ (error "unexpected form in compile" program))))))