Verified Commit 5d143121 authored by Vladimir Sedach's avatar Vladimir Sedach
Browse files

Fixed capture of loop variables, up to let renaming

parent 76f33d35
......@@ -157,9 +157,9 @@ of (declare ...) forms, and the remaining body."
(defun compile-function-body (args body)
(with-declaration-effects (body body)
(let* ((in-function-scope? t)
(*vars-needing-to-be-declared* ())
(*used-up-names* ())
(let* ((in-function-scope? t)
(*vars-needing-to-be-declared* ())
(*used-up-names* ())
(*enclosing-function-arguments*
(append args *enclosing-function-arguments*))
(*enclosing-lexicals*
......@@ -185,8 +185,7 @@ of (declare ...) forms, and the remaining body."
(compile-statement
`(progn
,@(mapcar
(lambda (var)
`(var ,var))
(lambda (var) `(var ,var))
(remove-duplicates *vars-needing-to-be-declared*))))))
(when in-loop-scope? ;; this might be broken when it comes to let-renaming
(setf *loop-scope-lexicals-captured*
......
......@@ -634,24 +634,20 @@ Parenscript now implements implicit return, update your code! Things like (lambd
init-forms))
(defun compile-loop-body (loop-vars body)
(let* ((in-loop-scope? t)
;; provides lexical bindings for all free variables using WITH
(in-function-scope? t)
(*loop-scope-lexicals* loop-vars)
(*loop-scope-lexicals-captured* ())
(*ps-gensym-counter* *ps-gensym-counter*)
(compiled-body (compile-statement `(progn ,@body))))
;; the sort is there to make order for output-tests consistent across implementations
(aif (sort (remove-duplicates *loop-scope-lexicals-captured*)
#'string< :key #'symbol-name)
(let*
((in-loop-scope? t)
;; provides lexical bindings for all free variables using WITH
(in-function-scope? t)
(*loop-scope-lexicals* ())
(*loop-scope-lexicals-captured* ())
(*ps-gensym-counter* *ps-gensym-counter*)
(compiled-body (compile-statement `(progn ,@body))))
(aif (remove-duplicates *loop-scope-lexicals-captured*)
`(ps-js:block
(ps-js:with
,(compile-expression
`(create
,@(loop for x in it
collect x
collect (when (member x loop-vars) x))))
,compiled-body))
,(compile-expression
`(create ,@(mapcan (lambda (x) (list x nil)) it)))
,compiled-body))
compiled-body)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
......
......@@ -810,3 +810,25 @@
(test-js-eval lambda-not-a-docstring
((lambda () "bar"))
"bar")
(test-js-eval loop-variable-capture1
(let ((x (make-array 10)))
(dotimes (i 10) (setf (aref x i) (lambda () i)))
(loop for x across x sum (funcall x)))
100)
(test-js-eval loop-variable-capture2
(let ((x (make-array 10)))
(dotimes (i 10)
(let ((y i))
(setf (aref x i) (lambda () y))))
(loop for x across x sum (funcall x)))
45)
(test-js-eval loop-variable-capture3
(let ((x (make-array 10)))
(dotimes (i 10)
(let ((i i))
(setf (aref x i) (lambda () i))))
(loop for x across x sum (funcall x)))
45)
......@@ -2687,12 +2687,11 @@ return x.offsetLeft;
(test-ps-js try-catch-return
(defun foo ()
(return-from foo
(try (foo)
(:catch (e)
(bar))
(:finally
(cleanup)))))
(try (foo)
(:catch (e)
(bar))
(:finally
(cleanup))))
"function foo() {
try {
return foo();
......@@ -2703,6 +2702,21 @@ try {
};
};")
(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
......@@ -3327,15 +3341,12 @@ var x = bar();")
};
});")
;; closures in loops need a new binding per loop iteration (idea borrowed from Scheme2JS)
(test-ps-js loop-closures
(dotimes (i 10) (lambda () (+ i 1)))
"(function () {
for (var i = 0; i < 10; i += 1) {
with ({ i : i }) {
function () {
return i + 1;
};
function () {
return i + 1;
};
};
})();")
......@@ -3346,7 +3357,7 @@ for (var i = 0; i < 10; i += 1) {
(lambda () (+ i x))))
"(function () {
for (var i = 0; i < 10; i += 1) {
with ({ i : i, x : null }) {
with ({ x : null }) {
var x = i + 1;
function () {
return i + x;
......@@ -3356,10 +3367,12 @@ for (var i = 0; i < 10; i += 1) {
})();")
(test-ps-js loop-closures-flet
(dotimes (i 10) (flet ((foo (x) (+ i x))) (lambda () (foo i))))
(dotimes (i 10)
(flet ((foo (x) (+ i x)))
(lambda () (foo i))))
"(function () {
for (var i = 0; i < 10; i += 1) {
with ({ foo : null, i : i }) {
with ({ foo : null }) {
var foo = function (x) {
return i + x;
};
......@@ -3372,13 +3385,13 @@ for (var i = 0; i < 10; i += 1) {
(test-ps-js while-closures-let
(while (foo)
(let ((x (bar)))
(lambda () (+ 1 x))))
(let ((abc (bar)))
(lambda () (+ 1 abc))))
"while (foo()) {
with ({ x : null }) {
var x = bar();
with ({ abc : null }) {
var abc = bar();
function () {
return 1 + x;
return 1 + abc;
};
};
};")
......@@ -3529,14 +3542,13 @@ for (var i = 0; i < 10; i += 1) {
})();")
(test-ps-js iteration-lambda-capture-no-need
(dolist (x y) (lambda (x) (1+ x))) ;; there's really no need to create a 'with' scope in this case
(dolist (x y)
(lambda (x) (1+ x)))
"(function () {
for (var x = null, _js_idx1 = 0; _js_idx1 < y.length; _js_idx1 += 1) {
with ({ x : x }) {
x = y[_js_idx1];
function (x) {
return x + 1;
};
x = y[_js_idx1];
function (x) {
return x + 1;
};
};
})();")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment