named-lambda is a function descriptor rather than a macro
authorDavid Vázquez <davazp@gmail.com>
Wed, 1 May 2013 03:31:42 +0000 (04:31 +0100)
committerDavid Vázquez <davazp@gmail.com>
Wed, 1 May 2013 03:31:42 +0000 (04:31 +0100)
It makes easier to deal with declarations and docstrings

src/boot.lisp
src/compiler.lisp

index 8af0c2b..11a29b4 100644 (file)
      ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring)))
      ',name))
 
-(defmacro named-lambda (name args &rest body)
-  (let ((x (gensym "FN")))
-    `(let ((,x (lambda ,args ,@body)))
-       (oset ,x "fname" ,name)
-       ,x)))
-
 (defmacro defun (name args &rest body)
   `(progn
-     
-     (fset ',name
-           (named-lambda ,(symbol-name name) ,args
-             ,@(if (and (stringp (car body)) (not (null (cdr body))))
-                   `(,(car body) (block ,name ,@(cdr body)))
-                   `((block ,name ,@body)))))
+     (fset ',name #'(named-lambda ,name ,args ,@body))
      ',name))
 
 (defun null (x)
index 94f5c7a..bf9b8ec 100644 (file)
           (ll-optional-arguments-canonical lambda-list))))
     (remove nil (mapcar #'third args))))
 
-(defun lambda-docstring-wrapper (docstring &rest strs)
-  (if docstring
+(defun lambda-name/docstring-wrapper (name docstring &rest strs)
+  (if (or name docstring)
       (js!selfcall
         "var func = " (join strs) ";" *newline*
-        "func.docstring = '" docstring "';" *newline*
+        (when name
+          (code "func.fname = '" (escape-string name) "';" *newline*))
+        (when docstring
+          (code "func.docstring = '" (escape-string docstring) "';" *newline*))
         "return func;" *newline*)
       (apply #'code strs)))
 
                       "throw 'Unknown keyword argument ' + arguments[i].name;" *newline*))
              "}" *newline*)))))
 
-(defun compile-lambda (ll body)
+;;; Compile a lambda function with lambda list LL and body BODY. If
+;;; NAME is given, it should be a constant string and it will become
+;;; the name of the function. If BLOCK is non-NIL, a named block is
+;;; created around the body. NOTE: No block (even anonymous) is
+;;; created if BLOCk is NIL.
+(defun compile-lambda (ll body &key name block)
   (let ((required-arguments (ll-required-arguments ll))
         (optional-arguments (ll-optional-arguments ll))
        (keyword-arguments  (ll-keyword-arguments  ll))
                                   optional-arguments
                                  keyword-arguments
                                   (ll-svars ll)))))
-      (lambda-docstring-wrapper
-       documentation
+      (lambda-name/docstring-wrapper name documentation
        "(function ("
        (join (cons "values"
                    (mapcar #'translate-variable
        (compile-lambda-rest ll)
        (compile-lambda-parse-keywords ll)
         (let ((*multiple-value-p* t))
-         (ls-compile-block body t)))
+          (if block
+              (ls-compile-block `((block ,block ,@body)) t)
+              (ls-compile-block body t))))
        "})"))))
 
 
   (cond
     ((and (listp x) (eq (car x) 'lambda))
      (compile-lambda (cadr x) (cddr x)))
+    ((and (listp x) (eq (car x) 'named-lambda))
+     ;; TODO: destructuring-bind now! Do error checking manually is
+     ;; very annoying.
+     (let ((name (cadr x))
+           (ll (caddr x))
+           (body (cdddr x)))
+       (compile-lambda ll body
+                       :name (symbol-name name)
+                       :block name)))
     ((symbolp x)
      (let ((b (lookup-in-lexenv x *environment* 'function)))
        (if b