*** empty log message ***
[bpt/guile.git] / module / system / il / compile.scm
index 68b3f42..e9354c4 100644 (file)
   :use-syntax (system base syntax)
   :use-module (system il glil)
   :use-module (system il ghil)
+  :use-module (ice-9 match)
   :use-module (ice-9 common-list)
   :export (compile))
 
 (define (compile x e . opts)
-  (set! x (parse-ghil x e))
   (if (memq :O opts) (set! x (optimize x)))
   (codegen x))
 
 
 (define (optimize x)
   (match x
-    (($ <ghil-call> proc args)
+    (($ <ghil-set> env var val)
+     (make-<ghil-set> env var (optimize val)))
+
+    (($ <ghil-if> test then else)
+     (make-<ghil-if> (optimize test) (optimize then) (optimize else)))
+
+    (($ <ghil-begin> exps)
+     (make-<ghil-begin> (map optimize exps)))
+
+    (($ <ghil-bind> env vars vals body)
+     (make-<ghil-bind> env vars (map optimize vals) (optimize body)))
+
+    (($ <ghil-lambda> env vars rest body)
+     (make-<ghil-lambda> env vars rest (optimize body)))
+
+    (($ <ghil-inst> inst args)
+     (make-<ghil-inst> inst (map optimize args)))
+
+    (($ <ghil-call> env proc args)
      (match proc
        ;; ((@lambda (VAR...) BODY...) ARG...) =>
        ;;   (@let ((VAR ARG) ...) BODY...)
-       (($ <ghil-lambda> env vars #f body)
-       (optimize (make-<ghil-bind> vars args body)))
+       (($ <ghil-lambda> lambda-env vars #f body)
+       (for-each (lambda (v)
+                   (if (eq? v.kind 'argument) (set! v.kind 'local))
+                   (set! v.env env)
+                   (ghil-env-add! env v))
+                 lambda-env.variables)
+       (optimize (make-<ghil-bind> env vars args body)))
        (else
-       (make-<ghil-call> (optimize proc) (for-each optimize args)))))
+       (make-<ghil-call> env (optimize proc) (map optimize args)))))
     (else x)))
 
 \f
@@ -55,8 +78,8 @@
 ;;;
 
 (define *ia-void* (make-<glil-void>))
-(define *ia-drop* (make-<glil-inst> 'drop))
-(define *ia-return* (make-<glil-inst> 'return))
+(define *ia-drop* (make-<glil-call> 'drop 0))
+(define *ia-return* (make-<glil-call> 'return 0))
 
 (define (make-label) (gensym ":L"))
 
     (define (push-code! code)
       (set! stack (cons code stack)))
     (define (comp tree tail drop)
+      (define (push-label! label)
+       (push-code! (make-<glil-label> label)))
+      (define (push-branch! inst label)
+       (push-code! (make-<glil-branch> inst label)))
+      (define (push-call! inst args)
+       (for-each comp-push args)
+       (push-code! (make-<glil-call> inst (length args))))
       ;; possible tail position
       (define (comp-tail tree) (comp tree tail drop))
       ;; push the result
       (define (comp-push tree) (comp tree #f #f))
       ;; drop the result
       (define (comp-drop tree) (comp tree #f #t))
+      ;; drop the result if unnecessary
+      (define (maybe-drop)
+       (if drop (push-code! *ia-drop*)))
+      ;; return here if necessary
+      (define (maybe-return)
+       (if tail (push-code! *ia-return*)))
       ;; return this code if necessary
       (define (return-code! code)
        (if (not drop) (push-code! code))
-       (if tail (push-code! *ia-return*)))
+       (maybe-return))
       ;; return void if necessary
-      (define (return-void!) (return-code! *ia-void*))
+      (define (return-void!)
+       (return-code! *ia-void*))
+      ;; return object if necessary
+      (define (return-object! obj)
+       (return-code! (make-<glil-const> obj)))
       ;;
       ;; dispatch
       (match tree
        (($ <ghil-void>)
         (return-void!))
 
-       (($ <ghil-quote> obj)
-        (return-code! (make-<glil-const> obj)))
+       (($ <ghil-quote> env loc obj)
+        (return-object! obj))
+
+       (($ <ghil-quasiquote> env loc exp)
+        (let loop ((x exp))
+          (match x
+            ((? list? ls)
+             (push-call! 'mark '())
+             (for-each loop ls)
+             (push-call! 'list-mark '()))
+            ((? pair? pp)
+             (loop (car pp))
+             (loop (cdr pp))
+             (push-code! (make-<glil-call> 'cons 2)))
+            (($ <ghil-unquote> env loc exp)
+             (comp-push exp))
+            (($ <ghil-unquote-splicing> env loc exp)
+             (comp-push exp)
+             (push-call! 'list-break '()))
+            (else
+             (push-code! (make-<glil-const> x)))))
+        (maybe-drop)
+        (maybe-return))
 
-       (($ <ghil-ref> env var)
+       (($ <ghil-ref> env loc var)
         (return-code! (make-glil-var 'ref env var)))
 
-       (($ <ghil-set> env var val)
+       ((or ($ <ghil-set> env loc var val)
+            ($ <ghil-define> env loc var val))
         (comp-push val)
         (push-code! (make-glil-var 'set env var))
         (return-void!))
 
-       (($ <ghil-if> test then else)
+       (($ <ghil-if> env loc test then else)
         ;;     TEST
         ;;     (br-if-not L1)
         ;;     THEN
-        ;;     (jump L2)
+        ;;     (br L2)
         ;; L1: ELSE
         ;; L2:
         (let ((L1 (make-label)) (L2 (make-label)))
           (comp-push test)
-          (push-code! (make-<glil-branch> 'br-if-not L1))
+          (push-branch! 'br-if-not L1)
           (comp-tail then)
-          (if (not tail) (push-code! (make-<glil-branch> 'jump L2)))
-          (push-code! (make-<glil-label> L1))
+          (if (not tail) (push-branch! 'br L2))
+          (push-label! L1)
           (comp-tail else)
-          (if (not tail) (push-code! (make-<glil-label> L2)))))
+          (if (not tail) (push-label! L2))))
 
-       (($ <ghil-begin> exps)
+       (($ <ghil-and> env loc exps)
+        ;;     EXP
+        ;;     (br-if-not L1)
+        ;;     ...
+        ;;     TAIL
+        ;;     (br L2)
+        ;; L1: (const #f)
+        ;; L2:
+        (let ((L1 (make-label)) (L2 (make-label)))
+          (if (null? exps)
+              (return-object! #t)
+              (do ((exps exps (cdr exps)))
+                  ((null? (cdr exps))
+                   (comp-tail (car exps))
+                   (if (not tail) (push-branch! 'br L2))
+                   (push-label! L1)
+                   (return-object! #f)
+                   (if (not tail) (push-label! L2))
+                   (maybe-drop)
+                   (maybe-return))
+                (comp-push (car exps))
+                (push-branch! 'br-if-not L1)))))
+
+       (($ <ghil-or> env loc exps)
+        ;;     EXP
+        ;;     (dup)
+        ;;     (br-if L1)
+        ;;     (drop)
+        ;;     ...
+        ;;     TAIL
+        ;; L1:
+        (let ((L1 (make-label)))
+          (if (null? exps)
+              (return-object! #f)
+              (do ((exps exps (cdr exps)))
+                  ((null? (cdr exps))
+                   (comp-tail (car exps))
+                   (push-label! L1)
+                   (maybe-drop)
+                   (maybe-return))
+                (comp-push (car exps))
+                (push-call! 'dup '())
+                (push-branch! 'br-if L1)
+                (push-call! 'drop '())))))
+
+       (($ <ghil-begin> env loc exps)
         ;; EXPS...
         ;; TAIL
         (if (null? exps)
                  (comp-tail (car exps)))
               (comp-drop (car exps)))))
 
-       (($ <ghil-bind> env vars vals body)
+       (($ <ghil-bind> env loc vars vals body)
         ;; VALS...
         ;; (set VARS)...
         ;; BODY
                   (reverse vars))
         (comp-tail body))
 
-       (($ <ghil-lambda> vars rest body)
+       (($ <ghil-lambda> env loc vars rest body)
         (return-code! (codegen tree)))
 
-       (($ <ghil-call> proc args)
+       (($ <ghil-inline> env loc inst args)
         ;; ARGS...
+        ;; (INST NARGS)
+        (push-call! inst args)
+        (maybe-drop)
+        (maybe-return))
+
+       (($ <ghil-call> env loc proc args)
         ;; PROC
+        ;; ARGS...
         ;; ([tail-]call NARGS)
-        (for-each comp-push args)
         (comp-push proc)
-        (let ((inst (if tail 'tail-call 'call)))
-          (push-code! (make-<glil-call> inst (length args))))
-        (if drop (push-code! *ia-drop*)))
-
-       (($ <ghil-inst> inst args)
-        ;; ARGS...
-        ;; (INST)
-        (for-each comp-push args)
-        (push-code! (make-<glil-inst> inst))
-        (if drop (push-code! *ia-drop*))
-        (if tail (push-code! *ia-return*)))))
+        (push-call! (if tail 'tail-call 'call) args)
+        (maybe-drop))))
     ;;
     ;; main
     (match ghil
-      (($ <ghil-lambda> env args rest body)
+      (($ <ghil-lambda> env loc args rest body)
        (let* ((vars env.variables)
              (locs (pick (lambda (v) (eq? v.kind 'local)) vars))
              (exts (pick (lambda (v) (eq? v.kind 'external)) vars)))
         (finalize-index! locs)
         (finalize-index! exts)
         ;; export arguments
-        (do ((n 0 (1+ n)) (l args (cdr l)))
+        (do ((n 0 (1+ n))
+             (l args (cdr l)))
             ((null? l))
           (let ((v (car l)))
             (if (eq? v.kind 'external)