Macro precompilation
authorDavid Vázquez <davazp@gmail.com>
Fri, 3 May 2013 15:56:20 +0000 (16:56 +0100)
committerDavid Vázquez <davazp@gmail.com>
Fri, 3 May 2013 15:56:20 +0000 (16:56 +0100)
jscl.lisp
src/compiler.lisp

index 7a31191..78850dc 100644 (file)
--- a/jscl.lisp
+++ b/jscl.lisp
          when (plusp (length compilation))
          do (write-string compilation out)))))
 
+
 (defun dump-global-environment (stream)
   (flet ((late-compile (form)
            (write-string (ls-compile-toplevel form) stream)))
-    ;; Set the initial global environment to be equal to the host global
-    ;; environment at this point of the compilation.
+    ;; We assume that environments have a friendly list representation
+    ;; for the compiler and it can be dumped.
+    (dolist (b (lexenv-function *environment*))
+      (when (eq (binding-type b) 'macro)
+        (push *magic-unquote-marker* (binding-value b))))
     (late-compile `(setq *environment* ',*environment*))
     ;; Set some counter variable properly, so user compiled code will
     ;; not collide with the compiler itself.
@@ -84,6 +88,7 @@
         (setq *gensym-counter* ,*gensym-counter*)))
     (late-compile `(setq *literal-counter* ,*literal-counter*))))
 
+
 (defun bootstrap ()
   (setq *environment* (make-lexenv))
   (setq *literal-table* nil)
index e02f253..e109404 100644 (file)
     (code "(" result ")")))
 
 
-;;; Literals
+;;; Compilation of literals an object dumping
+
 (defun escape-string (string)
   (let ((output "")
         (index 0)
       (incf index))
     output))
 
-
 (defvar *literal-table* nil)
 (defvar *literal-counter* 0)
 
+;;; BOOTSTRAP MAGIC: During bootstrap, we record the macro definitions
+;;; as lists. Once everything is compiled, we want to dump the whole
+;;; global environment to the output file to reproduce it in the
+;;; run-time. However, the environment must contain expander functions
+;;; rather than lists. We do not know how to dump function objects
+;;; itself, so we mark the definitions with this object and the
+;;; compiler will be called when this object has to be dumped.
+;;; Backquote/unquote does a similar magic, but this use is exclusive.
+(defvar *magic-unquote-marker* (gensym "MAGIC-UNQUOTE"))
+
 (defun genlit ()
   (code "l" (incf *literal-counter*)))
 
      (or (cdr (assoc sexp *literal-table*))
          (let ((dumped (typecase sexp
                          (symbol (dump-symbol sexp))
-                         (cons (dump-cons sexp))
+                         (cons
+                          (if (eq (car sexp) *magic-unquote-marker*)
+                              (ls-compile (cdr sexp))
+                              (dump-cons sexp)))
                          (array (dump-array sexp)))))
            (if (and recursive (not (symbolp sexp)))
                dumped
                  (toplevel-compilation (code "var " jsvar " = " dumped))
                  jsvar)))))))
 
+
 (define-compilation quote (sexp)
   (literal sexp))