Below is a DEFUN-JS macro for defining PS functions at the Lisp top-level.<div>It creates a Lisp stub with the same signature whose body simply throws</div><div>an error telling you that you tried to call a PS function from Lisp. Why is that</div>
<div>useful? Because now your PS functions are fully integrated with Slime.</div><div>You can jump around with M-., get arglist info in the minibuffer, and so on.</div><div><br></div><div>After a week of using this, I can't believe how much of a difference it makes.</div>
<div><br></div><div>In PS, DEFUN-JS translates trivially to DEFUN. Of course you still need a</div><div>way to collect the JS emitted by all these forms, but PS is agnostic on how</div><div>that should be done.</div><div>
<br></div><div>A side note: we also converted nearly all our ps macros to DEFMACRO+PS</div><div>forms at the toplevel. This has the neat property that you can now</div><div>look at expansions using the highly convenient Slime macroexpand. I doubt</div>
<div>that this is a perfect solution (no doubt you can trip yourself up on differences </div><div>between the CL and PS macro environments), but it's sure handier than calling </div><div>PS::PS-MACROEXPAND from the REPL.</div>
<div><div><div><br></div><div>Daniel</div><div><br></div><div>p.s. The following has been stripped of a couple of functions specific to</div><div>our project. I tested it a bit, but if I missed anything, let me know.</div>
<div><br></div><div><div><div><br></div><div><font class="Apple-style-span" face="'courier new', monospace">(defmacro defun-js (name lambda-list &body body)</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> (declare (ignore body))</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> (labels ((sym% (argspec) (if (symbolp argspec) argspec (car argspec))))</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> (multiple-value-bind (required optionals restp rest keyp keys allowp auxp aux morep more-context more-count beyond-requireds? key-object)</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> (ps::parse-lambda-list lambda-list)</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> (declare (ignore restp keyp allowp auxp aux morep more-context more-count beyond-requireds? key-object))</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> ;; get rid of init forms, which can't be evaluated in Lisp.</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> (setf optionals (mapcar #'sym% optionals) keys (mapcar #'sym% keys))</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> `(defun ,name (,@required ,@(when optionals `(&optional ,@optionals))</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> ,@(when rest `(&rest ,rest)) ,@(when keys `(&key ,@keys)))</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> (declare (ignore ,@required ,@optionals ,@(when rest (list rest)) ,@keys))</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> (error "The ~s function is js-only and cannot be called from Lisp." ',name)))))</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">(defpsmacro defun-js (name lambda-list &body body)</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> `(defun ,name ,lambda-list ,@body))</font></div></div></div></div></div>