007bc71b3417ed88edadf99af22ae5b53dde863e
[clinton/parenscript.git] / docs / reference.lisp
1 ;;;# Parenscript Language Reference
2
3 ;;; Create a useful package for the code here...
4 (in-package #:cl-user)
5 (defpackage #:ps-ref (:use #:ps))
6 (in-package #:ps-ref)
7
8 ;;; This chapters describes the core constructs of Parenscript, as
9 ;;; well as its compilation model. This chapter is aimed to be a
10 ;;; comprehensive reference for Parenscript developers. Programmers
11 ;;; looking for how to tweak the Parenscript compiler itself should
12 ;;; turn to the Parenscript Internals chapter.
13
14 ;;;# Statements and Expressions
15 ;;;t \index{statement}
16 ;;;t \index{expression}
17
18 ;;; In contrast to Lisp, where everything is an expression, JavaScript
19 ;;; makes the difference between an expression, which evaluates to a
20 ;;; value, and a statement, which has no value. Examples for
21 ;;; JavaScript statements are `for', `with' and `while'. Most
22 ;;; Parenscript forms are expression, but certain special forms are
23 ;;; not (the forms which are transformed to a JavaScript
24 ;;; statement). All Parenscript expressions are statements
25 ;;; though. Certain forms, like `IF' and `PROGN', generate different
26 ;;; JavaScript constructs whether they are used in an expression
27 ;;; context or a statement context. For example:
28
29 (+ i (if 1 2 3)) => i + (1 ? 2 : 3)
30
31 (if 1 2 3)
32 => if (1) {
33 2;
34 } else {
35 3;
36 }
37
38 ;;;# Symbol conversion
39 ;;;t \index{symbol}
40 ;;;t \index{symbol conversion}
41
42 ;;; Lisp symbols are converted to JavaScript symbols by following a
43 ;;; few simple rules. Special characters `!', `?', `#', `@', `%',
44 ;;; '/', `*' and `+' get replaced by their written-out equivalents
45 ;;; "bang", "what", "hash", "at", "percent", "slash",
46 ;;; "start" and "plus" respectively. The `$' character is untouched.
47
48 !?#@% => bangwhathashatpercent
49
50 ;;; The `-' is an indication that the following character should be
51 ;;; converted to uppercase. Thus, `-' separated symbols are converted
52 ;;; to camelcase. The `_' character however is left untouched.
53
54 bla-foo-bar => blaFooBar
55
56 ;;; If you want a JavaScript symbol beginning with an uppercase, you
57 ;;; can either use a leading `-', which can be misleading in a
58 ;;; mathematical context, or a leading `*'.
59
60 *array => Array
61
62 ;;; The `.' character is left as is in symbols. This allows the
63 ;;; Parenscript programmer to use a practical shortcut when accessing
64 ;;; slots or methods of JavaScript objects. Instead of writing
65
66 (slot-value foobar 'slot)
67
68 ;;; we can write
69
70 foobar.slot
71
72 ;;; A symbol beggining and ending with `+' or `*' is converted to all
73 ;;; uppercase, to signify that this is a constant or a global
74 ;;; variable.
75
76 *global-array* => GLOBALARRAY
77
78 *global-array*.length => GLOBALARRAY.length
79
80 ;;;## Reserved Keywords
81 ;;;t \index{keyword}
82 ;;;t \index{reserved keywords}
83
84 ;;; The following keywords and symbols are reserved in Parenscript,
85 ;;; and should not be used as variable names.
86
87 ! ~ ++ -- * / % + - << >> >>> < > <= >= == != ==== !== & ^ | && || *=
88 /= %= += -= <<= >>= >>>= &= ^= |= 1- 1+ ABSTRACT AND AREF ARRAY
89 BOOLEAN BREAK BYTE CASE CATCH CC-IF CHAR CLASS COMMA CONST CONTINUE
90 CREATE DEBUGGER DECF DEFAULT DEFUN DEFVAR DELETE DO DO* DOEACH DOLIST
91 DOTIMES DOUBLE ELSE ENUM EQL EXPORT EXTENDS F FALSE FINAL FINALLY
92 FLOAT FLOOR FOR FOR-IN FUNCTION GOTO IF IMPLEMENTS IMPORT IN INCF
93 INSTANCEOF INT INTERFACE JS LABELED-FOR LAMBDA LET LET* LEXICAL-LET
94 LEXICAL-LET* LISP LIST LONG MAKE-ARRAY NATIVE NEW NIL NOT OR PACKAGE
95 PRIVATE PROGN PROTECTED PUBLIC RANDOM REGEX RETURN SETF SHORT
96 SLOT-VALUE STATIC SUPER SWITCH SYMBOL-MACROLET SYNCHRONIZED T THIS
97 THROW THROWS TRANSIENT TRY TYPEOF UNDEFINED UNLESS VAR VOID VOLATILE
98 WHEN WHILE WITH WITH-SLOTS
99
100 ;;;# Literal values
101 ;;;t \index{literal value}
102
103 ;;;## Number literals
104 ;;;t \index{number}
105 ;;;t \index{number literal}
106
107 ; number ::= a Lisp number
108
109 ;;;
110 ;;; Parenscript supports the standard JavaScript literal
111 ;;; values. Numbers are compiled into JavaScript numbers.
112
113 1 => 1
114
115 123.123 => 123.123
116
117 ;;; Note that the base is not conserved between Lisp and JavaScript.
118
119 #x10 => 16
120
121 ;;;## String literals
122 ;;;t \index{string}
123 ;;;t \index{string literal}
124
125 ; string ::= a Lisp string
126
127 ;;; Lisp strings are converted into JavaScript literals.
128
129 "foobar" => 'foobar'
130
131 "bratzel bub" => 'bratzel bub'
132
133 ;;; Escapes in Lisp are not converted to JavaScript escapes. However,
134 ;;; to avoid having to use double backslashes when constructing a
135 ;;; string, you can use the CL-INTERPOL library by Edi Weitz.
136
137 ;;;## Array literals
138 ;;;t \index{array}
139 ;;;t \index{ARRAY}
140 ;;;t \index{MAKE-ARRAY}
141 ;;;t \index{AREF}
142 ;;;t \index{array literal}
143
144 ; (ARRAY {values}*)
145 ; (MAKE-ARRAY {values}*)
146 ; (AREF array index)
147 ;
148 ; values ::= a Parenscript expression
149 ; array ::= a Parenscript expression
150 ; index ::= a Parenscript expression
151
152 ;;; Array literals can be created using the `ARRAY' form.
153
154 (array) => [ ]
155
156 (array 1 2 3) => [ 1, 2, 3 ]
157
158 (array (array 2 3)
159 (array "foobar" "bratzel bub"))
160 => [ [ 2, 3 ], [ 'foobar', 'bratzel bub' ] ]
161
162 ;;; Arrays can also be created with a call to the `Array' function
163 ;;; using the `MAKE-ARRAY'. The two forms have the exact same semantic
164 ;;; on the JavaScript side.
165
166 (make-array) => new Array()
167
168 (make-array 1 2 3) => new Array(1, 2, 3)
169
170 (make-array
171 (make-array 2 3)
172 (make-array "foobar" "bratzel bub"))
173 => new Array(new Array(2, 3), new Array('foobar', 'bratzel bub'))
174
175 ;;; Indexing arrays in Parenscript is done using the form `AREF'. Note
176 ;;; that JavaScript knows of no such thing as an array. Subscripting
177 ;;; an array is in fact reading a property from an object. So in a
178 ;;; semantic sense, there is no real difference between `AREF' and
179 ;;; `SLOT-VALUE'.
180
181 ;;;## Object literals
182 ;;;t \index{CREATE}
183 ;;;t \index{SLOT-VALUE}
184 ;;;t \index{WITH-SLOTS}
185 ;;;t \index{object literal}
186 ;;;t \index{object}
187 ;;;t \index{object property}
188 ;;;t \index{property}
189
190 ; (CREATE {name value}*)
191 ; (SLOT-VALUE object slot-name)
192 ; (WITH-SLOTS ({slot-name}*) object body)
193 ;
194 ; name ::= a Parenscript symbol or a Lisp keyword
195 ; value ::= a Parenscript expression
196 ; object ::= a Parenscript object expression
197 ; slot-name ::= a quoted Lisp symbol
198 ; body ::= a list of Parenscript statements
199
200 ;;;
201 ;;; Object literals can be create using the `CREATE' form. Arguments
202 ;;; to the `CREATE' form is a list of property names and values. To be
203 ;;; more "lispy", the property names can be keywords.
204
205 (create :foo "bar" :blorg 1)
206 => { foo : 'bar', blorg : 1 }
207
208 (create :foo "hihi"
209 :blorg (array 1 2 3)
210 :another-object (create :schtrunz 1))
211 => { foo : 'hihi',
212 blorg : [ 1, 2, 3 ],
213 anotherObject : { schtrunz : 1 } }
214
215 ;;; Object properties can be accessed using the `SLOT-VALUE' form,
216 ;;; which takes an object and a slot-name.
217
218 (slot-value an-object 'foo) => anObject.foo
219
220 ;;; A programmer can also use the "." symbol notation explained above.
221
222 an-object.foo => anObject.foo
223
224 ;;; The form `WITH-SLOTS' can be used to bind the given slot-name
225 ;;; symbols to a macro that will expand into a `SLOT-VALUE' form at
226 ;;; expansion time.
227
228 (with-slots (a b c) this
229 (+ a b c))
230 => this.a + this.b + this.c;
231
232 ;;;## Regular Expression literals
233 ;;;t \index{REGEX}
234 ;;;t \index{regular expression}
235 ;;;t \index{CL-INTERPOL}
236
237 ; (REGEX regex)
238 ;
239 ; regex ::= a Lisp string
240
241 ;;; Regular expressions can be created by using the `REGEX' form. If
242 ;;; the argument does not start with a slash, it is surrounded by
243 ;;; slashes to make it a proper JavaScript regex. If the argument
244 ;;; starts with a slash it is left as it is. This makes it possible
245 ;;; to use modifiers such as slash-i (case-insensitive) or
246 ;;; slash-g (match-globally (all)).
247
248 (regex "foobar") => /foobar/
249
250 (regex "/foobar/i") => /foobar/i
251
252 ;;; Here CL-INTERPOL proves really useful.
253
254 (regex #?r"/([^\s]+)foobar/i") => /([^\s]+)foobar/i
255
256 ;;;## Literal symbols
257 ;;;t \index{T}
258 ;;;t \index{F}
259 ;;;t \index{FALSE}
260 ;;;t \index{NIL}
261 ;;;t \index{UNDEFINED}
262 ;;;t \index{THIS}
263 ;;;t \index{literal symbols}
264 ;;;t \index{null}
265 ;;;t \index{true}
266
267 ; T, F, FALSE, NIL, UNDEFINED, THIS
268
269 ;;; The Lisp symbols `T' and `FALSE' (or `F') are converted to their
270 ;;; JavaScript boolean equivalents `true' and `false'.
271
272 T => true
273
274 FALSE => false
275
276 F => false
277
278 ;;; The Lisp symbol `NIL' is converted to the JavaScript keyword
279 ;;; `null'.
280
281 NIL => null
282
283 ;;; The Lisp symbol `UNDEFINED' is converted to the JavaScript keyword
284 ;;; `undefined'.
285
286 UNDEFINED => undefined
287
288 ;;; The Lisp symbol `THIS' is converted to the JavaScript keyword
289 ;;; `this'.
290
291 THIS => this
292
293 ;;;# Variables
294 ;;;t \index{variable}
295 ;;;t \index{symbol}
296
297 ; variable ::= a Lisp symbol
298
299 ;;; All the other literal Lisp values that are not recognized as
300 ;;; special forms or symbol macros are converted to JavaScript
301 ;;; variables. This extreme freedom is actually quite useful, as it
302 ;;; allows the Parenscript programmer to be flexible, as flexible as
303 ;;; JavaScript itself.
304
305 variable => variable
306
307 a-variable => aVariable
308
309 *math => Math
310
311 *math.floor => Math.floor
312
313 ;;;# Function calls and method calls
314 ;;;t \index{function}
315 ;;;t \index{function call}
316 ;;;t \index{method}
317 ;;;t \index{method call}
318
319 ; (function {argument}*)
320 ; (method object {argument}*)
321 ;
322 ; function ::= a Parenscript expression or a Lisp symbol
323 ; method ::= a Lisp symbol beginning with .
324 ; object ::= a Parenscript expression
325 ; argument ::= a Parenscript expression
326
327 ;;; Any list passed to the JavaScript that is not recognized as a
328 ;;; macro or a special form (see "Macro Expansion" below) is
329 ;;; interpreted as a function call. The function call is converted to
330 ;;; the normal JavaScript function call representation, with the
331 ;;; arguments given in paren after the function name.
332
333 (blorg 1 2) => blorg(1, 2)
334
335 (foobar (blorg 1 2) (blabla 3 4) (array 2 3 4))
336 => foobar(blorg(1, 2), blabla(3, 4), [ 2, 3, 4 ])
337
338 ((slot-value this 'blorg) 1 2) => this.blorg(1, 2)
339
340 ((aref foo i) 1 2) => foo[i](1, 2)
341
342 ((slot-value (aref foobar 1) 'blorg) NIL T) => foobar[1].blorg(null, true)
343
344 ;;; Note that while most method calls can be abbreviated using the "."
345 ;;; trick in symbol names (see "Symbol Conversion" above), this is not
346 ;;; advised due to the fact that "object.function" is treated as a
347 ;;; symbol distinct from both "object" and "function," which will
348 ;;; cause problems if Parenscript package prefixes or package
349 ;;; obfuscation is used.
350
351 (this.blorg 1 2) => this.blorg(1, 2)
352
353 ;;;# Operator Expressions
354 ;;;t \index{operator}
355 ;;;t \index{operator expression}
356 ;;;t \index{assignment operator}
357 ;;;t \index{EQL}
358 ;;;t \index{NOT}
359 ;;;t \index{AND}
360 ;;;t \index{OR}
361
362 ; (operator {argument}*)
363 ; (single-operator argument)
364 ;
365 ; operator ::= one of *, /, %, +, -, <<, >>, >>>, < >, EQL,
366 ; ==, !=, =, ===, !==, &, ^, |, &&, AND, ||, OR.
367 ; single-operator ::= one of INCF, DECF, ++, --, NOT, !
368 ; argument ::= a Parenscript expression
369
370 ;;; Operator forms are similar to function call forms, but have an
371 ;;; operator as function name.
372 ;;;
373 ;;; Please note that `=' is converted to `==' in JavaScript. The `='
374 ;;; Parenscript operator is not the assignment operator. Unlike
375 ;;; JavaScript, Parenscript supports multiple arguments to the
376 ;;; operators.
377
378 (* 1 2) => 1 * 2
379
380 (= 1 2) => 1 == 2
381
382 (eql 1 2) => 1 == 2
383
384 ;;; Note that the resulting expression is correctly parenthesized,
385 ;;; according to the JavaScript operator precedence that can be found
386 ;;; in table form at:
387
388 ;;; http://www.codehouse.com/javascript/precedence/
389
390 (* 1 (+ 2 3 4) 4 (/ 6 7))
391 => 1 * (2 + 3 + 4) * 4 * (6 / 7)
392
393 ;;; The pre increment and decrement operators are also
394 ;;; available. `INCF' and `DECF' are the pre-incrementing and
395 ;;; pre-decrementing operators. These operators can
396 ;;; take only one argument.
397
398 (incf i) => ++i
399
400 (decf i) => --i
401
402 ;;; The `1+' and `1-' operators are shortforms for adding and
403 ;;; substracting 1.
404
405 (1- i) => i - 1
406
407 (1+ i) => i + 1
408
409 ;;; The `not' operator actually optimizes the code a bit. If `not' is
410 ;;; used on another boolean-returning operator, the operator is
411 ;;; reversed.
412
413 (not (< i 2)) => i >= 2
414
415 (not (eql i 2)) => i != 2
416
417 ;;;# Body forms
418 ;;;t \index{body form}
419 ;;;t \index{PROGN}
420 ;;;t \index{body statement}
421
422 ; (PROGN {statement}*) in statement context
423 ; (PROGN {expression}*) in expression context
424 ;
425 ; statement ::= a Parenscript statement
426 ; expression ::= a Parenscript expression
427
428 ;;; The `PROGN' special form defines a sequence of statements when
429 ;;; used in a statement context, or sequence of expression when used
430 ;;; in an expression context. The `PROGN' special form is added
431 ;;; implicitly around the branches of conditional executions forms,
432 ;;; function declarations and iteration constructs.
433
434 ;;; For example, in a statement context:
435
436 (progn (blorg i) (blafoo i))
437 => blorg(i);
438 blafoo(i);
439
440 ;;; In an expression context:
441
442 (+ i (progn (blorg i) (blafoo i)))
443 => i + (blorg(i), blafoo(i))
444
445 ;;; A `PROGN' form doesn't lead to additional indentation or
446 ;;; additional braces around it's body.
447
448 ;;;# Function Definition
449 ;;;t \index{function}
450 ;;;t \index{method}
451 ;;;t \index{function definition}
452 ;;;t \index{DEFUN}
453 ;;;t \index{LAMBDA}
454 ;;;t \index{closure}
455 ;;;t \index{anonymous function}
456
457 ; (DEFUN name ({argument}*) body)
458 ; (LAMBDA ({argument}*) body)
459 ;
460 ; name ::= a Lisp Symbol
461 ; argument ::= a Lisp symbol
462 ; body ::= a list of Parenscript statements
463
464 ;;; As in Lisp, functions are defined using the `DEFUN' form, which
465 ;;; takes a name, a list of arguments, and a function body. An
466 ;;; implicit `PROGN' is added around the body statements.
467
468 (defun a-function (a b)
469 (return (+ a b)))
470 => function aFunction(a, b) {
471 return a + b;
472 }
473
474 ;;; Anonymous functions can be created using the `LAMBDA' form, which
475 ;;; is the same as `DEFUN', but without function name. In fact,
476 ;;; `LAMBDA' creates a `DEFUN' with an empty function name.
477
478 (lambda (a b) (return (+ a b)))
479 => function (a, b) {
480 return a + b;
481 }
482
483 ;;;# Assignment
484 ;;;t \index{assignment}
485 ;;;t \index{SETF}
486 ;;;t \index{PSETF}
487 ;;;t \index{SETQ}
488 ;;;t \index{PSETQ}
489 ;;;t \index{DEFSETF}
490 ;;;t \index{assignment operator}
491
492 ; (SETF {lhs rhs}*)
493 ; (PSETF {lhs rhs}*)
494 ;
495 ; lhs ::= a Parenscript left hand side expression
496 ; rhs ::= a Parenscript expression
497
498 ; (SETQ {lhs rhs}*)
499 ; (PSETQ {lhs rhs}*)
500 ;
501 ; lhs ::= a Parenscript symbol
502 ; rhs ::= a Parenscript expression
503
504 ;;; Assignment is done using the `SETF', `PSETF', `SETQ', and `PSETQ'
505 ;;; forms, which are transformed into a series of assignments using
506 ;;; the JavaScript `=' operator.
507
508 (setf a 1) => a = 1;
509
510 (setf a 2 b 3 c 4 x (+ a b c))
511 => a = 2;
512 b = 3;
513 c = 4;
514 x = a + b + c;
515
516 ;;; The `SETF' form can transform assignments of a variable with an
517 ;;; operator expression using this variable into a more "efficient"
518 ;;; assignment operator form. For example:
519
520 (setf a (+ a 2 3 4 a)) => a += 2 + 3 + 4 + a;
521
522 (setf a (- 1 a)) => a = 1 - a;
523
524 ;;; The `PSETF' and `PSETQ' forms perform parallel assignment of
525 ;;; places or variables using a number of temporary variables created
526 ;;; by `PS-GENSYM'. For example:
527
528 (let* ((a 1) (b 2))
529 (psetf a b b a))
530 => var a = 1;
531 var b = 2;
532 var _js1 = b;
533 var _js2 = a;
534 a = _js1;
535 b = _js2;
536
537 ;;; The `SETQ' and `PSETQ' forms operate identically to `SETF' and
538 ;;; `PSETF', but throw a compile-time error if the left-hand side form
539 ;;; is not a symbol. For example:
540
541 (setq a 1) => a = 1;
542
543 ;; but...
544
545 (setq (aref a 0) 1)
546 ;; => ERROR: The value (AREF A 0) is not of type SYMBOL.
547
548 ;;; New types of setf places can be defined in one of two ways: using
549 ;;; `DEFSETF' or using `DEFUN' with a setf function name; both are
550 ;;; analogous to their Common Lisp counterparts.
551
552 ;;; `DEFSETF' supports both long and short forms, while `DEFUN' of a
553 ;;; setf place generates a JavaScript function name with the __setf_
554 ;;; prefix:
555
556 (defun (setf color) (new-color el)
557 (setf (slot-value (slot-value el 'style) 'color) new-color))
558 => function __setf_color(newColor, el) {
559 el.style.color = newColor;
560 };
561
562 (setf (color some-div) (+ 23 "em"))
563 => var _js2 = someDiv;
564 var _js1 = 23 + 'em';
565 __setf_color(_js1, _js2);
566
567 ;;; Note that temporary variables are generated to preserve evaluation
568 ;;; order of the arguments as they would be in Lisp.
569
570 ;;; The following example illustrates how setf places can be used to
571 ;;; provide a uniform protocol for positioning elements in HTML pages:
572
573 (defsetf left (el) (offset)
574 `(setf (slot-value (slot-value ,el 'style) 'left) ,offset))
575 => null
576
577 (setf (left some-div) (+ 123 "px"))
578 => var _js2 = someDiv;
579 var _js1 = 123 + 'px';
580 _js2.style.left = _js1;
581
582 (progn (defmacro left (el)
583 `(slot-value ,el 'offset-left))
584 (left some-div))
585 => someDiv.offsetLeft;
586
587 ;;;# Single argument statements
588 ;;;t \index{single-argument statement}
589 ;;;t \index{RETURN}
590 ;;;t \index{THROW}
591 ;;;t \index{THROW}
592 ;;;t \index{function}
593
594 ; (RETURN {value}?)
595 ; (THROW {value}?)
596 ;
597 ; value ::= a Parenscript expression
598
599 ;;; The single argument statements `return' and `throw' are generated
600 ;;; by the form `RETURN' and `THROW'. `THROW' has to be used inside a
601 ;;; `TRY' form. `RETURN' is used to return a value from a function
602 ;;; call.
603
604 (return 1) => return 1
605
606 (throw "foobar") => throw 'foobar'
607
608 ;;;# Single argument expression
609 ;;;t \index{single-argument expression}
610 ;;;t \index{object creation}
611 ;;;t \index{object deletion}
612 ;;;t \index{DELETE}
613 ;;;t \index{VOID}
614 ;;;t \index{TYPEOF}
615 ;;;t \index{INSTANCEOF}
616 ;;;t \index{NEW}
617 ;;;t \index{new}
618
619 ; (DELETE {value})
620 ; (VOID {value})
621 ; (TYPEOF {value})
622 ; (INSTANCEOF {value})
623 ; (NEW {value})
624 ;
625 ; value ::= a Parenscript expression
626
627 ;;; The single argument expressions `delete', `void', `typeof',
628 ;;; `instanceof' and `new' are generated by the forms `DELETE',
629 ;;; `VOID', `TYPEOF', `INSTANCEOF' and `NEW'. They all take a
630 ;;; Parenscript expression.
631
632 (delete (new (*foobar 2 3 4))) => delete new Foobar(2, 3, 4)
633
634 (if (= (typeof blorg) *string)
635 (alert (+ "blorg is a string: " blorg))
636 (alert "blorg is not a string"))
637 => if (typeof blorg == String) {
638 alert('blorg is a string: ' + blorg);
639 } else {
640 alert('blorg is not a string');
641 }
642
643 ;;;# Conditional Statements
644 ;;;t \index{conditional statements}
645 ;;;t \index{IF}
646 ;;;t \index{WHEN}
647 ;;;t \index{UNLESS}
648 ;;;t \index{conditionals}
649
650 ; (IF conditional then {else})
651 ; (WHEN condition then)
652 ; (UNLESS condition then)
653 ;
654 ; condition ::= a Parenscript expression
655 ; then ::= a Parenscript statement in statement context, a
656 ; Parenscript expression in expression context
657 ; else ::= a Parenscript statement in statement context, a
658 ; Parenscript expression in expression context
659
660 ;;; The `IF' form compiles to the `if' javascript construct. An
661 ;;; explicit `PROGN' around the then branch and the else branch is
662 ;;; needed if they consist of more than one statement. When the `IF'
663 ;;; form is used in an expression context, a JavaScript `?', `:'
664 ;;; operator form is generated.
665
666 (if (blorg.is-correct)
667 (progn (carry-on) (return i))
668 (alert "blorg is not correct!"))
669 => if (blorg.isCorrect()) {
670 carryOn();
671 return i;
672 } else {
673 alert('blorg is not correct!');
674 }
675
676 (+ i (if (blorg.add-one) 1 2))
677 => i + (blorg.addOne() ? 1 : 2)
678
679 ;;; The `WHEN' and `UNLESS' forms can be used as shortcuts for the
680 ;;; `IF' form.
681
682 (when (blorg.is-correct)
683 (carry-on)
684 (return i))
685 => if (blorg.isCorrect()) {
686 carryOn();
687 return i;
688 }
689
690 (unless (blorg.is-correct)
691 (alert "blorg is not correct!"))
692 => if (!blorg.isCorrect()) {
693 alert('blorg is not correct!');
694 }
695
696 ;;;# Variable declaration
697 ;;;t \index{variable}
698 ;;;t \index{variable declaration}
699 ;;;t \index{binding}
700 ;;;t \index{scoping}
701 ;;;t \index{DEFVAR}
702 ;;;t \index{VAR}
703 ;;;t \index{LET}
704 ;;;t \index{LET*}
705 ;;;t \index{LEXICAL-LET}
706 ;;;t \index{LEXICAL-LET*}
707
708 ; (DEFVAR var {value}?)
709 ; (VAR var {value}?)
710 ; (LET ({var | (var value)}*) body)
711 ; (LET* ({var | (var value)}*) body)
712 ; (LEXICAL-LET ({var | (var value)}*) body)
713 ; (LEXICAL-LET* ({var | (var value)}*) body)
714 ;
715 ; var ::= a Lisp symbol
716 ; value ::= a Parenscript expression
717 ; body ::= a list of Parenscript statements
718
719 ;;; Parenscript special variables can be declared using the `DEFVAR'
720 ;;; special form, which is similar to its equivalent form in
721 ;;; Lisp. Note that the result is undefined if `DEFVAR' is not used as
722 ;;; a top-level form.
723
724 (defvar *a* (array 1 2 3)) => var A = [ 1, 2, 3 ]
725
726 ;;; One feature present in Parenscript that is not part of Common Lisp
727 ;;; are lexically-scoped global variables, which are declared using
728 ;;; the `VAR' special form.
729
730 ;;; Parenscript provides two versions of the `LET' and `LET*' special
731 ;;; forms for manipulating local variables: `SIMPLE-LET' /
732 ;;; `SIMPLE-LET*' and `LEXICAL-LET' / `LEXICAL-LET*'. By default,
733 ;;; `LET' and `LET*' are aliased to `SIMPLE-LET' and `SIMPLE-LET*',
734 ;;; respectively.
735
736 ;;; `SIMPLE-LET' and `SIMPLE-LET*' bind their variable lists using
737 ;;; simple JavaScript assignment. This means that you cannot rely on
738 ;;; the bindings going out of scope at the end of the form.
739
740 ;;; `LEXICAL-LET' and `LEXICAL-LET*' actually introduce new lexical
741 ;;; environments for the variable bindings by creating anonymous
742 ;;; functions.
743
744 ;;; As you would expect, `SIMPLE-LET' and `LEXICAL-LET' do parallel
745 ;;; binding of their variable lists, while `SIMPLE-LET*' and
746 ;;; `LEXICAL-LET*' bind their variable lists sequentially.
747
748 ;;; examples:
749
750 (simple-let* ((a 0) (b 1))
751 (alert (+ a b)))
752 => var a = 0;
753 var b = 1;
754 alert(a + b);
755
756 (simple-let* ((a "World") (b "Hello"))
757 (simple-let ((a b) (b a))
758 (alert (+ a b))))
759 => var a = 'World';
760 var b = 'Hello';
761 var _js_a1 = b;
762 var _js_b2 = a;
763 var a = _js_a1;
764 var b = _js_b2;
765 delete _js_a1;
766 delete _js_b2;
767 alert(a + b);
768
769 (simple-let* ((a 0) (b 1))
770 (lexical-let* ((a 9) (b 8))
771 (alert (+ a b)))
772 (alert (+ a b)))
773 => var a = 0;
774 var b = 1;
775 (function () {
776 var a = 9;
777 var b = 8;
778 alert(a + b);
779 })();
780 alert(a + b);
781
782 (simple-let* ((a "World") (b "Hello"))
783 (lexical-let ((a b) (b a))
784 (alert (+ a b)))
785 (alert (+ a b)))
786 => var a = 'World';
787 var b = 'Hello';
788 (function (a, b) {
789 alert(a + b);
790 })(b, a);
791 alert(a + b);
792
793 ;;; Moreover, beware that scoping rules in Lisp and JavaScript are
794 ;;; quite different. For example, don't rely on closures capturing
795 ;;; local variables in the way that you would normally expect.
796
797 ;;;# Iteration constructs
798 ;;;t \index{iteration}
799 ;;;t \index{iteration construct}
800 ;;;t \index{loop}
801 ;;;t \index{array traversal}
802 ;;;t \index{property}
803 ;;;t \index{object property}
804 ;;;t \index{DO}
805 ;;;t \index{DOTIMES}
806 ;;;t \index{DOLIST}
807 ;;;t \index{DOEACH}
808 ;;;t \index{WHILE}
809
810 ; (DO ({var | (var {init}? {step}?)}*) (end-test {result}?) body)
811 ; (DO* ({var | (var {init}? {step}?)}*) (end-test {result}?) body)
812 ; (DOTIMES (var numeric-form {result}?) body)
813 ; (DOLIST (var list-form {result}?) body)
814 ; (DOEACH ({var | (key value)} object-form {result}?) body)
815 ; (WHILE end-test body)
816 ;
817 ; var ::= a Lisp symbol
818 ; numeric-form ::= a Parenscript expression resulting in a number
819 ; list-form ::= a Parenscript expression resulting in an array
820 ; object-form ::= a Parenscript expression resulting in an object
821 ; init ::= a Parenscript expression
822 ; step ::= a Parenscript expression
823 ; end-test ::= a Parenscript expression
824 ; result ::= a Parenscript expression
825 ; body ::= a list of Parenscript statements
826
827 ;;; All interation special forms are transformed into JavaScript `for'
828 ;;; statements and, if needed, lambda expressions.
829
830 ;;; `DO', `DO*', and `DOTIMES' carry the same semantics as their
831 ;;; Common Lisp equivalents.
832
833 ;;; `DO*' (note the variety of possible init-forms:
834
835 (do* ((a) b (c (array "a" "b" "c" "d" "e"))
836 (d 0 (1+ d))
837 (e (aref c d) (aref c d)))
838 ((or (= d c.length) (eql e "x")))
839 (setf a d b e)
840 (document.write (+ "a: " a " b: " b "<br/>")))
841 => 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]) {
842 a = d;
843 b = e;
844 document.write('a: ' + a + ' b: ' + b + '<br/>');
845 };
846
847 ;;; `DO' (note the parallel assignment):
848
849 (do ((i 0 (1+ i))
850 (s 0 (+ s i (1+ i))))
851 ((> i 10))
852 (document.write (+ "i: " i " s: " s "<br/>")))
853 => var _js_i1 = 0;
854 var _js_s2 = 0;
855 var i = _js_i1;
856 var s = _js_s2;
857 delete _js_i1;
858 delete _js_s2;
859 for (; i <= 10; ) {
860 document.write('i: ' + i + ' s: ' + s + '<br/>');
861 var _js3 = i + 1;
862 var _js4 = s + i + (i + 1);
863 i = _js3;
864 s = _js4;
865 };
866
867 ;;; compare to `DO*':
868
869 (do* ((i 0 (1+ i))
870 (s 0 (+ s i (1- i))))
871 ((> i 10))
872 (document.write (+ "i: " i " s: " s "<br/>")))
873 => for (var i = 0, s = 0; i <= 10; i += 1, s += i + (i - 1)) {
874 document.write('i: ' + i + ' s: ' + s + '<br/>');
875 };
876
877 ;;; `DOTIMES':
878
879 (let* ((arr (array "a" "b" "c" "d" "e")))
880 (dotimes (i arr.length)
881 (document.write (+ "i: " i " arr[i]: " (aref arr i) "<br/>"))))
882 => var arr = ['a', 'b', 'c', 'd', 'e'];
883 for (var i = 0; i < arr.length; i += 1) {
884 document.write('i: ' + i + ' arr[i]: ' + arr[i] + '<br/>');
885 };
886
887 ;;; `DOTIMES' with return value:
888
889 (let* ((res 0))
890 (alert (+ "Summation to 10 is "
891 (dotimes (i 10 res)
892 (incf res (1+ i))))))
893 => var res = 0;
894 alert('Summation to 10 is ' + (function () {
895 for (var i = 0; i < 10; i += 1) {
896 res += i + 1;
897 };
898 return res;
899 })());
900
901 ;;; `DOLIST' is like CL:DOLIST, but that it operates on numbered JS
902 ;;; arrays/vectors.
903
904 (let* ((l (list 1 2 4 8 16 32)))
905 (dolist (c l)
906 (document.write (+ "c: " c "<br/>"))))
907 => var l = [1, 2, 4, 8, 16, 32];
908 for (var c = null, _js_arrvar2 = l, _js_idx1 = 0; _js_idx1 < _js_arrvar2.length; _js_idx1 += 1) {
909 c = _js_arrvar2[_js_idx1];
910 document.write('c: ' + c + '<br/>');
911 };
912
913 (let* ((l (list 1 2 4 8 16 32))
914 (s 0))
915 (alert (+ "Sum of " l " is: "
916 (dolist (c l s)
917 (incf s c)))))
918 => var l = [1, 2, 4, 8, 16, 32];
919 var s = 0;
920 alert('Sum of ' + l + ' is: ' + (function () {
921 for (var c = null, _js_arrvar2 = l, _js_idx1 = 0; _js_idx1 < _js_arrvar2.length; _js_idx1 += 1) {
922 c = _js_arrvar2[_js_idx1];
923 s += c;
924 };
925 return s;
926 })());
927
928 ;;; `DOEACH' iterates across the enumerable properties of JS objects,
929 ;;; binding either simply the key of each slot, or alternatively, both
930 ;;; the key and the value.
931
932 (let* ((obj (create :a 1 :b 2 :c 3)))
933 (doeach (i obj)
934 (document.write (+ i ": " (aref obj i) "<br/>"))))
935 => var obj = { a : 1, b : 2, c : 3 };
936 for (var i in obj) {
937 document.write(i + ': ' + obj[i] + '<br/>');
938 };
939
940 (let* ((obj (create :a 1 :b 2 :c 3)))
941 (doeach ((k v) obj)
942 (document.write (+ k ": " v "<br/>"))))
943 => var obj = { a : 1, b : 2, c : 3 };
944 var v;
945 for (var k in obj) {
946 v = obj[k];
947 document.write(k + ': ' + v + '<br/>');
948 };
949
950 ;;; The `WHILE' form is transformed to the JavaScript form `while',
951 ;;; and loops until a termination test evaluates to false.
952
953 (while (film.is-not-finished)
954 (this.eat (new *popcorn)))
955 => while (film.isNotFinished()) {
956 this.eat(new Popcorn);
957 }
958
959 ;;;# The `CASE' statement
960 ;;;t \index{CASE}
961 ;;;t \index{SWITCH}
962 ;;;t \index{switch}
963
964 ; (CASE case-value clause*)
965 ;
966 ; clause ::= (value body) | ((value*) body) | t-clause
967 ; case-value ::= a Parenscript expression
968 ; value ::= a Parenscript expression
969 ; t-clause ::= {t | otherwise | default} body
970 ; body ::= a list of Parenscript statements
971
972 ;;; The Lisp `CASE' form is transformed to a `switch' statement in
973 ;;; JavaScript. Note that `CASE' is not an expression in
974 ;;; Parenscript.
975
976 (case (aref blorg i)
977 ((1 "one") (alert "one"))
978 (2 (alert "two"))
979 (t (alert "default clause")))
980 => switch (blorg[i]) {
981 case 1:
982 case 'one':
983 alert('one');
984 break;
985 case 2:
986 alert('two');
987 break;
988 default:
989 alert('default clause');
990 }
991
992 ; (SWITCH case-value clause*)
993 ; clause ::= (value body) | (default body)
994
995 ;;; The `SWITCH' form is the equivalent to a javascript switch statement.
996 ;;; No break statements are inserted, and the default case is named `DEFAULT'.
997 ;;; The `CASE' form should be prefered in most cases.
998
999 (switch (aref blorg i)
1000 (1 (alert "If I get here"))
1001 (2 (alert "I also get here"))
1002 (default (alert "I always get here")))
1003 => switch (blorg[i]) {
1004 case 1: alert('If I get here');
1005 case 2: alert('I also get here');
1006 default: alert('I always get here');
1007 }
1008
1009 ;;;# The `WITH' statement
1010 ;;;t \index{WITH}
1011 ;;;t \index{dynamic scope}
1012 ;;;t \index{binding}
1013 ;;;t \index{scoping}
1014 ;;;t \index{closure}
1015
1016 ; (WITH object body)
1017 ;
1018 ; object ::= a Parenscript expression evaluating to an object
1019 ; body ::= a list of Parenscript statements
1020
1021 ;;; The `WITH' form is compiled to a JavaScript `with' statements, and
1022 ;;; adds the object `object' as an intermediary scope objects when
1023 ;;; executing the body.
1024
1025 (with (create :foo "foo" :i "i")
1026 (alert (+ "i is now intermediary scoped: " i)))
1027 => with ({ foo : 'foo', i : 'i' }) {
1028 alert('i is now intermediary scoped: ' + i);
1029 }
1030
1031 ;;;# The `TRY' statement
1032 ;;;t \index{TRY}
1033 ;;;t \index{CATCH}
1034 ;;;t \index{FINALLY}
1035 ;;;t \index{exception}
1036 ;;;t \index{error handling}
1037
1038 ; (TRY body {(:CATCH (var) body)}? {(:FINALLY body)}?)
1039 ;
1040 ; body ::= a list of Parenscript statements
1041 ; var ::= a Lisp symbol
1042
1043 ;;; The `TRY' form is converted to a JavaScript `try' statement, and
1044 ;;; can be used to catch expressions thrown by the `THROW'
1045 ;;; form. The body of the catch clause is invoked when an exception
1046 ;;; is catched, and the body of the finally is always invoked when
1047 ;;; leaving the body of the `TRY' form.
1048
1049 (try (throw "i")
1050 (:catch (error)
1051 (alert (+ "an error happened: " error)))
1052 (:finally
1053 (alert "Leaving the try form")))
1054 => try {
1055 throw 'i';
1056 } catch (error) {
1057 alert('an error happened: ' + error);
1058 } finally {
1059 alert('Leaving the try form');
1060 }
1061
1062 ;;;# The HTML Generator
1063 ;;;t \index{PS-HTML}
1064 ;;;t \index{HTML generation}
1065
1066 ; (PS-HTML html-expression)
1067
1068 ;;; The HTML generator of Parenscript is very similar to the htmlgen
1069 ;;; HTML generator library included with AllegroServe. It accepts the
1070 ;;; same input forms as the AllegroServer HTML generator. However,
1071 ;;; non-HTML construct are compiled to JavaScript by the Parenscript
1072 ;;; compiler. The resulting expression is a JavaScript expression.
1073
1074 (ps-html ((:a :href "foobar") "blorg"))
1075 => '<A HREF=\"foobar\">blorg</A>'
1076
1077 (ps-html ((:a :href (generate-a-link)) "blorg"))
1078 => '<A HREF=\"' + generateALink() + '\">blorg</A>'
1079
1080 ;;; We can recursively call the Parenscript compiler in an HTML
1081 ;;; expression.
1082
1083 (document.write
1084 (ps-html ((:a :href "#"
1085 :onclick (ps-inline (transport))) "link")))
1086 => document.write('<A HREF=\"#\" ONCLICK=\"' + ('javascript:' + 'transport()') + '\">link</A>')
1087
1088 ;;; Forms may be used in attribute lists to conditionally generate
1089 ;;; the next attribute. In this example the textarea is sometimes disabled.
1090
1091 (let* ((disabled nil)
1092 (authorized t))
1093 (setf element.inner-h-t-m-l
1094 (ps-html ((:textarea (or disabled (not authorized)) :disabled "disabled")
1095 "Edit me"))))
1096 => var disabled = null;
1097 var authorized = true;
1098 element.innerHTML =
1099 '<TEXTAREA'
1100 + (disabled || !authorized ? ' DISABLED=\"' + 'disabled' + '\"' : '')
1101 + '>Edit me</TEXTAREA>';
1102
1103 ;;;# Macrology
1104 ;;;t \index{macro}
1105 ;;;t \index{macrology}
1106 ;;;t \index{DEFPSMACRO}
1107 ;;;t \index{DEFMACRO/PS}
1108 ;;;t \index{DEFMACRO+PS}
1109 ;;;t \index{DEFINE-PS-SYMBOL-MACRO}
1110 ;;;t \index{IMPORT-MACROS-FROM-LISP}
1111 ;;;t \index{MACROLET}
1112 ;;;t \index{SYMBOL-MACROLET}
1113 ;;;t \index{PS-GENSYM}
1114 ;;;t \index{compiler}
1115
1116 ; (DEFPSMACRO name lambda-list macro-body)
1117 ; (DEFPSMACRO/PS name lambda-list macro-body)
1118 ; (DEFPSMACRO+PS name lambda-list macro-body)
1119 ; (DEFINE-PS-SYMBOL-MACRO symbol expansion)
1120 ; (IMPORT-MACROS-FROM-LISP symbol*)
1121 ; (MACROLET ({name lambda-list macro-body}*) body)
1122 ; (SYMBOL-MACROLET ({name macro-body}*) body)
1123 ; (PS-GENSYM {string})
1124 ;
1125 ; name ::= a Lisp symbol
1126 ; lambda-list ::= a lambda list
1127 ; macro-body ::= a Lisp body evaluating to Parenscript code
1128 ; body ::= a list of Parenscript statements
1129 ; string ::= a string
1130
1131 ;;; Parenscript can be extended using macros, just like Lisp can be
1132 ;;; extended using Lisp macros. Using the special Lisp form
1133 ;;; `DEFPSMACRO', the Parenscript language can be
1134 ;;; extended. `DEFPSMACRO' adds the new macro to the toplevel macro
1135 ;;; environment, which is always accessible during Parenscript
1136 ;;; compilation. For example, the `1+' and `1-' operators are
1137 ;;; implemented using macros.
1138
1139 (defpsmacro 1- (form)
1140 `(- ,form 1))
1141
1142 (defpsmacro 1+ (form)
1143 `(+ ,form 1))
1144
1145 ;;; A more complicated Parenscript macro example is the implementation
1146 ;;; of the `DOLIST' form (note how `PS-GENSYM', the Parenscript of
1147 ;;; `GENSYM', is used to generate new Parenscript variable names):
1148
1149 (defpsmacro dolist ((var array &optional (result nil result?)) &body body)
1150 (let ((idx (ps-gensym "_js_idx"))
1151 (arrvar (ps-gensym "_js_arrvar")))
1152 `(do* (,var
1153 (,arrvar ,array)
1154 (,idx 0 (1+ ,idx)))
1155 ((>= ,idx (slot-value ,arrvar 'length))
1156 ,@(when result? (list result)))
1157 (setq ,var (aref ,arrvar ,idx))
1158 ,@body)))
1159
1160 ;;; Macros can be defined in Parenscript code itself (as opposed to
1161 ;;; from Lisp) by using the Parenscript `MACROLET' and `DEFMACRO'
1162 ;;; forms. Note that macros defined this way are defined in a null
1163 ;;; lexical environment (ex - (let ((x 1)) (defmacro baz (y) `(+ ,y
1164 ;;; ,x))) will not work), since the surrounding Parenscript code is
1165 ;;; just translated to JavaScript and not actually evaluated.
1166
1167 ;;; Parenscript also supports the use of macros defined in the
1168 ;;; underlying Lisp environment. Existing Lisp macros can be imported
1169 ;;; into the Parenscript macro environment by
1170 ;;; `IMPORT-MACROS-FROM-LISP'. This functionality enables code sharing
1171 ;;; between Parenscript and Lisp, and is useful in debugging since the
1172 ;;; full power of Lisp macroexpanders, editors and other supporting
1173 ;;; facilities can be used. However, it is important to note that the
1174 ;;; macroexpansion of Lisp macros and Parenscript macros takes place
1175 ;;; in their own respective environments, and many Lisp macros
1176 ;;; (especially those provided by the Lisp implementation) expand into
1177 ;;; code that is not usable by Parenscript. To make it easy for users
1178 ;;; to take advantage of these features, two additional macro
1179 ;;; definition facilities are provided by Parenscript: `DEFMACRO/PS'
1180 ;;; and `DEFMACRO+PS'. `DEFMACRO/PS' defines a Lisp macro and then
1181 ;;; imports it into the Parenscript macro environment, while
1182 ;;; `DEFMACRO+PS' defines two macros with the same name and expansion,
1183 ;;; one in Parenscript and one in Lisp. `DEFMACRO+PS' is used when the
1184 ;;; full 'macroexpand' of the Lisp macro yields code that cannot be
1185 ;;; used by Parenscript.
1186
1187 ;;; Parenscript also supports symbol macros, which can be introduced
1188 ;;; using the Parenscript form `SYMBOL-MACROLET' or defined in Lisp
1189 ;;; with `DEFINE-PS-SYMBOL-MACRO'. For example, the Parenscript
1190 ;;; `WITH-SLOTS' is implemented using symbol macros.
1191
1192 (defpsmacro with-slots (slots object &rest body)
1193 `(symbol-macrolet ,(mapcar #'(lambda (slot)
1194 `(,slot '(slot-value ,object ',slot)))
1195 slots)
1196 ,@body))
1197
1198 ;;;# The Parenscript namespace system
1199 ;;;t \index{package}
1200 ;;;t \index{namespace}
1201 ;;;t \index{PS-PACKAGE-PREFIX}
1202
1203 ; (setf (PS-PACKAGE-PREFIX package-designator) string)
1204
1205 ;;; Although JavaScript does not offer namespacing or a package
1206 ;;; system, Parenscript does provide a namespace mechanism for
1207 ;;; generated JavaScript by integrating with the Common Lisp package
1208 ;;; system. Since Parenscript code is normally read in by the Lisp
1209 ;;; reader, all symbols (except for uninterned ones, ie - those
1210 ;;; specified with the #: reader macro) have a Lisp package. By
1211 ;;; default, no packages are prefixed. You can specify that symbols in
1212 ;;; a particular package receive a prefix when translated to
1213 ;;; JavaScript with the `PS-PACKAGE-PREFIX' place.
1214
1215 (defpackage "MY-LIBRARY"
1216 (:use #:parenscript))
1217 (setf (ps-package-prefix :my-library) "my_library_")
1218
1219 (defun my-library::library-function (x y)
1220 (return (+ x y)))
1221 -> function my_library_libraryFunction(x, y) {
1222 return x + y;
1223 }
1224
1225 ;;;# Identifier obfuscation
1226 ;;;t \index{obfuscation}
1227 ;;;t \index{identifiers}
1228 ;;;t \index{OBFUSCATE-PACKAGE}
1229 ;;;t \index{UNOBFUSCATE-PACKAGE}
1230
1231 ; (OBFUSCATE-PACKAGE package-designator)
1232 ; (UNOBFUSCATE-PACKAGE package-designator)
1233
1234 ;;; Similar to the namespace mechanism, Parenscript provides a
1235 ;;; facility to generate obfuscated identifiers in certain Lisp
1236 ;;; packages.
1237
1238 (defpackage "OBFUSCATE-ME")
1239 (obfuscate-package :obfuscate-me)
1240
1241 (defun obfuscate-me::library-function2 (a b obfuscate-me::foo)
1242 (+ a (my-library::library-function b obfuscate-me::foo)))
1243
1244 ;;; The obfuscation and namespace facilities can be used on packages
1245 ;;; at the same time.
1246
1247 ;;;# The Parenscript Compiler
1248 ;;;t \index{compiler}
1249 ;;;t \index{Parenscript compiler}
1250 ;;;t \index{PS}
1251 ;;;t \index{PS*}
1252 ;;;t \index{PS1*}
1253 ;;;t \index{PS-INLINE}
1254 ;;;t \index{PS-INLINE*}
1255 ;;;t \index{LISP}
1256
1257 ; (PS &body body)
1258 ; (PS* &body body)
1259 ; (PS1* parenscript-form)
1260 ; (PS-INLINE form &optional *js-string-delimiter*)
1261 ; (PS-INLINE* form &optional *js-string-delimiter*)
1262
1263 ; (LISP lisp-forms)
1264 ;
1265 ; body ::= Parenscript statements comprising an implicit `PROGN'
1266
1267 ;;; For static Parenscript code, the macro `PS' compiles the provided
1268 ;;; forms at Common Lisp macro-expansion time. `PS*' and `PS1*'
1269 ;;; evaluate their arguments and then compile them. All these forms
1270 ;;; except for `PS1*' treat the given forms as an implicit
1271 ;;; `PROGN'.
1272
1273 ;;; `PS-INLINE' and `PS-INLINE*' take a single Parenscript form and
1274 ;;; output a string starting with "javascript:" that can be used in
1275 ;;; HTML node attributes. As well, they provide an argument to bind
1276 ;;; the value of *js-string-delimiter* to control the value of the
1277 ;;; JavaScript string escape character to be compatible with whatever
1278 ;;; the HTML generation mechanism is used (for example, if HTML
1279 ;;; strings are delimited using #\', using #\" will avoid conflicts
1280 ;;; without requiring the output JavaScript code to be escaped). By
1281 ;;; default the value is taken from *js-inline-string-delimiter*.
1282
1283 ;;; Parenscript can also call out to arbitrary Common Lisp code at
1284 ;;; code output time using the special form `LISP'. The form provided
1285 ;;; to `LISP' is evaluated, and its result is compiled as though it
1286 ;;; were Parenscript code. For `PS' and `PS-INLINE', the Parenscript
1287 ;;; output code is generated at macro-expansion time, and the `LISP'
1288 ;;; statements are inserted inline and have access to the enclosing
1289 ;;; Common Lisp lexical environment. `PS*' and `PS1*' evaluate the
1290 ;;; `LISP' forms with eval, providing them access to the current
1291 ;;; dynamic environment only.