From: Vladimir Sedach Date: Sun, 3 May 2009 20:42:12 +0000 (-0600) Subject: Implemented LET and LET* by variable renaming, which provides the X-Git-Url: http://git.hcoop.net/clinton/parenscript.git/commitdiff_plain/5ffb1ebaaff5e8f899fd4b1bd91b015f2c52d656 Implemented LET and LET* by variable renaming, which provides the 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. --- diff --git a/docs/reference.lisp b/docs/reference.lisp index 7d86890..fca8684 100644 --- a/docs/reference.lisp +++ b/docs/reference.lisp @@ -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 "
"))) + ((@ document write) (+ "a: " a " b: " b "
"))) => 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 + '
'); }; -;;; `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 "
"))) -=> 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 + '
'); - var _js3 = i + 1; - var _js4 = s + i + (i + 1); - i = _js3; - s = _js4; + ((@ document write) (+ "i: " i " s: " s "
"))) +=> var i1 = 0; + var s2 = 0; + for (; i1 <= 10; ) { + document.write('i: ' + i1 + ' s: ' + s2 + '
'); + 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 "
"))) + ((@ document write) (+ "i: " i " s: " s "
"))) => for (var i = 0, s = 0; i <= 10; i += 1, s += i + (i - 1)) { document.write('i: ' + i + ' s: ' + s + '
'); }; ;;; `DOTIMES': -(let* ((arr (array "a" "b" "c" "d" "e"))) - (dotimes (i arr.length) - (document.write (+ "i: " i " arr[i]: " (aref arr i) "
")))) -=> var arr = ['a', 'b', 'c', 'd', 'e']; - for (var i = 0; i < arr.length; i += 1) { - document.write('i: ' + i + ' arr[i]: ' + arr[i] + '
'); +(let ((arr (array "a" "b" "c" "d" "e"))) + (dotimes (i (@ arr length)) + ((@ document write) (+ "i: " i " arr[i]: " (aref arr i) "
")))) +=> var arr1 = ['a', 'b', 'c', 'd', 'e']; + for (var i = 0; i < arr1.length; i += 1) { + document.write('i: ' + i + ' arr[i]: ' + arr1[i] + '
'); }; ;;; `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 "
")))) -=> 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 "
")))) +=> 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 + '
'); }; -(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) "
")))) -=> var obj = { a : 1, b : 2, c : 3 }; - for (var i in obj) { - document.write(i + ': ' + obj[i] + '
'); + ((@ document write) (+ i ": " (aref obj i) "
")))) +=> var obj1 = { a : 1, b : 2, c : 3 }; + for (var i in obj1) { + document.write(i + ': ' + obj1[i] + '
'); }; ;;; 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('link') @@ -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 = 'Edit me'; ;;;# Macrology diff --git a/parenscript.asd b/parenscript.asd index c8d5696..e31b99e 100755 --- a/parenscript.asd +++ b/parenscript.asd @@ -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) diff --git a/src/compiler.lisp b/src/compiler.lisp index 2281ab3..0cc8dc7 100644 --- a/src/compiler.lisp +++ b/src/compiler.lisp @@ -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. diff --git a/src/lib/ps-macro-lib.lisp b/src/lib/ps-macro-lib.lisp index e6c32be..e3341e0 100644 --- a/src/lib/ps-macro-lib.lisp +++ b/src/lib/ps-macro-lib.lisp @@ -1,4 +1,4 @@ -(in-package :parenscript) +(in-package "PARENSCRIPT") ;;; Handy utilities for doing common tasks found in many web browser ;;; JavaScript implementations @@ -12,17 +12,17 @@ `(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)) @@ -31,21 +31,21 @@ (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 diff --git a/src/namespace.lisp b/src/namespace.lisp index 4bc2798..37b5b0d 100644 --- a/src/namespace.lisp +++ b/src/namespace.lisp @@ -29,8 +29,11 @@ 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))) diff --git a/src/package.lisp b/src/package.lisp index b57330b..41fbb6a 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -75,10 +75,6 @@ #:psetf #:setq #:psetq - #:simple-let* - #:simple-let - #:lexical-let* - #:lexical-let #:let* #:let diff --git a/src/printer.lisp b/src/printer.lisp index a4526ed..b649dae 100644 --- a/src/printer.lisp +++ b/src/printer.lisp @@ -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)) diff --git a/src/special-forms.lisp b/src/special-forms.lisp index 733db12..62d3864 100644 --- a/src/special-forms.lisp +++ b/src/special-forms.lisp @@ -198,14 +198,11 @@ ;;; 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)))) diff --git a/src/utils.lisp b/src/utils.lisp index f01a00c..31c488c 100644 --- a/src/utils.lisp +++ b/src/utils.lisp @@ -34,16 +34,15 @@ ;;; 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) @@ -54,43 +53,40 @@ 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)) diff --git a/t/package-system-tests.lisp b/t/package-system-tests.lisp index 05b9328..2fab062 100644 --- a/t/package-system-tests.lisp +++ b/t/package-system-tests.lisp @@ -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;") diff --git a/t/ps-tests.lisp b/t/ps-tests.lisp index 65f377b..69f1564 100644 --- a/t/ps-tests.lisp +++ b/t/ps-tests.lisp @@ -16,17 +16,17 @@ (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;") diff --git a/t/reference-tests.lisp b/t/reference-tests.lisp index 0701942..f3f7f88 100644 --- a/t/reference-tests.lisp +++ b/t/reference-tests.lisp @@ -31,14 +31,10 @@ *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") @@ -107,8 +103,8 @@ "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 @@ -159,10 +155,6 @@ *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)") @@ -183,10 +175,6 @@ ((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 "
"))) + ((@ document write) (+ "a: " a " b: " b "
"))) "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 "
"))) - "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 + '
'); - var _js3 = i + 1; - var _js4 = s + i + (i + 1); - i = _js3; - s = _js4; + ((@ document write) (+ "i: " i " s: " s "
"))) + "var i1 = 0; +var s2 = 0; +for (; i1 <= 10; ) { + document.write('i: ' + i1 + ' s: ' + s2 + '
'); + 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 "
"))) + ((@ document write) (+ "i: " i " s: " s "
"))) "for (var i = 0, s = 0; i <= 10; i += 1, 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) "
")))) - "var arr = ['a', 'b', 'c', 'd', 'e']; -for (var i = 0; i < arr.length; i += 1) { - document.write('i: ' + i + ' arr[i]: ' + arr[i] + '
'); + (let ((arr (array "a" "b" "c" "d" "e"))) + (dotimes (i (@ arr length)) + ((@ document write) (+ "i: " i " arr[i]: " (aref arr i) "
")))) + "var arr1 = ['a', 'b', 'c', 'd', 'e']; +for (var i = 0; i < arr1.length; i += 1) { + document.write('i: ' + i + ' arr[i]: ' + arr1[i] + '
'); };") (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 "
")))) - "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 "
")))) + "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 + '
'); };") (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) "
")))) - "var obj = { a : 1, b : 2, c : 3 }; -for (var i in obj) { - document.write(i + ': ' + obj[i] + '
'); + ((@ document write) (+ i ": " (aref obj i) "
")))) + "var obj1 = { a : 1, b : 2, c : 3 }; +for (var i in obj1) { + document.write(i + ': ' + obj1[i] + '
'); };") (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) { "'blorg'") (test-ps-js the-html-generator-3 - (document.write + ((@ document write) (ps-html ((:a :href "#" :onclick (ps-inline (transport))) "link"))) "document.write('link')") (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 = 'Edit me';")