Mercurial > urweb
diff lib/js/urweb.js @ 1260:25ebd8c4fafb
Thunking recursive JavaScripted function ASTs, to reduce page load time dramatically
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Sat, 22 May 2010 14:09:06 -0400 |
parents | 83b1853d1e58 |
children | 003df929ee08 |
line wrap: on
line diff
--- a/lib/js/urweb.js Tue May 18 14:47:56 2010 -0400 +++ b/lib/js/urweb.js Sat May 22 14:09:06 2010 -0400 @@ -1,10 +1,10 @@ // Detect browser quirks that we should be aware of. function needsDynPrefix() { - var span = document.createElement("span"); - span.innerHTML = "<script>alert('test');</script>"; - var scripts = span.getElementsByTagName("script"); - return scripts.length == 0; + var span = document.createElement("span"); + span.innerHTML = "<script>alert('test');</script>"; + var scripts = span.getElementsByTagName("script"); + return scripts.length == 0; } var dynPrefix = needsDynPrefix() ? "<span style=\"display:none\">A</span>" : ""; @@ -40,196 +40,196 @@ // Lists function cons(v, ls) { - return { next : ls, data : v }; + return { next : ls, data : v }; } function rev(ls) { - var acc = null; - for (; ls; ls = ls.next) - acc = cons(ls.data, acc); - return acc; + var acc = null; + for (; ls; ls = ls.next) + acc = cons(ls.data, acc); + return acc; } function concat(ls1, ls2) { - var acc = ls2; - ls1 = rev(ls1); - for (; ls1; ls1 = ls1.next) - acc = cons(ls1.data, acc); - return acc; + var acc = ls2; + ls1 = rev(ls1); + for (; ls1; ls1 = ls1.next) + acc = cons(ls1.data, acc); + return acc; } function member(x, ls) { - for (; ls; ls = ls.next) - if (ls.data == x) - return true; - return false; + for (; ls; ls = ls.next) + if (ls.data == x) + return true; + return false; } function remove(x, ls) { - var acc = null; + var acc = null; - for (; ls; ls = ls.next) - if (ls.data == x) - return concat(acc, ls.next); - else - acc = cons(ls.data, acc); + for (; ls; ls = ls.next) + if (ls.data == x) + return concat(acc, ls.next); + else + acc = cons(ls.data, acc); - return ls; + return ls; } function union(ls1, ls2) { - var acc = ls2; + var acc = ls2; - for (; ls1; ls1 = ls1.next) - if (!member(ls1.data, ls2)) - acc = cons(ls1.data, acc); + for (; ls1; ls1 = ls1.next) + if (!member(ls1.data, ls2)) + acc = cons(ls1.data, acc); - return acc; + return acc; } function length(ls) { - var acc = 0; + var acc = 0; - for (; ls; ls = ls.next) - ++acc; + for (; ls; ls = ls.next) + ++acc; - return acc; + return acc; } // Error handling function whine(msg) { - alert(msg); - throw msg; + alert(msg); + throw msg; } function pf(loc) { - throw ("Pattern match failure (" + loc + ")"); + throw ("Pattern match failure (" + loc + ")"); } function runHandlers(kind, ls, arg) { - if (ls == null) - alert(kind + ": " + arg); - for (; ls; ls = ls.next) - try { - exec({c:"a", f:{c:"a", f:ls.data, x:{c:"c", v:arg}}, x:{c:"c", v:null}}); - } catch (v) { } + if (ls == null) + alert(kind + ": " + arg); + for (; ls; ls = ls.next) + try { + exec({c:"a", f:{c:"a", f:ls.data, x:{c:"c", v:arg}}, x:{c:"c", v:null}}); + } catch (v) { } } var errorHandlers = null; function onError(f) { - errorHandlers = cons(f, errorHandlers); + errorHandlers = cons(f, errorHandlers); } function er(s) { - runHandlers("Error", errorHandlers, s); - throw {uw_error: s}; + runHandlers("Error", errorHandlers, s); + throw {uw_error: s}; } var failHandlers = null; function onFail(f) { - failHandlers = cons(f, failHandlers); + failHandlers = cons(f, failHandlers); } function doExn(v) { - if (v == null || v.uw_error == null) { - var s = (v == null ? "null" : v.message ? v.message : v.toString()); - if (v != null && v.fileName && v.lineNumber) - s += " (" + v.fileName + ":" + v.lineNumber + ")"; - runHandlers("Fail", failHandlers, s); - } + if (v == null || v.uw_error == null) { + var s = (v == null ? "null" : v.message ? v.message : v.toString()); + if (v != null && v.fileName && v.lineNumber) + s += " (" + v.fileName + ":" + v.lineNumber + ")"; + runHandlers("Fail", failHandlers, s); + } } var disconnectHandlers = null; function flift(f) { - return {env:cons(f,null), body:{c:"v", n:1}}; + return {env:cons(f,null), body:{c:"v", n:1}}; } function onDisconnect(f) { - disconnectHandlers = cons(flift(f), disconnectHandlers); + disconnectHandlers = cons(flift(f), disconnectHandlers); } function discon() { - runHandlers("Disconnect", disconnectHandlers, null); + runHandlers("Disconnect", disconnectHandlers, null); } var connectHandlers = null; function onConnectFail(f) { - connectHandlers = cons(flift(f), connectHandlers); + connectHandlers = cons(flift(f), connectHandlers); } function conn() { - runHandlers("Connect", connectHandlers, null); + runHandlers("Connect", connectHandlers, null); } var serverHandlers = null; function onServerError(f) { - serverHandlers = cons(f, serverHandlers); + serverHandlers = cons(f, serverHandlers); } function servErr(s) { - window.setTimeout(function () { runHandlers("Server", serverHandlers, s); }, 0); + window.setTimeout(function () { runHandlers("Server", serverHandlers, s); }, 0); } // Embedding closures in XML strings function cs(f) { - return {closure: f}; + return {closure: f}; } function isWeird(v) { - return v.closure != null || v.cat1 != null; + return v.closure != null || v.cat1 != null; } function cat(s1, s2) { - if (isWeird(s1) || isWeird(s2)) - return {cat1: s1, cat2: s2}; - else - return s1 + s2; + if (isWeird(s1) || isWeird(s2)) + return {cat1: s1, cat2: s2}; + else + return s1 + s2; } var closures = []; var freeClosures = null; function newClosure(f) { - var n; - if (freeClosures == null) { - n = closures.length; - } else { - n = freeClosures.data; - freeClosures = freeClosures.next; - } - closures[n] = f; - return n; + var n; + if (freeClosures == null) { + n = closures.length; + } else { + n = freeClosures.data; + freeClosures = freeClosures.next; + } + closures[n] = f; + return n; } function freeClosure(n) { - closures[n] = null; - freeClosures = cons(n, freeClosures); + closures[n] = null; + freeClosures = cons(n, freeClosures); } function cr(n) { - return closures[n]; + return closures[n]; } function flatten(cls, tr) { - if (tr.cat1 != null) - return flatten(cls, tr.cat1) + flatten(cls, tr.cat2); - else if (tr.closure != null) { - var cl = newClosure(tr.closure); - cls.v = cons(cl, cls.v); - return "cr(" + cl + ")"; - } else - return tr; + if (tr.cat1 != null) + return flatten(cls, tr.cat1) + flatten(cls, tr.cat2); + else if (tr.closure != null) { + var cl = newClosure(tr.closure); + cls.v = cons(cl, cls.v); + return "cr(" + cl + ")"; + } else + return tr; } function flattenLocal(s) { - var cls = {v : null}; - var r = flatten(cls, s); - for (cl = cls.v; cl != null; cl = cl.next) - freeClosure(cl.data); - return r; + var cls = {v : null}; + var r = flatten(cls, s); + for (cl = cls.v; cl != null; cl = cl.next) + freeClosure(cl.data); + return r; } @@ -237,292 +237,292 @@ // Dynamic tree management function populate(node) { - var s = node.signal; - var oldSources = node.sources; - try { - var sr = execF(s, null); - var newSources = sr._sources; + var s = node.signal; + var oldSources = node.sources; + try { + var sr = execF(s, null); + var newSources = sr._sources; - for (var sp = oldSources; sp; sp = sp.next) - if (!member(sp.data, newSources)) - sp.data.dyns = remove(node, sp.data.dyns); + for (var sp = oldSources; sp; sp = sp.next) + if (!member(sp.data, newSources)) + sp.data.dyns = remove(node, sp.data.dyns); - for (var sp = newSources; sp; sp = sp.next) - if (!member(sp.data, oldSources)) - sp.data.dyns = cons(node, sp.data.dyns); + for (var sp = newSources; sp; sp = sp.next) + if (!member(sp.data, oldSources)) + sp.data.dyns = cons(node, sp.data.dyns); - node.sources = newSources; - node.recreate(sr._data); - } catch (v) { - doExn(v); - } + node.sources = newSources; + node.recreate(sr._data); + } catch (v) { + doExn(v); + } } function sc(v) { - return {data : v, dyns : null}; + return {data : v, dyns : null}; } function sv(s, v) { - s.data = v; + s.data = v; - for (var ls = s.dyns; ls; ls = ls.next) - if (!ls.dead) - populate(ls.data); + for (var ls = s.dyns; ls; ls = ls.next) + if (!ls.dead) + populate(ls.data); } function sg(s) { - return s.data; + return s.data; } function ss(s) { - return {env:cons(s, null), body:{c:"r", l: - cons({n:"sources", v:{c:"c", v:cons(s, null)}}, - cons({n:"data", v:{c:"f", f:sg, a:cons({c:"v", n:1}, null)}}, null))}}; + return {env:cons(s, null), body:{c:"r", l: + cons({n:"sources", v:{c:"c", v:cons(s, null)}}, + cons({n:"data", v:{c:"f", f:sg, a:cons({c:"v", n:1}, null)}}, null))}}; } function sr(v) { - return {env:null, body:{c:"c", v:{_sources : null, _data : v}}}; + return {env:null, body:{c:"c", v:{_sources : null, _data : v}}}; } function sb(x,y) { - return {env:cons(y,cons(x,null)), - body:{c:"=", - e1:{c:"a", f:{c:"v", n:2}, x:{c:"c", v:null}}, - e2:{c:"=", - e1:{c:"a", - f:{c:"a", f:{c:"v", n:2}, x:{c:".", r:{c:"v", n:0}, f:"data"}}, - x:{c:"c", v:null}}, - e2:{c:"r", l:cons( - {n:"sources", v:{c:"f", f:union, a:cons({c:".", r:{c:"v", n:1}, f:"sources"}, - cons({c:".", r:{c:"v", n:0}, f:"sources"}, null))}}, - cons({n:"data", v:{c:".", r:{c:"v", n:0}, f:"data"}}, null))}}}}; + return {env:cons(y,cons(x,null)), + body:{c:"=", + e1:{c:"a", f:{c:"v", n:2}, x:{c:"c", v:null}}, + e2:{c:"=", + e1:{c:"a", + f:{c:"a", f:{c:"v", n:2}, x:{c:".", r:{c:"v", n:0}, f:"data"}}, + x:{c:"c", v:null}}, + e2:{c:"r", l:cons( + {n:"sources", v:{c:"f", f:union, a:cons({c:".", r:{c:"v", n:1}, f:"sources"}, + cons({c:".", r:{c:"v", n:0}, f:"sources"}, null))}}, + cons({n:"data", v:{c:".", r:{c:"v", n:0}, f:"data"}}, null))}}}}; } function scur(s) { - return execF(s, null)._data; + return execF(s, null)._data; } function lastParent() { - var pos = document.body; + var pos = document.body; - while (pos.lastChild && pos.lastChild.nodeType == 1) - pos = pos.lastChild; + while (pos.lastChild && pos.lastChild.nodeType == 1) + pos = pos.lastChild; - pos = pos.parentNode; + pos = pos.parentNode; - return pos; + return pos; } function parent() { - return thisScript ? thisScript.parentNode : lastParent(); + return thisScript ? thisScript.parentNode : lastParent(); } function addNode(node) { - if (thisScript) - thisScript.parentNode.replaceChild(node, thisScript); - else - lastParent().appendChild(node); + if (thisScript) + thisScript.parentNode.replaceChild(node, thisScript); + else + lastParent().appendChild(node); } var thisScript = null; function runScripts(node) { - if (node.getElementsByTagName) { - var savedScript = thisScript; + if (node.getElementsByTagName) { + var savedScript = thisScript; - var scripts = node.getElementsByTagName("script"), scriptsCopy = []; - var len = scripts.length; - for (var i = 0; i < len; ++i) - scriptsCopy[i] = scripts[i]; - for (var i = 0; i < len; ++i) { - thisScript = scriptsCopy[i]; + var scripts = node.getElementsByTagName("script"), scriptsCopy = []; + var len = scripts.length; + for (var i = 0; i < len; ++i) + scriptsCopy[i] = scripts[i]; + for (var i = 0; i < len; ++i) { + thisScript = scriptsCopy[i]; - try { - eval(thisScript.text); - } catch (v) { - doExn(v); - } - if (thisScript.parentNode) - thisScript.parentNode.removeChild(thisScript); + try { + eval(thisScript.text); + } catch (v) { + doExn(v); + } + if (thisScript.parentNode) + thisScript.parentNode.removeChild(thisScript); + } + + thisScript = savedScript; } - - thisScript = savedScript; - } } // Dynamic tree entry points function killScript(scr) { - scr.dead = true; - for (var ls = scr.sources; ls; ls = ls.next) - ls.data.dyns = remove(scr, ls.data.dyns); - for (var ls = scr.closures; ls; ls = ls.next) - freeClosure(ls.data); + scr.dead = true; + for (var ls = scr.sources; ls; ls = ls.next) + ls.data.dyns = remove(scr, ls.data.dyns); + for (var ls = scr.closures; ls; ls = ls.next) + freeClosure(ls.data); } function dyn(pnode, s) { - var x = document.createElement("script"); - x.dead = false; - x.signal = s; - x.sources = null; - x.closures = null; + var x = document.createElement("script"); + x.dead = false; + x.signal = s; + x.sources = null; + x.closures = null; - var firstChild = null; + var firstChild = null; - x.recreate = function(v) { - for (var ls = x.closures; ls; ls = ls.next) - freeClosure(ls.data); - - var next; - for (var child = firstChild; child && child != x; child = next) { - next = child.nextSibling; - - killScript(child); - if (child.getElementsByTagName) { - var arr = child.getElementsByTagName("script"); - for (var i = 0; i < arr.length; ++i) - killScript(arr[i]); - } - - if (child.parentNode) - child.parentNode.removeChild(child); - } - - var cls = {v : null}; - var html = flatten(cls, v); - if (pnode != "table" && pnode != "tr") - html = dynPrefix + html; - x.closures = cls.v; - - if (pnode == "table") { - var dummy = document.createElement("body"); - dummy.innerHTML = "<table>" + html + "</table>"; - runScripts(dummy); - var table = x.parentNode; - - if (table) { - firstChild = null; - var tbody; - - var arr = dummy.getElementsByTagName("tbody"); - - var tbody; - if (arr.length > 0 && arr[0].parentNode == dummy.firstChild) { - tbody = arr[0]; - var next; - for (var node = dummy.firstChild.firstChild; node; node = next) { - next = node.nextSibling; - - if (node.tagName != "TBODY") - tbody.appendChild(node); - } - } else - tbody = dummy.firstChild; + x.recreate = function(v) { + for (var ls = x.closures; ls; ls = ls.next) + freeClosure(ls.data); var next; - firstChild = document.createElement("script"); - table.insertBefore(firstChild, x); - for (var node = tbody.firstChild; node; node = next) { - next = node.nextSibling; - table.insertBefore(node, x); + for (var child = firstChild; child && child != x; child = next) { + next = child.nextSibling; + + killScript(child); + if (child.getElementsByTagName) { + var arr = child.getElementsByTagName("script"); + for (var i = 0; i < arr.length; ++i) + killScript(arr[i]); + } + + if (child.parentNode) + child.parentNode.removeChild(child); } - } - } else if (pnode == "tr") { - var dummy = document.createElement("body"); - dummy.innerHTML = "<table><tr>" + html + "</tr></table>"; - runScripts(dummy); - var table = x.parentNode; - if (table) { - var arr = dummy.getElementsByTagName("tr"); - firstChild = null; - var tr; - if (arr.length > 0 && table != null) - tr = arr[0]; - else - tr = dummy.firstChild; + var cls = {v : null}; + var html = flatten(cls, v); + if (pnode != "table" && pnode != "tr") + html = dynPrefix + html; + x.closures = cls.v; - var next; - firstChild = document.createElement("script"); - table.insertBefore(firstChild, x); - for (var node = tr.firstChild; node; node = next) { - next = node.nextSibling; - table.insertBefore(node, x); + if (pnode == "table") { + var dummy = document.createElement("body"); + dummy.innerHTML = "<table>" + html + "</table>"; + runScripts(dummy); + var table = x.parentNode; + + if (table) { + firstChild = null; + var tbody; + + var arr = dummy.getElementsByTagName("tbody"); + + var tbody; + if (arr.length > 0 && arr[0].parentNode == dummy.firstChild) { + tbody = arr[0]; + var next; + for (var node = dummy.firstChild.firstChild; node; node = next) { + next = node.nextSibling; + + if (node.tagName != "TBODY") + tbody.appendChild(node); + } + } else + tbody = dummy.firstChild; + + var next; + firstChild = document.createElement("script"); + table.insertBefore(firstChild, x); + for (var node = tbody.firstChild; node; node = next) { + next = node.nextSibling; + table.insertBefore(node, x); + } + } + } else if (pnode == "tr") { + var dummy = document.createElement("body"); + dummy.innerHTML = "<table><tr>" + html + "</tr></table>"; + runScripts(dummy); + var table = x.parentNode; + + if (table) { + var arr = dummy.getElementsByTagName("tr"); + firstChild = null; + var tr; + if (arr.length > 0 && table != null) + tr = arr[0]; + else + tr = dummy.firstChild; + + var next; + firstChild = document.createElement("script"); + table.insertBefore(firstChild, x); + for (var node = tr.firstChild; node; node = next) { + next = node.nextSibling; + table.insertBefore(node, x); + } + } + } else { + firstChild = document.createElement("span"); + firstChild.innerHTML = html; + runScripts(firstChild); + if (x.parentNode) + x.parentNode.insertBefore(firstChild, x); } - } - } else { - firstChild = document.createElement("span"); - firstChild.innerHTML = html; - runScripts(firstChild); - if (x.parentNode) - x.parentNode.insertBefore(firstChild, x); - } - }; + }; - addNode(x); - populate(x); + addNode(x); + populate(x); } function input(x, s, recreate, type) { - if (type) x.type = type; - x.dead = false; - x.signal = ss(s); - x.sources = null; - x.recreate = recreate(x); - addNode(x); - populate(x); + if (type) x.type = type; + x.dead = false; + x.signal = ss(s); + x.sources = null; + x.recreate = recreate(x); + addNode(x); + populate(x); - return x; + return x; } function inp(s) { - var x = input(document.createElement("input"), s, - function(x) { return function(v) { if (x.value != v) x.value = v; }; }); - x.value = s.data; - x.onkeyup = function() { sv(s, x.value) }; + var x = input(document.createElement("input"), s, + function(x) { return function(v) { if (x.value != v) x.value = v; }; }); + x.value = s.data; + x.onkeyup = function() { sv(s, x.value) }; - return x; + return x; } function sel(s, content) { - var dummy = document.createElement("span"); - dummy.innerHTML = "<select>" + content + "</select>"; - var x = input(dummy.firstChild, s, function(x) { return function(v) { if (x.value != v) x.value = v; }; }); - x.value = s.data; - if (x.value != s.data) - sv(s, x.value); - x.onchange = function() { sv(s, x.value) }; + var dummy = document.createElement("span"); + dummy.innerHTML = "<select>" + content + "</select>"; + var x = input(dummy.firstChild, s, function(x) { return function(v) { if (x.value != v) x.value = v; }; }); + x.value = s.data; + if (x.value != s.data) + sv(s, x.value); + x.onchange = function() { sv(s, x.value) }; - return x; + return x; } function chk(s) { - var x = input(document.createElement("input"), s, - function(x) { return function(v) { if (x.checked != v) x.checked = v; }; }, "checkbox"); - x.defaultChecked = x.checked = s.data; - x.onclick = function() { sv(s, x.checked) }; + var x = input(document.createElement("input"), s, + function(x) { return function(v) { if (x.checked != v) x.checked = v; }; }, "checkbox"); + x.defaultChecked = x.checked = s.data; + x.onclick = function() { sv(s, x.checked) }; - return x; + return x; } function tbx(s) { - var x = input(document.createElement("textarea"), s, - function(x) { return function(v) { if (x.innerHTML != v) x.innerHTML = v; }; }); - x.innerHTML = s.data; - x.onkeyup = function() { sv(s, x.value) }; + var x = input(document.createElement("textarea"), s, + function(x) { return function(v) { if (x.innerHTML != v) x.innerHTML = v; }; }); + x.innerHTML = s.data; + x.onkeyup = function() { sv(s, x.value) }; - return x; + return x; } function addOnChange(x, f) { - var old = x.onchange; - x.onchange = function() { old(); f (); }; + var old = x.onchange; + x.onchange = function() { old(); f (); }; } // Basic string operations function eh(x) { - if (x == null) - return "NULL"; - else - return x.split("&").join("&").split("<").join("<").split(">").join(">"); + if (x == null) + return "NULL"; + else + return x.split("&").join("&").split("<").join("<").split(">").join(">"); } function ts(x) { return x.toString() } @@ -533,102 +533,102 @@ function suf(s, i) { return s.substring(i); } function slen(s) { return s.length; } function sidx(s, ch) { - var r = s.indexOf(ch); - if (r == -1) - return null; - else - return r; + var r = s.indexOf(ch); + if (r == -1) + return null; + else + return r; } function sspn(s, chs) { - for (var i = 0; i < s.length; ++i) - if (chs.indexOf(s.charAt(i)) != -1) - return i; + for (var i = 0; i < s.length; ++i) + if (chs.indexOf(s.charAt(i)) != -1) + return i; - return null; + return null; } function schr(s, ch) { - var r = s.indexOf(ch); - if (r == -1) - return null; - else - return s.substring(r); + var r = s.indexOf(ch); + if (r == -1) + return null; + else + return s.substring(r); } function ssub(s, start, len) { - return s.substring(start, start+len); + return s.substring(start, start+len); } function pi(s) { - var r = parseInt(s); - if (r.toString() == s) - return r; - else - er("Can't parse int: " + s); + var r = parseInt(s); + if (r.toString() == s) + return r; + else + er("Can't parse int: " + s); } function pfl(s) { - var r = parseFloat(s); - if (r.toString() == s) - return r; - else - er("Can't parse float: " + s); + var r = parseFloat(s); + if (r.toString() == s) + return r; + else + er("Can't parse float: " + s); } function pio(s) { - var r = parseInt(s); - if (r.toString() == s) - return r; - else - return null; + var r = parseInt(s); + if (r.toString() == s) + return r; + else + return null; } function pflo(s) { - var r = parseFloat(s); - if (r.toString() == s) - return r; - else - return null; + var r = parseFloat(s); + if (r.toString() == s) + return r; + else + return null; } function uf(s) { - if (s.length == 0) - return "_"; - s = s.replace(new RegExp ("\\.", "g"), ".2E"); - return (s.charAt(0) == '_' ? "_" : "") + encodeURIComponent(s).replace(new RegExp ("%", "g"), "."); + if (s.length == 0) + return "_"; + s = s.replace(new RegExp ("\\.", "g"), ".2E"); + return (s.charAt(0) == '_' ? "_" : "") + encodeURIComponent(s).replace(new RegExp ("%", "g"), "."); } function uu(s) { - if (s.length > 0 && s.charAt(0) == '_') { - s = s.substring(1); - } else if (s.length >= 3 && (s.charAt(0) == '%' || s.charAt(0) == '.') - && s.charAt(1) == '5' && (s.charAt(2) == 'f' || s.charAt(2) == 'F')) - s = s.substring(3); - s = s.replace(new RegExp ("\\+", "g"), " "); - s = s.replace(new RegExp ("\\.", "g"), "%"); - return decodeURIComponent(s); + if (s.length > 0 && s.charAt(0) == '_') { + s = s.substring(1); + } else if (s.length >= 3 && (s.charAt(0) == '%' || s.charAt(0) == '.') + && s.charAt(1) == '5' && (s.charAt(2) == 'f' || s.charAt(2) == 'F')) + s = s.substring(3); + s = s.replace(new RegExp ("\\+", "g"), " "); + s = s.replace(new RegExp ("\\.", "g"), "%"); + return decodeURIComponent(s); } function atr(s) { - return s.replace(new RegExp ("\"", "g"), """).replace(new RegExp ("&", "g"), "&") -} + return s.replace(new RegExp ("\"", "g"), """).replace(new RegExp ("&", "g"), "&") + } function ub(b) { - return b ? "1" : "0"; + return b ? "1" : "0"; } function uul(getToken, getData) { - var tok = getToken(); - if (tok == "Nil") { - return null; - } else if (tok == "Cons") { - var d = getData(); - var l = uul(getToken, getData); - return {_1:d, _2:l}; - } else - whine("Can't unmarshal list (" + tok + ")"); + var tok = getToken(); + if (tok == "Nil") { + return null; + } else if (tok == "Cons") { + var d = getData(); + var l = uul(getToken, getData); + return {_1:d, _2:l}; + } else + whine("Can't unmarshal list (" + tok + ")"); } function strcmp(str1, str2) { - return ((str1 == str2) ? 0 : ((str1 > str2) ? 1 : -1)); + return ((str1 == str2) ? 0 : ((str1 > str2) ? 1 : -1)); } @@ -641,19 +641,19 @@ function getXHR(uri) { - try { - return new XMLHttpRequest(); - } catch (e) { try { - return new ActiveXObject("Msxml2.XMLHTTP"); + return new XMLHttpRequest(); } catch (e) { - try { - return new ActiveXObject("Microsoft.XMLHTTP"); - } catch (e) { - whine("Your browser doesn't seem to support AJAX."); - } + try { + return new ActiveXObject("Msxml2.XMLHTTP"); + } catch (e) { + try { + return new ActiveXObject("Microsoft.XMLHTTP"); + } catch (e) { + whine("Your browser doesn't seem to support AJAX."); + } + } } - } } var sig = null; @@ -661,230 +661,230 @@ var unloading = false, inFlight = null; function unload() { - unloading = true; + unloading = true; - for (; inFlight; inFlight = inFlight.next) { - inFlight.data.abort(); - } + for (; inFlight; inFlight = inFlight.next) { + inFlight.data.abort(); + } } function requestUri(xhr, uri, needsSig) { - if (unloading) - return; + if (unloading) + return; - xhr.open("POST", uri, true); - xhr.setRequestHeader("Content-type", "text/plain"); - xhr.setRequestHeader("Content-length", "0"); - xhr.setRequestHeader("Connection", "close"); + xhr.open("POST", uri, true); + xhr.setRequestHeader("Content-type", "text/plain"); + xhr.setRequestHeader("Content-length", "0"); + xhr.setRequestHeader("Connection", "close"); - if (client_id != null) { - xhr.setRequestHeader("UrWeb-Client", client_id.toString()); - xhr.setRequestHeader("UrWeb-Pass", client_pass.toString()); - } + if (client_id != null) { + xhr.setRequestHeader("UrWeb-Client", client_id.toString()); + xhr.setRequestHeader("UrWeb-Pass", client_pass.toString()); + } - if (needsSig) { - if (sig == null) - whine("Missing cookie signature!"); + if (needsSig) { + if (sig == null) + whine("Missing cookie signature!"); - xhr.setRequestHeader("UrWeb-Sig", sig); - } + xhr.setRequestHeader("UrWeb-Sig", sig); + } - inFlight = cons(xhr, inFlight); - xhr.send(null); + inFlight = cons(xhr, inFlight); + xhr.send(null); } function xhrFinished(xhr) { - xhr.abort(); - inFlight = remove(xhr, inFlight); + xhr.abort(); + inFlight = remove(xhr, inFlight); } function unurlify(parse, s) { - return parse(s); + return parse(s); } function rc(prefix, uri, parse, k, needsSig) { - uri = cat(prefix, uri); - uri = flattenLocal(uri); - var xhr = getXHR(); + uri = cat(prefix, uri); + uri = flattenLocal(uri); + var xhr = getXHR(); - xhr.onreadystatechange = function() { - if (xhr.readyState == 4) { - var isok = false; + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + var isok = false; - try { - if (xhr.status == 200) - isok = true; - } catch (e) { } + try { + if (xhr.status == 200) + isok = true; + } catch (e) { } - if (isok) { - try { - k(parse(xhr.responseText)); - } catch (v) { - doExn(v); + if (isok) { + try { + k(parse(xhr.responseText)); + } catch (v) { + doExn(v); + } + } else { + conn(); + } + + xhrFinished(xhr); } - } else { - conn(); - } + }; - xhrFinished(xhr); - } - }; - - requestUri(xhr, uri, needsSig); + requestUri(xhr, uri, needsSig); } function path_join(s1, s2) { - if (s1.length > 0 && s1.charAt(s1.length-1) == '/') - return s1 + s2; - else - return s1 + "/" + s2; + if (s1.length > 0 && s1.charAt(s1.length-1) == '/') + return s1 + s2; + else + return s1 + "/" + s2; } var channels = []; function newQueue() { - return { front : null, back : null }; + return { front : null, back : null }; } function enqueue(q, v) { - if (q.front == null) { - q.front = cons(v, null); - q.back = q.front; - } else { - var node = cons(v, null); - q.back.next = node; - q.back = node; - } + if (q.front == null) { + q.front = cons(v, null); + q.back = q.front; + } else { + var node = cons(v, null); + q.back.next = node; + q.back = node; + } } function dequeue(q) { - if (q.front == null) - return null; - else { - var r = q.front.data; - q.front = q.front.next; if (q.front == null) - q.back = null; - return r; - } + return null; + else { + var r = q.front.data; + q.front = q.front.next; + if (q.front == null) + q.back = null; + return r; + } } function newChannel() { - return { msgs : newQueue(), listeners : newQueue() }; + return { msgs : newQueue(), listeners : newQueue() }; } function listener() { - var uri = path_join(url_prefix, ".msgs"); - var xhr = getXHR(); - var tid, orsc, onTimeout; + var uri = path_join(url_prefix, ".msgs"); + var xhr = getXHR(); + var tid, orsc, onTimeout; - var connect = function () { - xhr.onreadystatechange = orsc; - tid = window.setTimeout(onTimeout, timeout * 500); - requestUri(xhr, uri, false); - } + var connect = function () { + xhr.onreadystatechange = orsc; + tid = window.setTimeout(onTimeout, timeout * 500); + requestUri(xhr, uri, false); + } - orsc = function() { - if (xhr.readyState == 4) { - window.clearTimeout(tid); + orsc = function() { + if (xhr.readyState == 4) { + window.clearTimeout(tid); - var isok = false; + var isok = false; - try { - if (xhr.status == 200) - isok = true; - } catch (e) { } + try { + if (xhr.status == 200) + isok = true; + } catch (e) { } - if (isok) { - var text = xhr.responseText - if (text == "") - return; - var lines = text.split("\n"); + if (isok) { + var text = xhr.responseText + if (text == "") + return; + var lines = text.split("\n"); - if (lines.length < 2) { - discon(); - return; + if (lines.length < 2) { + discon(); + return; + } + + for (var i = 0; i+1 < lines.length; i += 2) { + var chn = lines[i]; + var msg = lines[i+1]; + + if (chn < 0) + whine("Out-of-bounds channel in message from remote server"); + + var ch; + + if (chn >= channels.length || channels[chn] == null) { + ch = newChannel(); + channels[chn] = ch; + } else + ch = channels[chn]; + + var listener = dequeue(ch.listeners); + if (listener == null) { + enqueue(ch.msgs, msg); + } else { + try { + listener(msg); + } catch (v) { + doExn(v); + } + } + } + + xhrFinished(xhr); + + connect(); + } + else { + try { + if (xhr.status != 0) + servErr("Error querying remote server for messages: " + xhr.status); + } catch (e) { } + } } + }; - for (var i = 0; i+1 < lines.length; i += 2) { - var chn = lines[i]; - var msg = lines[i+1]; + onTimeout = function() { + xhrFinished(xhr); + connect(); + }; - if (chn < 0) - whine("Out-of-bounds channel in message from remote server"); - - var ch; - - if (chn >= channels.length || channels[chn] == null) { - ch = newChannel(); - channels[chn] = ch; - } else - ch = channels[chn]; - - var listener = dequeue(ch.listeners); - if (listener == null) { - enqueue(ch.msgs, msg); - } else { - try { - listener(msg); - } catch (v) { - doExn(v); - } - } - } - - xhrFinished(xhr); - - connect(); - } - else { - try { - if (xhr.status != 0) - servErr("Error querying remote server for messages: " + xhr.status); - } catch (e) { } - } - } - }; - - onTimeout = function() { - xhrFinished(xhr); connect(); - }; - - connect(); } function rv(chn, parse, k) { - if (chn == null) - return; + if (chn == null) + return; - if (chn < 0) - whine("Out-of-bounds channel receive"); + if (chn < 0) + whine("Out-of-bounds channel receive"); - var ch; + var ch; - if (chn >= channels.length || channels[chn] == null) { - ch = newChannel(); - channels[chn] = ch; - } else - ch = channels[chn]; + if (chn >= channels.length || channels[chn] == null) { + ch = newChannel(); + channels[chn] = ch; + } else + ch = channels[chn]; - var msg = dequeue(ch.msgs); - if (msg == null) { - enqueue(ch.listeners, function(msg) { k(parse(msg)); }); - } else { - try { - k(parse(msg)); - } catch (v) { - doExn(v); + var msg = dequeue(ch.msgs); + if (msg == null) { + enqueue(ch.listeners, function(msg) { k(parse(msg)); }); + } else { + try { + k(parse(msg)); + } catch (v) { + doExn(v); + } } - } } function sl(ms, k) { - window.setTimeout(function() { k(null); }, ms); + window.setTimeout(function() { k(null); }, ms); } function sp(e) { - execF(e, null); + execF(e, null); } @@ -893,7 +893,7 @@ var uw_event = null; function kc() { - return window.event ? uw_event.keyCode : uw_event.which; + return window.event ? uw_event.keyCode : uw_event.which; } @@ -902,262 +902,265 @@ var urfuncs = []; function lookup(env, n) { - while (env != null) { - if (n == 0) - return env.data; - else { - --n; - env = env.next; + while (env != null) { + if (n == 0) + return env.data; + else { + --n; + env = env.next; + } } - } - whine("Out-of-bounds Ur variable reference"); + whine("Out-of-bounds Ur variable reference"); } function execP(env, p, v) { - switch (p.c) { - case "w": - return env; - case "v": - return cons(v, env); - case "c": - if (v == p.v) - return env; - else - return false; - case "s": - if (v == null) - return false; - else - return execP(env, p.p, p.n ? v.v : v); - case "1": - if (v.n != p.n) - return false; - else - return execP(env, p.p, v.v); - case "r": - for (var fs = p.l; fs != null; fs = fs.next) { - env = execP(env, fs.data.p, v["_" + fs.data.n]); - if (env == false) - return false; + switch (p.c) { + case "w": + return env; + case "v": + return cons(v, env); + case "c": + if (v == p.v) + return env; + else + return false; + case "s": + if (v == null) + return false; + else + return execP(env, p.p, p.n ? v.v : v); + case "1": + if (v.n != p.n) + return false; + else + return execP(env, p.p, v.v); + case "r": + for (var fs = p.l; fs != null; fs = fs.next) { + env = execP(env, fs.data.p, v["_" + fs.data.n]); + if (env == false) + return false; + } + return env; + default: + whine("Unknown Ur pattern kind" + p.c); } - return env; - default: - whine("Unknown Ur pattern kind" + p.c); - } } function exec0(env, e) { - return exec1(env, null, e); + return exec1(env, null, e); } function exec1(env, stack, e) { - var stack, usedK = false; + var stack, usedK = false; - var saveEnv = function() { - if (stack.next != null && stack.next.data.c != "<") - stack = cons({c: "<", env: env}, stack.next); - else - stack = stack.next; - }; + var saveEnv = function() { + if (stack.next != null && stack.next.data.c != "<") + stack = cons({c: "<", env: env}, stack.next); + else + stack = stack.next; + }; - while (true) { - switch (e.c) { - case "c": - var v = e.v; - if (stack == null) - return v; - var fr = stack.data; + while (true) { + switch (e.c) { + case "c": + var v = e.v; + if (stack == null) + return v; + var fr = stack.data; - switch (fr.c) { - case "s": - e = {c: "c", v: {v: v}}; - stack = stack.next; - break; - case "1": - e = {c: "c", v: {n: fr.n, v: v}}; - stack = stack.next; - break; - case "f": - fr.args[fr.pos++] = v; - if (fr.a == null) { - var res; - stack = stack.next; + switch (fr.c) { + case "s": + e = {c: "c", v: {v: v}}; + stack = stack.next; + break; + case "1": + e = {c: "c", v: {n: fr.n, v: v}}; + stack = stack.next; + break; + case "f": + fr.args[fr.pos++] = v; + if (fr.a == null) { + var res; + stack = stack.next; - if (fr.f.apply) - res = fr.f.apply(null, fr.args); - else if (fr.args.length == 0) - res = fr.f(); - else if (fr.args.length == 1) - res = fr.f(fr.args[0]); - else if (fr.args.length == 2) - res = fr.f(fr.args[0], fr.args[1]); - else if (fr.args.length == 3) - res = fr.f(fr.args[0], fr.args[1], fr.args[2]); - else if (fr.args.length == 4) - res = fr.f(fr.args[0], fr.args[1], fr.args[2], fr.args[3]); - else if (fr.args.length == 5) - res = fr.f(fr.args[0], fr.args[1], fr.args[2], fr.args[3], fr.args[4]); - else - whine("Native function has " + fr.args.length + " args, but there is no special case for that count."); + if (fr.f.apply) + res = fr.f.apply(null, fr.args); + else if (fr.args.length == 0) + res = fr.f(); + else if (fr.args.length == 1) + res = fr.f(fr.args[0]); + else if (fr.args.length == 2) + res = fr.f(fr.args[0], fr.args[1]); + else if (fr.args.length == 3) + res = fr.f(fr.args[0], fr.args[1], fr.args[2]); + else if (fr.args.length == 4) + res = fr.f(fr.args[0], fr.args[1], fr.args[2], fr.args[3]); + else if (fr.args.length == 5) + res = fr.f(fr.args[0], fr.args[1], fr.args[2], fr.args[3], fr.args[4]); + else + whine("Native function has " + fr.args.length + " args, but there is no special case for that count."); - e = {c: "c", v: res}; - if (usedK) return null; - } else { - e = fr.a.data; - fr.a = fr.a.next; + e = {c: "c", v: res}; + if (usedK) return null; + } else { + e = fr.a.data; + fr.a = fr.a.next; + } + break; + case "a1": + e = fr.x; + stack = cons({c: "a2", f: v}, stack.next); + break; + case "a2": + if (fr.f == null) + whine("Ur: applying null function"); + else if (fr.f.body) { + saveEnv(); + env = cons(v, fr.f.env); + e = fr.f.body; + } else { + e = {c: "c", v: fr.f(v)}; + stack = stack.next; + } + break; + case "<": + env = fr.env; + stack = stack.next; + break; + case "r": + fr.fs["_" + fr.n] = v; + if (fr.l == null) { + e = {c: "c", v: fr.fs}; + stack = stack.next; + } else { + fr.n = fr.l.data.n; + e = fr.l.data.v; + fr.l = fr.l.next; + } + break; + case ".": + e = {c: "c", v: v["_" + fr.f]}; + stack = stack.next; + break; + case ";": + e = fr.e2; + stack = stack.next; + break; + case "=": + saveEnv(); + env = cons(v, env); + e = fr.e2; + break; + case "m": + var ps; + for (ps = fr.p; ps != null; ps = ps.next) { + var r = execP(env, ps.data.p, v); + if (r != false) { + saveEnv(); + env = r; + e = ps.data.b; + break; + } + } + if (ps == null) + whine("Match failure in Ur interpretation"); + break; + default: + whine("Unknown Ur continuation kind " + fr.c); + } + + break; + case "v": + e = {c: "c", v: lookup(env, e.n)}; + break; + case "n": + var idx = e.n; + e = urfuncs[idx]; + if (e.c == "t") + e = urfuncs[idx] = e.f(); + break; + case "s": + stack = cons({c: "s"}, stack); + e = e.v; + break; + case "1": + stack = cons({c: "1", n: e.n}, stack); + e = e.v; + break; + case "f": + if (e.a == null) + e = {c: "c", v: (eval(e.f))()}; + else { + var args = []; + stack = cons({c: "f", f: eval(e.f), args: args, pos: 0, a: e.a.next}, stack); + if (!e.a.data.c) alert("[2] fr.f = " + e.f + "; 0 = " + e.a.data); + e = e.a.data; + } + break; + case "l": + e = {c: "c", v: {env: env, body: e.b}}; + break; + case "a": + stack = cons({c: "a1", x: e.x}, stack); + e = e.f; + break; + case "r": + if (e.l == null) + whine("Empty Ur record in interpretation"); + var fs = {}; + stack = cons({c: "r", n: e.l.data.n, fs: fs, l: e.l.next}, stack); + e = e.l.data.v; + break; + case ".": + stack = cons({c: ".", f: e.f}, stack); + e = e.r; + break; + case ";": + stack = cons({c: ";", e2: e.e2}, stack); + e = e.e1; + break; + case "=": + stack = cons({c: "=", e2: e.e2}, stack); + e = e.e1; + break; + case "m": + stack = cons({c: "m", p: e.p}, stack); + e = e.e; + break; + case "e": + e = {c: "c", v: cs({c: "wc", env: env, body: e.e})}; + break; + case "wc": + env = e.env; + e = e.body; + break; + case "K": + { var savedStack = stack.next, savedEnv = env; + e = {c: "c", v: function(v) { return exec1(savedEnv, savedStack, {c: "c", v: v}); } };} + usedK = true; + break; + default: + whine("Unknown Ur expression kind " + e.c); } - break; - case "a1": - e = fr.x; - stack = cons({c: "a2", f: v}, stack.next); - break; - case "a2": - if (fr.f == null) - whine("Ur: applying null function"); - else if (fr.f.body) { - saveEnv(); - env = cons(v, fr.f.env); - e = fr.f.body; - } else { - e = {c: "c", v: fr.f(v)}; - stack = stack.next; - } - break; - case "<": - env = fr.env; - stack = stack.next; - break; - case "r": - fr.fs["_" + fr.n] = v; - if (fr.l == null) { - e = {c: "c", v: fr.fs}; - stack = stack.next; - } else { - fr.n = fr.l.data.n; - e = fr.l.data.v; - fr.l = fr.l.next; - } - break; - case ".": - e = {c: "c", v: v["_" + fr.f]}; - stack = stack.next; - break; - case ";": - e = fr.e2; - stack = stack.next; - break; - case "=": - saveEnv(); - env = cons(v, env); - e = fr.e2; - break; - case "m": - var ps; - for (ps = fr.p; ps != null; ps = ps.next) { - var r = execP(env, ps.data.p, v); - if (r != false) { - saveEnv(); - env = r; - e = ps.data.b; - break; - } - } - if (ps == null) - whine("Match failure in Ur interpretation"); - break; - default: - whine("Unknown Ur continuation kind " + fr.c); - } - - break; - case "v": - e = {c: "c", v: lookup(env, e.n)}; - break; - case "n": - e = urfuncs[e.n]; - break; - case "s": - stack = cons({c: "s"}, stack); - e = e.v; - break; - case "1": - stack = cons({c: "1", n: e.n}, stack); - e = e.v; - break; - case "f": - if (e.a == null) - e = {c: "c", v: (eval(e.f))()}; - else { - var args = []; - stack = cons({c: "f", f: eval(e.f), args: args, pos: 0, a: e.a.next}, stack); - if (!e.a.data.c) alert("[2] fr.f = " + e.f + "; 0 = " + e.a.data); - e = e.a.data; - } - break; - case "l": - e = {c: "c", v: {env: env, body: e.b}}; - break; - case "a": - stack = cons({c: "a1", x: e.x}, stack); - e = e.f; - break; - case "r": - if (e.l == null) - whine("Empty Ur record in interpretation"); - var fs = {}; - stack = cons({c: "r", n: e.l.data.n, fs: fs, l: e.l.next}, stack); - e = e.l.data.v; - break; - case ".": - stack = cons({c: ".", f: e.f}, stack); - e = e.r; - break; - case ";": - stack = cons({c: ";", e2: e.e2}, stack); - e = e.e1; - break; - case "=": - stack = cons({c: "=", e2: e.e2}, stack); - e = e.e1; - break; - case "m": - stack = cons({c: "m", p: e.p}, stack); - e = e.e; - break; - case "e": - e = {c: "c", v: cs({c: "wc", env: env, body: e.e})}; - break; - case "wc": - env = e.env; - e = e.body; - break; - case "K": - { var savedStack = stack.next, savedEnv = env; - e = {c: "c", v: function(v) { return exec1(savedEnv, savedStack, {c: "c", v: v}); } };} - usedK = true; - break; - default: - whine("Unknown Ur expression kind " + e.c); } - } } function execD(e) { - return exec0(null, e); + return exec0(null, e); } function exec(e) { - var r = exec0(null, e); + var r = exec0(null, e); - if (r != null && r.body != null) - return function(v) { return exec0(cons(v, r.env), r.body); }; - else - return r; + if (r != null && r.body != null) + return function(v) { return exec0(cons(v, r.env), r.body); }; + else + return r; } function execF(f, x) { - return exec0(cons(x, f.env), f.body); + return exec0(cons(x, f.env), f.body); }