Removed compile-time constant string concatenation from the Parenscript printer,...
[clinton/parenscript.git] / docs / reference.lisp
index 4c71e17..8ead719 100644 (file)
@@ -1,10 +1,15 @@
-;;;# ParenScript Language Reference
+;;;# Parenscript Language Reference
 
-;;; This chapters describes the core constructs of ParenScript, as
+;;; Create a useful package for the code here...
+(in-package #:cl-user)
+(defpackage #:ps-ref (:use #:ps))
+(in-package #:ps-ref)
+
+;;; This chapters describes the core constructs of Parenscript, as
 ;;; well as its compilation model. This chapter is aimed to be a
-;;; comprehensive reference for ParenScript developers. Programmers
-;;; looking for how to tweak the ParenScript compiler itself should
-;;; turn to the ParenScript Internals chapter.
+;;; comprehensive reference for Parenscript developers. Programmers
+;;; looking for how to tweak the Parenscript compiler itself should
+;;; turn to the Parenscript Internals chapter.
 
 ;;;# Statements and Expressions
 ;;;t \index{statement}
@@ -14,9 +19,9 @@
 ;;; makes the difference between an expression, which evaluates to a
 ;;; value, and a statement, which has no value. Examples for
 ;;; JavaScript statements are `for', `with' and `while'. Most
-;;; ParenScript forms are expression, but certain special forms are
+;;; Parenscript forms are expression, but certain special forms are
 ;;; not (the forms which are transformed to a JavaScript
-;;; statement). All ParenScript expressions are statements
+;;; statement). All Parenscript expressions are statements
 ;;; though. Certain forms, like `IF' and `PROGN', generate different
 ;;; JavaScript constructs whether they are used in an expression
 ;;; context or a statement context. For example:
 (+ i (if 1 2 3)) => i + (1 ? 2 : 3)
 
 (if 1 2 3)
-   => if (1) {
-        2;
-      } else {
-        3;
-      }
+=> if (1) {
+       2;
+   } else {
+       3;
+   }
 
 ;;;# Symbol conversion
 ;;;t \index{symbol}
@@ -55,7 +60,7 @@ bla-foo-bar => blaFooBar
 *array => Array
 
 ;;; The `.' character is left as is in symbols. This allows the
-;;; ParenScript programmer to use a practical shortcut when accessing
+;;; Parenscript programmer to use a practical shortcut when accessing
 ;;; slots or methods of JavaScript objects. Instead of writing
 
 (slot-value foobar 'slot)
@@ -76,19 +81,20 @@ foobar.slot
 ;;;t \index{keyword}
 ;;;t \index{reserved keywords}
 
-;;; The following keywords and symbols are reserved in ParenScript,
+;;; The following keywords and symbols are reserved in Parenscript,
 ;;; and should not be used as variable names.
 
-! ~ ++ -- * / % + - << >> >>> < > <= >= == != ==== !== & ^ | && ||
-*= /= %= += -= <<= >>= >>>= &= ^= |= 1- 1+
-ABSTRACT AND AREF ARRAY BOOLEAN BREAK BYTE CASE CATCH CC-IF CHAR CLASS
-COMMA CONST CONTINUE CREATE DEBUGGER DECF DEFAULT DEFUN DEFVAR DELETE
-DO DOEACH DOLIST DOTIMES DOUBLE ELSE ENUM EQL EXPORT EXTENDS FALSE
-FINAL FINALLY FLOAT FLOOR FOR FUNCTION GOTO IF IMPLEMENTS IMPORT IN INCF
-INSTANCEOF INT INTERFACE JS LAMBDA LET LISP LIST LONG MAKE-ARRAY NATIVE NEW
-NIL NOT OR PACKAGE PRIVATE PROGN PROTECTED PUBLIC RANDOM REGEX RETURN
-SETF SHORT SLOT-VALUE STATIC SUPER SWITCH SYMBOL-MACROLET SYNCHRONIZED T
-THIS THROW THROWS TRANSIENT TRY TYPEOF UNDEFINED UNLESS VAR VOID VOLATILE
+! ~ ++ -- * / % + - << >> >>> < > <= >= == != ==== !== & ^ | && || *=
+/= %= += -= <<= >>= >>>= &= ^= |= 1- 1+ ABSTRACT AND AREF ARRAY
+BOOLEAN BREAK BYTE CASE CATCH CC-IF CHAR CLASS COMMA CONST CONTINUE
+CREATE DEBUGGER DECF DEFAULT DEFUN DEFVAR DELETE DO DO* DOEACH DOLIST
+DOTIMES DOUBLE ELSE ENUM EQL EXPORT EXTENDS F FALSE FINAL FINALLY
+FLOAT FLOOR FOR FOR-IN FUNCTION GOTO IF IMPLEMENTS IMPORT IN INCF
+INSTANCEOF INT INTERFACE JS LABELED-FOR LAMBDA LET LET* LEXICAL-LET
+LEXICAL-LET* LISP LIST LONG MAKE-ARRAY NATIVE NEW NIL NOT OR PACKAGE
+PRIVATE PROGN PROTECTED PUBLIC RANDOM REGEX RETURN SETF SHORT
+SLOT-VALUE STATIC SUPER SWITCH SYMBOL-MACROLET SYNCHRONIZED T THIS
+THROW THROWS TRANSIENT TRY TYPEOF UNDEFINED UNLESS VAR VOID VOLATILE
 WHEN WHILE WITH WITH-SLOTS
 
 ;;;# Literal values
@@ -101,7 +107,7 @@ WHEN WHILE WITH WITH-SLOTS
 ; number ::= a Lisp number
 
 ;;;
-;;; ParenScript supports the standard JavaScript literal
+;;; Parenscript supports the standard JavaScript literal
 ;;; values. Numbers are compiled into JavaScript numbers.
 
 1       => 1
@@ -124,9 +130,10 @@ WHEN WHILE WITH WITH-SLOTS
 
 "bratzel bub" => 'bratzel bub'
 
-;;; Escapes in Lisp are not converted to JavaScript escapes. However,
-;;; to avoid having to use double backslashes when constructing a
-;;; string, you can use the CL-INTERPOL library by Edi Weitz.
+;;; Special characters such as newline and backspace are converted
+;;; into their corresponding JavaScript escape sequences.
+
+"      "   => '\\t'
 
 ;;;## Array literals
 ;;;t \index{array}
@@ -139,9 +146,9 @@ WHEN WHILE WITH WITH-SLOTS
 ; (MAKE-ARRAY {values}*)
 ; (AREF array index)
 ; 
-; values ::= a ParenScript expression
-; array  ::= a ParenScript expression
-; index  ::= a ParenScript expression
+; values ::= a Parenscript expression
+; array  ::= a Parenscript expression
+; index  ::= a Parenscript expression
 
 ;;; Array literals can be created using the `ARRAY' form.
 
@@ -151,7 +158,7 @@ WHEN WHILE WITH WITH-SLOTS
 
 (array (array 2 3)
        (array "foobar" "bratzel bub"))
-   => [ [ 2, 3 ], [ 'foobar', 'bratzel bub' ] ]
+=> [ [ 2, 3 ], [ 'foobar', 'bratzel bub' ] ]
 
 ;;; Arrays can also be created with a call to the `Array' function
 ;;; using the `MAKE-ARRAY'. The two forms have the exact same semantic
@@ -164,9 +171,9 @@ WHEN WHILE WITH WITH-SLOTS
 (make-array
  (make-array 2 3)
  (make-array "foobar" "bratzel bub"))
-  => new Array(new Array(2, 3), new Array('foobar', 'bratzel bub'))
+=> new Array(new Array(2, 3), new Array('foobar', 'bratzel bub'))
 
-;;; Indexing arrays in ParenScript is done using the form `AREF'. Note
+;;; Indexing arrays in Parenscript is done using the form `AREF'. Note
 ;;; that JavaScript knows of no such thing as an array. Subscripting
 ;;; an array is in fact reading a property from an object. So in a
 ;;; semantic sense, there is no real difference between `AREF' and
@@ -185,11 +192,11 @@ WHEN WHILE WITH WITH-SLOTS
 ; (SLOT-VALUE object slot-name)
 ; (WITH-SLOTS ({slot-name}*) object body)
 ;
-; name      ::= a ParenScript symbol or a Lisp keyword
-; value     ::= a ParenScript expression
-; object    ::= a ParenScript object expression
+; name      ::= a Parenscript symbol or a Lisp keyword
+; value     ::= a Parenscript expression
+; object    ::= a Parenscript object expression
 ; slot-name ::= a quoted Lisp symbol
-; body      ::= a list of ParenScript statements
+; body      ::= a list of Parenscript statements
 
 ;;;
 ;;; Object literals can be create using the `CREATE' form. Arguments
@@ -197,15 +204,14 @@ WHEN WHILE WITH WITH-SLOTS
 ;;; more "lispy", the property names can be keywords.
 
 (create :foo "bar" :blorg 1)
-   => { foo : 'bar',
-        blorg : 1 }
+=> { foo : 'bar', blorg : 1 }
 
 (create :foo "hihi"
         :blorg (array 1 2 3)
         :another-object (create :schtrunz 1))
-   => { foo : 'hihi',
-        blorg : [ 1, 2, 3 ],
-        anotherObject : { schtrunz : 1 } }
+=> { foo : 'hihi',
+     blorg : [ 1, 2, 3 ],
+     anotherObject : { schtrunz : 1 } }
 
 ;;; Object properties can be accessed using the `SLOT-VALUE' form,
 ;;; which takes an object and a slot-name.
@@ -222,7 +228,7 @@ an-object.foo => anObject.foo
 
 (with-slots (a b c) this
   (+ a b c))
-    => (this).a + (this).b + (this).c;
+=> this.a + this.b + this.c;
 
 ;;;## Regular Expression literals
 ;;;t \index{REGEX}
@@ -250,6 +256,7 @@ an-object.foo => anObject.foo
 
 ;;;## Literal symbols
 ;;;t \index{T}
+;;;t \index{F}
 ;;;t \index{FALSE}
 ;;;t \index{NIL}
 ;;;t \index{UNDEFINED}
@@ -258,15 +265,17 @@ an-object.foo => anObject.foo
 ;;;t \index{null}
 ;;;t \index{true}
 
-; T, FALSE, NIL, UNDEFINED, THIS
+; T, F, FALSE, NIL, UNDEFINED, THIS
 
-;;; The Lisp symbols `T' and `FALSE' are converted to their JavaScript
-;;; boolean equivalents `true' and `false'.
+;;; The Lisp symbols `T' and `FALSE' (or `F') are converted to their
+;;; JavaScript boolean equivalents `true' and `false'.
 
 T     => true
 
 FALSE => false
 
+F => false
+
 ;;; The Lisp symbol `NIL' is converted to the JavaScript keyword
 ;;; `null'.
 
@@ -291,7 +300,7 @@ THIS => this
 ;;; All the other literal Lisp values that are not recognized as
 ;;; special forms or symbol macros are converted to JavaScript
 ;;; variables. This extreme freedom is actually quite useful, as it
-;;; allows the ParenScript programmer to be flexible, as flexible as
+;;; allows the Parenscript programmer to be flexible, as flexible as
 ;;; JavaScript itself.
 
 variable    => variable
@@ -311,10 +320,10 @@ a-variable  => aVariable
 ; (function {argument}*)
 ; (method   object {argument}*)
 ;
-; function ::= a ParenScript expression or a Lisp symbol
+; function ::= a Parenscript expression or a Lisp symbol
 ; method   ::= a Lisp symbol beginning with .
-; object   ::= a ParenScript expression
-; argument ::= a ParenScript expression
+; object   ::= a Parenscript expression
+; argument ::= a Parenscript expression
 
 ;;; Any list passed to the JavaScript that is not recognized as a
 ;;; macro or a special form (see "Macro Expansion" below) is
@@ -325,24 +334,23 @@ a-variable  => aVariable
 (blorg 1 2) => blorg(1, 2)
 
 (foobar (blorg 1 2) (blabla 3 4) (array 2 3 4))
-   => foobar(blorg(1, 2), blabla(3, 4), [ 2, 3, 4 ])
+=> foobar(blorg(1, 2), blabla(3, 4), [ 2, 3, 4 ])
+
+((slot-value this 'blorg) 1 2) => this.blorg(1, 2)
 
 ((aref foo i) 1 2) => foo[i](1, 2)
 
-;;; A method call is a function call where the function name is a
-;;; symbol and begins with a "." . In a method call, the name of the
-;;; function is append to its first argument, thus reflecting the
-;;; method call syntax of JavaScript. Please note that most method
-;;; calls can be abbreviated using the "." trick in symbol names (see
-;;; "Symbol Conversion" above).
+((slot-value (aref foobar 1) 'blorg) NIL T) => foobar[1].blorg(null, true)
 
-(.blorg this 1 2) => this.blorg(1, 2)
+;;; Note that while most method calls can be abbreviated using the "."
+;;; trick in symbol names (see "Symbol Conversion" above), this is not
+;;; advised due to the fact that "object.function" is treated as a
+;;; symbol distinct from both "object" and "function," which will
+;;; cause problems if Parenscript package prefixes or package
+;;; obfuscation is used.
 
 (this.blorg 1 2) => this.blorg(1, 2)
 
-(.blorg (aref foobar 1) NIL T)
-   => foobar[1].blorg(null, true)
-
 ;;;# Operator Expressions
 ;;;t \index{operator}
 ;;;t \index{operator expression}
@@ -358,14 +366,14 @@ a-variable  => aVariable
 ; operator ::= one of *, /, %, +, -, <<, >>, >>>, < >, EQL,
 ;              ==, !=, =, ===, !==, &, ^, |, &&, AND, ||, OR.
 ; single-operator ::= one of INCF, DECF, ++, --, NOT, !
-; argument ::= a ParenScript expression
+; argument ::= a Parenscript expression
 
 ;;; Operator forms are similar to function call forms, but have an
 ;;; operator as function name.
 ;;;
 ;;; Please note that `=' is converted to `==' in JavaScript. The `='
-;;; ParenScript operator is not the assignment operator. Unlike
-;;; JavaScript, ParenScript supports multiple arguments to the
+;;; Parenscript operator is not the assignment operator. Unlike
+;;; JavaScript, Parenscript supports multiple arguments to the
 ;;; operators.
 
 (* 1 2)   => 1 * 2
@@ -374,25 +382,20 @@ a-variable  => aVariable
 
 (eql 1 2) => 1 == 2
 
-;;; Note that the resulting expression is correctly parenthized,
+;;; Note that the resulting expression is correctly parenthesized,
 ;;; according to the JavaScript operator precedence that can be found
 ;;; in table form at:
 
-    http://www.codehouse.com/javascript/precedence/
+;;;    http://www.codehouse.com/javascript/precedence/
 
 (* 1 (+ 2 3 4) 4 (/ 6 7))
-  => 1 * (2 + 3 + 4) * 4 * (6 / 7)
+=> 1 * (2 + 3 + 4) * 4 * (6 / 7)
 
-;;; The pre/post increment and decrement operators are also
+;;; The pre increment and decrement operators are also
 ;;; available. `INCF' and `DECF' are the pre-incrementing and
-;;; pre-decrementing operators, and `++' and `--' are the
-;;; post-decrementing version of the operators. These operators can
+;;; pre-decrementing operators. These operators can
 ;;; take only one argument.
 
-(++ i)   => i++
-
-(-- i)   => i--
-
 (incf i) => ++i
 
 (decf i) => --i
@@ -420,8 +423,8 @@ a-variable  => aVariable
 ; (PROGN {statement}*) in statement context
 ; (PROGN {expression}*) in expression context
 ;
-; statement  ::= a ParenScript statement
-; expression ::= a ParenScript expression
+; statement  ::= a Parenscript statement
+; expression ::= a Parenscript expression
 
 ;;; The `PROGN' special form defines a sequence of statements when
 ;;; used in a statement context, or sequence of expression when used
@@ -432,13 +435,13 @@ a-variable  => aVariable
 ;;; For example, in a statement context:
 
 (progn (blorg i) (blafoo i))
-   => blorg(i);
-      blafoo(i);
+=> blorg(i);
+   blafoo(i);
 
 ;;; In an expression context:
 
 (+ i (progn (blorg i) (blafoo i)))
-   => i + (blorg(i), blafoo(i))
+=> i + (blorg(i), blafoo(i))
 
 ;;; A `PROGN' form doesn't lead to additional indentation or
 ;;; additional braces around it's body.
@@ -457,7 +460,7 @@ a-variable  => aVariable
 ;
 ; name     ::= a Lisp Symbol
 ; argument ::= a Lisp symbol
-; body     ::= a list of ParenScript statements
+; body     ::= a list of Parenscript statements
 
 ;;; As in Lisp, functions are defined using the `DEFUN' form, which
 ;;; takes a name, a list of arguments, and a function body. An
@@ -465,49 +468,122 @@ a-variable  => aVariable
 
 (defun a-function (a b)
   (return (+ a b)))
-  => function aFunction(a, b) {
+=> function aFunction(a, b) {
        return a + b;
-     }
+   }
 
 ;;; Anonymous functions can be created using the `LAMBDA' form, which
 ;;; is the same as `DEFUN', but without function name. In fact,
 ;;; `LAMBDA' creates a `DEFUN' with an empty function name.
 
 (lambda (a b) (return (+ a b)))
-  => function (a, b) {
+=> function (a, b) {
        return a + b;
-     }
+   }
 
 ;;;# Assignment
 ;;;t \index{assignment}
 ;;;t \index{SETF}
+;;;t \index{PSETF}
+;;;t \index{SETQ}
+;;;t \index{PSETQ}
+;;;t \index{DEFSETF}
 ;;;t \index{assignment operator}
 
 ; (SETF {lhs rhs}*)
+; (PSETF {lhs rhs}*)
+;
+; lhs ::= a Parenscript left hand side expression
+; rhs ::= a Parenscript expression
+
+; (SETQ {lhs rhs}*)
+; (PSETQ {lhs rhs}*)
 ;
-; lhs ::= a ParenScript left hand side expression
-; rhs ::= a ParenScript expression
+; lhs ::= a Parenscript symbol
+; rhs ::= a Parenscript expression
 
-;;; Assignment is done using the `SETF' form, which is transformed
-;;; into a series of assignments using the JavaScript `=' operator.
+;;; Assignment is done using the `SETF', `PSETF', `SETQ', and `PSETQ'
+;;; forms, which are transformed into a series of assignments using
+;;; the JavaScript `=' operator.
 
-(setf a 1) => a = 1
+(setf a 1) => a = 1;
 
 (setf a 2 b 3 c 4 x (+ a b c))
-   => a = 2;
-      b = 3;
-      c = 4;
-      x = a + b + c;
+=> a = 2;
+   b = 3;
+   c = 4;
+   x = a + b + c;
 
 ;;; The `SETF' form can transform assignments of a variable with an
 ;;; operator expression using this variable into a more "efficient"
 ;;; assignment operator form. For example:
 
-(setf a (1+ a))          => a++
+(setf a (+ a 2 3 4 a))   => a += 2 + 3 + 4 + a;
+
+(setf a (- 1 a))         => a = 1 - a;
+
+;;; The `PSETF' and `PSETQ' forms perform parallel assignment of
+;;; places or variables using a number of temporary variables created
+;;; by `PS-GENSYM'.  For example:
+
+(let* ((a 1) (b 2))
+  (psetf a b b a))
+=> var a = 1;
+   var b = 2;
+   var _js1 = b;
+   var _js2 = a;
+   a = _js1;
+   b = _js2;
+
+;;; The `SETQ' and `PSETQ' forms operate identically to `SETF' and
+;;; `PSETF', but throw a compile-time error if the left-hand side form
+;;; is not a symbol.   For example:
+
+(setq a 1)   => a = 1;
+
+;; but...
+
+(setq (aref a 0) 1)
+;; => ERROR: The value (AREF A 0) is not of type SYMBOL.
+
+;;; New types of setf places can be defined in one of two ways: using
+;;; `DEFSETF' or using `DEFUN' with a setf function name; both are
+;;; analogous to their Common Lisp counterparts.
+
+;;; `DEFSETF' supports both long and short forms, while `DEFUN' of a
+;;; setf place generates a JavaScript function name with the __setf_
+;;; prefix:
+
+(defun (setf color) (new-color el)
+  (setf (slot-value (slot-value el 'style) 'color) new-color))
+=> function __setf_color(newColor, el) {
+       el.style.color = newColor;
+   };
 
-(setf a (+ a 2 3 4 a))   => a += 2 + 3 + 4 + a
+(setf (color some-div) (+ 23 "em"))
+=> var _js2 = someDiv;
+   var _js1 = 23 + 'em';
+   __setf_color(_js1, _js2);
 
-(setf a (- 1 a))         => a = 1 - a
+;;; Note that temporary variables are generated to preserve evaluation
+;;; order of the arguments as they would be in Lisp.
+
+;;; The following example illustrates how setf places can be used to
+;;; provide a uniform protocol for positioning elements in HTML pages:
+
+(defsetf left (el) (offset)
+  `(setf (slot-value (slot-value ,el 'style) 'left) ,offset))
+=> null
+
+(setf (left some-div) (+ 123 "px"))
+=> var _js2 = someDiv;
+   var _js1 = 123 + 'px';
+   _js2.style.left = _js1;
+
+(progn (defmacro left (el)
+         `(slot-value ,el 'offset-left))
+       (left some-div))
+=> someDiv.offsetLeft;
 
 ;;;# Single argument statements
 ;;;t \index{single-argument statement}
@@ -519,7 +595,7 @@ a-variable  => aVariable
 ; (RETURN {value}?)
 ; (THROW  {value}?)
 ;
-; value ::= a ParenScript expression
+; value ::= a Parenscript expression
 
 ;;; The single argument statements `return' and `throw' are generated
 ;;; by the form `RETURN' and `THROW'. `THROW' has to be used inside a
@@ -547,23 +623,23 @@ a-variable  => aVariable
 ; (INSTANCEOF {value})
 ; (NEW        {value})
 ;
-; value ::= a ParenScript expression
+; value ::= a Parenscript expression
 
 ;;; The single argument expressions `delete', `void', `typeof',
 ;;; `instanceof' and `new' are generated by the forms `DELETE',
 ;;; `VOID', `TYPEOF', `INSTANCEOF' and `NEW'. They all take a
-;;; ParenScript expression.
+;;; Parenscript expression.
 
 (delete (new (*foobar 2 3 4))) => delete new Foobar(2, 3, 4)
 
 (if (= (typeof blorg) *string)
     (alert (+ "blorg is a string: " blorg))
     (alert "blorg is not a string"))
-  => if (typeof blorg == String) {
+=> if (typeof blorg == String) {
        alert('blorg is a string: ' + blorg);
-     } else {
+   } else {
        alert('blorg is not a string');
-     }
+   }
 
 ;;;# Conditional Statements
 ;;;t \index{conditional statements}
@@ -576,11 +652,11 @@ a-variable  => aVariable
 ; (WHEN condition then)
 ; (UNLESS condition then)
 ;
-; condition ::= a ParenScript expression
-; then      ::= a ParenScript statement in statement context, a
-;                 ParenScript expression in expression context
-; else      ::= a ParenScript statement in statement context, a
-;                 ParenScript expression in expression context
+; condition ::= a Parenscript expression
+; then      ::= a Parenscript statement in statement context, a
+;                 Parenscript expression in expression context
+; else      ::= a Parenscript statement in statement context, a
+;                 Parenscript expression in expression context
 
 ;;; The `IF' form compiles to the `if' javascript construct. An
 ;;; explicit `PROGN' around the then branch and the else branch is
@@ -591,15 +667,15 @@ a-variable  => aVariable
 (if (blorg.is-correct)
     (progn (carry-on) (return i))
     (alert "blorg is not correct!"))
-   => if (blorg.isCorrect()) {
-        carryOn();
-        return i;
-      } else {
-        alert('blorg is not correct!');
-      }
+=> if (blorg.isCorrect()) {
+       carryOn();
+       return i;
+   } else {
+       alert('blorg is not correct!');
+   }
 
 (+ i (if (blorg.add-one) 1 2))
-   => i + (blorg.addOne() ? 1 : 2)
+=> i + (blorg.addOne() ? 1 : 2)
 
 ;;; The `WHEN' and `UNLESS' forms can be used as shortcuts for the
 ;;; `IF' form.
@@ -607,16 +683,16 @@ a-variable  => aVariable
 (when (blorg.is-correct)
   (carry-on)
   (return i))
-    => if (blorg.isCorrect()) {
-         carryOn();
-         return i;
-       }
+=> if (blorg.isCorrect()) {
+       carryOn();
+       return i;
+   }
 
 (unless (blorg.is-correct)
   (alert "blorg is not correct!"))
-    => if (!blorg.isCorrect()) {
-         alert('blorg is not correct!');
-       }
+=> if (!blorg.isCorrect()) {
+       alert('blorg is not correct!');
+   }
 
 ;;;# Variable declaration
 ;;;t \index{variable}
@@ -624,54 +700,100 @@ a-variable  => aVariable
 ;;;t \index{binding}
 ;;;t \index{scoping}
 ;;;t \index{DEFVAR}
+;;;t \index{VAR}
 ;;;t \index{LET}
+;;;t \index{LET*}
+;;;t \index{LEXICAL-LET}
+;;;t \index{LEXICAL-LET*}
 
 ; (DEFVAR var {value}?)
-; (LET ({var | (var value)) body)
+; (VAR var {value}?)
+; (LET ({var | (var value)}*) body)
+; (LET* ({var | (var value)}*) body)
+; (LEXICAL-LET ({var | (var value)}*) body)
+; (LEXICAL-LET* ({var | (var value)}*) body)
 ;
 ; var   ::= a Lisp symbol
-; value ::= a ParenScript expression
-; body  ::= a list of ParenScript statements
-
-;;; Variables (either local or global) can be declared using the
-;;; `DEFVAR' form, which is similar to its equivalent form in
-;;; Lisp. The `DEFVAR' is converted to "var ... = ..." form in
-;;; JavaScript.
-
-(defvar *a* (array 1 2 3)) => var A = [ 1, 2, 3 ];
-
-(if (= i 1)
-    (progn (defvar blorg "hallo")
-           (alert blorg))
-    (progn (defvar blorg "blitzel")
-           (alert blorg)))
-   => if (i == 1) {
-        var blorg = 'hallo';
-        alert(blorg);
-      } else {
-        var blorg = 'blitzel';
-        alert(blorg);
-      }
-
-;;; A more lispy way to declare local variable is to use the `LET'
-;;; form, which is similar to its Lisp form.
-
-(if (= i 1)
-    (let ((blorg "hallo"))
-      (alert blorg))
-    (let ((blorg "blitzel"))
-      (alert blorg)))
-   => if (i == 1) {
-        var blorg = 'hallo';
-        alert(blorg);
-      } else {
-        var blorg = 'blitzel';
-        alert(blorg);
-      }
-
-;;; However, beware that scoping in Lisp and JavaScript are quite
-;;; different. For example, don't rely on closures capturing local
-;;; variables in the way you'd think they would.
+; value ::= a Parenscript expression
+; body  ::= a list of Parenscript statements
+
+;;; Parenscript special variables can be declared using the `DEFVAR'
+;;; special form, which is similar to its equivalent form in
+;;; Lisp. Note that the result is undefined if `DEFVAR' is not used as
+;;; a top-level form.
+
+(defvar *a* (array 1 2 3)) => var A = [ 1, 2, 3 ]
+
+;;; One feature present in Parenscript that is not part of Common Lisp
+;;; are lexically-scoped global variables, which are declared using
+;;; the `VAR' special form.
+
+;;; Parenscript provides two versions of the `LET' and `LET*' special
+;;; forms for manipulating local variables: `SIMPLE-LET' /
+;;; `SIMPLE-LET*' and `LEXICAL-LET' / `LEXICAL-LET*'.  By default,
+;;; `LET' and `LET*' are aliased to `SIMPLE-LET' and `SIMPLE-LET*',
+;;; respectively.
+
+;;; `SIMPLE-LET' and `SIMPLE-LET*' bind their variable lists using
+;;; simple JavaScript assignment.  This means that you cannot rely on
+;;; the bindings going out of scope at the end of the form.
+
+;;; `LEXICAL-LET' and `LEXICAL-LET*' actually introduce new lexical
+;;; environments for the variable bindings by creating anonymous
+;;; functions.
+
+;;; As you would expect, `SIMPLE-LET' and `LEXICAL-LET' do parallel
+;;; binding of their variable lists, while `SIMPLE-LET*' and
+;;; `LEXICAL-LET*' bind their variable lists sequentially.
+
+;;; examples:
+
+(simple-let* ((a 0) (b 1))
+  (alert (+ a b)))
+=> var a = 0;
+   var b = 1;
+   alert(a + b);
+
+(simple-let* ((a "World") (b "Hello"))
+  (simple-let ((a b) (b a))
+    (alert (+ a b))))
+=> var a = 'World';
+   var b = 'Hello';
+   var _js_a1 = b;
+   var _js_b2 = a;
+   var a = _js_a1;
+   var b = _js_b2;
+   delete _js_a1;
+   delete _js_b2;
+   alert(a + b);
+
+(simple-let* ((a 0) (b 1))
+  (lexical-let* ((a 9) (b 8))
+    (alert (+ a b)))
+  (alert (+ a b)))
+=> var a = 0;
+   var b = 1;
+   (function () {
+       var a = 9;
+       var b = 8;
+       alert(a + b);
+   })();
+   alert(a + b);
+
+(simple-let* ((a "World") (b "Hello"))
+  (lexical-let ((a b) (b a))
+    (alert (+ a b)))
+  (alert (+ a b)))
+=> var a = 'World';
+   var b = 'Hello';
+   (function (a, b) {
+       alert(a + b);
+   })(b, a);
+   alert(a + b);
+
+;;; Moreover, beware that scoping rules in Lisp and JavaScript are
+;;; quite different. For example, don't rely on closures capturing
+;;; local variables in the way that you would normally expect.
 
 ;;;# Iteration constructs
 ;;;t \index{iteration}
@@ -686,80 +808,154 @@ a-variable  => aVariable
 ;;;t \index{DOEACH}
 ;;;t \index{WHILE}
 
-; (DO ({var | (var {init}? {step}?)}*) (end-test) body)
-; (DOTIMES (var numeric-form) body)
-; (DOLIST (var list-form) body)
-; (DOEACH (var object) body)
+; (DO ({var | (var {init}? {step}?)}*) (end-test {result}?) body)
+; (DO* ({var | (var {init}? {step}?)}*) (end-test {result}?) body)
+; (DOTIMES (var numeric-form {result}?) body)
+; (DOLIST (var list-form {result}?) body)
+; (DOEACH ({var | (key value)} object-form {result}?) body)
 ; (WHILE end-test body)
 ;
 ; var          ::= a Lisp symbol
-; numeric-form ::= a ParenScript expression resulting in a number
-; list-form    ::= a ParenScript expression resulting in an array
-; object       ::= a ParenScript expression resulting in an object
-; init         ::= a ParenScript expression
-; step         ::= a ParenScript expression
-; end-test     ::= a ParenScript expression
-; body         ::= a list of ParenScript statements
-
-;;; The `DO' form, which is similar to its Lisp form, is transformed
-;;; into a JavaScript `for' statement. Note that the ParenScript `DO'
-;;; form does not have a return value, that is because `for' is a
-;;; statement and not an expression in JavaScript.
+; numeric-form ::= a Parenscript expression resulting in a number
+; list-form    ::= a Parenscript expression resulting in an array
+; object-form  ::= a Parenscript expression resulting in an object
+; init         ::= a Parenscript expression
+; step         ::= a Parenscript expression
+; end-test     ::= a Parenscript expression
+; result       ::= a Parenscript expression
+; body         ::= a list of Parenscript statements
+
+;;; All interation special forms are transformed into JavaScript `for'
+;;; statements and, if needed, lambda expressions.
+
+;;; `DO', `DO*', and `DOTIMES' carry the same semantics as their
+;;; Common Lisp equivalents.
+
+;;; `DO*' (note the variety of possible init-forms:
+
+(do* ((a) b (c (array "a" "b" "c" "d" "e"))
+      (d 0 (1+ d))
+      (e (aref c d) (aref c d)))
+     ((or (= d c.length) (eql e "x")))
+  (setf a d b e)
+  (document.write (+ "a: " a " b: " b "<br/>")))
+=> for (var a = null, b = null, c = ['a', 'b', 'c', 'd', 'e'], d = 0, e = c[d]; !(d == c.length || e == 'x'); d += 1, e = c[d]) {
+       a = d;
+       b = e;
+       document.write('a: ' + a + ' b: ' + b + '<br/>');
+   };
+
+;;; `DO' (note the parallel assignment):
 
 (do ((i 0 (1+ i))
-     (l (aref blorg i) (aref blorg i)))
-    ((or (= i blorg.length)
-         (eql l "Fumitastic")))
-  (document.write (+ "L is " l)))
-   => for (var i = 0, l = blorg[i];
-           !(i == blorg.length || l == 'Fumitastic');
-           i = i + 1, l = blorg[i]) {
-        document.write('L is ' + l);
-      }
-
-;;; The `DOTIMES' form, which lets a variable iterate from 0 upto an
-;;; end value, is a shortcut for `DO'.
-
-(dotimes (i blorg.length)
-  (document.write (+ "L is " (aref blorg i))))
-   => for (var i = 0; i < blorg.length; i = i + 1) {
-        document.write('L is ' + blorg[i]);
-      }
-
-;;; The `DOLIST' form is a shortcut for iterating over an array. Note
-;;; that this form creates temporary variables using a function called
-;;; `JS-GENSYM', which is similar to its Lisp counterpart `GENSYM'.
-
-(dolist (l blorg)
-  (document.write (+ "L is " l)))
-   => {
-        var tmpArr1 = blorg;
-        for (var tmpI2 = 0; tmpI2 < tmpArr1.length;
-          tmpI2 = tmpI2 + 1) {
-          var l = tmpArr1[tmpI2];
-          document.write('L is ' + l);
-        };
-      }
-
-
-;;; The `DOEACH' form is converted to a `for (var .. in ..)' form in
-;;; JavaScript. It is used to iterate over the enumerable properties
-;;; of an object.
-
-(doeach (i object)
-   (document.write (+ i " is " (aref object i))))
-   => for (var i in object) {
-        document.write(i + ' is ' + object[i]);
-      }
+     (s 0 (+ s i (1+ i))))
+    ((> i 10))
+  (document.write (+ "i: " i " s: " s "<br/>")))
+=> var _js_i1 = 0;
+   var _js_s2 = 0;
+   var i = _js_i1;
+   var s = _js_s2;
+   delete _js_i1;
+   delete _js_s2;
+   for (; i <= 10; ) {
+       document.write('i: ' + i + ' s: ' + s + '<br/>');
+       var _js3 = i + 1;
+       var _js4 = s + i + (i + 1);
+       i = _js3;
+       s = _js4;
+   };
+
+;;; compare to `DO*':
+
+(do* ((i 0 (1+ i))
+      (s 0 (+ s i (1- i))))
+     ((> i 10))
+  (document.write (+ "i: " i " s: " s "<br/>")))
+=> for (var i = 0, s = 0; i <= 10; i += 1, s += i + (i - 1)) {
+       document.write('i: ' + i + ' s: ' + s + '<br/>');
+   };
+
+;;; `DOTIMES':
+
+(let* ((arr (array "a" "b" "c" "d" "e")))
+  (dotimes (i arr.length)
+    (document.write (+ "i: " i " arr[i]: " (aref arr i) "<br/>"))))
+=> var arr = ['a', 'b', 'c', 'd', 'e'];
+   for (var i = 0; i < arr.length; i += 1) {
+       document.write('i: ' + i + ' arr[i]: ' + arr[i] + '<br/>');
+   };
+
+;;; `DOTIMES' with return value:
+
+(let* ((res 0))
+  (alert (+ "Summation to 10 is "
+            (dotimes (i 10 res)
+              (incf res (1+ i))))))
+=> var res = 0;
+   alert('Summation to 10 is ' + (function () {
+       for (var i = 0; i < 10; i += 1) {
+           res += i + 1;
+       };
+       return res;
+   })());
+
+;;; `DOLIST' is like CL:DOLIST, but that it operates on numbered JS
+;;; arrays/vectors.
+
+(let* ((l (list 1 2 4 8 16 32)))
+  (dolist (c l)
+    (document.write (+ "c: " c "<br/>"))))
+=> var l = [1, 2, 4, 8, 16, 32];
+   for (var c = null, _js_arrvar2 = l, _js_idx1 = 0; _js_idx1 < _js_arrvar2.length; _js_idx1 += 1) {
+       c = _js_arrvar2[_js_idx1];
+       document.write('c: ' + c + '<br/>');
+   };
+
+(let* ((l (list 1 2 4 8 16 32))
+       (s 0))
+  (alert (+ "Sum of " l " is: "
+            (dolist (c l s)
+              (incf s c)))))
+=> var l = [1, 2, 4, 8, 16, 32];
+   var s = 0;
+   alert('Sum of ' + l + ' is: ' + (function () {
+       for (var c = null, _js_arrvar2 = l, _js_idx1 = 0; _js_idx1 < _js_arrvar2.length; _js_idx1 += 1) {
+           c = _js_arrvar2[_js_idx1];
+           s += c;
+       };
+       return s;
+   })());
+
+;;; `DOEACH' iterates across the enumerable properties of JS objects,
+;;; binding either simply the key of each slot, or alternatively, both
+;;; the key and the value.
+
+(let* ((obj (create :a 1 :b 2 :c 3)))
+  (doeach (i obj)
+    (document.write (+ i ": " (aref obj i) "<br/>"))))
+=> var obj = { a : 1, b : 2, c : 3 };
+   for (var i in obj) {
+       document.write(i + ': ' + obj[i] + '<br/>');
+   };
+
+(let* ((obj (create :a 1 :b 2 :c 3)))
+  (doeach ((k v) obj)
+    (document.write (+ k ": " v "<br/>"))))
+=> var obj = { a : 1, b : 2, c : 3 };
+   var v;
+   for (var k in obj) {
+       v = obj[k];
+       document.write(k + ': ' + v + '<br/>');
+   };
 
 ;;; The `WHILE' form is transformed to the JavaScript form `while',
 ;;; and loops until a termination test evaluates to false.
 
 (while (film.is-not-finished)
   (this.eat (new *popcorn)))
-   => while (film.isNotFinished()) {
-        this.eat(new Popcorn);
-      }
+=> while (film.isNotFinished()) {
+       this.eat(new Popcorn);
+   }
 
 ;;;# The `CASE' statement
 ;;;t \index{CASE}
@@ -769,28 +965,29 @@ a-variable  => aVariable
 ; (CASE case-value clause*)
 ;
 ; clause     ::= (value body) | ((value*) body) | t-clause
-; case-value ::= a ParenScript expression
-; value      ::= a ParenScript expression
+; case-value ::= a Parenscript expression
+; value      ::= a Parenscript expression
 ; t-clause   ::= {t | otherwise | default} body
-; body       ::= a list of ParenScript statements
+; body       ::= a list of Parenscript statements
 
 ;;; The Lisp `CASE' form is transformed to a `switch' statement in
 ;;; JavaScript. Note that `CASE' is not an expression in
-;;; ParenScript. 
+;;; Parenscript. 
 
 (case (aref blorg i)
   ((1 "one") (alert "one"))
   (2 (alert "two"))
   (t (alert "default clause")))
-    => switch (blorg[i]) {
-         case 1:   ;
-         case 'one':
-                   alert('one');
-                   break;
-         case 2:
-                   alert('two');
-                   break;
-         default:   alert('default clause');
+=> switch (blorg[i]) {
+       case 1:
+       case 'one':
+           alert('one');
+           break;
+       case 2:
+           alert('two');
+           break;
+       default: 
+           alert('default clause');
        }
 
 ; (SWITCH case-value clause*)
@@ -804,12 +1001,11 @@ a-variable  => aVariable
   (1 (alert "If I get here"))
   (2 (alert "I also get here"))
   (default (alert "I always get here")))
-    => switch (blorg[i]) {
-         case 1:   alert('If I get here');
-         case 2:   alert('I also get here');
-         default:   alert('I always get here');
-       }
-
+=> switch (blorg[i]) {
+       case 1: alert('If I get here');
+       case 2: alert('I also get here');
+       default: alert('I always get here');
+   }
 
 ;;;# The `WITH' statement
 ;;;t \index{WITH}
@@ -820,8 +1016,8 @@ a-variable  => aVariable
 
 ; (WITH object body)
 ;
-; object ::= a ParenScript expression evaluating to an object
-; body   ::= a list of ParenScript statements
+; object ::= a Parenscript expression evaluating to an object
+; body   ::= a list of Parenscript statements
 
 ;;; The `WITH' form is compiled to a JavaScript `with' statements, and
 ;;; adds the object `object' as an intermediary scope objects when
@@ -829,10 +1025,9 @@ a-variable  => aVariable
 
 (with (create :foo "foo" :i "i")
   (alert (+ "i is now intermediary scoped: " i)))
-   => with ({ foo : 'foo',
-              i : 'i' }) {
-        alert('i is now intermediary scoped: ' + i);
-      }
+=> with ({ foo : 'foo', i : 'i' }) {
+       alert('i is now intermediary scoped: ' + i);
+   }
 
 ;;;# The `TRY' statement
 ;;;t \index{TRY}
@@ -843,7 +1038,7 @@ a-variable  => aVariable
 
 ; (TRY body {(:CATCH (var) body)}? {(:FINALLY body)}?)
 ;
-; body ::= a list of ParenScript statements
+; body ::= a list of Parenscript statements
 ; var  ::= a Lisp symbol
 
 ;;; The `TRY' form is converted to a JavaScript `try' statement, and
@@ -857,235 +1052,253 @@ a-variable  => aVariable
    (alert (+ "an error happened: " error)))
  (:finally
    (alert "Leaving the try form")))
-   => try {
-        throw 'i';
-      } catch (error) {
-        alert('an error happened: ' + error);
-      } finally {
-        alert('Leaving the try form');
-      }
+=> try {
+       throw 'i';
+   } catch (error) {
+       alert('an error happened: ' + error);
+   } finally {
+       alert('Leaving the try form');
+   }
 
 ;;;# The HTML Generator
-;;;t \index{HTML}
+;;;t \index{PS-HTML}
 ;;;t \index{HTML generation}
-;;;t \index{CSS}
-;;;t \index{CSS generation}
 
+; (PS-HTML html-expression)
 
-; (HTML html-expression)
-
-;;; The HTML generator of ParenScript is very similar to the HTML
-;;; generator included in AllegroServe. It accepts the same input
-;;; forms as the AllegroServer HTML generator. However, non-HTML
-;;; construct are compiled to JavaScript by the ParenScript
+;;; The HTML generator of Parenscript is very similar to the htmlgen
+;;; HTML generator library included with AllegroServe. It accepts the
+;;; same input forms as the AllegroServer HTML generator. However,
+;;; non-HTML construct are compiled to JavaScript by the Parenscript
 ;;; compiler. The resulting expression is a JavaScript expression.
 
-(html ((:a :href "foobar") "blorg"))
-  => '<a href=\"foobar\">blorg</a>'
+(ps-html ((:a :href "foobar") "blorg"))
+=> '<A HREF=\"foobar\">blorg</A>'
 
-(html ((:a :href (generate-a-link)) "blorg"))
-  => '<a href=\"' + generateALink() + '\">blorg</a>'
+(ps-html ((:a :href (generate-a-link)) "blorg"))
+=> '<A HREF=\"' + generateALink() + '\">blorg</A>'
 
-;;; We can recursively call the JS compiler in a HTML expression.
+;;; We can recursively call the Parenscript compiler in an HTML
+;;; expression.
 
 (document.write
-  (html ((:a :href "#"
-            :onclick (js-inline (transport))) "link")))
-  => document.write
-     ('<a href=\"#\" onclick=\"' + 'javascript:transport();' + '\">link</a>')
+  (ps-html ((:a :href "#"
+                :onclick (ps-inline (transport))) "link")))
+=> document.write('<A HREF=\"#\" ONCLICK=\"' + ('javascript:' + 'transport' + '(' + ')') + '\">link</A>')
 
 ;;; Forms may be used in attribute lists to conditionally generate
 ;;; the next attribute. In this example the textarea is sometimes disabled.
 
-(let ((disabled nil)
+(let* ((disabled nil)
       (authorized t))
    (setf element.inner-h-t-m-l
-         (html ((:textarea (or disabled (not authorized)) :disabled "disabled")
+         (ps-html ((:textarea (or disabled (not authorized)) :disabled "disabled")
                 "Edit me"))))
-  =>  {
-        var disabled = null;
-        var authorized = true;
-        element.innerHTML =
-        '<textarea'
-        + (disabled || !authorized ? ' disabled=\"' + 'disabled' + '\"' : '')
-        + '>Edit me</textarea>';
-      }
-
-; (CSS-INLINE css-expression)
-
-;;; Stylesheets can also be created in ParenScript.
-
-(css-inline :color "red"
-            :font-size "x-small")
-  => 'color:red;font-size:x-small'
-
-(defun make-color-div(color-name)
-    (return (html ((:div :style (css-inline :color color-name))
-                   color-name " looks like this."))))
-  => function makeColorDiv(colorName) {
-       return '<div style=\"' + ('color:' + colorName) + '\">' + colorName
-         + ' looks like this.</div>';
-     }
+=> var disabled = null;
+   var authorized = true;
+   element.innerHTML =
+   '<TEXTAREA'
+   + (disabled || !authorized ? ' DISABLED=\"' + 'disabled' + '\"' : '')
+   + '>Edit me</TEXTAREA>';
 
 ;;;# Macrology
 ;;;t \index{macro}
 ;;;t \index{macrology}
-;;;t \index{DEFJSMACRO}
+;;;t \index{DEFPSMACRO}
+;;;t \index{DEFMACRO/PS}
+;;;t \index{DEFMACRO+PS}
+;;;t \index{DEFINE-PS-SYMBOL-MACRO}
+;;;t \index{IMPORT-MACROS-FROM-LISP}
 ;;;t \index{MACROLET}
 ;;;t \index{SYMBOL-MACROLET}
-;;;t \index{JS-GENSYM}
+;;;t \index{PS-GENSYM}
 ;;;t \index{compiler}
 
-; (DEFJSMACRO name lambda-list macro-body)
+; (DEFPSMACRO name lambda-list macro-body)
+; (DEFPSMACRO/PS name lambda-list macro-body)
+; (DEFPSMACRO+PS name lambda-list macro-body)
+; (DEFINE-PS-SYMBOL-MACRO symbol expansion)
+; (IMPORT-MACROS-FROM-LISP symbol*)
 ; (MACROLET ({name lambda-list macro-body}*) body)
 ; (SYMBOL-MACROLET ({name macro-body}*) body)
-; (JS-GENSYM {string}?)
+; (PS-GENSYM {string})
 ;
 ; name        ::= a Lisp symbol
 ; lambda-list ::= a lambda list
-; macro-body  ::= a Lisp body evaluating to ParenScript code
-; body        ::= a list of ParenScript statements
+; macro-body  ::= a Lisp body evaluating to Parenscript code
+; body        ::= a list of Parenscript statements
 ; string      ::= a string
 
-;;; ParenScript can be extended using macros, just like Lisp can be
+;;; Parenscript can be extended using macros, just like Lisp can be
 ;;; extended using Lisp macros. Using the special Lisp form
-;;; `DEFJSMACRO', the ParenScript language can be
-;;; extended. `DEFJSMACRO' adds the new macro to the toplevel macro
-;;; environment, which is always accessible during ParenScript
+;;; `DEFPSMACRO', the Parenscript language can be
+;;; extended. `DEFPSMACRO' adds the new macro to the toplevel macro
+;;; environment, which is always accessible during Parenscript
 ;;; compilation. For example, the `1+' and `1-' operators are
 ;;; implemented using macros.
 
-(defjsmacro 1- (form)
+(defpsmacro 1- (form)
   `(- ,form 1))
 
-(defjsmacro 1+ (form)
+(defpsmacro 1+ (form)
   `(+ ,form 1))
 
-;;; A more complicated ParenScript macro example is the implementation
-;;; of the `DOLIST' form (note how `JS-GENSYM', the ParenScript of
-;;; `GENSYM', is used to generate new ParenScript variable names):
-
-(defjsmacro dolist (i-array &rest body)
-  (let ((var (first i-array))
-        (array (second i-array))
-        (arrvar (js-gensym "arr"))
-        (idx (js-gensym "i")))
-    `(let ((,arrvar ,array))
-      (do ((,idx 0 (++ ,idx)))
-          ((>= ,idx (slot-value ,arrvar 'length)))
-        (let ((,var (aref ,arrvar ,idx)))
-          ,@body)))))
-
-;;; Macros can be defined in ParenScript itself (as opposed to Lisp)
-;;; by using the ParenScript `MACROLET' and 'DEFMACRO' forms.
-
-;;; ParenScript also supports the use of macros defined in the
-;;; underlying Lisp. Existing Lisp macros can be imported into the
-;;; ParenScript macro environment by 'IMPORT-MACROS-FROM-LISP'. This
-;;; functionality enables code sharing between ParenScript and Lisp,
-;;; and is useful in debugging since the full power of Lisp
-;;; macroexpanders, editors and other supporting facilities can be
-;;; used. However, it is important to note that the macroexpansion of
-;;; Lisp macros and ParenScript macros takes place in their own
-;;; respective environments, and many Lisp macros (especially those
-;;; provided by the Lisp implementation) expand into code that is not
-;;; usable by ParenScript. To make it easy for users to take advantage
-;;; of these features, two additional macro definition facilities are
-;;; provided by ParenScript: 'DEFMACRO/JS' and
-;;; 'DEFMACRO+JS'. 'DEFMACRO/JS' defines a Lisp macro and then imports
-;;; it into the ParenScript macro environment, while 'DEFMACRO+JS'
-;;; defines two macros with the same name and expansion, one in
-;;; ParenScript and one in Lisp. 'DEFMACRO+JS' is used when the full
-;;; 'macroexpand' of the Lisp macro yields code that cannot be used by
-;;; ParenScript.
-
-;;; ParenScript also supports symbol macros, which can be introduced
-;;; using the ParenScript form `SYMBOL-MACROLET'. A new macro
-;;; environment is created and added to the current macro environment
-;;; list while compiling the body of the `SYMBOL-MACROLET' form. For
-;;; example, the ParenScript `WITH-SLOTS' is implemented using symbol
-;;; macros.
-
-(defjsmacro with-slots (slots object &rest body)
+;;; A more complicated Parenscript macro example is the implementation
+;;; of the `DOLIST' form (note how `PS-GENSYM', the Parenscript of
+;;; `GENSYM', is used to generate new Parenscript variable names):
+
+(defpsmacro dolist ((var array &optional (result nil result?)) &body body)
+  (let ((idx (ps-gensym "_js_idx"))
+        (arrvar (ps-gensym "_js_arrvar")))
+    `(do* (,var
+           (,arrvar ,array)
+           (,idx 0 (1+ ,idx)))
+          ((>= ,idx (slot-value ,arrvar 'length))
+           ,@(when result? (list result)))
+       (setq ,var (aref ,arrvar ,idx))
+       ,@body)))
+
+;;; Macros can be defined in Parenscript code itself (as opposed to
+;;; from Lisp) by using the Parenscript `MACROLET' and `DEFMACRO'
+;;; forms. Note that macros defined this way are defined in a null
+;;; lexical environment (ex - (let ((x 1)) (defmacro baz (y) `(+ ,y
+;;; ,x))) will not work), since the surrounding Parenscript code is
+;;; just translated to JavaScript and not actually evaluated.
+
+;;; Parenscript also supports the use of macros defined in the
+;;; underlying Lisp environment. Existing Lisp macros can be imported
+;;; into the Parenscript macro environment by
+;;; `IMPORT-MACROS-FROM-LISP'. This functionality enables code sharing
+;;; between Parenscript and Lisp, and is useful in debugging since the
+;;; full power of Lisp macroexpanders, editors and other supporting
+;;; facilities can be used. However, it is important to note that the
+;;; macroexpansion of Lisp macros and Parenscript macros takes place
+;;; in their own respective environments, and many Lisp macros
+;;; (especially those provided by the Lisp implementation) expand into
+;;; code that is not usable by Parenscript. To make it easy for users
+;;; to take advantage of these features, two additional macro
+;;; definition facilities are provided by Parenscript: `DEFMACRO/PS'
+;;; and `DEFMACRO+PS'. `DEFMACRO/PS' defines a Lisp macro and then
+;;; imports it into the Parenscript macro environment, while
+;;; `DEFMACRO+PS' defines two macros with the same name and expansion,
+;;; one in Parenscript and one in Lisp. `DEFMACRO+PS' is used when the
+;;; full 'macroexpand' of the Lisp macro yields code that cannot be
+;;; used by Parenscript.
+
+;;; Parenscript also supports symbol macros, which can be introduced
+;;; using the Parenscript form `SYMBOL-MACROLET' or defined in Lisp
+;;; with `DEFINE-PS-SYMBOL-MACRO'. For example, the Parenscript
+;;; `WITH-SLOTS' is implemented using symbol macros.
+
+(defpsmacro with-slots (slots object &rest body)
   `(symbol-macrolet ,(mapcar #'(lambda (slot)
                                  `(,slot '(slot-value ,object ',slot)))
                              slots)
     ,@body))
 
-;;;# The ParenScript Compiler
+;;;# The Parenscript namespace system
+;;;t \index{package}
+;;;t \index{namespace}
+;;;t \index{PS-PACKAGE-PREFIX}
+
+; (setf (PS-PACKAGE-PREFIX package-designator) string)
+
+;;; Although JavaScript does not offer namespacing or a package
+;;; system, Parenscript does provide a namespace mechanism for
+;;; generated JavaScript by integrating with the Common Lisp package
+;;; system. Since Parenscript code is normally read in by the Lisp
+;;; reader, all symbols (except for uninterned ones, ie - those
+;;; specified with the #: reader macro) have a Lisp package. By
+;;; default, no packages are prefixed. You can specify that symbols in
+;;; a particular package receive a prefix when translated to
+;;; JavaScript with the `PS-PACKAGE-PREFIX' place.
+
+(defpackage "PS-REF.MY-LIBRARY"
+  (:use "PARENSCRIPT"))
+(setf (ps-package-prefix "PS-REF.MY-LIBRARY") "my_library_")
+
+(defun ps-ref.my-library::library-function (x y)
+  (return (+ x y)))
+  -> function my_library_libraryFunction(x, y) {
+        return x + y;
+     }
+
+;;;# Identifier obfuscation
+;;;t \index{obfuscation}
+;;;t \index{identifiers}
+;;;t \index{OBFUSCATE-PACKAGE}
+;;;t \index{UNOBFUSCATE-PACKAGE}
+
+; (OBFUSCATE-PACKAGE package-designator &optional symbol-map)
+; (UNOBFUSCATE-PACKAGE package-designator)
+
+;;; Similar to the namespace mechanism, Parenscript provides a
+;;; facility to generate obfuscated identifiers in specified CL
+;;; packages. The function `OBFUSCATE-PACKAGE' may optionally be
+;;; passed a hash-table or a closure that maps symbols to their
+;;; obfuscated counterparts. By default, the mapping is done using
+;;; `PS-GENSYM'.
+
+(defpackage "PS-REF.OBFUSCATE-ME")
+(obfuscate-package "PS-REF.OBFUSCATE-ME"
+  (let ((code-pt-counter #x8CF0)
+        (symbol-map (make-hash-table)))
+    (lambda (symbol)
+      (or (gethash symbol symbol-map)
+          (setf (gethash symbol symbol-map)
+                (make-symbol (string (code-char (incf code-pt-counter)))))))))
+
+(defun ps-ref.obfuscate-me::a-function (a b ps-ref.obfuscate-me::foo)
+  (+ a (ps-ref.my-library::library-function b ps-ref.obfuscate-me::foo)))
+  -> function 賱(a, b, 賲) {
+       a + my_library_libraryFunction(b, 賲);
+     }
+
+;;; The obfuscation and namespace facilities can be used on packages
+;;; at the same time.
+
+;;;# The Parenscript Compiler
 ;;;t \index{compiler}
-;;;t \index{ParenScript compiler}
-;;;t \index{JS-COMPILE}
-;;;t \index{JS-TO-STRINGS}
-;;;t \index{JS-TO-STATEMENT-STRINGS}
-;;;t \index{JS-TO-STRING}
-;;;t \index{JS-TO-LINE}
-;;;t \index{JS}
-;;;t \index{JS-INLINE}
-;;;t \index{JS-FILE}
-;;;t \index{JS-SCRIPT}
-;;;t \index{nested compilation}
-
-; (JS-COMPILE expr)
-; (JS-TO-STRINGS compiled-expr position)
-; (JS-TO-STATEMENT-STRINGS compiled-expr position)
+;;;t \index{Parenscript compiler}
+;;;t \index{PS}
+;;;t \index{PS*}
+;;;t \index{PS1*}
+;;;t \index{PS-INLINE}
+;;;t \index{PS-INLINE*}
+;;;t \index{LISP}
+
+; (PS &body body)
+; (PS* &body body)
+; (PS1* parenscript-form)
+; (PS-INLINE form &optional *js-string-delimiter*)
+; (PS-INLINE* form &optional *js-string-delimiter*)
+
+; (LISP lisp-forms)
 ;
-; compiled-expr ::= a compiled ParenScript expression
-; position      ::= a column number
-;
-; (JS-TO-STRING expression)
-; (JS-TO-LINE expression)
-;
-; expression ::= a Lisp list of ParenScript code
-;
-; (JS body)
-; (JS-INLINE body)
-; (JS-FILE body)
-; (JS-SCRIPT body)
-;
-; body ::= a list of ParenScript statements
-
-;;; The ParenScript compiler can be invoked from withing Lisp and from
-;;; within ParenScript itself. The primary API function is
-;;; `JS-COMPILE', which takes a list of ParenScript, and returns an
-;;; internal object representing the compiled ParenScript.
-
-(js-compile '(foobar 1 2))
-  => #<JS::FUNCTION-CALL {584AA5DD}>
-
-;;; This internal object can be transformed to a string using the
-;;; methods `JS-TO-STRINGS' and `JS-TO-STATEMENT-STRINGS', which
-;;; interpret the ParenScript in expression and in statement context
-;;; respectively. They take an additional parameter indicating the
-;;; start-position on a line (please note that the indentation code is
-;;; not perfect, and this string interface will likely be
-;;; changed). They return a list of strings, where each string
-;;; represents a new line of JavaScript code. They can be joined
-;;; together to form a single string.
-
-(js-to-strings (js-compile '(foobar 1 2)) 0)
-  => ("foobar(1, 2)")
-
-;;; As a shortcut, ParenScript provides the functions `JS-TO-STRING'
-;;; and `JS-TO-LINE', which return the JavaScript string of the
-;;; compiled expression passed as an argument.
-
-(js-to-string '(foobar 1 2))
-  => "foobar(1, 2)"
-
-;;; For static ParenScript code, the macros `JS', `JS-INLINE',
-;;; `JS-FILE' and `JS-SCRIPT' avoid the need to quote the ParenScript
-;;; expression. All these forms add an implicit `PROGN' form around
-;;; the body. `JS' returns a string of the compiled body, where the
-;;; other expression return an expression that can be embedded in a
-;;; HTML generation construct using the AllegroServe HTML
-;;; generator. `JS-SCRIPT' generates a "SCRIPT" node, `JS-INLINE'
-;;; generates a string to be used in node attributs, and `JS-FILE'
-;;; prints the compiled ParenScript code to the HTML stream.
-
-;;; These macros are also available inside ParenScript itself, and
-;;; generate strings that can be used inside ParenScript code. Note
-;;; that `JS-INLINE' in ParenScript is not the same `JS-INLINE' form
-;;; as in Lisp, for example. The same goes for the other compilation
-;;; macros.
-
+; body ::= Parenscript statements comprising an implicit `PROGN'
+
+;;; For static Parenscript code, the macro `PS' compiles the provided
+;;; forms at Common Lisp macro-expansion time. `PS*' and `PS1*'
+;;; evaluate their arguments and then compile them. All these forms
+;;; except for `PS1*' treat the given forms as an implicit
+;;; `PROGN'.
+
+;;; `PS-INLINE' and `PS-INLINE*' take a single Parenscript form and
+;;; output a string starting with "javascript:" that can be used in
+;;; HTML node attributes. As well, they provide an argument to bind
+;;; the value of *js-string-delimiter* to control the value of the
+;;; JavaScript string escape character to be compatible with whatever
+;;; the HTML generation mechanism is used (for example, if HTML
+;;; strings are delimited using #\', using #\" will avoid conflicts
+;;; without requiring the output JavaScript code to be escaped). By
+;;; default the value is taken from *js-inline-string-delimiter*.
+
+;;; Parenscript can also call out to arbitrary Common Lisp code at
+;;; code output time using the special form `LISP'. The form provided
+;;; to `LISP' is evaluated, and its result is compiled as though it
+;;; were Parenscript code. For `PS' and `PS-INLINE', the Parenscript
+;;; output code is generated at macro-expansion time, and the `LISP'
+;;; statements are inserted inline and have access to the enclosing
+;;; Common Lisp lexical environment. `PS*' and `PS1*' evaluate the
+;;; `LISP' forms with eval, providing them access to the current
+;;; dynamic environment only.