Implemented LET and LET* by variable renaming, which provides the
authorVladimir Sedach <vsedach@gmail.com>
Sun, 3 May 2009 20:42:12 +0000 (14:42 -0600)
committerVladimir Sedach <vsedach@gmail.com>
Sun, 3 May 2009 20:42:12 +0000 (14:42 -0600)
correct scoping semantics, and simplifies both the producing and the
produced code.

Removed the "." and "[]" name-mangling conventions from
symbol-to-js-string. Any code that uses symbols such as "foo.bar[baz]"
will now issue a warning, and needs to be rewritten to use standard
Lisp accessors. This is needed for variable renaming to work, and is
an extension of the patch that eliminated the ".method" method-calling
convention.

Thanks to Daniel Gackle and Dough Hoyte for opening my eyes to this
technique, which was right in front of me all along.

12 files changed:
docs/reference.lisp
parenscript.asd
src/compiler.lisp
src/lib/ps-macro-lib.lisp
src/namespace.lisp
src/package.lisp
src/printer.lisp
src/special-forms.lisp
src/utils.lisp
t/package-system-tests.lisp
t/ps-tests.lisp
t/reference-tests.lisp

index 7d86890..fca8684 100644 (file)
@@ -59,24 +59,12 @@ bla-foo-bar => blaFooBar
 
 *array => Array
 
-;;; The `.' character is left as is in symbols. This allows the
-;;; Parenscript programmer to use a practical shortcut when accessing
-;;; slots or methods of JavaScript objects. Instead of writing
-
-(slot-value foobar 'slot)
-
-;;; we can write
-
-foobar.slot
-
 ;;; 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
-
 ;;;## Reserved Keywords
 ;;;t \index{keyword}
 ;;;t \index{reserved keywords}
@@ -85,17 +73,16 @@ foobar.slot
 ;;; 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}
@@ -182,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}
@@ -218,9 +206,10 @@ WHEN WHILE WITH WITH-SLOTS
 
 (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
@@ -309,8 +298,6 @@ a-variable  => aVariable
 
 *math       => Math
 
-*math.floor => Math.floor
-
 ;;;# Function calls and method calls
 ;;;t \index{function}
 ;;;t \index{function call}
@@ -341,15 +328,6 @@ a-variable  => aVariable
 
 ((slot-value (aref foobar 1) 'blorg) NIL T) => foobar[1].blorg(null, true)
 
-;;; Note that while most method calls can be abbreviated using the "."
-;;; trick in symbol names (see "Symbol Conversion" above), this is not
-;;; advised due to the fact that "object.function" is treated as a
-;;; symbol distinct from both "object" and "function," which will
-;;; cause problems if Parenscript package prefixes or package
-;;; obfuscation is used.
-
-(this.blorg 1 2) => this.blorg(1, 2)
-
 ;;;# Operator Expressions
 ;;;t \index{operator}
 ;;;t \index{operator expression}
@@ -525,14 +503,14 @@ 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;
-   var _js1 = b;
-   var _js2 = a;
-   a = _js1;
-   b = _js2;
+=> var a1 = 1;
+   var b2 = 2;
+   var _js3_5 = b2;
+   var _js4_6 = a1;
+   a1 = _js3_5;
+   b2 = _js4_6;
 
 ;;; The `SETQ' and `PSETQ' forms operate identically to `SETF' and
 ;;; `PSETF', but throw a compile-time error if the left-hand side form
@@ -560,9 +538,9 @@ a-variable  => aVariable
    };
 
 (setf (color some-div) (+ 23 "em"))
-=> var _js2 = someDiv;
-   var _js1 = 23 + 'em';
-   __setf_color(_js1, _js2);
+=> var _js2_3 = someDiv;
+   var _js1_4 = 23 + 'em';
+   __setf_color(_js1_4, _js2_3);
 
 ;;; Note that temporary variables are generated to preserve evaluation
 ;;; order of the arguments as they would be in Lisp.
@@ -575,9 +553,9 @@ a-variable  => aVariable
 => null
 
 (setf (left some-div) (+ 123 "px"))
-=> var _js2 = someDiv;
-   var _js1 = 123 + 'px';
-   _js2.style.left = _js1;
+=> var _js2_3 = someDiv;
+   var _js1_4 = 123 + 'px';
+   _js2_3.style.left = _js1_4;
 
 (progn (defmacro left (el)
          `(slot-value ,el 'offset-left))
@@ -663,7 +641,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()) {
@@ -673,13 +651,13 @@ a-variable  => aVariable
        alert('blorg is not correct!');
    }
 
-(+ i (if (blorg.add-one) 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()) {
@@ -687,7 +665,7 @@ a-variable  => aVariable
        return i;
    }
 
-(unless (blorg.is-correct)
+(unless ((@ blorg is-correct))
   (alert "blorg is not correct!"))
 => if (!blorg.isCorrect()) {
        alert('blorg is not correct!');
@@ -702,15 +680,11 @@ 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
@@ -727,72 +701,38 @@ a-variable  => aVariable
 ;;; 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 x1 = 1;
+   var A2;
+   try {
+       A2 = A;
+       A = 2;
+       var y3 = x1 + 1;
+       var x4 = x1 + y3;
+       A + x4 + y3;
+   } finally {
+       A = A2;
+   };
 
 ;;;# Iteration constructs
 ;;;t \index{iteration}
@@ -835,33 +775,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)) (eql 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;
-   for (; i <= 10; ) {
-       document.write('i: ' + i + ' s: ' + s + '<br/>');
-       var _js3 = i + 1;
-       var _js4 = s + i + (i + 1);
-       i = _js3;
-       s = _js4;
+  ((@ document write) (+ "i: " i " s: " s "<br/>")))
+=> var i1 = 0;
+   var s2 = 0;
+   for (; i1 <= 10; ) {
+       document.write('i: ' + i1 + ' s: ' + s2 + '<br/>');
+       var _js3_5 = i1 + 1;
+       var _js4_6 = s2 + i1 + (i1 + 1);
+       i1 = _js3_5;
+       s2 = _js4_6;
    };
 
 ;;; compare to `DO*':
@@ -869,77 +805,77 @@ 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/>"))))
-=> 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/>');
+(let ((arr (array "a" "b" "c" "d" "e")))
+  (dotimes (i (@ arr length))
+    ((@ document write) (+ "i: " i " arr[i]: " (aref arr i) "<br/>"))))
+=> var arr1 = ['a', 'b', 'c', 'd', 'e'];
+   for (var i = 0; i < arr1.length; i += 1) {
+       document.write('i: ' + i + ' arr[i]: ' + arr1[i] + '<br/>');
    };
 
 ;;; `DOTIMES' with return value:
 
-(let* ((res 0))
+(let ((res 0))
   (alert (+ "Summation to 10 is "
             (dotimes (i 10 res)
               (incf res (1+ i))))))
-=> var res = 0;
+=> var res1 = 0;
    alert('Summation to 10 is ' + (function () {
        for (var i = 0; i < 10; i += 1) {
-           res += i + 1;
+           res1 += i + 1;
        };
-       return res;
+       return res1;
    })());
 
 ;;; `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/>"))))
-=> 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/>"))))
+=> var l1 = [1, 2, 4, 8, 16, 32];
+   for (var c = null, _js_arrvar3 = l1, _js_idx2 = 0; _js_idx2 < _js_arrvar3.length; _js_idx2 += 1) {
+       c = _js_arrvar3[_js_idx2];
        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)))))
-=> var l = [1, 2, 4, 8, 16, 32];
-   var s = 0;
-   alert('Sum of ' + l + ' is: ' + (function () {
-       for (var c = null, _js_arrvar2 = l, _js_idx1 = 0; _js_idx1 < _js_arrvar2.length; _js_idx1 += 1) {
-           c = _js_arrvar2[_js_idx1];
-           s += c;
+=> var l1 = [1, 2, 4, 8, 16, 32];
+   var s2 = 0;
+   alert('Sum of ' + l1 + ' is: ' + (function () {
+       for (var c = null, _js_arrvar4 = l1, _js_idx3 = 0; _js_idx3 < _js_arrvar4.length; _js_idx3 += 1) {
+           c = _js_arrvar4[_js_idx3];
+           s2 += c;
        };
-       return s;
+       return s2;
    })());
 
 ;;; `FOR-IN' is translated to the JS `for...in' statement.
 
-(let* ((obj (create :a 1 :b 2 :c 3)))
+(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/>');
+    ((@ document write) (+ i ": " (aref obj i) "<br/>"))))
+=> var obj1 = { a : 1, b : 2, c : 3 };
+   for (var i in obj1) {
+       document.write(i + ': ' + obj1[i] + '<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);
    }
@@ -1068,7 +1004,7 @@ a-variable  => aVariable
 ;;; We can recursively call the Parenscript compiler in an HTML
 ;;; expression.
 
-(document.write
+((@ document write)
   (ps-html ((:a :href "#"
                 :onclick (ps-inline (transport))) "link")))
 => document.write('<A HREF=\"#\" ONCLICK=\"' + ('javascript:' + 'transport' + '(' + ')') + '\">link</A>')
@@ -1076,16 +1012,16 @@ a-variable  => aVariable
 ;;; 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;
-   var authorized = true;
+=> var disabled1 = null;
+   var authorized2 = true;
    element.innerHTML =
    '<TEXTAREA'
-   + (disabled || !authorized ? ' DISABLED=\"' + 'disabled' + '\"' : '')
+   + (disabled1 || !authorized2 ? ' DISABLED=\"' + 'disabled' + '\"' : '')
    + '>Edit me</TEXTAREA>';
 
 ;;;# Macrology
index c8d5696..e31b99e 100755 (executable)
@@ -36,7 +36,7 @@
                (:module :runtime
                         :components ((:file "ps-runtime-lib"))
                         :depends-on (:src)))
-  :depends-on ())
+  :depends-on (:cl-ppcre))
 
 (defmethod asdf:perform :after ((op asdf:load-op) (system (eql (asdf:find-system :parenscript)))) 
   (pushnew :parenscript cl:*features*))
@@ -53,7 +53,7 @@
                                      (:file "reference-tests")
                                      (:file "ps-tests")
                                      (:file "package-system-tests"))))
-  :depends-on (:parenscript :fiveam :cl-ppcre))
+  :depends-on (:parenscript :fiveam))
 
 (defmethod asdf:perform ((o test-op) (c (eql (find-system :parenscript.test))))
   (asdf:operate 'asdf:load-op :parenscript.test)
index 2281ab3..0cc8dc7 100644 (file)
@@ -52,6 +52,9 @@ lexical block.")
 
 (defvar *ps-special-variables* ())
 
+(defun ps-special-variable-p (sym)
+  (member sym *ps-special-variables*))
+
 ;;; form predicates
 
 (defun op-form-p (form)
@@ -273,7 +276,10 @@ the form cannot be compiled to a symbol."
 (defvar *ps-gensym-counter* 0)
 
 (defun ps-gensym (&optional (prefix "_js"))
-  (make-symbol (format nil "~A~A" prefix (incf *ps-gensym-counter*))))
+  (let ((prefix (if (stringp prefix) prefix (symbol-to-js-string prefix nil))))
+    (make-symbol (format nil "~A~:[~;_~]~A" prefix
+                         (digit-char-p (char prefix (1- (length prefix))))
+                         (incf *ps-gensym-counter*)))))
 
 (defmacro with-ps-gensyms (symbols &body body)
   "Evaluate BODY with SYMBOLS bound to unique ParenScript identifiers.
index e6c32be..e3341e0 100644 (file)
@@ -1,4 +1,4 @@
-(in-package :parenscript)
+(in-package "PARENSCRIPT")
 
 ;;; Handy utilities for doing common tasks found in many web browser
 ;;; JavaScript implementations
   `(progn ,@(mapcar (lambda (def) (cons 'defpsmacro def)) mathdefs)))
 
 (def-js-maths
-    (max (&rest nums) `(*math.max ,@nums))
-    (min (&rest nums) `(*math.min ,@nums))
-    (floor (n &optional divisor) `(*math.floor ,(if divisor `(/ ,n ,divisor) n)))
-    (ceiling (n &optional divisor) `(*math.ceil ,(if divisor `(/ ,n ,divisor) n)))
-    (round (n &optional divisor) `(*math.round ,(if divisor `(/ ,n ,divisor) n)))
-    (sin (n) `(*math.sin ,n))
-    (cos (n) `(*math.cos ,n))
-    (tan (n) `(*math.tan ,n))
-    (asin (n) `(*math.asin ,n))
-    (acos (n) `(*math.acos ,n))
-    (atan (y &optional x) (if x `(*math.atan2 ,y ,x) `(*math.atan ,y)))
+    (max (&rest nums) `((@ *math max) ,@nums))
+    (min (&rest nums) `((@ *math min) ,@nums))
+    (floor (n &optional divisor) `((@ *math floor) ,(if divisor `(/ ,n ,divisor) n)))
+    (ceiling (n &optional divisor) `((@ *math ceil) ,(if divisor `(/ ,n ,divisor) n)))
+    (round (n &optional divisor) `((@ *math round) ,(if divisor `(/ ,n ,divisor) n)))
+    (sin (n) `((@ *math sin) ,n))
+    (cos (n) `((@ *math cos) ,n))
+    (tan (n) `((@ *math tan) ,n))
+    (asin (n) `((@ *math asin) ,n))
+    (acos (n) `((@ *math acos) ,n))
+    (atan (y &optional x) (if x `((@ *math atan2) ,y ,x) `((@ *math atan) ,y)))
     (sinh (n) `((lambda (x) (return (/ (- (exp x) (exp (- x))) 2))) ,n))
     (cosh (n) `((lambda (x) (return (/ (+ (exp x) (exp (- x))) 2))) ,n))
     (tanh (n) `((lambda (x) (return (/ (- (exp x) (exp (- x))) (+ (exp x) (exp (- x)))))) ,n))
     (atanh (n) `((lambda (x) (return (/ (- (log (+ 1 x)) (log (- 1 x))) 2))) ,n))
     (1+ (n) `(+ ,n 1))
     (1- (n) `(- ,n 1))
-    (abs (n) `(*math.abs ,n))
+    (abs (n) `((@ *math abs) ,n))
     (evenp (n) `(not (oddp ,n)))
     (oddp (n) `(% ,n 2))
-    (exp (n) `(*math.exp ,n))
-    (expt (base power) `(*math.pow ,base ,power))
+    (exp (n) `((@ *math exp) ,n))
+    (expt (base power) `((@ *math pow) ,base ,power))
     (log (n &optional base)
-      (or (and (null base) `(*math.log ,n))
-          (and (numberp base) (= base 10) `(* (log ,n) *math.*log10e*))
+      (or (and (null base) `((@ *math log) ,n))
+          (and (numberp base) (= base 10) `(* (log ,n) (@ *math *log10e*)))
           `(/ (log ,n) (log ,base))))
-    (sqrt (n) `(*math.sqrt ,n))
+    (sqrt (n) `((@ *math sqrt) ,n))
     (random (&optional upto) (if upto
-                                 `(floor (* ,upto (*math.random)))
-                                 '(*math.random))))
+                                 `(floor (* ,upto ((@ *math random))))
+                                 '((@ *math random)))))
 
-(define-ps-symbol-macro pi *math.*pi*)
+(define-ps-symbol-macro pi (@ *math *pi*))
 
 ;;; Exception handling
 
index 4bc2798..37b5b0d 100644 (file)
 designated package when translating ParenScript code."
   `(gethash (find-package ,package) *package-prefix-table*))
 
-(defun symbol-to-js-string (symbol)
-  (let ((symbol-name (symbol-name-to-js-string (maybe-obfuscate-symbol symbol))))
+(defun symbol-to-js-string (symbol &optional (mangle-symbol-name t))
+  (let ((symbol-name (funcall (if mangle-symbol-name
+                                  #'symbol-name-to-js-string
+                                  #'symbol-name)
+                              (maybe-obfuscate-symbol symbol))))
     (aif (ps-package-prefix (symbol-package symbol))
          (format nil "~A~A" it symbol-name)
          symbol-name)))
index b57330b..41fbb6a 100644 (file)
       #:psetf
       #:setq
       #:psetq
-      #:simple-let*
-      #:simple-let
-      #:lexical-let*
-      #:lexical-let
       #:let*
       #:let
 
index a4526ed..b649dae 100644 (file)
@@ -281,7 +281,7 @@ arguments, defines a printer for that form using the given body."
   (ps-print body-block))
 
 (defprinter js:for-in (var object body-block)
-  (psw "for (") (ps-print var) (psw " in ")
+  (psw "for (var ") (ps-print var) (psw " in ")
   (if (> (expression-precedence object) (op-precedence 'in))
       (parenthesize-print object)
       (ps-print object))
index 733db12..62d3864 100644 (file)
 ;;; function definition
 (defun compile-function-definition (args body)
   (list (mapcar (lambda (arg) (compile-parenscript-form arg :expecting :symbol)) args)
-        (let ((*enclosing-lexical-block-declarations* ()))
-          ;; the first compilation will produce a list of variables we need to declare in the function body
-          (compile-parenscript-form `(progn ,@body) :expecting :statement)
-          ;; now declare and compile
-          (compile-parenscript-form `(progn
-                                       ,@(mapcar (lambda (var) `(var ,var)) *enclosing-lexical-block-declarations*)
-                                       ,@body)
-                                    :expecting :statement))))
+        (let* ((*enclosing-lexical-block-declarations* ())
+               (body (compile-parenscript-form `(progn ,@body)))
+               (var-decls (compile-parenscript-form
+                           `(progn ,@(mapcar (lambda (var) `(var ,var)) *enclosing-lexical-block-declarations*)))))
+          `(js:block ,@(cdr var-decls) ,@(cdr body)))))
 
 (define-ps-special-form %js-lambda (args &rest body)
   `(js:lambda ,@(compile-function-definition args body)))
@@ -520,11 +517,11 @@ lambda-list::=
     `(progn ,@(loop for (place value) on args by #'cddr collect (process-setf-clause place value)))))
 
 (defpsmacro psetf (&rest args)
-  (let ((vars (loop for x in args by #'cddr collect x))
+  (let ((places (loop for x in args by #'cddr collect x))
         (vals (loop for x in (cdr args) by #'cddr collect x)))
-    (let ((gensyms (mapcar (lambda (x) (declare (ignore x)) (ps-gensym)) vars)))
-      `(simple-let* ,(mapcar #'list gensyms vals)
-         (setf ,@(mapcan #'list vars gensyms))))))
+    (let ((gensyms (mapcar (lambda (x) (declare (ignore x)) (ps-gensym)) places)))
+      `(let ,(mapcar #'list gensyms vals)
+         (setf ,@(mapcan #'list places gensyms))))))
 
 (defun check-setq-args (args)
   (let ((vars (loop for x in args by #'cddr collect x)))
@@ -542,72 +539,53 @@ lambda-list::=
 
 (define-ps-special-form var (name &optional (value (values) value-provided?) documentation)
   (declare (ignore documentation))
-  `(js:var ,name ,@(when value-provided?
-                         (list (compile-parenscript-form value :expecting :expression)))))
+  (ecase expecting
+    (:statement
+     `(js:var ,name ,@(when value-provided?
+                            (list (compile-parenscript-form value :expecting :expression)))))
+    (:expression
+     (push name *enclosing-lexical-block-declarations*)
+     (when value-provided?
+       (compile-parenscript-form `(setf ,name ,value) :expecting :expression)))))
 
 (defpsmacro defvar (name &optional (value (values) value-provided?) documentation)
-  "Note: this must be used as a top-level form, otherwise the result will be undefined behavior."
+  ;; this must be used as a top-level form, otherwise the resulting behavior will be undefined.
+  (declare (ignore documentation))
   (pushnew name *ps-special-variables*)
   `(var ,name ,@(when value-provided? (list value))))
 
-(defun make-let-vars (bindings)
-  (mapcar (lambda (x) (if (listp x) (car x) x)) bindings))
-
-(defun make-let-vals (bindings)
-  (mapcar (lambda (x) (if (or (atom x) (endp (cdr x))) nil (second x))) bindings))
-
-(defpsmacro lexical-let* (bindings &body body)
-  `((lambda ()
-      (let* ,bindings
-        ,@body))))
-
-(defpsmacro lexical-let (bindings &body body)
-  `((lambda ,(make-let-vars bindings)
-      ,@body)
-    ,@(make-let-vals bindings)))
+(defpsmacro let (bindings &body body)
+  (flet ((add-renamed-vars (bindings predicate)
+           (mapcar (lambda (x) (append x (list (ps-gensym (car x)))))
+                   (remove-if predicate bindings :key #'car)))
+         (var (x) (first x))
+         (val (x) (second x))
+         (renamed (x) (third x)))
+    (let* ((normalized-bindings (mapcar (lambda (x) (if (symbolp x) `(,x nil) x)) bindings))
+           (lexical-bindings (add-renamed-vars normalized-bindings #'ps-special-variable-p))
+           (dynamic-bindings (add-renamed-vars normalized-bindings (complement #'ps-special-variable-p)))
+           (renamed-body `(symbol-macrolet ,(mapcar (lambda (x) (list (var x) (renamed x)))
+                                                    lexical-bindings)
+                            ,@body)))
+    `(progn
+       ,@(mapcar (lambda (x) `(var ,(renamed x) ,(val x))) lexical-bindings)
+       ,(if dynamic-bindings
+            `(progn ,@(mapcar (lambda (x) `(var ,(renamed x))) dynamic-bindings)
+                    (try (progn (setf ,@(loop for x in dynamic-bindings append
+                                             `(,(renamed x) ,(var x)
+                                               ,(var x) ,(val x))))
+                                ,renamed-body)
+                         (:finally
+                          (setf ,@(mapcan (lambda (x) `(,(var x) ,(renamed x))) dynamic-bindings)))))
+            renamed-body)))))
 
-(defpsmacro simple-let* (bindings &body body)
+(defpsmacro let* (bindings &body body)
   (if bindings
-      (let ((var (if (listp (car bindings)) (caar bindings) (car bindings))))
-        `(,(if (member var *ps-special-variables*) 'let1-dynamic 'let1) ,(car bindings)
-           (simple-let* ,(cdr bindings) ,@body)))
+      `(let (,(car bindings))
+         (let* ,(cdr bindings)
+           ,@body))
       `(progn ,@body)))
 
-(defpsmacro simple-let (bindings &body body)
-  (let ((vars (mapcar (lambda (x) (if (atom x) x (first x))) bindings))
-        (vals (mapcar (lambda (x) (if (or (atom x) (endp (cdr x))) nil (second x))) bindings)))
-    (let ((gensyms (mapcar (lambda (x) (ps-gensym (format nil "_js_~a" x))) vars)))
-      `(simple-let* ,(mapcar #'list gensyms vals)
-         (simple-let* ,(mapcar #'list vars gensyms)
-           ,@(mapcar (lambda (x) `(delete ,x)) gensyms)
-           ,@body)))))
-
-(defpsmacro let* (bindings &body body)
-  `(simple-let* ,bindings ,@body))
-
-(defpsmacro let (bindings &body body)
-  `(,(if (= 1 (length bindings)) 'simple-let* 'simple-let) ,bindings ,@body))
-
-(define-ps-special-form let1 (binding &rest body)
-  (ecase expecting
-    (:statement
-     (compile-parenscript-form `(progn ,(if (atom binding) `(var ,binding) `(var ,@binding)) ,@body) :expecting :statement))
-    (:expression
-     (let ((var (if (atom binding) binding (car binding)))
-           (variable-assignment (when (listp binding) (cons 'setf binding))))
-       (push var *enclosing-lexical-block-declarations*)
-       (compile-parenscript-form `(progn ,variable-assignment ,@body) :expecting :expression)))))
-
-(defpsmacro let1-dynamic ((var value) &rest body)
-  (with-ps-gensyms (temp-stack-var)
-    `(progn (var ,temp-stack-var)
-      (try (progn (setf ,temp-stack-var ,var)
-                  (setf ,var ,value)
-                  ,@body)
-       (:finally
-        (setf ,var ,temp-stack-var)
-        (delete ,temp-stack-var))))))
-
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; iteration
 (defun make-for-vars/inits (init-forms)
@@ -680,7 +658,7 @@ lambda-list::=
               ,(do-make-iter-psteps decls)))))
 
 (define-ps-special-form for-in ((var object) &rest body)
-  `(js:for-in ,(compile-parenscript-form `(var ,var) :expecting :expression)
+  `(js:for-in ,(compile-parenscript-form var :expecting :expression)
               ,(compile-parenscript-form object :expecting :expression)
               ,(compile-parenscript-form `(progn ,@body))))
 
index f01a00c..31c488c 100644 (file)
 
 ;;; Parenscript-style symbol -> Javascript-style symbol
 
-(defun constant-string-p (string)
-  (let ((len (length string))
-        (constant-chars '(#\+ #\*)))
-    (and (> len 2)
-         (member (char string 0) constant-chars)
-         (member (char string (1- len)) constant-chars))))
+(defun special-symbol-delimiter? (char)
+  (or (eql char #\+) (eql char #\*)))
+
+(defun special-symbol-name? (string)
+  (nth-value 1 (cl-ppcre:scan-to-strings "[\\*|\\+](.*)[\\*|\\+]([0-9]*)" string)))
 
 (defun first-uppercase-p (string)
   (and (> (length string) 1)
-       (member (char string 0) '(#\+ #\*))))
+       (special-symbol-delimiter? (char string 0))))
 
 (defun untouchable-string-p (string)
   (and (> (length string) 1)
 identifier by following transformation heuristics case conversion. For
 example, paren-script becomes parenScript, *some-global* becomes
 SOMEGLOBAL."
-  (when (symbolp symbol)
-    (setf symbol (symbol-name symbol)))
-  (let ((symbols (string-split symbol '(#\. #\[ #\]) :keep-separators t :remove-empty-subseqs t)))
-    (cond ((null symbols) "")
-          ((= (length symbols) 1)
-           (let (res
-                 (do-not-touch nil)
-                 (lowercase t)
-                 (all-uppercase nil))
-             (cond ((constant-string-p symbol)
-                    (setf all-uppercase t
-                          symbol (subseq symbol 1 (1- (length symbol)))))
-                   ((first-uppercase-p symbol)
-                    (setf lowercase nil
-                          symbol (subseq symbol 1)))
-                   ((untouchable-string-p symbol)
-                    (setf do-not-touch t
-                          symbol (subseq symbol 1))))
-             (flet ((reschar (c)
-                      (push (cond
-                              (do-not-touch c)
-                              ((and lowercase (not all-uppercase))
-                               (char-downcase c))
-                              (t (char-upcase c)))
-                            res)
-                      (setf lowercase t)))
-               (dotimes (i (length symbol))
-                 (let ((c (char symbol i)))
-                   (cond
-                     ((eql c #\-)
-                      (setf lowercase (not lowercase)))
-                     ((assoc c *special-chars*)
-                      (dolist (i (coerce (cdr (assoc c *special-chars*)) 'list))
-                        (reschar i)))
-                     (t (reschar c))))))
-             (coerce (nreverse res) 'string)))
-          (t (string-join (mapcar #'symbol-name-to-js-string symbols) "")))))
+  (let ((sym-name (string symbol))
+        res
+        (do-not-touch nil)
+        (lowercase t)
+        (all-uppercase nil))
+    (when (and (not (eq symbol '[]))
+               (find-if (lambda (x) (member x '(#\. #\[ #\]))) sym-name))
+      (warn "Symbol ~A contains one of '.[]' - this compound naming convention is no longer supported by Parenscript!"
+            symbol))
+    (cond ((special-symbol-name? sym-name)
+           (setf all-uppercase t
+                 sym-name (let ((parts (special-symbol-name? sym-name)))
+                            (concatenate 'string (aref parts 0) (aref parts 1)))))
+          ((first-uppercase-p sym-name)
+           (setf lowercase nil
+                 sym-name (subseq sym-name 1)))
+          ((untouchable-string-p sym-name)
+           (setf do-not-touch t
+                 sym-name (subseq sym-name 1))))
+    (flet ((reschar (c)
+             (push (cond (do-not-touch c)
+                         ((and lowercase (not all-uppercase)) (char-downcase c))
+                         (t (char-upcase c)))
+                   res)
+             (setf lowercase t)))
+      (dotimes (i (length sym-name))
+        (let ((c (char sym-name i)))
+          (cond ((eql c #\-)
+                 (setf lowercase (not lowercase)))
+                ((assoc c *special-chars*)
+                 (dolist (i (coerce (cdr (assoc c *special-chars*)) 'list))
+                   (reschar i)))
+                (t (reschar c))))))
+    (coerce (nreverse res) 'string)))
 
 (defun ordered-set-difference (list1 list2 &key (test #'eql)) ; because the CL set-difference may not preserve order
   (reduce (lambda (list el) (remove el list :test test))
index 05b9328..2fab062 100644 (file)
@@ -61,9 +61,7 @@ foo.my_library_foo;")
 (common-lisp:in-package "PS-TEST.PSTSTPKG")
 
 (ps-test::test-ps-js namespace-and-special-forms
-  (let* ((foo (create :bar 1 not-a-keyword something)))
+  (let ((foo (create :bar 1 not-a-keyword something)))
     (return (and (not foo) (+ (slot-value foo bar) some-other-var))))
-  "        var prefix_foo =
-            { bar : 1, 
-              prefix_notAKeyword : prefix_something };
-        return !prefix_foo && prefix_foo[prefix_bar] + prefix_someOtherVar;")
+"var prefix_foo1 = { bar : 1, prefix_notAKeyword : prefix_something };
+return !prefix_foo1 && prefix_foo1[prefix_bar] + prefix_someOtherVar;")
index 65f377b..69f1564 100644 (file)
 
 (test-ps-js setf-side-effects
   (progn
-    (let* ((x 10))
+    (let ((x 10))
       (defun side-effect() 
         (setf x 4)
         (return 3))
       (setf x (+ 2 (side-effect) x 5))))
-  "var x = 10;
+  "var x1 = 10;
 function sideEffect() {
-  x = 4;
+  x1 = 4;
   return 3;
 };
-x = 2 + sideEffect() + x + 5;")
+x1 = 2 + sideEffect() + x1 + 5;")
 ;; Parenscript used to optimize incorrectly:
 ;;   var x = 10;
 ;;   function sideEffect() {
@@ -90,18 +90,18 @@ x = 2 + sideEffect() + x + 5;")
     (is (char= char-before a-parenthesis))))
 
 (test-ps-js simple-slot-value
-  (let* ((foo (create :a 1)))
+  (let ((foo (create :a 1)))
     (alert (slot-value foo 'a)))
-  "var foo = { a : 1 };
-   alert(foo.a);")
+  "var foo1 = { a : 1 };
+   alert(foo1.a);")
 
 (test-ps-js buggy-slot-value
-   (let* ((foo (create :a 1))
-          (slot-name "a"))
+   (let ((foo (create :a 1))
+         (slot-name "a"))
     (alert (slot-value foo slot-name)))
-  " var foo = { a : 1 };
-    var slotName = 'a';
-    alert(foo[slotName]);
+  " var foo1 = { a : 1 };
+    var slotName2 = 'a';
+    alert(foo1[slotName2]);
    "); Last line was alert(foo.slotName) before bug-fix.
 
 (test-ps-js buggy-slot-value-two
@@ -181,18 +181,10 @@ x = 2 + sideEffect() + x + 5;")
                    ("u0080" . ,(code-char 128)) ;;Character over 127. Actually valid, parenscript escapes them to be sure.
                    ("uABCD" . ,(code-char #xabcd)))));; Really above ascii.
     (loop for (js-escape . lisp-char) in escapes
-          for generated = (ps1* `(let* ((x ,(format nil "hello~ahi" lisp-char)))))
-          for wanted = (format nil "var x = 'hello\\~ahi';" js-escape)
+          for generated = (ps-doc* `(let ((x ,(format nil "hello~ahi" lisp-char)))))
+          for wanted = (format nil "var x1 = 'hello\\~ahi';" js-escape)
           do (is (string= (normalize-js-code generated) wanted)))))
   
-(test-ps-js complicated-symbol-name1
-  grid-rows[foo].bar
-  "gridRows[foo].bar")
-
-(test-ps-js complicated-symbol-name2
-  *grid-rows*[foo].bar
-  "GRIDROWS[foo].bar")
-
 (test-ps-js slot-value-setf
   (setf (slot-value x 'y) (+ (+ a 3) 4))
   "x.y = (a + 3) + 4;")
@@ -226,7 +218,10 @@ x = 2 + sideEffect() + x + 5;")
 (test-ps-js defsetf1
   (progn (defsetf baz (x y) (newval) `(set-baz ,x ,y ,newval))
          (setf (baz 1 2) 3))
-  "var _js2 = 1; var _js3 = 2; var _js1 = 3; setBaz(_js2, _js3, _js1);")
+  "var _js2_4 = 1;
+var _js3_5 = 2;
+var _js1_6 = 3;
+setBaz(_js2_4, _js3_5, _js1_6);")
 
 (test-ps-js defsetf-short
   (progn (defsetf baz set-baz "docstring")
@@ -240,10 +235,10 @@ x = 2 + sideEffect() + x + 5;")
 "function __setf_someThing(newVal, i1, i2) {
     SOMETHING[i1][i2] = newVal;
 };
-var _js2 = 1;
-var _js3 = 2;
-var _js1 = 'foo';
-__setf_someThing(_js1, _js2, _js3);")
+var _js2_4 = 1;
+var _js3_5 = 2;
+var _js1_6 = 'foo';
+__setf_someThing(_js1_6, _js2_4, _js3_5);")
 
 (test-ps-js defun-optional1
   (defun test-opt (&optional x) (return (if x "yes" "no")))
@@ -361,7 +356,7 @@ __setf_someThing(_js1, _js2, _js3);")
   "[[1, 2], ['a', 'b']]")
 
 (test-ps-js defun-rest1
-  (defun foo (&rest bar) (alert bar[1]))
+  (defun foo (&rest bar) (alert (aref bar 1)))
   "function foo() {
     var bar = [];
     for (var i1 = 0; i1 < arguments.length - 0; i1 += 1) {
@@ -384,8 +379,8 @@ __setf_someThing(_js1, _js2, _js3);")
   (defun zoo (foo bar &key baz) (return (+ foo bar baz)))
 "function zoo(foo, bar) {
     var baz;
-    var _js3 = arguments.length;
-    for (var n1 = 2; n1 < _js3; n1 += 2) {
+    var _js2 = arguments.length;
+    for (var n1 = 2; n1 < _js2; n1 += 2) {
         switch (arguments[n1]) {
         case 'baz':
             {
@@ -403,8 +398,8 @@ __setf_someThing(_js1, _js2, _js3);")
   (defun zoo (&key baz) (return (* baz baz)))
   "function zoo() {
     var baz;
-    var _js3 = arguments.length;
-    for (var n1 = 0; n1 < _js3; n1 += 2) {
+    var _js2 = arguments.length;
+    for (var n1 = 0; n1 < _js2; n1 += 2) {
         switch (arguments[n1]) {
         case 'baz':
             {
@@ -423,8 +418,8 @@ __setf_someThing(_js1, _js2, _js3);")
   "function zoo() {
     var baz;
     var bar;
-    var _js3 = arguments.length;
-    for (var n1 = 0; n1 < _js3; n1 += 2) {
+    var _js2 = arguments.length;
+    for (var n1 = 0; n1 < _js2; n1 += 2) {
         switch (arguments[n1]) {
         case 'baz':
             {
@@ -451,8 +446,8 @@ __setf_someThing(_js1, _js2, _js3);")
     my-name)
   "function helloWorld() {
     var myName;
-    var _js3 = arguments.length;
-    for (var n1 = 0; n1 < _js3; n1 += 2) {
+    var _js2 = arguments.length;
+    for (var n1 = 0; n1 < _js2; n1 += 2) {
         switch (arguments[n1]) {
         case 'my-name-key':
             {
@@ -527,7 +522,7 @@ __setf_someThing(_js1, _js2, _js3);")
 }")
 
 (test-ps-js funcall-if-expression
-  (document.write
+  ((@ document write)
    (if (= *linkornot* 1)
        (ps-html ((:a :href "#"
                      :onclick (ps-inline (transport)))
@@ -596,37 +591,34 @@ __setf_someThing(_js1, _js2, _js3);")
 (test-ps-js let-decl-in-expression
   (defun f (x) (return (if x 1 (let* ((foo x)) foo))))
   "function f(x) {
-    var foo;
-    return x ? 1 : (foo = x, foo);
+    var foo1;
+    return x ? 1 : (foo1 = x, foo1);
 }")
 
 (test-ps-js special-var1
   (progn (defvar *foo*) (let* ((*foo* 2)) (* *foo* 2)))
   "var FOO;
-var tempstackvar1;
+var FOO1;
 try {
-    tempstackvar1 = FOO;
+    FOO1 = FOO;
     FOO = 2;
     FOO * 2;
 } finally {
-    FOO = tempstackvar1;
-    delete tempstackvar1;
+    FOO = FOO1;
 };")
 
 (test-ps-js special-var2
   (progn (defvar *foo*) (let* ((*baz* 3) (*foo* 2)) (* *foo* 2 *baz*)))
   "var FOO;
-var BAZ = 3;
-var tempstackvar1;
+var BAZ1 = 3;
+var FOO2;
 try {
-    tempstackvar1 = FOO;
+    FOO2 = FOO;
     FOO = 2;
-    FOO * 2 * BAZ;
+    FOO * 2 * BAZ1;
 } finally {
-    FOO = tempstackvar1;
-    delete tempstackvar1;
-};
-")
+    FOO = FOO2;
+};")
 
 (test-ps-js literal1
   (setf x undefined)
@@ -650,7 +642,7 @@ try {
 
 (test-ps-js setf-operator-priority
   (return (or (slot-value cache id)
-              (setf (slot-value cache id) (document.get-element-by-id id))))
+              (setf (slot-value cache id) ((@ document get-element-by-id) id))))
   "return cache[id] || (cache[id] = document.getElementById(id))")
 
 (test-ps-js aref-operator-priority
@@ -813,10 +805,10 @@ try {
 (test-ps-js ps-js-target-version-keyword-test1
   (defun foo (x y &key bar baz))
   "function foo(x, y) {
-    var x1 = Array.prototype.indexOf.call(arguments, 'bar', 2);
-    var bar = -1 == x1 ? null : arguments[x1 + 1];
-    var x2 = Array.prototype.indexOf.call(arguments, 'baz', 2);
-    var baz = -1 == x2 ? null : arguments[x2 + 1];
+    var x1_3 = Array.prototype.indexOf.call(arguments, 'bar', 2);
+    var bar = -1 == x1_3 ? null : arguments[x1_3 + 1];
+    var x2_4 = Array.prototype.indexOf.call(arguments, 'baz', 2);
+    var baz = -1 == x2_4 ? null : arguments[x2_4 + 1];
 }"
   :js-target-version 1.6)
 
@@ -827,3 +819,94 @@ try {
 (test-ps-js nested-if-expressions2
   (return (if x y (if z a b)))
   "return x ? y : (z ? a : b)")
+
+(test-ps-js let1
+  (let (x)
+    (+ x x))
+  "var x1 = null;
+x1 + x1;")
+
+(test-ps-js let2
+  (let ((x 1))
+    (+ x x))
+  "var x1 = 1;
+x1 + x1;")
+
+(test-ps-js let3
+  (let ((x 1)
+        (y 2))
+    (+ x x))
+  "var x1 = 1;
+var y2 = 2;
+x1 + x1;")
+
+(test-ps-js let4
+  (let ((x 1)
+        (y (1+ x)))
+    (+ x y))
+  "var x1 = 1;
+var y2 = x + 1;
+x1 + y2;")
+
+(test-ps-js let5
+  (let ((x 1))
+    (+ x 1)
+    (let ((x (+ x 5)))
+      (+ x 1))
+    (+ x 1))
+  "var x1 = 1;
+x1 + 1;
+var x2 = x1 + 5;
+x2 + 1;
+x1 + 1;")
+
+(test-ps-js let6
+  (let ((x 2))
+    (let ((x 1)
+          (y (1+ x)))
+      (+ x y)))
+  "var x1 = 2;
+var x2 = 1;
+var y3 = x1 + 1;
+x2 + y3;")
+
+(test-ps-js let-exp1
+  (lambda ()
+    (return (let (x) (+ x x))))
+  "function () {
+    var x1;
+    return (x1 = null, x1 + x1);
+}")
+
+(test-ps-js let*1
+  (let* ((x 1)) (+ x x))
+"var x1 = 1;
+x1 + x1;")
+
+(test-ps-js let*2
+  (let* ((x 1)
+         (y (+ x 2)))
+    (+ x y))
+  "var x1 = 1;
+var y2 = x1 + 2;
+x1 + y2;")
+
+(test-ps-js let*3
+  (let ((x 3))
+        (let* ((x 1) 
+               (y (+ x 2))) 
+          (+ x y)))
+  "var x1 = 3;
+var x2 = 1;
+var y3 = x2 + 2;
+x2 + y3;")
+
+(test-ps-js let*4
+  (let ((x 3))
+        (let* ((y (+ x 2))
+               (x 1))
+          (+ x y)))
+  "var x1 = 3;
+var y2 = x1 + 2;
+var x3 = 1;
+x3 + y2;")
index 0701942..f3f7f88 100644 (file)
   *array
   "Array")
 
-(test-ps-js symbol-conversion-6
+(test-ps-js symbol-conversion-4
   *global-array*
   "GLOBALARRAY")
 
-(test-ps-js symbol-conversion-7
-  *global-array*.length
-  "GLOBALARRAY.length")
-
 (test-ps-js number-literals-1
   1
   "1")
   "anObject.foo")
 
 (test-ps-js object-literals-4
-  an-object.foo
-  "anObject.foo")
+  (@ an-object foo bar)
+  "anObject.foo.bar")
 
 (test-ps-js object-literals-5
   (with-slots (a b c) this
   *math
   "Math")
 
-(test-ps-js variables-4
-  *math.floor
-  "Math.floor")
-
 (test-ps-js function-calls-and-method-calls-1
   (blorg 1 2)
   "blorg(1, 2)")
   ((slot-value (aref foobar 1) 'blorg) NIL T)
   "foobar[1].blorg(null, true)")
 
-(test-ps-js function-calls-and-method-calls-6
-  (this.blorg 1 2)
-  "this.blorg(1, 2)")
-
 (test-ps-js operator-expressions-1
   (* 1 2)
   "1 * 2")
@@ -269,14 +257,14 @@ x = a + b + c;")
   "a = 1 - a;")
 
 (test-ps-js assignment-5
-  (let* ((a 1) (b 2))
+  (let ((a 1) (b 2))
   (psetf a b b a))
-  "var a = 1;
-var b = 2;
-var _js1 = b;
-var _js2 = a;
-a = _js1;
-b = _js2;")
+  "var a1 = 1;
+var b2 = 2;
+var _js3_5 = b2;
+var _js4_6 = a1;
+a1 = _js3_5;
+b2 = _js4_6;")
 
 (test-ps-js assignment-6
   (setq a 1)
@@ -291,9 +279,9 @@ b = _js2;")
 
 (test-ps-js assignment-9
   (setf (color some-div) (+ 23 "em"))
-  "var _js2 = someDiv;
-var _js1 = 23 + 'em';
-__setf_color(_js1, _js2);")
+  "var _js2_3 = someDiv;
+var _js1_4 = 23 + 'em';
+__setf_color(_js1_4, _js2_3);")
 
 (test-ps-js assignment-10
   (defsetf left (el) (offset)
@@ -302,9 +290,9 @@ __setf_color(_js1, _js2);")
 
 (test-ps-js assignment-11
   (setf (left some-div) (+ 123 "px"))
-  "var _js2 = someDiv;
-var _js1 = 123 + 'px';
-_js2.style.left = _js1;")
+  "var _js2_3 = someDiv;
+var _js1_4 = 123 + 'px';
+_js2_3.style.left = _js1_4;")
 
 (test-ps-js assignment-12
   (progn (defmacro left (el)
@@ -335,7 +323,7 @@ _js2.style.left = _js1;")
 }")
 
 (test-ps-js conditional-statements-1
-  (if (blorg.is-correct)
+  (if ((@ blorg is-correct))
     (progn (carry-on) (return i))
     (alert "blorg is not correct!"))
   "if (blorg.isCorrect()) {
@@ -346,11 +334,11 @@ _js2.style.left = _js1;")
 }")
 
 (test-ps-js conditional-statements-2
-  (+ i (if (blorg.add-one) 1 2))
+  (+ i (if ((@ blorg add-one)) 1 2))
   "i + (blorg.addOne() ? 1 : 2)")
 
 (test-ps-js conditional-statements-3
-  (when (blorg.is-correct)
+  (when ((@ blorg is-correct))
   (carry-on)
   (return i))
   "if (blorg.isCorrect()) {
@@ -359,7 +347,7 @@ _js2.style.left = _js1;")
 }")
 
 (test-ps-js conditional-statements-4
-  (unless (blorg.is-correct)
+  (unless ((@ blorg is-correct))
   (alert "blorg is not correct!"))
   "if (!blorg.isCorrect()) {
     alert('blorg is not correct!');
@@ -370,59 +358,33 @@ _js2.style.left = _js1;")
   "var A = [ 1, 2, 3 ]")
 
 (test-ps-js variable-declaration-2
-  (simple-let* ((a 0) (b 1))
-  (alert (+ a b)))
-  "var a = 0;
-var b = 1;
-alert(a + b);")
-
-(test-ps-js variable-declaration-3
-  (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);")
-
-(test-ps-js variable-declaration-4
-  (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);")
-
-(test-ps-js variable-declaration-5
-  (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);")
+  (progn 
+  (defvar *a* 4)
+  (let ((x 1)
+        (*a* 2))
+    (let* ((y (+ x 1))
+           (x (+ x y)))
+      (+ *a* x y))))
+  "var A = 4;
+var x1 = 1;
+var A2;
+try {
+    A2 = A;
+    A = 2;
+    var y3 = x1 + 1;
+    var x4 = x1 + y3;
+    A + x4 + y3;
+} finally {
+    A = A2;
+};")
 
 (test-ps-js iteration-constructs-1
   (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)) (eql 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;
@@ -433,90 +395,86 @@ alert(a + b);")
   (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;
-for (; i <= 10; ) {
-    document.write('i: ' + i + ' s: ' + s + '<br/>');
-    var _js3 = i + 1;
-    var _js4 = s + i + (i + 1);
-    i = _js3;
-    s = _js4;
+  ((@ document write) (+ "i: " i " s: " s "<br/>")))
+  "var i1 = 0;
+var s2 = 0;
+for (; i1 <= 10; ) {
+    document.write('i: ' + i1 + ' s: ' + s2 + '<br/>');
+    var _js3_5 = i1 + 1;
+    var _js4_6 = s2 + i1 + (i1 + 1);
+    i1 = _js3_5;
+    s2 = _js4_6;
 };")
 
 (test-ps-js iteration-constructs-3
   (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/>');
 };")
 
 (test-ps-js iteration-constructs-4
-  (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/>');
+  (let ((arr (array "a" "b" "c" "d" "e")))
+  (dotimes (i (@ arr length))
+    ((@ document write) (+ "i: " i " arr[i]: " (aref arr i) "<br/>"))))
+  "var arr1 = ['a', 'b', 'c', 'd', 'e'];
+for (var i = 0; i < arr1.length; i += 1) {
+    document.write('i: ' + i + ' arr[i]: ' + arr1[i] + '<br/>');
 };")
 
 (test-ps-js iteration-constructs-5
-  (let* ((res 0))
+  (let ((res 0))
   (alert (+ "Summation to 10 is "
             (dotimes (i 10 res)
               (incf res (1+ i))))))
-  "var res = 0;
+  "var res1 = 0;
 alert('Summation to 10 is ' + (function () {
     for (var i = 0; i < 10; i += 1) {
-        res += i + 1;
+        res1 += i + 1;
     };
-    return res;
+    return res1;
 })());")
 
 (test-ps-js iteration-constructs-6
-  (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/>"))))
-  "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/>"))))
+  "var l1 = [1, 2, 4, 8, 16, 32];
+for (var c = null, _js_arrvar3 = l1, _js_idx2 = 0; _js_idx2 < _js_arrvar3.length; _js_idx2 += 1) {
+    c = _js_arrvar3[_js_idx2];
     document.write('c: ' + c + '<br/>');
 };")
 
 (test-ps-js iteration-constructs-7
-  (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)))))
-  "var l = [1, 2, 4, 8, 16, 32];
-var s = 0;
-alert('Sum of ' + l + ' is: ' + (function () {
-    for (var c = null, _js_arrvar2 = l, _js_idx1 = 0; _js_idx1 < _js_arrvar2.length; _js_idx1 += 1) {
-        c = _js_arrvar2[_js_idx1];
-        s += c;
+  "var l1 = [1, 2, 4, 8, 16, 32];
+var s2 = 0;
+alert('Sum of ' + l1 + ' is: ' + (function () {
+    for (var c = null, _js_arrvar4 = l1, _js_idx3 = 0; _js_idx3 < _js_arrvar4.length; _js_idx3 += 1) {
+        c = _js_arrvar4[_js_idx3];
+        s2 += c;
     };
-    return s;
+    return s2;
 })());")
 
 (test-ps-js iteration-constructs-8
-  (let* ((obj (create :a 1 :b 2 :c 3)))
+  (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/>');
+    ((@ document write) (+ i ": " (aref obj i) "<br/>"))))
+  "var obj1 = { a : 1, b : 2, c : 3 };
+for (var i in obj1) {
+    document.write(i + ': ' + obj1[i] + '<br/>');
 };")
 
 (test-ps-js iteration-constructs-9
-  (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);
 }")
@@ -579,21 +537,21 @@ for (var i in obj) {
   "'<A HREF=\"' + generateALink() + '\">blorg</A>'")
 
 (test-ps-js the-html-generator-3
-  (document.write
+  ((@ document write)
   (ps-html ((:a :href "#"
                 :onclick (ps-inline (transport))) "link")))
   "document.write('<A HREF=\"#\" ONCLICK=\"' + ('javascript:' + 'transport' + '(' + ')') + '\">link</A>')")
 
 (test-ps-js the-html-generator-4
-  (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;
-var authorized = true;
+  "var disabled1 = null;
+var authorized2 = true;
 element.innerHTML =
 '<TEXTAREA'
-+ (disabled || !authorized ? ' DISABLED=\"' + 'disabled' + '\"' : '')
++ (disabled1 || !authorized2 ? ' DISABLED=\"' + 'disabled' + '\"' : '')
 + '>Edit me</TEXTAREA>';")