aboutsummaryrefslogtreecommitdiffstats
path: root/lib/csc/compiler.csc
diff options
context:
space:
mode:
authorRose Hogenson <rhogenson@posteo.net>2022-08-01 19:35:19 -0700
committerRose Hogenson <rhogenson@posteo.net>2022-08-01 19:35:19 -0700
commitacc561366f3fe6ec0377103f52ef0f7e923711c9 (patch)
treed7a19cfbad78a69ebea71b27302e708c0655863d /lib/csc/compiler.csc
parent99ce19a8053a93457885f32ec54c1c5b7c1961c1 (diff)
downloadchromatopelma-acc561366f3fe6ec0377103f52ef0f7e923711c9.tar.zst
Modify the project structure.
Now the lib directory contains what will eventually end up on the user's /usr/lib/csc. When I write make install, it will copy all of the .csc files from lib into the destination lib directory. This means I can start working on the standard library in lib/scheme.
Diffstat (limited to 'lib/csc/compiler.csc')
-rw-r--r--lib/csc/compiler.csc164
1 files changed, 164 insertions, 0 deletions
diff --git a/lib/csc/compiler.csc b/lib/csc/compiler.csc
new file mode 100644
index 0000000..20d5d37
--- /dev/null
+++ b/lib/csc/compiler.csc
@@ -0,0 +1,164 @@
+(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 ir2)
+ *tail*)
+ (only (csc linker)
+ link)
+ (only (csc list)
+ revappend)
+ (only (csc loop)
+ loop
+ return)
+ (only (csc macros)
+ builtins-environment
+ 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)
+ ((string<? (sprintf "{}" x) (sprintf "{}" y)) -1)
+ (else 1)))))
+
+
+ (define *library-search-dirs* '())
+
+
+ (define (find-library name)
+ (define library-roots (cons *standard-library-dir* *library-search-dirs*))
+ (loop for dir in library-roots
+ for file-path = (loop for part in name
+ collect (symbol->string part) into path
+ finally (return (sprintf "{}/{}.csc" dir (join "/" 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 (load-library import)))
+ 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))
+ exported-symbols)
+ (_ (error "unexpected form in compile-library" lib))))
+ (define (load-library lib)
+ (match lib
+ ('(csc builtins)
+ builtins-environment)
+ (_ (or (lookup library-symbols lib #f)
+ (call-with-input-file (find-library lib)
+ (lambda (f)
+ (compile-library (read f))))))))
+
+ (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 (list (list 'exit (list 'const 0))))))))
+ (_ (error "unexpected form in compile" program))))))