Added defsetf long-form.
[clinton/parenscript.git] / docs / reference.lisp
index f0f9e40..d7219f5 100644 (file)
 ;;;t \index{symbol conversion}
 
 ;;; Lisp symbols are converted to JavaScript symbols by following a
-;;; few simple rules. Special characters `!', `?', `#', `$', `@', `%',
+;;; few simple rules. Special characters `!', `?', `#', `@', `%',
 ;;; '/', `*' and `+' get replaced by their written-out equivalents
-;;; "bang", "what", "hash", "dollar", "at", "percent", "slash",
-;;; "start" and "plus" respectively.
+;;; "bang", "what", "hash", "at", "percent", "slash",
+;;; "start" and "plus" respectively. The `$' character is untouched.
 
-!?#$@% => bangwhathashdollaratpercent
+!?#@% => bangwhathashatpercent
 
 ;;; The `-' is an indication that the following character should be
 ;;; converted to uppercase. Thus, `-' separated symbols are converted
@@ -222,7 +222,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}
@@ -233,9 +233,14 @@ an-object.foo => anObject.foo
 ;
 ; regex ::= a Lisp string
 
-;;; Regular expressions can be created by using the `REGEX' form. The
-;;; regex form actually does nothing at all to its argument, and
-;;; prints it as is.
+;;; Regular expressions can be created by using the `REGEX' form. If
+;;; the argument does not start with a slash, it is surrounded by
+;;; slashes to make it a proper JavaScript regex. If the argument
+;;; starts with a slash it is left as it is. This makes it possible
+;;; to use modifiers such as slash-i (case-insensitive) or
+;;; slash-g (match-globally (all)).
+
+(regex "foobar") => /foobar/
 
 (regex "/foobar/i") => /foobar/i
 
@@ -486,7 +491,7 @@ a-variable  => aVariable
 ;;; Assignment is done using the `SETF' form, which is 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;
@@ -498,11 +503,11 @@ a-variable  => aVariable
 ;;; operator expression using this variable into a more "efficient"
 ;;; assignment operator form. For example:
 
-(setf a (1+ a))          => a++
+(setf a (1+ a))          => a++;
 
-(setf a (* 2 3 4 a 4 a)) => a *= 2 * 3 * 4 * 4 * a
+(setf a (+ a 2 3 4 a))   => a += 2 + 3 + 4 + a;
 
-(setf a (- 1 a))         => a = 1 - a
+(setf a (- 1 a))         => a = 1 - a;
 
 ;;;# Single argument statements
 ;;;t \index{single-argument statement}
@@ -733,7 +738,7 @@ a-variable  => aVariable
           tmpI2 = tmpI2 + 1) {
           var l = tmpArr1[tmpI2];
           document.write('L is ' + l);
-        }
+        };
       }
 
 
@@ -758,30 +763,54 @@ a-variable  => aVariable
 
 ;;;# The `CASE' statement
 ;;;t \index{CASE}
+;;;t \index{SWITCH}
 ;;;t \index{switch}
 
 ; (CASE case-value clause*)
 ;
-; clause     ::= (value body)
+; clause     ::= (value body) | ((value*) body) | t-clause
 ; case-value ::= a ParenScript expression
 ; value      ::= a ParenScript expression
+; t-clause   ::= {t | otherwise | default} body
 ; 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. The default case is not named `T' in ParenScript, but
-;;; `DEFAULT' instead.
+;;; ParenScript. 
 
 (case (aref blorg i)
-  (1 (alert "one"))
+  ((1 "one") (alert "one"))
   (2 (alert "two"))
-  (default (alert "default clause")))
+  (t (alert "default clause")))
     => switch (blorg[i]) {
-         case 1:   alert('one');
-         case 2:   alert('two');
+         case 1:   ;
+         case 'one':
+                   alert('one');
+                   break;
+         case 2:
+                   alert('two');
+                   break;
          default:   alert('default clause');
        }
 
+; (SWITCH case-value clause*)
+; clause     ::= (value body) | (default body)
+
+;;; The `SWITCH' form is the equivalent to a javascript switch statement.
+;;; No break statements are inserted, and the default case is named `DEFAULT'.
+;;; The `CASE' form should be prefered in most cases.
+
+(switch (aref blorg i)
+  (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');
+       }
+
+
 ;;;# The `WITH' statement
 ;;;t \index{WITH}
 ;;;t \index{dynamic scope}
@@ -789,7 +818,7 @@ a-variable  => aVariable
 ;;;t \index{scoping}
 ;;;t \index{closure}
 
-; (WITH (object) body)
+; (WITH object body)
 ;
 ; object ::= a ParenScript expression evaluating to an object
 ; body   ::= a list of ParenScript statements
@@ -798,7 +827,7 @@ a-variable  => aVariable
 ;;; adds the object `object' as an intermediary scope objects when
 ;;; executing the body.
 
-(with ((create :foo "foo" :i "i"))
+(with (create :foo "foo" :i "i")
   (alert (+ "i is now intermediary scoped: " i)))
    => with ({ foo : 'foo',
               i : 'i' }) {
@@ -865,6 +894,23 @@ a-variable  => aVariable
   => 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)
+      (authorized t))
+   (setf element.inner-h-t-m-l
+         (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.
@@ -930,9 +976,28 @@ a-variable  => aVariable
         (let ((,var (aref ,arrvar ,idx)))
           ,@body)))))
 
-;;; Macros can be added dynamically to the macro environment by using
-;;; the ParenScript `MACROLET' form (note that while `DEFJSMACRO' is a
-;;; Lisp form, `MACROLET' and `SYMBOL-MACROLET' are ParenScript forms).
+;;; 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