Fixed nary comparison operators (ex: (< 1 2 3) should translate to (1
[clinton/parenscript.git] / docs / reference.lisp
index b61fadf..9af69c9 100644 (file)
@@ -1,15 +1,15 @@
-;;;# ParenScript Language Reference
+;;;# Parenscript Language Reference
 
 ;;; 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
+;;; 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}
 ;;; 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)
+(+ i (if 1 2 3)) => i + (1 ? 2 : 3);
 
 (if 1 2 3)
 => if (1) {
        2;
    } else {
        3;
-   }
+   };
 
 ;;;# Symbol conversion
 ;;;t \index{symbol}
 ;;; "bang", "what", "hash", "at", "percent", "slash",
 ;;; "start" and "plus" respectively. The `$' character is untouched.
 
-!?#@% => bangwhathashatpercent
+!?#@% => bangwhathashatpercent;
 
 ;;; The `-' is an indication that the following character should be
 ;;; converted to uppercase. Thus, `-' separated symbols are converted
 ;;; to camelcase. The `_' character however is left untouched.
 
-bla-foo-bar => blaFooBar
+bla-foo-bar => blaFooBar;
 
 ;;; If you want a JavaScript symbol beginning with an uppercase, you
 ;;; can either use a leading `-', which can be misleading in a
 ;;; mathematical context, or a leading `*'.
 
-*array => Array
-
-;;; The `.' character is left as is in symbols. This allows the
-;;; ParenScript programmer to use a practical shortcut when accessing
-;;; slots or methods of JavaScript objects. Instead of writing
-
-(slot-value foobar 'slot)
-
-;;; we can write
-
-foobar.slot
+*array => Array;
 
 ;;; A symbol beggining and ending with `+' or `*' is converted to all
 ;;; uppercase, to signify that this is a constant or a global
 ;;; variable.
 
-*global-array*        => GLOBALARRAY
-
-*global-array*.length => GLOBALARRAY.length
+*global-array*        => GLOBALARRAY;
 
 ;;;## Reserved Keywords
 ;;;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
+/= %= += -= <<= >>= >>>= &= ^= |= 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
+INSTANCEOF INT INTERFACE JS LABELED-FOR LAMBDA LET 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
 ;;;t \index{literal value}
@@ -107,16 +94,16 @@ 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
+1       => 1;
 
-123.123 => 123.123
+123.123 => 123.123;
 
 ;;; Note that the base is not conserved between Lisp and JavaScript.
 
-#x10    => 16
+#x10    => 16;
 
 ;;;## String literals
 ;;;t \index{string}
@@ -126,13 +113,14 @@ WHEN WHILE WITH WITH-SLOTS
 
 ;;; Lisp strings are converted into JavaScript literals.
 
-"foobar"      => 'foobar'
+"foobar"      => 'foobar';
 
-"bratzel bub" => 'bratzel bub'
+"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}
@@ -145,34 +133,34 @@ 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.
 
-(array)       => [  ]
+(array)       => [  ];
 
-(array 1 2 3) => [ 1, 2, 3 ]
+(array 1 2 3) => [ 1, 2, 3 ];
 
 (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
 ;;; on the JavaScript side.
 
-(make-array)       => new Array()
+(make-array)       => new Array();
 
-(make-array 1 2 3) => new Array(1, 2, 3)
+(make-array 1 2 3) => new Array(1, 2, 3);
 
 (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
@@ -181,6 +169,7 @@ WHEN WHILE WITH WITH-SLOTS
 ;;;## Object literals
 ;;;t \index{CREATE}
 ;;;t \index{SLOT-VALUE}
+;;;t \index{@}
 ;;;t \index{WITH-SLOTS}
 ;;;t \index{object literal}
 ;;;t \index{object}
@@ -191,11 +180,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
@@ -203,23 +192,24 @@ 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 } }
+     anotherObject : { schtrunz : 1 } };
 
 ;;; Object properties can be accessed using the `SLOT-VALUE' form,
 ;;; which takes an object and a slot-name.
 
-(slot-value an-object 'foo) => anObject.foo
+(slot-value an-object 'foo) => anObject.foo;
 
-;;; A programmer can also use the "." symbol notation explained above.
+;;; The convenience macro `@' is provided to make multiple levels of
+;;; indirection easy to express
 
-an-object.foo => anObject.foo
+(@ an-object foo bar) => anObject.foo.bar;
 
 ;;; The form `WITH-SLOTS' can be used to bind the given slot-name
 ;;; symbols to a macro that will expand into a `SLOT-VALUE' form at
@@ -245,13 +235,13 @@ an-object.foo => anObject.foo
 ;;; to use modifiers such as slash-i (case-insensitive) or
 ;;; slash-g (match-globally (all)).
 
-(regex "foobar") => /foobar/
+(regex "foobar") => /foobar/;
 
-(regex "/foobar/i") => /foobar/i
+(regex "/foobar/i") => /foobar/i;
 
 ;;; Here CL-INTERPOL proves really useful.
 
-(regex #?r"/([^\s]+)foobar/i") => /([^\s]+)foobar/i
+(regex #?r"/([^\s]+)foobar/i") => /([^\s]+)foobar/i;
 
 ;;;## Literal symbols
 ;;;t \index{T}
@@ -269,26 +259,26 @@ an-object.foo => anObject.foo
 ;;; The Lisp symbols `T' and `FALSE' (or `F') are converted to their
 ;;; JavaScript boolean equivalents `true' and `false'.
 
-T     => true
+T     => true;
 
-FALSE => false
+FALSE => false;
 
-F => false
+F => false;
 
 ;;; The Lisp symbol `NIL' is converted to the JavaScript keyword
 ;;; `null'.
 
-NIL => null
+NIL => null;
 
 ;;; The Lisp symbol `UNDEFINED' is converted to the JavaScript keyword
 ;;; `undefined'.
 
-UNDEFINED => undefined
+UNDEFINED => undefined;
 
 ;;; The Lisp symbol `THIS' is converted to the JavaScript keyword
 ;;; `this'.
 
-THIS => this
+THIS => this;
 
 ;;;# Variables
 ;;;t \index{variable}
@@ -299,16 +289,14 @@ 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
-
-a-variable  => aVariable
+variable    => variable;
 
-*math       => Math
+a-variable  => aVariable;
 
-*math.floor => Math.floor
+*math       => Math;
 
 ;;;# Function calls and method calls
 ;;;t \index{function}
@@ -317,12 +305,11 @@ a-variable  => aVariable
 ;;;t \index{method call}
 
 ; (function {argument}*)
-; (method   object {argument}*)
+
 ;
-; function ::= a ParenScript expression or a Lisp symbol
-; method   ::= a Lisp symbol beginning with .
-; object   ::= a ParenScript expression
-; argument ::= a ParenScript expression
+; function ::= a Parenscript expression or a Lisp symbol
+; 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
@@ -330,26 +317,16 @@ a-variable  => aVariable
 ;;; the normal JavaScript function call representation, with the
 ;;; arguments given in paren after the function name.
 
-(blorg 1 2) => blorg(1, 2)
+(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 ])
-
-((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).
+=> foobar(blorg(1, 2), blabla(3, 4), [ 2, 3, 4 ]);
 
-(.blorg this 1 2) => this.blorg(1, 2)
+((slot-value this 'blorg) 1 2) => this.blorg(1, 2);
 
-(this.blorg 1 2) => this.blorg(1, 2)
+((aref foo i) 1 2) => foo[i](1, 2);
 
-(.blorg (aref foobar 1) NIL T)
-=> foobar[1].blorg(null, true)
+((slot-value (aref foobar 1) 'blorg) NIL T) => foobar[1].blorg(null, true);
 
 ;;;# Operator Expressions
 ;;;t \index{operator}
@@ -366,21 +343,17 @@ 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
-;;; operators.
+;;; Parenscript operator is not the assignment operator.
 
-(* 1 2)   => 1 * 2
+(* 1 2)   => 1 * 2;
 
-(= 1 2)   => 1 == 2
-
-(eql 1 2) => 1 == 2
+(= 1 2)   => 1 == 2;
 
 ;;; Note that the resulting expression is correctly parenthesized,
 ;;; according to the JavaScript operator precedence that can be found
@@ -389,31 +362,28 @@ a-variable  => aVariable
 ;;;    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 increment and decrement operators are also
 ;;; available. `INCF' and `DECF' are the pre-incrementing and
 ;;; pre-decrementing operators. These operators can
 ;;; take only one argument.
 
-(incf i) => ++i
+(incf i) => ++i;
 
-(decf i) => --i
+(decf i) => --i;
 
 ;;; The `1+' and `1-' operators are shortforms for adding and
 ;;; substracting 1.
 
-(1- i) => i - 1
-
-(1+ i) => i + 1
+(1- i) => i - 1;
 
-;;; The `not' operator actually optimizes the code a bit. If `not' is
-;;; used on another boolean-returning operator, the operator is
-;;; reversed.
+(1+ i) => i + 1;
 
-(not (< i 2))   => i >= 2
+;;; If `not' is used on another boolean-returning operator, the
+;;; operator is reversed.
 
-(not (eql i 2)) => i != 2
+(not (< i 2))   => i >= 2;
 
 ;;;# Body forms
 ;;;t \index{body form}
@@ -423,8 +393,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
@@ -441,7 +411,7 @@ a-variable  => aVariable
 ;;; 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.
@@ -460,7 +430,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
@@ -470,7 +440,7 @@ a-variable  => aVariable
   (return (+ 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,
@@ -479,7 +449,7 @@ a-variable  => aVariable
 (lambda (a b) (return (+ a b)))
 => function (a, b) {
        return a + b;
-   }
+   };
 
 ;;;# Assignment
 ;;;t \index{assignment}
@@ -493,14 +463,14 @@ a-variable  => aVariable
 ; (SETF {lhs rhs}*)
 ; (PSETF {lhs rhs}*)
 ;
-; lhs ::= a ParenScript left hand side expression
-; rhs ::= a ParenScript expression
+; lhs ::= a Parenscript left hand side expression
+; rhs ::= a Parenscript expression
 
 ; (SETQ {lhs rhs}*)
 ; (PSETQ {lhs rhs}*)
 ;
-; lhs ::= a ParenScript symbol
-; rhs ::= a ParenScript expression
+; lhs ::= a Parenscript symbol
+; rhs ::= a Parenscript expression
 
 ;;; Assignment is done using the `SETF', `PSETF', `SETQ', and `PSETQ'
 ;;; forms, which are transformed into a series of assignments using
@@ -526,7 +496,7 @@ a-variable  => aVariable
 ;;; places or variables using a number of temporary variables created
 ;;; by `PS-GENSYM'.  For example:
 
-(let* ((a 1) (b 2))
+(let ((a 1) (b 2))
   (psetf a b b a))
 => var a = 1;
    var b = 2;
@@ -573,16 +543,16 @@ a-variable  => aVariable
 
 (defsetf left (el) (offset)
   `(setf (slot-value (slot-value ,el 'style) 'left) ,offset))
-=> null
+=> 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))
+(macrolet ((left (el)
+             `(slot-value ,el 'offset-left)))
+  (left some-div))
 => someDiv.offsetLeft;
 
 ;;;# Single argument statements
@@ -595,16 +565,16 @@ 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
 ;;; `TRY' form. `RETURN' is used to return a value from a function
 ;;; call.
 
-(return 1)       => return 1
+(return 1)       => return 1;
 
-(throw "foobar") => throw 'foobar'
+(throw "foobar") => throw 'foobar';
 
 ;;;# Single argument expression
 ;;;t \index{single-argument expression}
@@ -623,14 +593,14 @@ 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)
+(delete (new (*foobar 2 3 4))) => delete new Foobar(2, 3, 4);
 
 (if (= (typeof blorg) *string)
     (alert (+ "blorg is a string: " blorg))
@@ -639,7 +609,7 @@ a-variable  => aVariable
        alert('blorg is a string: ' + blorg);
    } else {
        alert('blorg is not a string');
-   }
+   };
 
 ;;;# Conditional Statements
 ;;;t \index{conditional statements}
@@ -652,11 +622,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
@@ -664,7 +634,7 @@ a-variable  => aVariable
 ;;; form is used in an expression context, a JavaScript `?', `:'
 ;;; operator form is generated.
 
-(if (blorg.is-correct)
+(if ((@ blorg is-correct))
     (progn (carry-on) (return i))
     (alert "blorg is not correct!"))
 => if (blorg.isCorrect()) {
@@ -672,27 +642,27 @@ a-variable  => aVariable
        return i;
    } else {
        alert('blorg is not correct!');
-   }
+   };
 
-(+ i (if (blorg.add-one) 1 2))
-=> i + (blorg.addOne() ? 1 : 2)
+(+ i (if ((@ blorg add-one)) 1 2))
+=> i + (blorg.addOne() ? 1 : 2);
 
 ;;; The `WHEN' and `UNLESS' forms can be used as shortcuts for the
 ;;; `IF' form.
 
-(when (blorg.is-correct)
+(when ((@ blorg is-correct))
   (carry-on)
   (return i))
 => if (blorg.isCorrect()) {
        carryOn();
        return i;
-   }
+   };
 
-(unless (blorg.is-correct)
+(unless ((@ blorg is-correct))
   (alert "blorg is not correct!"))
 => if (!blorg.isCorrect()) {
        alert('blorg is not correct!');
-   }
+   };
 
 ;;;# Variable declaration
 ;;;t \index{variable}
@@ -703,97 +673,59 @@ a-variable  => aVariable
 ;;;t \index{VAR}
 ;;;t \index{LET}
 ;;;t \index{LET*}
-;;;t \index{LEXICAL-LET}
-;;;t \index{LEXICAL-LET*}
 
 ; (DEFVAR var {value}?)
 ; (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
+; 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 ]
+(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.
+;;; Parenscript provides the `LET' and `LET*' special forms for
+;;; creating new variable bindings. Both special forms implement
+;;; lexical scope by renaming the provided variables via `GENSYM', and
+;;; implement dynamic binding using `TRY'-`FINALY'. Note that
+;;; top-level `LET' and `LET*' forms will create new global variables.
 
-;;; `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.
+;;; 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.
 
-;;; 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.
+(progn 
+  (defvar *a* 4)
+  (let ((x 1)
+        (*a* 2))
+    (let* ((y (+ x 1))
+           (x (+ x y)))
+      (+ *a* x y))))
+=> var A = 4;
+   var x = 1;
+   var A_TMPSTACK1;
+   try {
+       A_TMPSTACK1 = A;
+       A = 2;
+       var y = x + 1;
+       var x2 = x + y;
+       A + x2 + y;
+   } finally {
+       A = A_TMPSTACK1;
+   };
 
 ;;;# Iteration constructs
 ;;;t \index{iteration}
@@ -805,25 +737,25 @@ a-variable  => aVariable
 ;;;t \index{DO}
 ;;;t \index{DOTIMES}
 ;;;t \index{DOLIST}
-;;;t \index{DOEACH}
+;;;t \index{FOR-IN}
 ;;;t \index{WHILE}
 
 ; (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)
+; (FOR-IN (var object) 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-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
+; 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.
@@ -836,33 +768,29 @@ a-variable  => aVariable
 (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")))
+     ((or (= d (@ c length)) (== e "x")))
   (setf a d b e)
-  (document.write (+ "a: " a " b: " b "<br/>")))
+  ((@ 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'
 
 (do ((i 0 (1+ 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;
+  ((@ document write) (+ "i: " i " s: " s "<br/>")))
+=> var i = 0;
+   var s = 0;
    for (; i <= 10; ) {
        document.write('i: ' + i + ' s: ' + s + '<br/>');
-       var _js3 = i + 1;
-       var _js4 = s + i + (i + 1);
-       i = _js3;
-       s = _js4;
+       var _js1 = i + 1;
+       var _js2 = s + i + (i + 1);
+       i = _js1;
+       s = _js2;
    };
 
 ;;; compare to `DO*':
@@ -870,16 +798,16 @@ a-variable  => aVariable
 (do* ((i 0 (1+ i))
       (s 0 (+ s i (1- i))))
      ((> i 10))
-  (document.write (+ "i: " i " s: " s "<br/>")))
+  ((@ 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/>"))))
+(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/>');
@@ -887,7 +815,7 @@ a-variable  => aVariable
 
 ;;; `DOTIMES' with return value:
 
-(let* ((res 0))
+(let ((res 0))
   (alert (+ "Summation to 10 is "
             (dotimes (i 10 res)
               (incf res (1+ i))))))
@@ -902,17 +830,17 @@ a-variable  => aVariable
 ;;; `DOLIST' is like CL:DOLIST, but that it operates on numbered JS
 ;;; arrays/vectors.
 
-(let* ((l (list 1 2 4 8 16 32)))
+(let ((l (list 1 2 4 8 16 32)))
   (dolist (c l)
-    (document.write (+ "c: " c "<br/>"))))
+    ((@ 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))
+(let ((l '(1 2 4 8 16 32))
+      (s 0))
   (alert (+ "Sum of " l " is: "
             (dolist (c l s)
               (incf s c)))))
@@ -926,36 +854,24 @@ a-variable  => aVariable
        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.
+;;; `FOR-IN' is translated to the JS `for...in' statement.
 
-(let* ((obj (create :a 1 :b 2 :c 3)))
-  (doeach (i obj)
-    (document.write (+ i ": " (aref obj i) "<br/>"))))
+(let ((obj (create :a 1 :b 2 :c 3)))
+  (for-in (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 is-not-finished))
+  ((@ this eat) (new *popcorn)))
 => while (film.isNotFinished()) {
        this.eat(new Popcorn);
-   }
+   };
 
 ;;;# The `CASE' statement
 ;;;t \index{CASE}
@@ -965,14 +881,14 @@ 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"))
@@ -988,7 +904,7 @@ a-variable  => aVariable
            break;
        default: 
            alert('default clause');
-       }
+       };
 
 ; (SWITCH case-value clause*)
 ; clause     ::= (value body) | (default body)
@@ -1005,7 +921,7 @@ a-variable  => aVariable
        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}
@@ -1016,8 +932,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
@@ -1027,7 +943,7 @@ a-variable  => aVariable
   (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}
@@ -1038,7 +954,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
@@ -1058,7 +974,7 @@ a-variable  => aVariable
        alert('an error happened: ' + error);
    } finally {
        alert('Leaving the try form');
-   }
+   };
 
 ;;;# The HTML Generator
 ;;;t \index{PS-HTML}
@@ -1066,32 +982,32 @@ a-variable  => aVariable
 
 ; (PS-HTML html-expression)
 
-;;; The HTML generator of ParenScript is very similar to the htmlgen
+;;; 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
+;;; non-HTML construct are compiled to JavaScript by the Parenscript
 ;;; compiler. The resulting expression is a JavaScript expression.
 
 (ps-html ((:a :href "foobar") "blorg"))
-=> '<A HREF=\"foobar\">blorg</A>'
+=> '<A HREF=\"foobar\">blorg</A>';
 
 (ps-html ((:a :href (generate-a-link)) "blorg"))
-=> '<A HREF=\"' + generateALink() + '\">blorg</A>'
+=> '<A HREF=\"' + generateALink() + '\">blorg</A>';
 
-;;; We can recursively call the ParenScript compiler in an HTML
+;;; We can recursively call the Parenscript compiler in an HTML
 ;;; expression.
 
-(document.write
+((@ document write)
   (ps-html ((:a :href "#"
-                :onclick (lisp (ps-inline (transport)))) "link")))
-=> document.write('<A HREF=\"#\" ONCLICK=\"' + 'javascript:transport()' + '\">link</A>')
+                :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
+   (setf (@ element inner-h-t-m-l)
          (ps-html ((:textarea (or disabled (not authorized)) :disabled "disabled")
                 "Edit me"))))
 => var disabled = null;
@@ -1105,27 +1021,35 @@ a-variable  => aVariable
 ;;;t \index{macro}
 ;;;t \index{macrology}
 ;;;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{PS-GENSYM}
 ;;;t \index{compiler}
 
 ; (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)
 ; (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
-;;; `DEFPSMACRO', the ParenScript language can be
+;;; `DEFPSMACRO', the Parenscript language can be
 ;;; extended. `DEFPSMACRO' adds the new macro to the toplevel macro
-;;; environment, which is always accessible during ParenScript
+;;; environment, which is always accessible during Parenscript
 ;;; compilation. For example, the `1+' and `1-' operators are
 ;;; implemented using macros.
 
@@ -1135,9 +1059,9 @@ a-variable  => aVariable
 (defpsmacro 1+ (form)
   `(+ ,form 1))
 
-;;; 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):
+;;; 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"))
@@ -1150,42 +1074,45 @@ a-variable  => aVariable
        (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.
+;;; 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
+;;; 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
+;;; 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
+;;; 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
+;;; 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
+;;; 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'
+;;; 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
+;;; 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
+;;; 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.
+;;; used by Parenscript.
 
-;;; ParenScript also supports symbol macros, which can be introduced
-;;; using the ParenScript form `SYMBOL-MACROLET'.For example, the
-;;; ParenScript `WITH-SLOTS' is implemented using symbol macros.
+;;; 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.
 
-(defjsmacro with-slots (slots object &rest body)
+(defpsmacro with-slots (slots object &rest body)
   `(symbol-macrolet ,(mapcar #'(lambda (slot)
                                  `(,slot '(slot-value ,object ',slot)))
                              slots)
     ,@body))
 
-
-;;;# The ParenScript namespace system
+;;;# The Parenscript namespace system
 ;;;t \index{package}
 ;;;t \index{namespace}
 ;;;t \index{PS-PACKAGE-PREFIX}
@@ -1193,24 +1120,24 @@ a-variable  => aVariable
 ; (setf (PS-PACKAGE-PREFIX package-designator) string)
 
 ;;; Although JavaScript does not offer namespacing or a package
-;;; system, ParenScript does provide a namespace mechanism for
+;;; 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
+;;; 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 "MY-LIBRARY"
-  (:use #:parenscript))
-(setf (ps-package-prefix :my-library) "my_library_")
+(defpackage "PS-REF.MY-LIBRARY"
+  (:use "PARENSCRIPT"))
+(setf (ps-package-prefix "PS-REF.MY-LIBRARY") "my_library_")
 
-(defun my-library::library-function (x y)
+(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}
@@ -1218,25 +1145,37 @@ a-variable  => aVariable
 ;;;t \index{OBFUSCATE-PACKAGE}
 ;;;t \index{UNOBFUSCATE-PACKAGE}
 
-; (OBFUSCATE-PACKAGE package-designator)
+; (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 certain Lisp
-;;; packages.
-
-(defpackage "OBFUSCATE-ME")
-(obfuscate-package :obfuscate-me)
-
-(defun obfuscate-me::library-function2 (a b obfuscate-me::foo)
-  (+ a (my-library::library-function b obfuscate-me::foo)))
+;;; 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
+;;;# The Parenscript Compiler
 ;;;t \index{compiler}
-;;;t \index{ParenScript compiler}
+;;;t \index{Parenscript compiler}
 ;;;t \index{PS}
 ;;;t \index{PS*}
 ;;;t \index{PS1*}
@@ -1252,15 +1191,15 @@ a-variable  => aVariable
 
 ; (LISP lisp-forms)
 ;
-; body ::= ParenScript statements comprising an implicit `PROGN'
+; body ::= Parenscript statements comprising an implicit `PROGN'
 
-;;; For static ParenScript code, the macro `PS' compiles the provided
+;;; 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
+;;; `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
@@ -1270,10 +1209,10 @@ a-variable  => aVariable
 ;;; 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
+;;; 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
+;;; 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