netzstaub

beatz & funkz

Monday, March 14, 2005

ParenScript

I actually have a lot of real work to do, so I had to quit my “opensource-programming” procrastination as fast as possible. That’s why I rushed the release of my Lisp to Javascript “compiler” ParenScript. Compiler is actually a very big word, as ParenScript doesn’t do much more than correctly indent a Lisp expression representing Javascript code (it does a few optimization on the way, though). I had at first written a very hackish implementation of the compiler, with an undefinite intermediary representation somehow consisting of strings and lists of strings. After I got the mess working, I decided to rewrite the compiler in a clean way. ParenScript in the version 0.1.0 actually is a lot cleaner, a few people may even understand its inner workings, but there still is a lot to do. It has been given next to none testing in a real setup. The indentation is a bit weird sometimes, and could be given a lift up. The error handling is very minimal.

However, as rushed as I was to release ParenScript, I put the whole day into its manual, and I think it has turned out to be quite nice. Here is the ParenScript webpage, the software, the manual and the language reference. ParenScript it also installable using ASDF-INSTALL, just type

(asdf-install:install 'parenscript)

and it should install fine.

To give you a little idea of what ParenScript does, here is a ParenScript program and the generated JavaScript:

(defun apply-effect () 
   (when (and document.all photoslider.filters) 
      (let ((trans photoslider.filters.reveal-trans)) 
          (setf (slot-value trans ’*Transition) 
                (floor (* (random) 23))) 
          (trans.stop) 
          (trans.apply))))

The generated JavaScript code looks like this:

function applyEffect() { 
   if (document.all && photoslider.filters) { 
      var trans = photoslider.filters.revealTrans; 
      trans.Transition = Math.floor(Math.random() * 23); 
      trans.stop(); 
      trans.apply(); 
   } 
} 

From the feature list:

  • Supports all the expressions and statements of EcmaScript 262
  • Converts Lisp symbols to java-style camelcase (taken from linj)
  • Lisp-style iteration with DO, DOTIMES, DOEACH, DOLIST
  • Complete macro environment with MACROLET, SYMBOL-MACROLET
  • Uses the Lisp reader for reader macros
  • ParenScript HTML generator for embedding HTML in JavaScript code (not more ugly document.writes)
  • Allows for recursive compilation of ParenScript (generate Javascript in Javascript in Javascript…)
  • Lispy CSS syntax

UPDATE: I’ve blogged about the javascript compiler before. In english here: javascript experiences, and in german here: lisp to CSS, javascript, so eine geile sprache, javascript expressions , javascript compiler and lisp to javascript.

posted by manuel at 9:32 pm  

17 Comments »

  1. Insanely cool!

    Comment by Anonymous — March 15, 2005 @ 6:53 pm

  2. What is the license for ParenScript?

    Comment by Anonymous — March 17, 2005 @ 12:44 am

  3. It’s BSD. I am a tad busy right now, but I will make a new release next week, with an updated manual, a LICENSE file, and a lot more examples 🙂

    Comment by manuel — March 17, 2005 @ 6:42 am

  4. I found a bug in the dotimes expansion. It increments the counter by two, because

    (dotimes (i a)
    …)

    expands to

    for (var i = 0; i != args.length; i = i++) {

    }

    This has the unfortunate efect that if the list has even elements this will loop forever.

    The fix is rather trivial, though it generates i = i + 1, rather than i++ :

    — js.lisp~ 2005-03-14 23:44:19.000000000 +0200
    +++ js.lisp 2005-05-04 18:30:45.166825686 +0300
    @@ -942,7 +942,7 @@
    (defjsmacro dotimes (iter &rest body)
    (let ((var (first iter))
    (times (second iter)))
    – `(do ((,var 0 (++ ,var)))
    + `(do ((,var 0 (1+ ,var)))
    ((= ,var ,times))
    ,@body)))

    Comment by Ivan Toshkov — May 4, 2005 @ 4:54 pm

  5. Actually, the problem is that `i = i++’ leaves `i’ unchanged.

    I’ve put this bug report and the patch at http://www.cliki.net/parenscript

    Comment by Ivan Toshkov — May 6, 2005 @ 9:08 pm

  6. i found i like the style of your blog, and i also have used html tools or JavaScript tools at http://www.yaodownload.com/web-authoring/ , such as HTML to AnyCode Converter , it can translate some HTML code to JavaScript, ASP or other scripts.

    Comment by mike — April 14, 2006 @ 4:30 am

  7. Maybe I’m crazy, but mike’s comment reads as “clever” spam.

    ?

    Comment by Hexstream — May 12, 2007 @ 4:41 am

  8. Yeah you’re right, slipped pas the spam recognition. 🙂

    Comment by manuel — May 12, 2007 @ 10:54 am

  9. Nice blog !

    Comment by Acnezine — August 31, 2007 @ 9:00 am

  10. Good post. You make some great points that most people do not fully understand.

    “ParenScript in the version 0.1.0 actually is a lot cleaner, a few people may even understand its inner workings, but there still is a lot to do. It has been given next to none testing in a real setup. The indentation is a bit weird sometimes, and could be given a lift up. The error handling is very minimal.”

    I like how you explained that. Very helpful. Thanks.

    Comment by chiz — February 18, 2008 @ 3:55 pm

  11. This is an interesting hack. Since you posted this, the project has been scrapped and replaced with another project called “Parenthetix”, which departs radically from the original design. Parenthetix is much more Java-like (or, should I say, much more Pascal-like). It has semi-colons and a complicated grammar. Imperative programming style is much more pervasive in Parenthetix than it was in ParenScript. ParenScript can at least be adapted for functional programming, even though it doesn’t do it out of the box.

    I don’t care for Parenthetix because it takes away the promise that ParenScript had: To make JavaScript more like Lisp.

    With a few macros on the Lisp side, and a few support functions, you can eliminate many of the situations where ParenScript forces you into imperative programming. For example, the following creates a ParenScript macro that allows you to define functions that behave like Lisp functions (that is, they evaluate to a certain value, without an explicit “return” statement… the -f suffix stands for “functional”):

    (defmacro+ps defun-f (name lambda-list &rest body)
    `(defun ,name ,lambda-list
    ,@(reform-body body)))

    ;; The macro requires this function:

    (defun reform-body (body)
    (if (= (length body) 1)
    `(,(append `(return ,(car body))))
    (append (all-but-last body)
    `(,(append ‘(return) (last body))))))

    ;; There’s also a lambda-f, let-f, and progn-f, but I’ll leave them out for brevity.

    ;; You can also have a genuine Lisp “cond” (expands into
    ;; a hornet’s nest of if’s, but you get the right semantics):
    (defun cond-expand (conditions)
    (if conditions
    (if (equalp (caar conditions) t)
    (cadar conditions)
    `(if ,(caar conditions)
    ,(cadar conditions)
    ,(cond-expand (cdr conditions))))))

    (js:defjsmacro cond (&rest conditions)
    (cond-expand conditions))

    ;; JavaScript has a “random”, and ParenScript uses it,
    ;; but it has different semantics from the CL function
    ;; with the same name. This macro fixes that (the
    ;; random-state argument is ignored):
    (js:defjsmacro random (num &optional random-state)
    `(*math.floor (* (*math.random) ,num)))

    I’ve spent some time trying to get a small CL program I wrote while learning Lisp to compile into runnable JavaScript with ParenScript. Certain CL functions can be implemented in ParenScript itself, such as car, cdr, find-if, nth, nthcdr,
    and assoc.

    The nth, car, and cdr functions have special semantics when it comes to NIL (namely, (= (nth n nil) nil)
    evaluates to true, whereas (= (aref nil n) nil) is an error), and therefore, the AREF function is not equivalent to them.

    I’ve written a half-assed version of equalp. At least I _think_ it works.

    Comment by Voice of Reason — March 21, 2008 @ 8:40 am

  12. Forgot to include the definnition of ALL-BUT-LAST:

    (defun all-but-last (a-list)
    (if (cdr a-list)
    (cons (car a-list) (all-but-last (cdr a-list)))
    nil))

    Comment by Voice of Reason — March 21, 2008 @ 9:49 am

  13. Good post. You make some great points that most people do not fully understand.

    “I actually have a lot of real work to do, so I had to quit my “opensource-programming” procrastination as fast as possible. That’s why I rushed the release of my Lisp to Javascript “compiler” ParenScript. Compiler is actually a very big word, as ParenScript doesn’t do much more than correctly indent a Lisp expression representing Javascript code (it does a few optimization on the way, though). I had at first written a very hackish implementation of the compiler, with an undefinite intermediary representation somehow consisting of strings and lists of strings. After I got the mess working, I decided to rewrite the compiler in a clean way. ParenScript in the version 0.1.0 actually is a lot cleaner, a few people may even understand its inner workings, but there still is a lot to do. It has been given next to none testing in a real setup. The indentation is a bit weird sometimes, and could be given a lift up. The error handling is very minimal.”

    I like how you explained that. Very helpful. Thanks.

    Comment by Evaine — April 24, 2008 @ 5:33 pm

  14. […] Unfortunately, this isn’t the first time I’ve had this problem. Enter Six Apart. When signed up and tested, I couldn’t leave comments on my own brand new TypePad blog (tdavid.typepad.com). This was around Christmas time two years ago and it took a week or so to find out that the reason my comments were being blocked was because makeyougohmm.com was listed on an old spam service. […]

    Comment by battery — June 24, 2008 @ 2:35 pm

  15. e focus on bring the best acer btp-550 battery sales to our customers and strong desire our customers can buy their satisfaction acer btp-550 laptop battery. We are committed to providing customers with high-quality, high-capacity and low price btp-550 laptop batteries.

    Comment by laptop batteries — September 10, 2008 @ 6:41 am

  16. http://www.batteryfast.com/dell/w6617.htm dell w6617 battery,

    Comment by baterry — November 18, 2008 @ 3:36 pm

  17. Excellent Post, thanx for sharing the same.. Will keep on reading the post 😀

    Stumbled your post .. cheers

    Comment by Saniya — January 2, 2009 @ 1:53 pm

RSS feed for comments on this post.

Leave a comment

Powered by WordPress