It has been a rough week, i finally find time to write this email. I think
i have finished the code to support javascript continuations in core server
just like the one in jwacs, narrativejs, flapjax etc.
To be precise, ivent implemented a trampoline to run cps, since i don't
think we need endless recursion, i generally see web apps as running until
ve save the current continuation to some kind of event (ie click event of a
button).
I've implemented a one pass cps conversion functor here:
http://labs.core.gen.tr/repos/core-server/src/javascript/cps.lisp
Moreover, i've added a beta reductor function "fix-excessive-recursion" in
order firefox 3.5.2 do not complain as "too much recursion".
In order to use cps style javascript, one may need a lisp-style javascript
library located at:
http://labs.core.gen.tr/repos/core-server/src/javascript/library.lisp
Every application defined has the url handler registered at "library.*" to
serve the javascript library, so it's enough to embed it to you pages via a
<script> tag.
Let's see how it works on the repl:
SERVER> (with-js () (make-indented-stream *core-output*)
(with-call/cc
(lambda ()
(let/cc k
(let ((a (+ 2 3)))
(call/cc k a))))))
k(function (k13225) {
var k = k13225;
return k(2 + 3, k);
})
- The k at the begining is the identity k which is actually window.k in a
browser, it is simply the identity function (ie function (a) { return a; })
provided by the library.
- The cps functor adds a last variable k to every lambda defined.
- To define a function use defun/cc:
SERVER> (with-js () (make-indented-stream *core-output*)
(defun/cc add-me (a)
(+ a 3)))
function addMe(a, k3229) {
k3229 = k3229 || window.k;
return k3229(a + 3);
}
- When we define functions with defun/cc, functor will record that
specific function would be called as cps style:
SERVER> (with-js () (make-indented-stream *core-output*)
(with-call/cc
(add-me 1)))
addMe(1, k)
- Normal functions are called as normal:
SERVER> (with-js () (make-indented-stream *core-output*)
(with-call/cc
(console.debug 1 2 3)))
k(console.debug(1, 2, 3))
- Saving current-continuation:
SERVER> (with-js () (make-indented-stream *core-output*)
(with-call/cc
(lambda ()
(let/cc k
(setf window.current-k k)))))
k(function (k13242) {
var k = k13242;
return k(window.currentK = k);
})
- Continuing the k:
SERVER> (with-js () (make-indented-stream *core-output*)
(with-call/cc
(call/cc window.k 1)))
window.k(1, k)
- Suspending the control flow:
SERVER> (with-js () (make-indented-stream *core-output*)
(with-call/cc
(lambda ()
(let/cc k
(setf window.current-k k)
(suspend)))))
k(function (k13250) {
var k = k13250;
window.currentK = k;
return null;
})
So far so good. Now let's see how this helps us to get to the point, let's
see the funcall-cc function in our library:
(defun/cc funcall-cc (action args)
(let/cc current-continuation
(let ((hash (+ "__result"
(.get-time (new (*date)))
(.substr (*string.concat "" (*math.random 10)) 3 5))))
(setf (slot-value args "__hash") hash)
(let ((script (make-dom-element "script"
(jobject :src
(+ "" action (serialize-to-uri args)))
nil)))
(setf (slot-value script 'onload)
(event ()
(document.body.remove-child script)
(current-continuation (slot-value window hash))))
(document.body.append-child script)
(suspend)))))
and the result:
function funcallCc(action, args, k7) {
k7 = k7 || window.k;
var currentContinuation = k7;
var g8 = '__result' + new Date().getTime() + String.concat('',
Math.random(10)).substr(3, 5);
args['__hash'] = g8;
var g11 = makeDomElement('script', {
src: '' + action + serializeToUri(args)
}, null);
g11.onload = function () {
document.body.removeChild(g11);
return currentContinuation(window[g8]);
};
document.body.appendChild(g11);
return null;
};
This is the real catch i've been upto for a while. Now we can make
function calls to core-server from any client without the CROOS-DOMAIN
security restriction since we only add a script tag to the browser document
not calling the so called XMLHttpRequest object. The only problem here is
URL length is fixed across browser but it can be easily worked out with a
transaction macro which accumulates long parameters.
I know my mail is somewhat over-crowded. I'll try to document it soon when
i finish fixing small bugs in javascript component system. I just wanted to
get attention to what's going on in the core server development team.
Have a nice day,
Evrim.