ParenscriptTipsAndTricks
This page is for snippets of code that are useful in writing ParenScript code. Please add your own!

Debugging with FireBug

The FireBug extension for FireFox has a nice console that you can write output to. This is much nicer than using "alert", since you can write as much debugging output as you want without annoying the user (or yourself). Here's a debug macro that outputs a message only if the *debug* variable is true:
(defvar *debug* t)

(defjsmacro debug (message)
  (if *debug*
      `(if window.console
           (console.log ,message))))
When you're ready to deploy your code, set *debug* to nil, and all the "console.log" calls will disappear from your JavaScript output.

Returning multiple values

These macros provide a way to return multiple values from a function. The "receive" macro is also useful in asynchronous programming, since it uses a callback that can delay execution arbitrarily.
(defjsmacro receive (args proc &rest body)
  `(,proc (lambda (,@args) ,@body)))

(defjsmacro values (&rest args)
  `(lambda (proc) (proc ,@args)))
Example:
(defun divmod (a b)
  (return (values (/ a b) (% a b))))

(receive (div mod) (divmod 10 3)  
         (debug (+ "div: " div ", mod: " mod)))
Result:
div: 3.3333333333333335, mod: 1

"After" macro

Lisp makes it easy to wrap code in macros that would otherwise requre passing functional arguments. Here's a macro that executes some code in the future:
(defjsmacro after (ival &rest body)
  `(set-timeout (lambda () ,@body) ,ival))
Example:
(after 2000
  (alert "two seconds have elapsed!"))

Real let-bindings

The "let" macro that comes with ParenScript doesn't introduce a new lexical scope like proper Lisp. However, there is the "lexical-let" macro which does.

Binding Elements by IDs

You can use the above technique to implement other binding macros, such as the following, which looks DOM elements up by their IDs:
(defjsmacro with-elements-by-ids (binds &body body)
  `((lambda ,(mapcar #'(lambda (x)
                         (if (consp x) (car x) x))
                     binds)
      ,@body)
    ,@(mapcar #'(lambda (x) `(document.get-element-by-id
                              ,(if (consp x)
                                   (cadr x)
                                 (string-downcase (symbol-name x)))))
              binds)))
Example:
(with-elements-by-ids (mydiv (other "otherdiv"))
  (setf mydiv.inner-h-t-m-l other.inner-h-t-m-l))
Result:
(function (mydiv, other) {
   mydiv.innerHTML = other.innerHTML;
 })
(document.getElementById('mydiv'), document.getElementById('otherdiv'));


ParenScript