;;; Copyright 2005-2006 Henrik Hjelte
;;; Copyright 2007-2012 Vladimir Sedach
;;; SPDX-License-Identifier: BSD-3-Clause
;;; Redistribution and use in source and binary forms, with or
;;; without modification, are permitted provided that the following
;;; conditions are met:
;;; 1. Redistributions of source code must retain the above copyright
;;; notice, this list of conditions and the following disclaimer.
;;; 2. Redistributions in binary form must reproduce the above
;;; copyright notice, this list of conditions and the following
;;; disclaimer in the documentation and/or other materials provided
;;; with the distribution.
;;; 3. Neither the name of the copyright holder nor the names of its
;;; contributors may be used to endorse or promote products derived
;;; from this software without specific prior written permission.
;;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
;;; CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
;;; INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
;;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
;;; BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
;;; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
;;; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
;;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
;;; ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
;;; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
;;; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
;;; POSSIBILITY OF SUCH DAMAGE.
(in-package #:parenscript.tests)
(named-readtables:in-readtable :parenscript)
(fiveam:in-suite output-tests)
(test-ps-js statements-and-expressions-1
(+ i (if 1 2 3))
"i + (1 ? 2 : 3);")
(test-ps-js statements-and-expressions-2
(if 1 2 3)
"if (1) {
2;
} else {
3;
};")
(test-ps-js symbol-conversion-1
!?#@%
"bangwhathashatpercent;")
(test-ps-js symbol-conversion-2
bla-foo-bar
"blaFooBar;")
(test-ps-js symbol-conversion-3
*array
"Array;")
(test-ps-js symbol-conversion-4
*global-array*
"GLOBALARRAY;")
(test-ps-js symbol-conversion-5
encodeURIComponent
"encodeURIComponent;")
(test-ps-js symbol-conversion-6
URI
"URI;")
(test-ps-js number-literals-1
1
"1;")
(test-ps-js number-literals-2
123.123
"123.123;")
(test-ps-js number-literals-3
#x10
"16;")
(test-ps-js string-literals-1
"foobar"
"'foobar';")
(test-ps-js string-literals-2
"bratzel bub"
"'bratzel bub';")
(test-ps-js string-literals-3
" "
"'\\t';")
(test-ps-js array-literals-1
(array)
"[];")
(test-ps-js array-literals-2
(array 1 2 3)
"[1, 2, 3];")
(test-ps-js array-literals-3
(array (array 2 3)
(array "foobar" "bratzel bub"))
"[[2, 3], ['foobar', 'bratzel bub']];")
(test-ps-js array-literals-4
(make-array)
"new Array();")
(test-ps-js array-literals-5
(make-array 1 2 3)
"new Array(1, 2, 3);")
(test-ps-js array-literals-6
(make-array
(make-array 2 3)
(make-array "foobar" "bratzel bub"))
"new Array(new Array(2, 3), new Array('foobar', 'bratzel bub'));")
(test-ps-js array-init-1
(make-array 2 :initial-contents '(10 20))
"(function () {
var arr1 = new Array(2);
var init2 = [10, 20];
for (var i4 = 0; i4 < Math.min(arr1.length, init2.length); i4 += 1) {
arr1[i4] = init2[i4];
};
return arr1;
})();")
(test-ps-js array-init-2
(make-array 5 :initial-element 10)
"(function () {
var arr1 = new Array(5);
var elt3 = 10;
for (var i4 = 0; i4 < arr1.length; i4 += 1) {
arr1[i4] = elt3;
};
return arr1;
})();")
(test-ps-js object-literals-1
(create foo "bar" :blorg 1)
"({ foo : 'bar', 'blorg' : 1 });")
(test-ps-js object-literals-2
(create foo "hihi"
blorg (array 1 2 3)
another-object (create :schtrunz 1))
"({ foo : 'hihi',
blorg : [1, 2, 3],
anotherObject : { 'schtrunz' : 1 } });")
(test-ps-js object-literals-3
(getprop an-object 'foo)
"anObject.foo;")
(test-ps-js object-literals-4
(@ an-object foo bar)
"anObject.foo.bar;")
(test-ps-js object-literals-5
(with-slots (a b c) this
(+ a b c))
"this.a + this.b + this.c;")
(test-ps-js with-slots-single-eval
(lambda () (with-slots (a b) (foo) (+ a b)))
"(function () {
var object1 = foo();
return object1.a + object1.b;
});")
(test-ps-js object-literal-quoted-symbols
(create 'test "bang" 'symbol-saved-my-life "parenscript")
"({ 'test' : 'bang', 'symbolSavedMyLife' : 'parenscript' });")
(test-ps-js object-literal-property-accessors
(defun foo ()
(let ((x 10))
(create (get x) x
(set x v) (setf x v))))
"function foo() {
var x = 10;
return { get x() {
return x;
}, set x(v) {
return x = v;
} };
};"
:js-target-version "1.8.5")
(test-ps-js object-method-apply-1
(apply (@ an-object foo) nil)
"anObject.foo.apply(anObject, null);")
(test-ps-js object-method-apply-2
(apply (getprop (make-an-object) foo 'bar) nil)
"(function () {
var _js1 = makeAnObject()[foo];
var _js2 = _js1.bar;
return _js2.apply(_js1, null);
})();")
(test-ps-js object-method-apply-3
(apply (@ (make-an-object) foo) (bar))
"(function () {
var _js1 = makeAnObject();
var _js2 = _js1.foo;
return _js2.apply(_js1, bar());
})();")
(test-ps-js regular-expression-literals-1
(regex "foobar")
"/foobar/;")
(test-ps-js regular-expression-literals-2
(regex "/foobar/i")
"/foobar/i;")
(test-ps-js literal-symbols-1
t
"true;")
(test-ps-js literal-symbols-2
false
"false;")
(test-ps-js literal-symbols-3
f
"false;")
(test-ps-js literal-symbols-4
(lambda () nil)
"(function () {
return null;
});")
(test-ps-js literal-symbols-5
undefined
"undefined;")
(test-ps-js literal-symbols-6
this
"this;")
(test-ps-js variables-1
variable
"variable;")
(test-ps-js variables-2
a-variable
"aVariable;")
(test-ps-js variables-3
*math
"Math;")
(test-ps-js function-calls-and-method-calls-1
(blorg 1 2)
"blorg(1, 2);")
(test-ps-js function-calls-and-method-calls-2
(foobar (blorg 1 2) (blabla 3 4) (array 2 3 4))
"foobar(blorg(1, 2), blabla(3, 4), [2, 3, 4]);")
(test-ps-js function-calls-and-method-calls-3
((getprop this 'blorg) 1 2)
"this.blorg(1, 2);")
(test-ps-js function-calls-and-method-calls-4
((aref foo i) 1 2)
"foo[i](1, 2);")
(test-ps-js function-calls-and-method-calls-5
((getprop (aref foobar 1) 'blorg) nil t)
"foobar[1].blorg(null, true);")
(test-ps-js operator-expressions-1
(* 1 2)
"1 * 2;")
(test-ps-js operator-expressions-2
(= 1 2)
"1 === 2;")
(test-ps-js operator-expressions-3
(* 1 (+ 2 3 4) 4 (/ 6 7))
"1 * (2 + 3 + 4) * 4 * (6 / 7);")
(test-ps-js operator-expressions-4
(incf i)
"++i;")
(test-ps-js operator-expressions-5
(decf i)
"--i;")
(test-ps-js operator-expressions-6
(1- i)
"i - 1;")
(test-ps-js operator-expressions-7
(1+ i)
"i + 1;")
(test-ps-js operator-expressions-8
(not (< i 2))
"i >= 2;")
(test-ps-js body-forms-1
(progn (blorg i) (blafoo i))
"blorg(i);
blafoo(i);")
(test-ps-js body-forms-2
(+ i (progn (blorg i) (blafoo i)))
"i + (blorg(i), blafoo(i));")
(test-ps-js function-definition-1
(defun a-function (a b)
(+ a b))
"function aFunction(a, b) {
return a + b;
};")
(test-ps-js lambda-definition-2
(lambda (a b) (+ a b))
"(function (a, b) {
return a + b;
});")
(test-ps-js assignment-1
(setf a 1)
"a = 1;")
(test-ps-js assignment-2
(setf a 2 b 3 c 4 x (+ a b c))
"a = 2;
b = 3;
c = 4;
x = a + b + c;")
(test-ps-js assignment-3
(setf a (+ a 2 3 4 a))
"a = a + 2 + 3 + 4 + a;")
(test-ps-js assignment-4
(setf a (- 1 a))
"a = 1 - a;")
(test-ps-js assignment-5
(let ((a 1) (b 2))
(psetf a b b a))
"(function () {
var a = 1;
var b = 2;
var _js3 = b;
var _js4 = a;
a = _js3;
return b = _js4;
})();")
(test-ps-js assignment-6
(setq a 1)
"a = 1;")
(test-ps-js assignment-8
(progn
(defun (setf color) (new-color el)
(setf (getprop (getprop el 'style) 'color) new-color))
(setf (color some-div) (+ 23 "em")))
"function __setf_color(newColor, el) {
return el.style.color = newColor;
};
__setf_color(23 + 'em', someDiv);")
(test-ps-js assignment-10
(progn
(defsetf left (el) (offset)
`(setf (getprop (getprop ,el 'style) 'left) ,offset))
(setf (left some-div) (+ 123 "px")))
"(function () {
var _js2 = someDiv;
var _js1 = 123 + 'px';
return _js2.style.left = _js1;
})();")
(test-ps-js assignment-12
(macrolet ((left (el)
`(getprop ,el 'offset-left)))
(left some-div))
"someDiv.offsetLeft;")
(test-ps-js nil-block-return-1
(block nil (return) 1)
"(function () {
return null;
return 1;
})();")
(test-ps-js single-argument-statements-2
(throw "foobar")
"throw 'foobar';")
(test-ps-js single-argument-expression-1
(delete (new (*foobar 2 3 4)))
"delete new Foobar(2, 3, 4);")
(test-ps-js single-argument-expression-2
(if (= (typeof blorg) *string)
(alert (+ "blorg is a string: " blorg))
(alert "blorg is not a string"))
"if (typeof blorg === String) {
alert('blorg is a string: ' + blorg);
} else {
alert('blorg is not a string');
};")
(test-ps-js conditional-statements-1
(defun foo ()
(if ((@ blorg is-correct))
(progn (carry-on) (return-from foo i))
(alert "blorg is not correct!")))
"function foo() {
if (blorg.isCorrect()) {
carryOn();
return i;
} else {
return alert('blorg is not correct!');
};
};")
(test-ps-js conditional-statements-2
(+ i (if ((@ blorg add-one)) 1 2))
"i + (blorg.addOne() ? 1 : 2);")
(test-ps-js conditional-statements-3
(defun foo ()
(when ((@ blorg is-correct))
(carry-on)
(return-from foo i)))
"function foo() {
if (blorg.isCorrect()) {
carryOn();
return i;
};
};")
(test-ps-js conditional-statements-4
(unless ((@ blorg is-correct))
(alert "blorg is not correct!"))
"if (!blorg.isCorrect()) {
alert('blorg is not correct!');
};")
(test-ps-js variable-declaration-1
(defvar *a* (array 1 2 3))
"var A = [1, 2, 3];")
(test-ps-js variable-declaration-2
(progn (defvar *a* 4)
(let ((x 1)
(*a* 2))
(let* ((y (+ x 1))
(x (+ x y)))
(+ *a* x y))))
"var A = 4;
(function () {
var x = 1;
var A_TMPSTACK1;
try {
A_TMPSTACK1 = A;
A = 2;
var y = x + 1;
var x2 = x + y;
return A + x2 + y;
} finally {
A = A_TMPSTACK1;
};
})();")
(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)) (string= e "x")))
(setf a d b e)
(funcall (@ document write) (+ "a: " a " b: " b "
")))
"(function () {
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 + '
');
};
})();")
(test-ps-js iteration-constructs-2
(do ((i 0 (1+ i))
(s 0 (+ s i (1+ i))))
((> i 10))
(funcall (@ document write) (+ "i: " i " s: " s "
")))
"(function () {
var i = 0;
var s = 0;
for (; i <= 10; ) {
document.write('i: ' + i + ' s: ' + s + '
');
var _js1 = i + 1;
var _js2 = s + i + (i + 1);
i = _js1;
s = _js2;
};
})();")
(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 "
")))
"(function () {
for (var i = 0, s = 0; i <= 10; i += 1, s = s + i + (i - 1)) {
document.write('i: ' + i + ' s: ' + s + '
');
};
})();")
(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) "
"))))
"(function () {
var arr = ['a', 'b', 'c', 'd', 'e'];
for (var i = 0; i < arr.length; i += 1) {
document.write('i: ' + i + ' arr[i]: ' + arr[i] + '
');
};
})();")
(test-ps-js iteration-constructs-5
(let ((res 0))
(alert (+ "Summation to 10 is "
(dotimes (i 10 res)
(incf res (1+ i))))))
"(function () {
var res = 0;
return alert('Summation to 10 is ' + (function () {
for (var i = 0; i < 10; i += 1) {
res += i + 1;
};
return res;
})());
})();")
(test-ps-js iteration-constructs-6
(let ((l (list 1 2 4 8 16 32)))
(dolist (c l)
((@ document write) (+ "c: " c "
"))))
"(function () {
var l = [1, 2, 4, 8, 16, 32];
for (var c = null, _js_idx2 = 0; _js_idx2 < l.length; _js_idx2 += 1) {
c = l[_js_idx2];
document.write('c: ' + c + '
');
};
})();")
(test-ps-js iteration-constructs-7
(let ((l '(1 2 4 8 16 32))
(s 0))
(alert (+ "Sum of " l " is: "
(dolist (c l s)
(incf s c)))))
"(function () {
var l = [1, 2, 4, 8, 16, 32];
var s = 0;
return alert('Sum of ' + l + ' is: ' + (function () {
for (var c = null, _js_idx1 = 0; _js_idx1 < l.length; _js_idx1 += 1) {
c = l[_js_idx1];
s += c;
};
return s;
})());
})();")
(test-ps-js iteration-constructs-8
(let ((obj (create a 1 b 2 c 3)))
(for-in (i obj)
((@ document write) (+ i ": " (aref obj i) "
"))))
"(function () {
var obj = { a : 1, b : 2, c : 3 };
for (var i in obj) {
document.write(i + ': ' + obj[i] + '
');
};
})();")
(test-ps-js iteration-constructs-9
(while ((@ film is-not-finished))
((@ this eat) (new *popcorn)))
"while (film.isNotFinished()) {
this.eat(new Popcorn);
};")
(test-ps-js loop-for-bindings
(loop :for ((a b) (:c :d)) :in arr :do (foo a b c d))
"(function () {
var _js2 = arr.length;
for (var _js1 = 0; _js1 < _js2; _js1 += 1) {
var _db4 = arr[_js1];
var _db5 = _db4[0];
var a = _db5[0];
var b = _db5[1];
var _js3 = _db4[1];
var c = _js3['c'];
var d = _js3['d'];
foo(a, b, c, d);
};
})();")
(test-ps-js loop-for-on
(loop :for (k v) :on plist :by 2 :do (foo k v))
"(function () {
for (var _js1 = plist; _js1.length > 0; _js1 = _js1['slice'](2)) {
var k = _js1[0];
var v = _js1[1];
foo(k, v);
};
})();")
(test-ps-js loop-for-keys-of
(loop :for k :of obj :do (foo k))
"(function () {
for (var k in obj) {
foo(k);
};
})();")
(test-ps-js loop-for-key-val-pairs-of
(loop :for (k v) :of obj :do (foo k v))
"(function () {
for (var k in obj) {
var v = obj[k];
foo(k, v);
};
})();")
(test-ps-js loop-for-key-val-pairs-of-with-bindings
(loop :for (k (a b)) :of obj :do (foo k a b))
"(function () {
for (var k in obj) {
var _db1 = obj[k];
var a = _db1[0];
var b = _db1[1];
foo(k, a, b);
};
})();")
(test-ps-js loop-for-just-vals-of
(loop :for (nil v) :of obj :do (foo k v))
"(function () {
for (var _js1 in obj) {
var v = obj[_js1];
foo(k, v);
};
})();")
(test-ps-js loop-map-to
(loop :for str :in strs :map str :to (length str))
"(function () {
var _js2 = strs.length;
var map3 = { };
for (var _js1 = 0; _js1 < _js2; _js1 += 1) {
var str = strs[_js1];
map3[str] = str.length;
};
return map3;
})();")
(test-ps-js loop-for-of-map-to
(loop :for k :of obj :map k :to (foo k))
"(function () {
var map1 = { };
for (var k in obj) {
map1[k] = foo(k);
};
return map1;
})();")
(test-ps-js loop-for-of-when
(loop :for k :of obj :when (foo k) :map k :to (bar k))
"(function () {
var map1 = { };
for (var k in obj) {
if (foo(k)) {
map1[k] = bar(k);
};
};
return map1;
})();")
(test-ps-js loop-for-in-until-when
(loop :for a :in b :until (> a 100) :when (< a 50) :do (foo a))
"(function () {
var _js2 = b.length;
for (var _js1 = 0; _js1 < _js2; _js1 += 1) {
var a = b[_js1];
if (a > 100) {
break;
};
if (a < 50) {
foo(a);
};
};
})();")
(test-ps-js loop-with-for-when
(loop :with c = c1 :for d :from c1 :below c2
:when (foo c d) :do (setf c d)
:do (bar d))
"(function () {
var c = c1;
for (var d = c1; d < c2; d += 1) {
if (foo(c, d)) {
c = d;
};
bar(d);
};
})();")
(test-ps-js loop-for-then-for-in-while
(defun blah (c)
(loop :for a = (foo) :then (bar) :for b :in c :while b :do (foo a b c)))
"function blah(c) {
var _js2 = c.length;
var FIRST3 = true;
for (var a = foo(); true; a = bar()) {
var _js1 = FIRST3 ? 0 : _js1 + 1;
if (_js1 >= _js2) {
break;
};
var b = c[_js1];
if (!b) {
break;
};
foo(a, b, c);
FIRST3 = null;
};
};")
(test-ps-js loop-while-when
(loop :for a = (pop stack) :while a :for (b c) = (foo a) :when b :do (bar c))
"(function () {
for (var a = pop(stack); a; a = pop(stack)) {
var _db1 = foo(a);
var b = _db1[0];
var c = _db1[1];
if (b) {
bar(c);
};
};
})();")
(test-ps-js loop-for-of-for-in
(defun blah (obj b)
(loop :for k :of obj :for a :in b :do (foo k a)))
"function blah(obj, b) {
var _js2 = b.length;
var FIRST3 = true;
for (var k in obj) {
var _js1 = FIRST3 ? 0 : _js1 + 1;
if (_js1 >= _js2) {
break;
};
var a = b[_js1];
foo(k, a);
FIRST3 = null;
};
};")
(test-ps-js loop-for-dot
(loop :for (op . args) :in expr :do (foo op args))
"(function () {
var _js2 = expr.length;
for (var _js1 = 0; _js1 < _js2; _js1 += 1) {
var _db3 = expr[_js1];
var op = _db3[0];
var args = _db3.length > 1 ? _db3.slice(1) : [];
foo(op, args);
};
})();")
(test-ps-js loop-for-rest
(loop :for (op &rest args) :in expr :do (foo op args))
"(function () {
var _js2 = expr.length;
for (var _js1 = 0; _js1 < _js2; _js1 += 1) {
var _db3 = expr[_js1];
var op = _db3[0];
var args = _db3.length > 1 ? _db3.slice(1) : [];
foo(op, args);
};
})();")
(test-ps-js loop-collect
(setf x (loop :for a :in b :collect (foo a)))
"x = (function () {
var _js2 = b.length;
var collect3 = [];
for (var _js1 = 0; _js1 < _js2; _js1 += 1) {
var a = b[_js1];
collect3.push(foo(a));
};
return collect3;
})();")
(test-ps-js loop-append
(loop :for a :in b :append a)
"(function () {
var _js2 = b.length;
var append3 = [];
for (var _js1 = 0; _js1 < _js2; _js1 += 1) {
var a = b[_js1];
append3 = append3.concat(a);
};
return append3;
})();")
(test-ps-js the-case-statement-1
(case (aref blorg i)
((1 "one") (alert "one"))
(2 (alert "two"))
(t (alert "default clause")))
"switch (blorg[i]) {
case 1:
case 'one':
alert('one');
break;
case 2:
alert('two');
break;
default:
alert('default clause');
};")
(test-ps-js the-case-statement-2
(switch (aref blorg i)
(1 (alert "If I get here"))
(2 (alert "I also get here"))
(default (alert "I always get here")))
"switch (blorg[i]) {
case 1: alert('If I get here');
case 2: alert('I also get here');
default: alert('I always get here');
};")
(test-ps-js the-try-statement-1
(try (throw "i")
(:catch (error)
(alert (+ "an error happened: " error)))
(:finally
(alert "Leaving the try form")))
"try {
throw 'i';
} catch (error) {
alert('an error happened: ' + error);
} finally {
alert('Leaving the try form');
};")
(test-ps-js the-html-generator-1
(ps-html ((:a :href "foobar") "blorg"))
"'blorg';")
(test-ps-js the-html-generator-2
(ps-html ((:a :href (generate-a-link)) "blorg"))
"['blorg'].join('');")
(test-ps-js the-html-generator-3
(funcall (getprop document 'write)
(ps-html ((:a :href "#"
:onclick (ps-inline (transport))) "link")))
"document.write(['link'].join(''));")
(test-ps-js the-html-generator-4
(let ((disabled nil)
(authorized t))
(setf (getprop element 'inner-h-t-m-l)
(ps-html ((:textarea (or disabled (not authorized)) :disabled "disabled")
"Edit me"))))
"(function () {
var disabled = null;
var authorized = true;
return element.innerHTML = [''].join('');
})();")
(test-ps-js plus-is-not-commutative
(setf x (+ "before" x "after"))
"x = 'before' + x + 'after';")
(test-ps-js plus-works-if-first
(setf x (+ x "middle" "after"))
"x = x + 'middle' + 'after';")
(test-ps-js method-call-op-form
(funcall (getprop (+ "" x) 'to-string))
"('' + x).toString();")
(test-ps-js method-call-op-form-args
(funcall (getprop (+ "" x) 'foo) 1 2 :baz 3)
"('' + x).foo(1, 2, 'baz', 3);")
(test-ps-js method-call-string
((getprop "hi" 'to-string))
"'hi'.toString();")
(test-ps-js method-call-conditional
((if a x y) 1)
"(a ? x : y)(1);")
(test-ps-js method-call-variable
((@ x to-string))
"x.toString();")
(test-ps-js method-call-array
((@ (list 10 20) to-string))
"[10, 20].toString();")
(test-ps-js method-call-lambda-call
(funcall (getprop (funcall (lambda (x) x) 10) 'to-string))
"(function (x) { return x; })(10).toString();")
(fiveam:test no-whitespace-before-dot
(let ((str (ps* '((@ ((lambda (x) x) 10) to-string)))))
(fiveam:is (char= #\) (elt str (1- (position #\. str)))))))
(test-ps-js simple-getprop
(let ((foo (create a 1)))
(alert (getprop foo 'a)))
"(function () {
var foo = { a : 1 };
return alert(foo.a);
})();")
(test-ps-js buggy-getprop
(getprop foo slot-name)
"foo[slotName];")
(test-ps-js buggy-getprop-two
(getprop foo (get-slot-name))
"foo[getSlotName()];")
(test-ps-js old-case-is-now-switch
;; Switch was "case" before, but that was very non-lispish.
;; For example, this code makes three messages and not one
;; which may have been expected. This is because a switch
;; statment must have a break statement for it to return
;; after the alert. Otherwise it continues on the next
;; clause.
(switch (aref blorg i)
(1 (alert "one"))
(2 (alert "two"))
(default (alert "default clause")))
"switch (blorg[i]) {
case 1: alert('one');
case 2: alert('two');
default: alert('default clause');
};")
(test-ps-js lisp-like-case
(case (aref blorg i)
(1 (alert "one"))
(2 (alert "two"))
(t (alert "default clause")))
"switch (blorg[i]) {
case 1:
alert('one');
break;
case 2:
alert('two');
break;
default: alert('default clause');
};")
(test-ps-js even-lispier-case
(case (aref blorg i)
((1 2) (alert "Below three"))
(3 (alert "Three"))
(t (alert "Something else")))
"switch (blorg[i]) {
case 1:
case 2:
alert('Below three');
break;
case 3:
alert('Three');
break;
default: alert('Something else');
};")
(test-ps-js otherwise-case
(case (aref blorg i)
(1 (alert "one"))
(otherwise (alert "default clause")))
"switch (blorg[i]) {
case 1:
alert('one');
break;
default: alert('default clause');
};")
(fiveam:test escape-sequences-in-string
(let ((escapes
`((#\\ . #\\)
(#\b . #\Backspace)
(#\f . ,(code-char 12))
("u000B" . ,(code-char #x000b)) ; vertical tab
(#\n . #\Newline)
(#\r . #\Return)
(#\' . #\')
(#\" . #\")
(#\t . #\Tab)
("u001F" . ,(code-char #x001f)) ; character below 32
("u0080" . ,(code-char 128)) ; character over 127
("uABCD" . ,(code-char #xabcd))))) ; well above ASCII
(loop for (js-escape . lisp-char) in escapes
for generated = (ps-doc* (format nil "hello~ahi" lisp-char))
for wanted = (format nil "'hello\\~ahi';" js-escape)
do (fiveam:is (string= generated wanted)))))
(fiveam:test escape-doublequotes
(let ((*js-string-delimiter* #\"))
(fiveam:is (string= (ps-doc* "hello\"hi") "\"hello\\\"\hi\";"))))
(test-ps-js getprop-setf
(setf (getprop x 'y) (+ (+ a 3) 4))
"x.y = (a + 3) + 4;")
(test-ps-js getprop-conditional1
(getprop (if zoo foo bar) 'x)
"(zoo ? foo : bar).x;")
(test-ps-js getprop-conditional2
(getprop (if (not zoo) foo bar) 'x)
"(!zoo ? foo : bar).x;")
(fiveam:test script-star-eval1
(fiveam:is (string=
(normalize-js-output (ps* '(setf x 1) '(setf y 2)))
"x = 1; y = 2;")))
(fiveam:test script-star-eval2
(fiveam:is (string=
(normalize-js-output (ps* '(setf x 1)))
"x = 1;")))
(test-ps-js list-with-single-nil
(array nil)
"[null];")
(test-ps-js quoted-nil-is-array
'nil
"[];")
(test-ps-js quoted-nil-is-array1
'()
"[];")
(test-ps-js literal-nil
(foo ())
"foo(null);")
(test-ps-js quoted-quoted-nil
'(())
"[null];")
(test-ps-js quoted-quoted-nil1
'(1 ())
"[1, null];")
(test-ps-js defsetf1
(progn (defsetf baz (x y) (newval) `(set-baz ,x ,y ,newval))
(setf (baz 1 2) 3))
"(function () {
var _js2 = 1;
var _js3 = 2;
var _js1 = 3;
return setBaz(_js2, _js3, _js1);
})();")
(test-ps-js setf-macroexpands1
(macrolet ((bar (x y)
`(aref ,x ,y 1)))
(setf (bar foo 2) 3))
"foo[2][1] = 3;")
(test-ps-js defsetf-short
(progn (defsetf baz set-baz "docstring")
(setf (baz 1 2 3) "foo"))
"setBaz(1, 2, 3, 'foo');")
(test-ps-js defun-setf1
(progn (defun (setf some-thing) (new-val i1 i2)
(setf (aref *some-thing* i1 i2) new-val))
(setf (some-thing 1 2) "foo"))
"function __setf_someThing(newVal, i1, i2) {
return SOMETHING[i1][i2] = newVal;
};
__setf_someThing('foo', 1, 2);")
(test-ps-js defun-optional1
(defun test-opt (&optional x)
(if x "yes" "no"))
"function testOpt(x) {
return x ? 'yes' : 'no';
};")
(test-ps-js defun-optional2
(defun foo (x &optional y)
(+ x y))
"function foo(x, y) {
return x + y;
};")
(test-ps-js defun-optional3
(defun blah (&optional (x 0))
x)
"function blah(x) {
if (x === undefined) {
x = 0;
};
return x;
};")
(test-ps-js arglist-optional4
(lambda (&optional (x 0 supplied?))
x)
"(function (x) {
var suppliedwhat = x !== undefined;
if (!suppliedwhat) {
x = 0;
};
return x;
});")
(test-ps-js return-nothing
(defun foo () (return-from foo))
"function foo() {
return null;
};")
(test-ps-js return-values
(defun foo () (return-from foo (values 1 2 3)))
"function foo() {
__PS_MV_REG = { 'tag' : arguments.callee, 'values' : [2, 3] };
return 1;
};")
(test-ps-js set-timeout
(set-timeout (lambda () (alert "foo")) 10)
"setTimeout(function () { return alert('foo'); }, 10);")
(test-ps-js operator-precedence
(* 3 (+ 4 5) 6)
"3 * (4 + 5) * 6;")
(test-ps-js operators-1
(in prop obj)
"prop in obj;")
(test-ps-js incf1
(incf foo bar)
"foo += bar;")
(test-ps-js decf1
(decf foo bar)
"foo -= bar;")
(test-ps-js incf2
(incf x 5)
"x += 5;")
(test-ps-js decf2
(decf y 10)
"y -= 10;")
(test-ps-js setf-conditional
(setf foo (if x 1 2))
"foo = x ? 1 : 2;")
(test-ps-js obj-literal-numbers
(create 1 "foo")
"({ 1 : 'foo' });")
(test-ps-js obj-literal-strings
(create "foo" 2)
"({ 'foo' : 2 });")
(test-ps-js getprop-string
(getprop foo "bar")
"foo['bar'];")
(test-ps-js getprop-string1
(getprop "bar" 'length)
"'bar'.length;")
(test-ps-js getprop-progn
(getprop (progn (some-fun "abc") "123") "length")
"(someFun('abc'), '123')['length'];")
(test-ps-js getprop-multi1
(getprop foo 1 "two" three 'bar 1 2)
"foo[1]['two'][three].bar[1][2];")
(test-ps-js method-call-block
((@ (progn (some-fun "abc") "123") to-string))
"(someFun('abc'), '123').toString();")
(test-ps-js create-blank
(create)
"({ });")
(test-ps-js blank-object-literal
{}
"({ });")
(test-ps-js array-literal1
[]
"[];")
(test-ps-js array-literal2
([])
"[];")
(test-ps-js array-literal3
([] 1 2 3)
"[1, 2, 3];")
(test-ps-js array-literal4
([] 1 (2 3))
"[1, [2, 3]];")
(test-ps-js array-literal5
([] (1 2) ("a" "b"))
"[[1, 2], ['a', 'b']];")
(test-ps-js defun-rest1
(defun foo (&rest bar)
(alert (aref bar 1)))
"function foo() {
var bar = Array.prototype.slice.call(arguments, 0);
return alert(bar[1]);
};")
(test-ps-js defun-rest2
(defun foo (baz &rest bar) (+ baz (aref bar 1)))
"function foo(baz) {
var bar = Array.prototype.slice.call(arguments, 1);
return baz + bar[1];
};")
(test-ps-js defun-keyword1
(defun zoo (foo bar &key baz) (+ foo bar baz))
"function zoo(foo, bar) {
var _js2 = arguments.length;
for (var n1 = 2; n1 < _js2; n1 += 2) {
switch (arguments[n1]) {
case 'baz':
baz = arguments[n1 + 1];
};
};
var baz;
return foo + bar + baz;
};")
(test-ps-js defun-keyword2
(defun zoo (&key baz) (* baz baz))
"function zoo() {
var _js2 = arguments.length;
for (var n1 = 0; n1 < _js2; n1 += 2) {
switch (arguments[n1]) {
case 'baz':
baz = arguments[n1 + 1];
};
};
var baz;
return baz * baz;
};")
(test-ps-js defun-keyword3
(defun zoo (&key baz (bar 4)) (* baz bar))
"function zoo() {
var _js2 = arguments.length;
for (var n1 = 0; n1 < _js2; n1 += 2) {
switch (arguments[n1]) {
case 'baz':
baz = arguments[n1 + 1];
break;
case 'bar':
bar = arguments[n1 + 1];
};
};
var baz;
var bar = 'undefined' === typeof bar ? 4 : bar;
return baz * bar;
};")
(test-ps-js defun-keyword4
(defun hello-world (&key ((:my-name-key my-name) 1))
my-name)
"function helloWorld() {
var _js2 = arguments.length;
for (var n1 = 0; n1 < _js2; n1 += 2) {
switch (arguments[n1]) {
case 'my-name-key':
myName = arguments[n1 + 1];
};
};
var myName = 'undefined' === typeof myName ? 1 : myName;
return myName;
};")
(test-ps-js arglist-keyword-supplied
(lambda (&key (foo 1 supplied?))
foo)
"(function () {
var _js2 = arguments.length;
for (var n1 = 0; n1 < _js2; n1 += 2) {
switch (arguments[n1]) {
case 'foo':
foo = arguments[n1 + 1];
suppliedwhat = true;
};
};
var suppliedwhat;
var foo = 'undefined' === typeof foo ? 1 : foo;
return foo;
});")
(test-ps-js keyword-funcall1
(func :baz 1)
"func('baz', 1);")
(test-ps-js keyword-funcall2
(func :baz 1 :bar foo)
"func('baz', 1, 'bar', foo);")
(test-ps-js keyword-funcall3
(fun a b :baz c)
"fun(a, b, 'baz', c);")
(test-ps-js cond1
(cond ((= x 1) 1))
"if (x === 1) {
1;
};")
(test-ps-js cond2
(cond ((= x 1) 2)
((= y (* x 4)) (foo "blah") (* x y)))
"if (x === 1) {
2;
} else if (y === x * 4) {
foo('blah');
x * y;
};")
(test-ps-js if-exp-without-else-return
(defun foo () (return-from foo (if x 1)))
"function foo() {
return x ? 1 : null;
};")
(test-ps-js progn-expression-single-statement
(defun foo () (return-from foo (progn (* x y))))
"function foo() {
return x * y;
};")
(test-ps-js cond-expression1
(defun foo ()
(cond ((< 1 2) (bar "foo") (* 4 5))))
"function foo() {
if (1 < 2) {
bar('foo');
return 4 * 5;
};
};")
(test-ps-js cond-expression2
(defun foo ()
(cond ((< 2 1) "foo")
((= 7 7) "bar")))
"function foo() {
if (2 < 1) {
return 'foo';
} else if (7 === 7) {
return 'bar';
};
};")
(test-ps-js cond-expression-final-t-clause
(defun foo ()
(cond ((< 1 2) (bar "foo") (* 4 5))
((= a b) (+ c d))
((< 1 2 3 4 5) x)
(t "foo")))
"function foo() {
var _cmp1;
var _cmp2;
var _cmp3;
if (1 < 2) {
bar('foo');
return 4 * 5;
} else if (a === b) {
return c + d;
} else if (_cmp1 = 2, _cmp2 = 3, _cmp3 = 4, 1 < _cmp1 && _cmp1 < _cmp2 && _cmp2 < _cmp3 && _cmp3 < 5) {
return x;
} else {
return 'foo';
};
};")
(test-ps-js cond-expression-middle-t-clause ;; should this signal a warning?
(defun foo ()
(cond ((< 2 1) 5)
(t "foo")
((< 1 2) "bar")))
"function foo() {
if (2 < 1) {
return 5;
} else {
return 'foo';
};
};")
(test-ps-js funcall-if-expression
(funcall (getprop document 'write)
(if (= *linkornot* 1)
(ps-html ((:a :href "#"
:onclick (ps-inline (transport)))
img))
img))
"document.write(LINKORNOT === 1 ? ['', img, ''].join('') : img);")
(test-ps-js negate-number-literal
(- 1)
"-1;")
(fiveam:test macro-environment1
(fiveam:is
(string=
(normalize-js-output
(let* ((macroname (gensym)))
(ps* `(defmacro ,macroname (x) `(+ ,x 123))
`(defun test1 ()
(macrolet ((,macroname (x) `(aref data ,x)))
(when (,macroname x)
(setf (,macroname x) 123)))))))
(normalize-js-output
"function test1() {
return data[x] ? (data[x] = 123) : null;
};"))))
(fiveam:test macro-environment2
(fiveam:is
(string=
(let ((outer-lexical-variable 1))
(defpsmacro macro-environment2-macro (x)
`(+ ,outer-lexical-variable ,x))
(ps* '(macro-environment2-macro 2)))
"1 + 2;")))
(test-ps-js ampersand-whole-1
(macrolet ((foo (&whole foo bar baz)
(declare (ignore bar baz))
(with-standard-io-syntax
(let ((*print-case* :downcase))
(format nil "~a" foo)))))
(foo 1 2))
"'(foo 1 2)';")
(test-ps-js ampersand-whole-2
(macrolet ((foo (&whole foo bar baz)
`(+ ,bar ,baz)))
(foo 1 2))
"1 + 2;")
(test-ps-js keyword-consistent
:x
"'x';")
(test-ps-js simple-symbol-macrolet
(symbol-macrolet ((x 1)) x)
"1;")
(test-ps-js compound-symbol-macrolet
(symbol-macrolet ((x 123)
(y (* 2 x)))
y)
"2 * 123;")
(test-ps-js define-symbol-macro
(progn (define-symbol-macro tst-sym-macro 2)
tst-sym-macro)
"2;")
(test-ps-js define-symbol-macro1
(progn (define-symbol-macro tst-sym-macro1 2)
(foo tst-sym-macro1))
"foo(2);")
(test-ps-js define-symbol-macro2
(progn (define-symbol-macro tst-sym-macro2 3)
(list tst-sym-macro2))
"[3];")
(test-ps-js define-symbol-macro3
(progn (define-symbol-macro tst-sym-macro3 4)
(setq foo (create tst-sym-macro3 tst-sym-macro3)))
"foo = { tstSymMacro3 : 4 };")
(test-ps-js define-symbol-macro4
(progn (define-symbol-macro tst-sym-macro4 5)
(setq foo (if (baz) tst-sym-macro4 bar)))
"foo = baz() ? 5 : bar;")
(test-ps-js expression-progn
(1+ (progn (foo) (if x 1 2)))
"(foo(), x ? 1 : 2) + 1;")
(test-ps-js let-decl-in-expression
(defun f (x)
(if x 1 (let* ((foo x)) foo)))
"function f(x) {
if (x) {
return 1;
} else {
var foo = x;
return foo;
};
};")
(test-ps-js special-var1
(progn (defvar *foo*)
(let* ((*foo* 2))
(* *foo* 2)))
"var FOO;
(function () {
var FOO_TMPSTACK1;
try {
FOO_TMPSTACK1 = FOO;
FOO = 2;
return FOO * 2;
} finally {
FOO = FOO_TMPSTACK1;
};
})();")
(test-ps-js special-var2
(progn (defvar *foo*)
(let* ((*baz* 3)
(*foo* 2))
(* *foo* 2 *baz*)))
"var FOO;
(function () {
var BAZ = 3;
var FOO_TMPSTACK1;
try {
FOO_TMPSTACK1 = FOO;
FOO = 2;
return FOO * 2 * BAZ;
} finally {
FOO = FOO_TMPSTACK1;
};
})();")
(test-ps-js literal1
(setf x undefined)
"x = undefined;")
(test-ps-js literal2
(aref this x)
"this[x];")
(test-ps-js setf-dec1
(setf x (- 1 x 2))
"x = 1 - x - 2;")
(test-ps-js setf-dec2
(setf x (- x 1 2))
"x = x - 1 - 2;")
(test-ps-js special-char-equals
blah=
"blahequals;")
(test-ps-js setf-operator-priority
(defun foo ()
(or (getprop cache id)
(setf (getprop cache id) ((@ document get-element-by-id) id))))
"function foo() {
return cache[id] || (cache[id] = document.getElementById(id));
};")
(test-ps-js aref-operator-priority
(aref (if (and x (> (length x) 0))
(aref x 0)
y)
z)
"(x && x.length > 0 ? x[0] : y)[z];")
(test-ps-js aref-operator-priority1
(aref (or (getprop x 'y)
(getprop a 'b))
z)
"(x.y || a.b)[z];")
(test-ps-js aref-operator-priority2
(aref (if a b c) 0)
"(a ? b : c)[0];")
(test-ps-js negate-operator-priority
(- (if x y z))
"-(x ? y : z);")
(test-ps-js op-p1
(new (or a b))
"new (a || b);")
(test-ps-js op-p2
(delete (if a (or b c) d))
"delete (a ? b || c : d);")
(test-ps-js op-p3
(not (if (or x (not y)) z))
"!(x || !y ? z : null);")
(test-ps-js op-p4
(- (- (* 1 2) 3))
"-(1 * 2 - 3);")
(test-ps-js op-p5
(instanceof (or a b) (if x y z))
"((a || b) instanceof (x ? y : z));")
(test-ps-js op-p7
(or x (if (= x 0) "zero" "empty"))
"x || (x === 0 ? 'zero' : 'empty');")
(test-ps-js named-op-expression
(throw (if a b c))
"throw a ? b : c;")
(test-ps-js named-op-expression1
(typeof (or x y))
"typeof (x || y);")
(test-ps-js aref-array-expression
(aref (or a b c) 0)
"(a || b || c)[0];")
(test-ps-js getprop-operator
(getprop (or a b c) 'd)
"(a || b || c).d;")
(test-ps-js getprop-parens
(getprop (getprop foo 'bar) 'baz)
"foo.bar.baz;")
(test-ps-js funcall-funcall
((foo))
"foo()();")
(test-ps-js expression-funcall
((or (@ window eval) eval) foo nil)
"(window.eval || eval)(foo, null);")
(test-ps-js expression-funcall1
(((or (@ window eval) eval) foo nil))
"(window.eval || eval)(foo, null)();")
(test-ps-js expression-funcall2
(((or (@ window eval) eval)) foo nil)
"(window.eval || eval)()(foo, null);")
(test-ps-js who-html1
(who-ps-html (:span :class "ticker-symbol"
:ticker-symbol symbol
(:a :href "http://foo.com"
symbol)
(:span :class "ticker-symbol-popup")))
"['', symbol, ''].join('');")
(test-ps-js who-html2
(who-ps-html (:p "t0" (:span "t1")))
"'
t0t1
';") (test-ps-js flet1 ((lambda () (flet ((foo (x) (1+ x))) (foo 1)))) "(function () { var foo = function (x) { return x + 1; }; return foo(1); })();") (test-ps-js flet2 (flet ((foo (x) (1+ x)) (bar (y) (+ 2 y))) (bar (foo 1))) "(function () { var foo = function (x) { return x + 1; }; var bar = function (y) { return 2 + y; }; return bar(foo(1)); })();") (test-ps-js flet3 (flet ((foo (x) (+ 2 x))) (flet ((foo (x) (1+ x)) (bar (y) (+ 2 (foo y)))) (bar (foo 1)))) "(function () { var foo = function (x) { return 2 + x; }; var foo1 = function (x) { return x + 1; }; var bar = function (y) { return 2 + foo(y); }; return bar(foo1(1)); })();") (test-ps-js labels1 ((lambda () (labels ((foo (x) (if (= 0 x) 0 (+ x (foo (1- x)))))) (foo 3)))) "(function () { var foo = function (x) { return 0 === x ? 0 : x + foo(x - 1); }; return foo(3); })();") (test-ps-js labels2 (labels ((foo (x) (1+ (bar x))) (bar (y) (+ 2 (foo y)))) (bar (foo 1))) "(function () { var foo = function (x) { return bar(x) + 1; }; var bar = function (y) { return 2 + foo(y); }; return bar(foo(1)); })();") (test-ps-js labels3 (labels ((foo (x) (1+ x)) (bar (y) (+ 2 (foo y)))) (bar (foo 1))) "(function () { var foo = function (x) { return x + 1; }; var bar = function (y) { return 2 + foo(y); }; return bar(foo(1)); })();") (test-ps-js labels-lambda-list (labels ((foo (x &optional (y 0)) (+ x y))) (foo 1)) "(function () { var foo = function (x, y) { if (y === undefined) { y = 0; }; return x + y; }; return foo(1); })();") (test-ps-js for-loop-var-init-exp ((lambda (x) (do* ((y (if x 0 1) (1+ y)) (z 0 (1+ z))) ((= y 3) z))) t) "(function (x) { for (var y = x ? 0 : 1, z = 0; y !== 3; y += 1, z += 1) { }; return z; })(true);") (test-ps-js math-pi pi "Math.PI;") (test-ps-js literal-array '(1 2 3) "[1, 2, 3];") (test-ps-js literal-array-1 '(1 foo 3) "[1, 'foo', 3];") (test-ps-js literal-array-literal '[] "[];") (test-ps-js literal-array-literal1 '(1 []) "[1, []];") (fiveam:test ps-lisp-expands-in-lexical-environment (fiveam:is (string= (let ((x 5)) (ps (lisp x))) "5;"))) (fiveam:test ps-lisp-expands-in-lexical-environment1 (fiveam:is (string= (let ((x 5)) (ps (+ 1 (lisp x)))) "1 + 5;"))) (fiveam:test ps-lisp-expands-in-lexical-environment2 (fiveam:is (string= (let ((x 2)) (ps (+ 1 (lisp x) 3))) "1 + 2 + 3;"))) (fiveam:test ps*-lisp-expands-in-null-lexical-environment (fiveam:signals unbound-variable (let ((x 5)) (declare (ignore x)) (ps* '(lisp x))))) (fiveam:test ps*-lisp-expands-in-dynamic-environment (fiveam:is (string= (let ((foo 2)) (declare (special foo)) (ps* '(+ 1 (lisp (locally (declare (special foo)) foo))))) "1 + 2;"))) (fiveam:test ps-lisp-dynamic-environment (fiveam:is (string= (let ((foo 2)) (declare (special foo)) (ps (+ 1 (lisp foo)))) "1 + 2;"))) (test-ps-js nested-if-expressions1 (defun foo () (return-from foo (if (if x y z) a b))) "function foo() { if (x ? y : z) { return a; } else { return b; }; };") (test-ps-js nested-if-expressions2 (defun foo () (if x y (if z a b))) "function foo() { if (x) { return y; } else { return z ? a : b; }; };") (test-ps-js nested-if-expressions3 (foo (if (if x y z) a b) (if x y (if z a b))) "foo((x ? y : z) ? a : b, x ? y : (z ? a : b));") (test-ps-js let1 (let (x) (+ x x)) "(function () { var x = null; return x + x; })();") (test-ps-js let2 (let ((x 1)) (+ x x)) "(function () { var x = 1; return x + x; })();") (test-ps-js let-x-x (let ((x (1+ x))) (+ x x)) "(function () { var x1 = x + 1; return x1 + x1; })();") (test-ps-js let3 (let ((x 1) (y 2)) (+ x x)) "(function () { var x = 1; var y = 2; return x + x; })();") (test-ps-js let4 (let ((x 1) (y (1+ x))) (+ x y)) "(function () { var x1 = 1; var y = x + 1; return x1 + y; })();") (test-ps-js let5 (let ((x 1)) (+ x 1) (let ((x (+ x 5))) (+ x 1)) (+ x 1)) "(function () { var x = 1; x + 1; var x1 = x + 5; x1 + 1; return x + 1; })();") (test-ps-js let6 (let ((x 2)) (let ((x 1) (y (1+ x))) (+ x y))) "(function () { var x = 2; var x1 = 1; var y = x + 1; return x1 + y; })();") (test-ps-js let-exp1 (lambda () (let (x) (+ x x))) "(function () { var x = null; return x + x; });") (test-ps-js let*1 (let* ((x 1)) (+ x x)) "(function () { var x = 1; return x + x; })();") (test-ps-js let*2 (let* ((x 1) (y (+ x 2))) (+ x y)) "(function () { var x = 1; var y = x + 2; return x + y; })();") (test-ps-js let*3 (let ((x 3)) (let* ((x 1) (y (+ x 2))) (+ x y))) "(function () { var x = 3; var x1 = 1; var y = x1 + 2; return x1 + y; })();") (test-ps-js let*4 (let ((x 3)) (let* ((y (+ x 2)) (x 1)) (+ x y))) "(function () { var x = 3; var y = x + 2; var x1 = 1; return x1 + y; })();") (test-ps-js symbol-macrolet-var (symbol-macrolet ((x y)) (var x)) "var y;") (test-ps-js setf-conditional1 (setf x (unless (null a) (1+ a))) "x = a != null ? a + 1 : null;") (test-ps-js setf-let1 (setf x (let ((a 1)) a)) "x = (function () { var a = 1; return a; })();") (test-ps-js setf-let2 (setf x (let ((a (foo))) (unless (null a) (1+ a)))) "x = (function () { var a = foo(); return a != null ? a + 1 : null; })();") (test-ps-js symbol-macro-env1 (symbol-macrolet ((bar 1)) (macrolet ((bar (x y) `(+ ,x ,y))) (bar bar bar))) "1 + 1;") (test-ps-js symbol-macrolet-fun1 (symbol-macrolet ((baz +)) (baz 1 2)) "baz(1, 2);") (test-ps-js lisp2-namespaces1 (let ((list nil)) (setf list (list 1 2 3))) "(function () { var list = null; return list = [1, 2, 3]; })();") (test-ps-js let-shadows-symbol-macrolet (symbol-macrolet ((x y)) (let ((x 1)) (+ x x)) (+ x x)) "(function () { var x1 = 1; return x1 + x1; })(); y + y;") (test-ps-js let-rename-optimization1 (let ((x 1)) (+ x x)) "(function () { var x = 1; return x + x; })();") (test-ps-js let-rename-optimization2 (lambda (x) (let ((x (+ 1 x))) x)) "(function (x) { var x1 = 1 + x; return x1; });") (test-ps-js symbol-macro-array (symbol-macrolet ((x 1)) (list x)) "[1];") (test-ps-js symbol-macro-obj (symbol-macrolet ((x (+ 1 2))) (create x 1)) "({ x : 1 });") (test-ps-js symbol-macro-obj1 (symbol-macrolet ((x (+ 1 2))) (ps:create x x)) "({ x : 1 + 2 });") (test-ps-js symbol-macro-getprop1 (symbol-macrolet ((x (+ 1 2))) (ps:getprop a x)) "a[1 + 2];") (test-ps-js symbol-macro-getprop1 (symbol-macrolet ((x (+ 1 2))) (ps:getprop a 'x)) "a.x;") (test-ps-js let-let-create (let ((a 99)) (let ((a 22)) (create a 33))) "(function () { var a = 99; var a1 = 22; return { a : 33 }; })();") (test-ps-js symbol-macro-conditional1 (symbol-macrolet ((x y)) (if x x x)) "if (y) { y; } else { y; };") (test-ps-js symbol-macro-conditional2 (symbol-macrolet ((x y)) (1+ (if x x x))) "(y ? y : y) + 1;") (test-ps-js preserve-this (defun foo () (let ((y (block nil (bar this)))) (baz y))) "function foo() { var y = (function () { return bar(this); }).call(this); return baz(y); };") (test-ps-js flet-apply (flet ((foo () 'bar)) (apply (function foo) nil)) "(function () { var foo = function () { return 'bar'; }; return foo.apply(this, null); }).call(this);") (test-ps-js let-apply (let ((foo (lambda () 1))) (let ((foo (lambda () 2))) (apply foo nil))) "(function () { var foo = function () { return 1; }; var foo1 = function () { return 2; }; return foo1.apply(this, null); }).call(this);") (test-ps-js flet-let (flet ((x (x) (1+ x))) (let ((x 2)) (x x))) "(function () { var x = function (x) { return x + 1; }; var x1 = 2; return x(x1); })();") (test-ps-js let-flet (let ((x 2)) (flet ((x (x) (1+ x))) (x x))) "(function () { var x = 2; var x1 = function (x) { return x + 1; }; return x1(x); })();") (test-ps-js labels-let (labels ((x (x) (1+ x))) (let ((x 2)) (x x))) "(function () { var x = function (x) { return x + 1; }; var x1 = 2; return x(x1); })();") (test-ps-js let-labels (let ((x 2)) (labels ((x (x) (1+ x))) (x x))) "(function () { var x = 2; var x1 = function (x) { return x + 1; }; return x1(x); })();") (test-ps-js macrolet-let-inteference (macrolet ((a (n) `(+ ,n 5))) (let ((a (a 1))) (let ((b (a (- a 4)))) (+ a b)))) "(function () { var a = 1 + 5; var b = (a - 4) + 5; return a + b; })();") (test-ps-js let-subtract-add (let ((x 1)) (let ((x 2)) (- x x) (- x) (decf x) (incf x))) "(function () { var x = 1; var x1 = 2; x1 - x1; -x1; --x1; return ++x1; })();") (test-ps-js create-reserved-word (create :default 1) "({ 'default' : 1 });") (test-ps-js getprop-reserved-word (getprop foo :default) "foo['default'];") (test-ps-js getprop-reserved-word1 (getprop foo 'default) "foo['default'];") (test-ps-js eval-when-ps-side (eval-when (:execute) 5) "5;") (defvar *lisp-output* nil) (fiveam:test eval-when-lisp-side () (setf *lisp-output* 'original-value) (let ((js-output (normalize-js-output (ps-doc* `(eval-when (:compile-toplevel) (setf *lisp-output* 'it-works)))))) (fiveam:is (eql 'it-works *lisp-output*)) (fiveam:is (string= "" js-output)))) (defpsmacro my-in-package (package-name) `(eval-when (:compile-toplevel) (setf *lisp-output* ,package-name))) (fiveam:test eval-when-macro-expansion () (setf *lisp-output* 'original-value) (let ((js-output (normalize-js-output (ps-doc* `(progn (my-in-package :cl-user) 3))))) (declare (ignore js-output)) (fiveam:is (eql :cl-user *lisp-output*)))) (fiveam:test eval-when-macrolet-expansion () (setf *lisp-output* 'original-value) (let ((js-output (normalize-js-output (ps-doc* `(macrolet ((my-in-package2 (package-name) `(eval-when (:compile-toplevel) (setf *lisp-output* ,package-name)))) (my-in-package2 :cl-user) 3))))) (declare (ignore js-output)) (fiveam:is (eql :cl-user *lisp-output*)))) (test-ps-js getprop-keyword (getprop foo :bar) "foo['bar'];") (test-ps-js nary-comparison1 (lambda () (< 1 2 3)) "(function () { var _cmp1; return (_cmp1 = 2, 1 < _cmp1 && _cmp1 < 3); });") (test-ps-js chain-getprop1 (chain ($ "foo") (bar x z) frob (baz 5)) "$('foo').bar(x, z).frob.baz(5);") (test-ps-js chain-getprop2 (chain ($ "foo") bar baz) "$('foo').bar.baz;") (test-ps-js chain-getprop3 (chain ($ "foo") bar (x y) baz) "$('foo').bar.x(y).baz;") (test-ps-js flet-expression (1+ (flet ((foo (x) (1+ x))) (foo 1))) "(function () { var foo = function (x) { return x + 1; }; return foo(1); })() + 1;") (test-ps-js flet-lambda-list (flet ((foo (x &key (y 0)) (+ x y))) (foo 1 :y 2)) "(function () { var foo = function (x) { var _js2 = arguments.length; for (var n1 = 1; n1 < _js2; n1 += 2) { switch (arguments[n1]) { case 'y': y = arguments[n1 + 1]; }; }; var y = 'undefined' === typeof y ? 0 : y; return x + y; }; return foo(1, 'y', 2); })();") (test-ps-js return-case-break-elimination (defun foo () (case 1 (0 1) (otherwise 2))) "function foo() { switch (1) { case 0: return 1; default: return 2; }; };") (test-ps-js aplusplus a++ "aplusplus;") (test-ps-js astarstar a** "astarstar;") (test-ps-js switch-return-fallthrough (defun foo () (switch x (1 (foo) break) (2 (bar)) (default 4))) "function foo() { switch (x) { case 1: return foo(); case 2: bar(); default: return 4; }; };") (test-ps-js return-last-case (defun foo () (case x (:a 'eh) (:b 'bee))) "function foo() { switch (x) { case 'a': return 'eh'; case 'b': return 'bee'; }; };") (test-ps-js return-macrolet (defun foo () (macrolet ((x () 1)) (case (x) (:a 'eh) (:b 'bee)))) "function foo() { switch (1) { case 'a': return 'eh'; case 'b': return 'bee'; }; };") (test-ps-js mv-bind1 (multiple-value-bind (a b) (progn (returns-mv) (doesnt)) (alert a) (alert b)) "returnsMv(); (function () { var prevMv1 = 'undefined' === typeof __PS_MV_REG ? (__PS_MV_REG = undefined) : __PS_MV_REG; try { var a = doesnt(); var _db2 = doesnt === __PS_MV_REG['tag'] ? __PS_MV_REG['values'] : []; var b = _db2[0]; alert(a); return alert(b); } finally { __PS_MV_REG = prevMv1; }; })();") (test-ps-js mv-bind2 (multiple-value-bind (a b) (let ((a 1)) (returns-mv a) (doesnt b)) (alert a) (alert b)) "(function () { var a = 1; returnsMv(a); var prevMv2 = 'undefined' === typeof __PS_MV_REG ? (__PS_MV_REG = undefined) : __PS_MV_REG; try { var a3 = doesnt(b); var _db4 = doesnt === __PS_MV_REG['tag'] ? __PS_MV_REG['values'] : []; var b = _db4[0]; alert(a3); return alert(b); } finally { __PS_MV_REG = prevMv2; }; })();") (test-ps-js multiple-value-bind-simple (multiple-value-bind (a b) (blah) (+ a b)) "(function () { var prevMv1 = 'undefined' === typeof __PS_MV_REG ? (__PS_MV_REG = undefined) : __PS_MV_REG; try { var a = blah(); var _db2 = blah === __PS_MV_REG['tag'] ? __PS_MV_REG['values'] : []; var b = _db2[0]; return a + b; } finally { __PS_MV_REG = prevMv1; }; })();") (test-ps-js values0 (lambda () (values)) "(function () { __PS_MV_REG = {}; return null; });") (test-ps-js values1 (values x) "x;") (test-ps-js values2 (lambda () (values x y)) "(function () { __PS_MV_REG = { 'tag' : arguments.callee, 'values' : [y] }; return x; });") (test-ps-js values3 (lambda () (values x y z)) "(function () { __PS_MV_REG = { 'tag' : arguments.callee, 'values' : [y, z] }; return x; });") (test-ps-js values-return (defun foo (x y) (return-from foo (values (* x x) y))) "function foo(x, y) { var val1_1 = x * x; __PS_MV_REG = { 'tag' : arguments.callee, 'values' : [y] }; return val1_1; };") (test-ps-js return-macrolet1 (defun foo () (symbol-macrolet ((x 2)) (loop do (+ x x)))) "function foo() { while (true) { 2 + 2; }; };") (test-ps-js return-cond (defun foo () (return-from foo (cond ((foo? x) (loop for y in x do (foo y))) ((bar? x) x) (t 3)))) "function foo() { if (foowhat(x)) { var _js2 = x.length; for (var _js1 = 0; _js1 < _js2; _js1 += 1) { var y = x[_js1]; foo(y); }; } else if (barwhat(x)) { return x; } else { return 3; }; };") (test-ps-js return-case (defun foo () (return-from foo (case x (1 (loop for y in x do (foo y))) (2 x) ((t) 3)))) "function foo() { switch (x) { case 1: var _js2 = x.length; for (var _js1 = 0; _js1 < _js2; _js1 += 1) { var y = x[_js1]; foo(y); }; return; case 2: return x; case true: return 3; }; };") (test-ps-js return-case1 (defun foo () (return-from foo (case x (1 (if a 1 2)) (2 x) ((t) 3)))) "function foo() { switch (x) { case 1: return a ? 1 : 2; case 2: return x; case true: return 3; }; };") (test-ps-js lambda-loop-if-return (lambda () (if a (loop for y in x do (foo y)) c)) "(function () { if (a) { var _js4 = x.length; for (var _js3 = 0; _js3 < _js4; _js3 += 1) { var y = x[_js3]; foo(y); }; } else { return c; }; });") (test-ps-js lambda-loop-if-return1 (defun baz () (foo (lambda () (if a (progn (loop for y in x do (foo y)) (return-from baz)) c)))) "function baz() { try { return foo(function () { if (a) { var _js4 = x.length; for (var _js3 = 0; _js3 < _js4; _js3 += 1) { var y = x[_js3]; foo(y); }; throw { '__ps_block_tag' : 'baz', '__ps_value1' : null }; } else { return c; }; }); } catch (_ps_err5) { if (_ps_err5 && 'baz' === _ps_err5['__ps_block_tag']) { __PS_MV_REG = { 'tag' : arguments.callee, 'values' : _ps_err5['__ps_values'] }; return _ps_err5['__ps_value1']; } else { throw _ps_err5; }; }; };") (test-ps-js switch-loop (defun foo (x) (case x (1 (dolist (a b))))) "function foo(x) { switch (x) { case 1: for (var a = null, _js_idx1 = 0; _js_idx1 < b.length; _js_idx1 += 1) { a = b[_js_idx1]; }; return; }; };") (test-ps-js switch-folds-blocks (defun foo () (case x (1 (loop repeat 3 do (alert "foo"))) (2 "bar"))) "function foo() { switch (x) { case 1: for (var _js1 = 0; _js1 < 3; _js1 += 1) { alert('foo'); }; return; case 2: return 'bar'; }; };") (test-ps-js setf-places-before-macros (lambda () (defsetf left (el) (offset) `(setf (@ ,el style left) ,offset)) (macrolet ((left (el) `(@ ,el offset-left))) (setf (left x) 10) (left x))) "(function () { var _js2 = x; var _js1 = 10; _js2.style.left = _js1; return x.offsetLeft; });") (test-ps-js for-return (lambda () (dolist (arg args) (foo arg))) "(function () { for (var arg = null, _js_idx1 = 0; _js_idx1 < args.length; _js_idx1 += 1) { arg = args[_js_idx1]; foo(arg); }; });") (test-ps-js try-catch-return (defun foo () (try (foo) (:catch (e) (bar)) (:finally (cleanup)))) "function foo() { try { return foo(); } catch (e) { return bar(); } finally { cleanup(); }; };") (test-ps-js let-try (let ((x (ps:try (+ 1 2) (:catch (y) 5)))) x) "(function () { var x = (function () { try { return 1 + 2; } catch (y) { return 5; }; })(); return x; })();") (test-ps-js try-finally-return-from (defun xyz () (return-from xyz (ps:try (when (blah) 4) (:finally (foo)))) (dont-call-me)) "function xyz() { try { return blah() ? 4 : null; } finally { foo(); }; return dontCallMe(); };") (test-ps-js defun-setf-optional (defun (setf foo) (new-value b &optional c) (setf (aref b (or c 0)) new-value)) "function __setf_foo(newValue, b, c) { return b[c || 0] = newValue; };") (test-ps-js defun-setf-rest (progn (defun (setf foo) (new-value b &rest foo) (do-something b foo new-value)) (setf (foo x 1 2 3 4) 5)) "function __setf_foo(newValue, b) { var foo = Array.prototype.slice.call(arguments, 2); return doSomething(b, foo, newValue); }; __setf_foo(5, x, 1, 2, 3, 4);") (test-ps-js return-null (defun foo () (return-from foo nil)) "function foo() { return null; };") (test-ps-js implicit-return-null (lambda () ) "(function () { return null; });") (test-ps-js implicit-return-null (lambda () nil) "(function () { return null; });") (test-ps-js return-conditional-nested (defun blep (ss x y) (when foo? (let ((pair (bar))) (unless (null pair) (destructuring-bind (a b) pair (unless (or (null a) (null b)) (let ((val (baz a b))) (unless (null val) (when (blah val) (unless (blee) t)))))))))) "function blep(ss, x, y) { if (foowhat) { var pair = bar(); if (pair != null) { var a = pair[0]; var b = pair[1]; if (!(a == null || b == null)) { var val = baz(a, b); if (val != null) { if (blah(val)) { return !blee() ? true : null; }; }; }; }; }; };") (test-ps-js return-when-returns-broken-return (defun foo () (return-from foo (when x 1)) (+ 2 3)) "function foo() { return x ? 1 : null; return 2 + 3; };") (test-ps-js return-case-conditional (defun foo () (return-from foo (case foo (123 (when (bar) t)) (345 (blah))))) "function foo() { switch (foo) { case 123: return bar() ? true : null; case 345: return blah(); }; };") (test-ps-js return-try-conditional (defun foo () (return-from foo (try (when x 1) (:catch (x) 2) (:finally (bar))))) "function foo() { try { return x ? 1 : null; } catch (x) { return 2; } finally { bar(); }; };") (test-ps-js function-declare-special (lambda () (declare (special *foo*)) (let ((*foo* 1)) (1+ *foo*))) "(function () { var FOO_TMPSTACK1; try { FOO_TMPSTACK1 = FOO; FOO = 1; return FOO + 1; } finally { FOO = FOO_TMPSTACK1; }; });") (test-ps-js declare-special-let (let ((*foo* 123)) (declare (special *foo*)) (blah)) "(function () { var FOO_TMPSTACK1; try { FOO_TMPSTACK1 = FOO; FOO = 123; return blah(); } finally { FOO = FOO_TMPSTACK1; }; })();") (test-ps-js declare-special-let-scope (block nil (let ((*foo* 123)) (declare (special *foo*)) (blah)) (let ((*foo* 456)) (+ 4 5))) "(function () { var FOO_TMPSTACK1; try { FOO_TMPSTACK1 = FOO; FOO = 123; blah(); } finally { FOO = FOO_TMPSTACK1; }; var FOO = 456; return 4 + 5; })();") (test-ps-js declare-special-let* (let* ((*foo* 123) (*bar* (+ *foo* *bar*))) (declare (special *foo* *bar*)) (blah)) "(function () { var FOO_TMPSTACK1; try { FOO_TMPSTACK1 = FOO; FOO = 123; var BAR_TMPSTACK2; try { BAR_TMPSTACK2 = BAR; BAR = FOO + BAR; return blah(); } finally { BAR = BAR_TMPSTACK2; }; } finally { FOO = FOO_TMPSTACK1; }; })();") (test-ps-js defun-multiple-declarations-around-docstring (defun foo (x y) (declare (ignorable x y)) (declare (integer x) (float y)) "Fooes X while barring Y." (declare (special *foo*) (special *bar*)) (let ((*bar* (bar y))) (funcall *foo* x))) "/** Fooes X while barring Y. */ function foo(x, y) { var BAR_TMPSTACK1; try { BAR_TMPSTACK1 = BAR; BAR = bar(y); return FOO(x); } finally { BAR = BAR_TMPSTACK1; }; };") (test-ps-js macro-null-toplevel (progn (defmacro macro-null-toplevel () nil) (macro-null-toplevel)) "") (test-ps-js define-symbol-macro-let (progn (define-symbol-macro test-symbol-macro 1) (let ((test-symbol-macro 2)) (1+ test-symbol-macro)) (1+ test-symbol-macro)) "(function () { var testSymbolMacro1 = 2; return testSymbolMacro1 + 1; })(); 1 + 1;") (test-ps-js define-symbol-macro-flet (progn (define-symbol-macro test-symbol-macro1 1) (flet ((test-symbol-macro1 () 2)) (foo test-symbol-macro1) (test-symbol-macro1)) (bar test-symbol-macro1)) "(function () { var testSymbolMacro1_1 = function () { return 2; }; foo(1); return testSymbolMacro1_1(); })(); bar(1);") (fiveam:test compile-stream-nulls (fiveam:is (string= (with-input-from-string (s " (defmacro macro-null-toplevel () nil) (macro-null-toplevel)") (ps-compile-stream s)) ""))) (fiveam:test compile-stream1 (fiveam:is (string= (with-input-from-string (s " (define-symbol-macro test-symbol-macro1 1) (flet ((test-symbol-macro1 () 2)) (foo test-symbol-macro1) (test-symbol-macro1)) (bar test-symbol-macro1)") (ps::with-blank-compilation-environment (ps-compile-stream s))) "(function () { var testSymbolMacro1_1 = function () { return 2; }; foo(1); return testSymbolMacro1_1(); })(); bar(1); "))) (test-ps-js equality-nary1 (let ((x 10) (y 10) (z 10)) (= x y z)) "(function () { var _cmp1; var x = 10; var y = 10; var z = 10; return (_cmp1 = y, x === _cmp1 && _cmp1 === z); })();") (test-ps-js equality1 (progn (equal a b) (eql a b) (eq a b) (= a b)) "a == b; a === b; a === b; a === b;") (test-ps-js getprop-quote-reserved (getprop foo ':break) "foo['break'];") (test-ps-js defun-block-return-from (defun foo (x) (baz 4) (return-from foo x) (bar 5)) "function foo(x) { baz(4); return x; return bar(5); };") (test-ps-js block-return-from (block scope (foo) (when (bar) (return-from scope)) (blee)) "(function () { foo(); if (bar()) { return null; }; return blee(); })();") (test-ps-js block-return-from0 (defun baz () (block scope (foo) (when (bar) (return-from scope)) (blee))) "function baz() { foo(); if (bar()) { return null; }; return blee(); };") (test-ps-js block-return-from01 (defun baz () (block scope (foo) (when (bar) (return-from scope)) (blee)) 2) "function baz() { scope: { foo(); if (bar()) { break scope; }; blee(); }; return 2; };") (test-ps-js block-return-from02 (defun baz () (block scope (foo) (when (bar) (return-from scope (foobar))) (blee)) 2) "function baz() { scope: { foo(); if (bar()) { foobar(); break scope; }; blee(); }; return 2; };") (test-ps-js block-return-from1 (lambda () (block scope (foo) (when (bar) (return-from scope)) (blee)) (+ 1 2)) "(function () { scope: { foo(); if (bar()) { break scope; }; blee(); }; return 1 + 2; });") (test-ps-js block-return-from2 (lambda () (bar 5) (block scope (foo) (when (bar) (return-from scope 6)) (blee))) "(function () { bar(5); foo(); if (bar()) { return 6; }; return blee(); });") (test-ps-js let-funcall (let ((x foo)) (funcall x) (let ((x bar)) (funcall x)) (funcall x)) "(function () { var x = foo; x(); var x1 = bar; x1(); return x(); })();") (test-ps-js symbol-macrolet-funcall (symbol-macrolet ((foo bar)) (funcall foo 1 2 3)) "bar(1, 2, 3);") (test-ps-js times-assign (setf x (* x 1000)) "x *= 1000;") (test-ps-js vector-literal #(1 2 3) "[1, 2, 3];") (test-ps-js vector-literal1 #(1 2 #(a b) 3) "[1, 2, ['a', 'b'], 3];") (test-ps-js rem1 (+ 1 (rem 2 (+ 3 4))) "1 + 2 % (3 + 4);") (test-ps-js non-associative (+ (/ 1 (/ 2 3)) (- 1 (- 2 3))) "1 / (2 / 3) + (1 - (2 - 3));") (test-ps-js lambda-apply (lambda (x) (apply (lambda (y) (bar (1+ y))) x)) "(function (x) { return (function (y) { return bar(y + 1); }).apply(this, x); });") (test-ps-js operator-expressions-nested-let (let ((x (let ((y 1)) y))) x) "(function () { var y; var x = (y = 1, y); return x; })();") (test-ps-js operator-expressions-array-nested-let (list (let ((y 1)) y) 2) "[(function () { var y = 1; return y; })(), 2];") (test-ps-js add-subtract-precedence (- x (+ y z)) "x - (y + z);") (test-ps-js ps-inline-toplevel (ps-inline (foo)) "'javascript:' + 'foo()';") (test-ps-js no-clause-progn-exp (setf x (progn)) "x = null;") (test-ps-js no-clause-progn-return (defun foo () (return-from foo (progn))) "function foo() { return null; };") (test-ps-js empty-cond-clause (setf x (cond ((foo)))) "x = (function () { var testResult1 = foo(); return testResult1 ? testResult1 : null; })();") (test-ps-js empty-cond-clause1 (setf x (cond ((foo) 123) ((bar)) (t 456))) "x = foo() ? 123 : (function () { var testResult1 = bar(); if (testResult1) { return testResult1; } else { if (true) { return 456; }; }; })();") (test-ps-js let-no-body (defun foo () (return-from foo (let ((foo bar))))) "function foo() { var foo1 = bar; return null; };") (test-ps-js rename-lexical-dupes (lambda () (list (let ((foo 12)) (* foo 2)) (let ((foo 13)) (* foo 3)))) "(function () { var foo; var foo1; return [(foo = 12, foo * 2), (foo1 = 13, foo1 * 3)]; });") (test-ps-js defun-comment1 (defun foo (x) "BARBAR is a revolutionary new foobar. X y and x." (1+ x)) "/** * BARBAR is a revolutionary new foobar. * X y and x. */ function foo(x) { return x + 1; };") (test-ps-js var-comment (var x 1 "foo") "/** foo */ var x = 1;") (test-ps-js case-return-break-broken-return (defun foo () (case x ("bar" (if y (return-from foo t) nil)) ("baz" nil))) "function foo() { switch (x) { case 'bar': if (y) { return true; } else { return null; }; case 'baz': return null; }; };") (test-ps-js case-return-break1-broken-return (defun foo () (case x ("bar" (if y (return-from foo t))) ("baz" nil))) "function foo() { switch (x) { case 'bar': if (y) { return true; } else { return null; }; case 'baz': return null; }; };") (test-ps-js setf-progn (setf foo (progn (bar) (baz) 3)) "bar(); baz(); foo = 3;") (test-ps-js var-progn (var x (progn (foo) (bar))) "foo(); var x = bar();") (test-ps-js implicit-return-loop (lambda () (if baz 7 (progn (loop :repeat 100 :do (bar)) 42))) "(function () { if (baz) { return 7; } else { for (var _js2 = 0; _js2 < 100; _js2 += 1) { bar(); }; return 42; }; });") (test-ps-js loop-closures (dotimes (i 10) (lambda () (+ i 1))) "(function () { for (var i = 0; i < 10; i += 1) { function () { return i + 1; }; }; })();") (test-ps-js loop-closures-let (dotimes (i 10) (let ((x (+ i 1))) (lambda () (+ i x)))) "(function () { for (var i = 0; i < 10; i += 1) { with ({ x : null }) { var x = i + 1; function () { return i + x; }; }; }; })();") (test-ps-js loop-closures-flet (dotimes (i 10) (flet ((foo (x) (+ i x))) (lambda () (foo i)))) "(function () { for (var i = 0; i < 10; i += 1) { with ({ foo : null }) { var foo = function (x) { return i + x; }; function () { return foo(i); }; }; }; })();") (test-ps-js while-closures-let (while (foo) (let ((abc (bar))) (lambda () (+ 1 abc)))) "while (foo()) { with ({ abc : null }) { var abc = bar(); function () { return 1 + abc; }; }; };") (test-ps-js dotted-list-form (defun foo (a) (when a (destructuring-bind (b . c) bar (list b c)))) "function foo(a) { if (a) { var b = bar[0]; var c = bar.length > 1 ? bar.slice(1) : []; return [b, c]; }; };") (test-ps-js explicit-nil-block (defun bar () (foo 1) (block nil (return (foo 2)) (+ 1 2)) 2) "function bar() { foo(1); nilBlock: { foo(2); break nilBlock; 1 + 2; }; return 2; };") (test-ps-js dynamic-extent-function-return (defun foo () ((lambda () (return-from foo 6)))) "function foo() { try { return (function () { throw { '__ps_block_tag' : 'foo', '__ps_value1' : 6 }; })(); } catch (_ps_err1) { if (_ps_err1 && 'foo' === _ps_err1['__ps_block_tag']) { __PS_MV_REG = { 'tag' : arguments.callee, 'values' : _ps_err1['__ps_values'] }; return _ps_err1['__ps_value1']; } else { throw _ps_err1; }; }; };") (test-ps-js dynamic-extent-function-return-nothing (defun foo () ((lambda () (return-from foo)))) "function foo() { try { return (function () { throw { '__ps_block_tag' : 'foo', '__ps_value1' : null }; })(); } catch (_ps_err1) { if (_ps_err1 && 'foo' === _ps_err1['__ps_block_tag']) { __PS_MV_REG = { 'tag' : arguments.callee, 'values' : _ps_err1['__ps_values'] }; return _ps_err1['__ps_value1']; } else { throw _ps_err1; }; }; };") (test-ps-js dynamic-extent-function-return-values (defun foo () ((lambda () (return-from foo (values 1 2 3))))) "function foo() { try { __PS_MV_REG = {}; return (function () { throw { '__ps_block_tag' : 'foo', '__ps_value1' : 1, '__ps_values' : [2, 3] }; })(); } catch (_ps_err1) { if (_ps_err1 && 'foo' === _ps_err1['__ps_block_tag']) { __PS_MV_REG = { 'tag' : arguments.callee, 'values' : _ps_err1['__ps_values'] }; return _ps_err1['__ps_value1']; } else { throw _ps_err1; }; }; };") (test-ps-js dynamic-extent-function-return-funcall (defun foo () ((lambda () (return-from foo (if baz 6 5))))) "function foo() { try { return (function () { throw { '__ps_block_tag' : 'foo', '__ps_value1' : baz ? 6 : 5 }; })(); } catch (_ps_err1) { if (_ps_err1 && 'foo' === _ps_err1['__ps_block_tag']) { __PS_MV_REG = { 'tag' : arguments.callee, 'values' : _ps_err1['__ps_values'] }; return _ps_err1['__ps_value1']; } else { throw _ps_err1; }; }; };") (test-ps-js block-dynamic-return (var foo ((lambda () (block nil ((lambda () (return 6))) (+ 1 2))))) "var foo = (function () { try { (function () { throw { '__ps_block_tag' : 'nilBlock', '__ps_value1' : 6 }; })(); return 1 + 2; } catch (_ps_err1) { if (_ps_err1 && 'nilBlock' === _ps_err1['__ps_block_tag']) { __PS_MV_REG = { 'tag' : arguments.callee, 'values' : _ps_err1['__ps_values'] }; return _ps_err1['__ps_value1']; } else { throw _ps_err1; }; }; })();") (test-ps-js block-dynamic-return1 (var foo ((lambda () (block nil ((lambda () (return 6))) (+ 1 2)) (foobar 1 2)))) "var foo = (function () { nilBlock: { (function () { break nilBlock; })(); 1 + 2; }; return foobar(1, 2); })();") (test-ps-js iteration-lambda-capture-no-need (dolist (x y) (lambda (x) (1+ x))) "(function () { for (var x = null, _js_idx1 = 0; _js_idx1 < y.length; _js_idx1 += 1) { x = y[_js_idx1]; function (x) { return x + 1; }; }; })();") (test-ps-js case-invert1 (encodeURIComponent fooBar) "encodeURIComponent(fooBar);") (test-ps-js simple-ash (+ (ash 4 1) (ash 4 -1)) "(4 << 1) + (4 >> 1);") (test-ps-js progn-nil-expression (bar (progn (foo) nil)) "bar((foo(), null));") (test-ps-js other-progn-nil-exp (defun blah () (or (foo) (progn (bar) nil))) "function blah() { return foo() || (bar(), null); };") (test-ps-js lambda-nil-return (lambda (x) (block nil (when x (return 1)) 2)) "(function (x) { if (x) { return 1; }; return 2; });") (test-ps-js lambda-nil-return-implicit-nested2 (lambda (x) (block foo (if x (return-from foo 1) (dotimes (i 4) (return-from foo i))) 2)) "(function (x) { if (x) { return 1; } else { for (var i = 0; i < 4; i += 1) { return i; }; }; return 2; });") (test-ps-js throw-is-a-statement (defun blah () (let ((result (foo))) (unless (null result) (throw result)))) "function blah() { var result = foo(); if (result != null) { throw result; }; };") (test-ps-js expressify1 (defun blah () (when (some-condition) (foo) (bar) (baz))) "function blah() { if (someCondition()) { foo(); bar(); return baz(); }; };") (test-ps-js case-when-return (defun blah (a) (case a ("a" (when (foo) (return-from blah 111))) ("b" t))) "function blah(a) { switch (a) { case 'a': if (foo()) { return 111; } else { return null; }; case 'b': return true; }; };") (test-ps-js flet-return-from (defun abc () (flet ((foo () (return-from foo 123))) (foo))) "function abc() { var foo = function () { return 123; }; return foo(); };") (test-ps-js flet-return-from1 (flet ((foo () (return-from foo 123))) (foo)) "(function () { var foo = function () { return 123; }; return foo(); })();") (test-ps-js lambda-docstring-declarations (lambda (x) "This is a docstring" (declare (ignore x)) 2) "(function (x) { return 2; });") (test-ps-js setf-let-exp (setf foo (let ((x (+ 1 2))) (if x 123 456))) "foo = (function () { var x = 1 + 2; return x ? 123 : 456; })();") (test-ps-js create-let-exp (create :abc (let ((x (+ 1 2))) (if x 123 456))) "({ 'abc' : (function () { var x = 1 + 2; return x ? 123 : 456; })() });") (test-ps-js eql-eql-eql-precedence (unless (equal (= 3 3) (= 3 4)) (chain console (log 1))) "if ((3 === 3) != (3 === 4)) { console.log(1); };") (test-ps-js case-cond-breaks (defun blah (x) (case x (123 (cond ((foo1) (when (foo2) (when (foo3) (return-from blah nil)) t)))) (456 (foo7)))) "function blah(x) { switch (x) { case 123: if (foo1()) { if (foo2()) { if (foo3()) { return null; }; return true; } else { return null; }; } else { return null; }; case 456: return foo7(); }; };") (test-ps-js cond-double-t (lambda () (cond (foo 1) (t 2) (t 3))) "(function () { if (foo) { return 1; } else { return 2; }; });") (test-ps-js let-let-funcall-lambda (let ((x 5)) (let ((x 7)) (funcall (lambda (x) (+ x 9)) x))) "(function () { var x = 5; var x1 = 7; return (function (x) { return x + 9; })(x1); })();") (test-ps-js let-let-lambda (let ((x 5)) (let ((x 7)) (lambda (x) (+ x 9)))) "(function () { var x = 5; var x1 = 7; return function (x) { return x + 9; }; })();") (test-ps-js let-lambda (let ((x 5)) (lambda (x) (+ x 9))) "(function () { var x = 5; return function (x) { return x + 9; }; })();") (test-ps-js symbol-macrolet-no-shadow-lambda (symbol-macrolet ((x y)) (lambda (x) (+ x x))) "(function (x) { return x + x; });") (test-ps-js divide-one-arg-reciprocal (/ 2) "1 / 2;") (test-ps-js division-not-associative (/ a (* b c)) "a / (b * c);") (test-ps-js divide-expressions (/ (foo) (bar)) "foo() / bar();") (test-ps-js divide-expressions1 (floor (1- x) y) "Math.floor((x - 1) / y);") (test-ps-js lexical-funargs-shadow1 (lambda (x) (let ((x 1)) (foo x)) (incf x)) "(function (x) { var x1 = 1; foo(x1); return ++x; });") (test-ps-js times-rem (* x (rem y z)) "x * (y % z);") (test-ps-js rem-divide (/ x (rem y z)) "x / (y % z);") (test-ps-js case-break-return (lambda () (case x (:foo) (:bar 1))) "(function () { switch (x) { case 'foo': return null; case 'bar': return 1; }; });") (test-ps-js trivial-expression-switch (foobar (case x (1 2))) "foobar((function () { switch (x) { case 1: return 2; }; })());") (test-ps-js trivial-expression-while (foobar (while (< 0 x) (decf x))) "foobar((function () { while (0 < x) { --x; }; })());") (test-ps-js funcall-block-expression-loop-lambda (foobar (loop for i from 0 to 10 do (1+ i))) "foobar((function () { for (var i = 0; i <= 10; i += 1) { i + 1; }; })());") (test-ps-js plus-block-expression-loop-lambda (1+ (loop for i from 0 to 10 do (1+ i))) "(function () { for (var i = 0; i <= 10; i += 1) { i + 1; }; })() + 1;") (test-ps-js let-closures-rename (lambda () (let ((x 1)) (lambda () (1+ x))) (let ((x 2)) (lambda () (1+ x)))) "(function () { var x = 1; function () { return x + 1; }; var x1 = 2; return function () { return x1 + 1; }; });") (test-ps-js let-closures-rename1 (lambda () (let ((x 1)) (let ((y 2)) (lambda () (+ x y)))) (let ((x 2)) (let ((y 3)) (lambda () (+ x y))))) "(function () { var x = 1; var y = 2; function () { return x + y; }; var x1 = 2; var y2 = 3; return function () { return x1 + y2; }; });") (test-ps-js let-closures-rename2 (defun make-closures () (list (let ((x 1)) (lambda () (1+ x))) (let ((x 2)) (lambda () (1+ x))))) "function makeClosures() { var x; var x1; return [(x = 1, function () { return x + 1; }), (x1 = 2, function () { return x1 + 1; })]; };") (test-ps-js conditional-not-used-up (lambda (bar) (when bar (let ((x 1)) (1+ x)))) "(function (bar) { if (bar) { var x = 1; return x + 1; }; });") (test-ps-js toplevel-local-scope (create "fn" (let ((x 5)) (lambda () x))) "({ 'fn' : (function () { var x = 5; return function () { return x; }; })() });") (test-ps-js toplevel-local-scope1 (defvar foo (create "fn" (let ((x 5)) (lambda () x)))) "var foo = { 'fn' : (function () { var x = 5; return function () { return x; }; })() };") (test-ps-js block-let (block foobar (let ((x 1)) (return-from foobar x) 2)) "(function () { var x = 1; return x; return 2; })();") (test-ps-js expressionize-if-macroexpand-error (progn (defmacro xbaz () `(blah)) (defun foo (xbaz) (unless (blah) (cond (xbaz (blah)) (t (blahblah)))))) "function foo(xbaz) { if (!blah()) { if (xbaz) { return blah(); } else { return blahblah(); }; }; };") (test-ps-js toplevel-defun-macroexpand (progn (defmacro defun-js (name lambda-list &body body) `(defun ,name ,lambda-list ,@body)) (let ((foo 0)) (defun-js bar () (1+ foo)) (defvar baz 2))) "var foo = 0; function bar() { return foo + 1; }; var baz = 2;") (test-ps-js js-ir-package-unique-symbols (loop :for i :from 0 :below 5 :do (let ((block (elt blocks i))) (foo block) (lambda () nil))) "(function () { for (var i = 0; i < 5; i += 1) { var block = blocks[i]; foo(block); function () { return null; }; }; })();") (test-ps-js broken-quote-expansion1 (lambda (p) (with-slots (x y) p (if (< x 0) y x))) "(function (p) { return p.x < 0 ? p.y : p.x; });") (test-ps-js broken-quote-expansion2 (progn (define-symbol-macro foo123 (ps:@ a foo123)) (lambda () (when (> foo123 1) 2))) "(function () { return a.foo123 > 1 ? 2 : null; });") (test-ps-js unused-named-block-not-printed1 (block foobar (+ 1 2 3)) "(function () { return 1 + 2 + 3; })();") (test-ps-js unused-named-block-not-printed2 (block nil (block nil (+ 1 2 3))) "(function () { return 1 + 2 + 3; })();") (test-ps-js unused-named-block-not-printed3 (block foobar (block nil (+ 1 2 3))) "(function () { return 1 + 2 + 3; })();") (test-ps-js unused-named-block-not-printed4 (block nil (block foobar (block nil (+ 1 2 3)))) "(function () { return 1 + 2 + 3; })();") (test-ps-js trig-no-bind1 (cosh 3.14) "(Math.exp(3.14) + Math.exp(-3.14)) / 2;") (test-ps-js trig-bind1 (acosh (blah 3.14)) "(function () { var x1 = blah(3.14); return 2 * Math.log(Math.sqrt((x1 + 1) / 2) + Math.sqrt((x1 - 1) / 2)); })();") (test-ps-js double-negation (or (not foo) (not (not foo)) (not (not (not foo)))) "!foo || foo || !foo;") (test-ps-js empty-let (defun foo () (let ((a (bar))))) "function foo() { var a = bar(); return null; };") (test-ps-js empty-let* (defun foo () (let* ((a (bar))))) "function foo() { var a = bar(); return null; };") (test-ps-js defun-no-body-declare (defun foo () (declare (ignore x))) "function foo() { return null; };") (test-ps-js defun-no-body-let-decare (defun foo () (let () (declare (ignore x)))) "function foo() { return null; };") (test-ps-js empty-defun-docstring-declare (defun foo (x) "docstring" (declare (ignore x))) "/** docstring */ function foo(x) { return null; };") (test-ps-js defun-docstring-string (defun foo (x) "docstring" "abc") "/** docstring */ function foo(x) { return 'abc'; };") (test-ps-js return-object (defun foo (obj) (ps:create :abc (let ((x (ps:getprop obj "blah"))) (if x 123 456)))) "function foo(obj) { var x; return { 'abc' : (x = obj['blah'], x ? 123 : 456) }; };") ;;; broken ;; (test-ps-js let-defun-toplevel ;; (progn (let ((foo 0)) ;; (defun bar () foo)) ;; (bar)) ;; "var bar_foo1 = 0; ;; function bar() { ;; return bar_foo1; ;; }; ;; bar();") ;; (test-ps-js let-defvar-toplevel ;; (progn (let ((foo 0)) ;; (defvar bar (1+ foo))) ;; bar) ;; "var bar_foo1 = 0; ;; var bar = bar_foo1 + 1; ;; bar;") ;; (test-ps-js setf-side-effects ;; (progn ;; (let ((x 10)) ;; (defun side-effect() ;; (setf x 4) ;; 3) ;; (setf x (+ 2 (side-effect) x 5)))) ;; "var sideEffect_x1 = 10; ;; function sideEffect() { ;; sideEffect_x1 = 4; ;; return 3; ;; }; ;; sideEffect_x1 = 2 + sideEffect() + x + 5;")