Add `remhash' function
[jscl.git] / src / compiler / compiler.lisp
index 73223aa..60860b3 100644 (file)
 ;;; function call.
 (defvar *multiple-value-p* nil)
 
+;;; It is bound dinamically to the number of nested calls to
+;;; `convert'. Therefore, a form is being compiled as toplevel if it
+;;; is zero.
+(defvar *convert-level* -1)
+
+
 ;;; Environment
 
 (def!struct binding
                  (push (cons sexp jsvar) *literal-table*)
                  (toplevel-compilation `(var (,jsvar ,dumped)))
                  (when (keywordp sexp)
-                   (toplevel-compilation `(= ,(get jsvar "value") ,jsvar)))
+                   (toplevel-compilation `(= (get ,jsvar "value") ,jsvar)))
                  jsvar)))))))
 
 
       ,(convert-block body t))))
 
 
+;;; Was the compiler invoked from !compile-file?
 (defvar *compiling-file* nil)
-(define-compilation eval-when-compile (&rest body)
-  (if *compiling-file*
-      (progn
-        (eval (cons 'progn body))
-        (convert 0))
-      (convert `(progn ,@body))))
+
+;;; NOTE: It is probably wrong in many cases but we will not use this
+;;; heavily. Please, do not rely on wrong cases of this
+;;; implementation.
+(define-compilation eval-when (situations &rest body)
+  ;; TODO: Error checking
+  (cond
+    ;; Toplevel form compiled by !compile-file.
+    ((and *compiling-file* (zerop *convert-level*))
+     ;; If the situation `compile-toplevel' is given. The form is
+     ;; evaluated at compilation-time.
+     (when (find :compile-toplevel situations)
+       (eval (cons 'progn body)))
+     ;; `load-toplevel' is given, then just compile the subforms as usual.
+     (when (find :load-toplevel situations)
+       (convert-toplevel `(progn ,@body) *multiple-value-p*)))
+    ((find :execute situations)
+     (convert `(progn ,@body) *multiple-value-p*))
+    (t
+     (convert nil))))
 
 (defmacro define-transformation (name args form)
   `(define-compilation ,name ,args
         ,@(mapcar (lambda (key)
                     `(progn
                        (= obj (property obj (call |xstring| ,(convert key))))
-                       (if (=== object undefined)
+                       (if (=== obj undefined)
                            (throw "Impossible to set object property."))))
                   (butlast keys))
         (var (tmp
 (define-builtin in (key object)
   `(bool (in (call |xstring| ,key) ,object)))
 
+(define-builtin delete-property (key object)
+  `(selfcall
+    (delete (property ,object (call |xstring| ,key)))))
+
 (define-builtin map-for-in (function object)
   `(selfcall
     (var (f ,function)
     (when expandedp
       (return-from convert (convert sexp multiple-value-p)))
     ;; The expression has been macroexpanded. Now compile it!
-    (let ((*multiple-value-p* multiple-value-p))
+    (let ((*multiple-value-p* multiple-value-p)
+          (*convert-level* (1+ *convert-level*)))
       (cond
         ((symbolp sexp)
          (let ((b (lookup-in-lexenv sexp *environment* 'variable)))
     (subseq string 0 n)))
 
 (defun convert-toplevel (sexp &optional multiple-value-p)
-  (let ((*toplevel-compilations* nil))
+  ;; Macroexpand sexp as much as possible
+  (multiple-value-bind (sexp expandedp) (!macroexpand-1 sexp)
+    (when expandedp
+      (return-from convert-toplevel (convert-toplevel sexp multiple-value-p))))
+  ;; Process as toplevel
+  (let ((*convert-level* -1)
+        (*toplevel-compilations* nil))
     (cond
       ;; Non-empty toplevel progn
       ((and (consp sexp)