Add instructions for doing very late binding
[bpt/guile.git] / module / system / vm / assemble.scm
index a37314a..3197f71 100644 (file)
@@ -27,7 +27,6 @@
                        make-binding
                        bytecode->objcode))
   :use-module (system vm conv)
-  :use-module (ice-9 match)
   :use-module (ice-9 regex)
   :use-module (ice-9 common-list)
   :use-module (srfi srfi-4)
@@ -45,6 +44,8 @@
 (define-record (<venv> parent nexts closure?))
 (define-record (<vmod> id))
 (define-record (<vlink> module name))
+(define-record (<vlate-bound> name))
+(define-record (<vdefine> module name))
 (define-record (<bytespec> vars bytes meta objs closure?))
 
 \f
 ;;;
 
 (define (preprocess x e)
-  (match x
-    ((<glil-asm> vars body)
-     (let* ((venv (<venv> :parent e :nexts (slot vars 'nexts) :closure? #f))
+  (record-case x
+    ((<glil-asm> vars body)
+     (let* ((venv (make-venv :parent e :nexts (glil-vars-nexts vars) :closure? #f))
            (body (map (lambda (x) (preprocess x venv)) body)))
-       (<vm-asm> :venv venv :glil x :body body)))
-    ((<glil-external> op depth index)
+       (make-vm-asm :venv venv :glil x :body body)))
+    ((<glil-external> op depth index)
      (do ((d depth (- d 1))
-         (e e (slot e 'parent)))
+         (e e (venv-parent e)))
         ((= d 0))
-       (set! (slot e 'closure?) #t))
+       (set! (venv-closure? e) #t))
      x)
     (else x)))
 
@@ -72,8 +73,8 @@
 ;;;
 
 (define (codegen glil toplevel)
-  (match glil
-    (($ <vm-asm> venv ($ <glil-asm> vars _) body)
+  (record-case glil
+    ((<vm-asm> venv glil body) (record-case glil ((<glil-asm> vars)
      (let ((stack '())
           (binding-alist '())
           (source-alist '())
                 (else 3)))
         (apply + (map byte-length stack)))
        (define (generate-code x)
-        (match x
-          ((<vm-asm> venv)
+        (record-case x
+          ((<vm-asm> venv)
            (push-object! (codegen x #f))
-           (if (slot venv 'closure?) (push-code! `(make-closure))))
+           (if (venv-closure? venv) (push-code! `(make-closure))))
 
-          (($ <glil-bind> binds)
+          ((<glil-bind> (binds vars))
            (let ((bindings
                   (map (lambda (v)
                          (let ((name (car v)) (type (cadr v)) (i (caddr v)))
                            (case type
                              ((argument) (make-binding name #f i))
-                             ((local) (make-binding name #f (+ vars.nargs i)))
+                             ((local) (make-binding name #f (+ (glil-vars-nargs vars) i)))
                              ((external) (make-binding name #t i)))))
                        binds)))
              (set! binding-alist
                    (acons (current-address) bindings binding-alist))))
 
-          ((<glil-unbind>)
+          ((<glil-unbind>)
            (set! binding-alist (acons (current-address) #f binding-alist)))
 
-          ((<glil-source> loc)
+          ((<glil-source> loc)
            (set! source-alist (acons (current-address) loc source-alist)))
 
-          ((<glil-void>)
+          ((<glil-void>)
            (push-code! '(void)))
 
-          (($ <glil-const> x)
-           (push-object! x))
+          ((<glil-const> obj)
+           (push-object! obj))
 
-          ((<glil-argument> op index)
+          ((<glil-argument> op index)
            (if (eq? op 'ref)
                (push-code! `(local-ref ,index))
                (push-code! `(local-set ,index))))
 
-          ((<glil-local> op index)
+          ((<glil-local> op index)
            (if (eq? op 'ref)
-               (push-code! `(local-ref ,(+ vars.nargs index)))
-               (push-code! `(local-set ,(+ vars.nargs index)))))
+               (push-code! `(local-ref ,(+ (glil-vars-nargs vars) index)))
+               (push-code! `(local-set ,(+ (glil-vars-nargs vars) index)))))
 
-          ((<glil-external> op depth index)
-           (do ((e venv e.parent)
+          ((<glil-external> op depth index)
+           (do ((e venv (venv-parent e))
                 (d depth (1- d))
-                (n 0 (+ n e.nexts)))
+                (n 0 (+ n (venv-nexts e))))
                ((= d 0)
                 (if (eq? op 'ref)
                     (push-code! `(external-ref ,(+ n index)))
                     (push-code! `(external-set ,(+ n index)))))))
 
-          (($ <glil-module> op module name)
-           (push-object! (<vlink> :module #f :name name))
-           (if (eq? op 'ref)
-               (push-code! '(variable-ref))
-               (push-code! '(variable-set))))
+          ((<glil-module> op module name)
+            (case op
+              ((ref)
+               (push-object! (make-vlink :module module :name name))
+               (push-code! '(variable-ref)))
+              ((set)
+               (push-object! (make-vlink :module module :name name))
+               (push-code! '(variable-set)))
+              ((define)
+               (push-object! (make-vdefine :module module :name name))
+               (push-code! '(variable-set)))))
+
+          ((<glil-late-bound> op name)
+            (let* ((var (make-vlate-bound :name name))
+                   (i (cond ((object-assoc var object-alist) => cdr)
+                            (else
+                             (let ((i (length object-alist)))
+                               (set! object-alist (acons var i object-alist))
+                               i)))))
+              (case op
+                ((ref)
+                 (push-code! `(late-variable-ref ,i)))
+                ((set)
+                 (push-code! `(late-variable-set ,i)))
+                (else (error "unknown late bound" op name)))))
 
-          ((<glil-label> label)
+          ((<glil-label> label)
            (set! label-alist (assq-set! label-alist label (current-address))))
 
-          ((<glil-branch> inst label)
+          ((<glil-branch> inst label)
            (set! stack (cons (list inst label) stack)))
 
-          ((<glil-call> inst nargs)
+          ((<glil-call> inst nargs)
            (if (instruction? inst)
                (let ((pops (instruction-pops inst)))
                  (cond ((< pops 0)
 ;       (format #t "codegen: stack = ~a~%" (reverse stack))
        (let ((bytes (stack->bytes (reverse! stack) label-alist)))
         (if toplevel
-            (bytecode->objcode bytes vars.nlocs vars.nexts)
-            (<bytespec> :vars vars :bytes bytes
-                        :meta (if (and (null? binding-alist)
-                                       (null? source-alist))
-                                #f
-                                (cons (reverse! binding-alist)
-                                      (reverse! source-alist)))
-                        :objs (let ((objs (map car (reverse! object-alist))))
-                                (if (null? objs) #f (list->vector objs)))
-                        :closure? venv.closure?)))))))
+            (bytecode->objcode bytes (glil-vars-nlocs vars) (glil-vars-nexts vars))
+            (make-bytespec :vars vars :bytes bytes
+                            :meta (if (and (null? binding-alist)
+                                           (null? source-alist))
+                                      #f
+                                      (cons (reverse! binding-alist)
+                                            (reverse! source-alist)))
+                            :objs (let ((objs (map car (reverse! object-alist))))
+                                    (if (null? objs) #f (list->vector objs)))
+                            :closure? (venv-closure? venv))))))))))
 
 (define (object-assoc x alist)
-  (match x
-    ((<vlink>) (assoc x alist))
+  (record-case x
+    ((<vlink>) (assoc x alist))
     (else        (assq x alist))))
 
 (define (stack->bytes stack label-alist)
   (let dump! ((x x))
     (cond
      ((object->code x) => push-code!)
-     (else
-      (match x
-       ((<bytespec> vars bytes meta objs closure?)
+     ((record? x)
+      (record-case x
+       ((<bytespec> vars bytes meta objs closure?)
         ;; dump parameters
-        (let ((nargs vars.nargs) (nrest vars.nrest)
-              (nlocs vars.nlocs) (nexts vars.nexts))
+        (let ((nargs (glil-vars-nargs vars)) (nrest (glil-vars-nrest vars))
+              (nlocs (glil-vars-nlocs vars)) (nexts (glil-vars-nexts vars)))
           (cond
             ((and (< nargs 4) (< nlocs 8) (< nexts 4))
              ;; 8-bit representation
         (if meta (dump! meta))
         ;; dump bytecode
         (push-code! `(load-program ,bytes)))
-       (($ <vlink> module name)
+       ((<vlink> module name)
+         (dump! (and=> module module-name))
+         (dump! name)
+        (push-code! '(link)))
+       ((<vdefine> module name)
         ;; FIXME: dump module
-        (push-code! `(link ,(symbol->string name))))
-       (($ <vmod> id)
+        (push-code! `(define ,(symbol->string name))))
+       ((<vlate-bound> name)
+        (push-code! `(late-bind ,(symbol->string name))))
+       ((<vmod> id)
         (push-code! `(load-module ,id)))
-       ((and ($ integer) ($ exact))
-        (let ((str (do ((n x (quotient n 256))
-                        (l '() (cons (modulo n 256) l)))
-                       ((= n 0)
-                        (apply u8vector l)))))
-          (push-code! `(load-integer ,str))))
-       (($ number)
-        (push-code! `(load-number ,(number->string x))))
-       (($ string)
-        (push-code! `(load-string ,x)))
-       (($ symbol)
-        (push-code! `(load-symbol ,(symbol->string x))))
-       (($ keyword)
-        (push-code! `(load-keyword
-                      ,(symbol->string (keyword-dash-symbol x)))))
-       (($ list)
-        (for-each dump! x)
-        (let ((len (length x)))
-          (if (>= len 65536) (too-long 'list))
-          (push-code! `(list ,(quotient len 256) ,(modulo len 256)))))
-       (($ pair)
-        (dump! (car x))
-        (dump! (cdr x))
-        (push-code! `(cons)))
-       (($ vector)
-        (for-each dump! (vector->list x))
-        (let ((len (vector-length x)))
-          (if (>= len 65536) (too-long 'vector))
-          (push-code! `(vector ,(quotient len 256) ,(modulo len 256)))))
-       (else
-        (error "assemble: unrecognized object" x)))))))
+        (else
+         (error "assemble: unknown record type" (record-type-descriptor x)))))
+     ((and (integer? x) (exact? x))
+      (let ((str (do ((n x (quotient n 256))
+                      (l '() (cons (modulo n 256) l)))
+                     ((= n 0)
+                      (apply u8vector l)))))
+        (push-code! `(load-integer ,str))))
+     ((number? x)
+      (push-code! `(load-number ,(number->string x))))
+     ((string? x)
+      (push-code! `(load-string ,x)))
+     ((symbol? x)
+      (push-code! `(load-symbol ,(symbol->string x))))
+     ((keyword? x)
+      (push-code! `(load-keyword ,(symbol->string (keyword->symbol x)))))
+     ((list? x)
+      (for-each dump! x)
+      (let ((len (length x)))
+        (if (>= len 65536) (too-long 'list))
+        (push-code! `(list ,(quotient len 256) ,(modulo len 256)))))
+     ((pair? x)
+      (dump! (car x))
+      (dump! (cdr x))
+      (push-code! `(cons)))
+     ((vector? x)
+      (for-each dump! (vector->list x))
+      (let ((len (vector-length x)))
+        (if (>= len 65536) (too-long 'vector))
+        (push-code! `(vector ,(quotient len 256) ,(modulo len 256)))))
+     (else
+      (error "assemble: unrecognized object" x)))))