aboutsummaryrefslogtreecommitdiffstats
path: root/csc/compiler.csc
blob: ee0b3b432e031d7f10274c863418010e834d2fba (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
(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)
            ((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 (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))))))