comparison lib/js/urweb.js @ 692:09df0c85f306

Fix overzealous Marshalcheck; garbage-collect string-embedded closures when no dyns are active
author Adam Chlipala <adamc@hcoop.net>
date Sat, 04 Apr 2009 12:54:39 -0400
parents cc58941da3e2
children 655bcc9b77e0
comparison
equal deleted inserted replaced
691:cc58941da3e2 692:09df0c85f306
1 // Lists
2
1 function cons(v, ls) { 3 function cons(v, ls) {
2 return { next : ls, data : v }; 4 return { next : ls, data : v };
3 } 5 }
4 function concat(ls1, ls2) { 6 function concat(ls1, ls2) {
5 return (ls1 ? cons(ls1.data, concat(ls1.next, ls2)) : ls2); 7 return (ls1 ? cons(ls1.data, concat(ls1.next, ls2)) : ls2);
15 } 17 }
16 function union(ls1, ls2) { 18 function union(ls1, ls2) {
17 return (ls1 ? (member(ls1.data, ls2) ? union(ls1.next, ls2) : cons(ls1.data, union(ls1.next, ls2))) : ls2); 19 return (ls1 ? (member(ls1.data, ls2) ? union(ls1.next, ls2) : cons(ls1.data, union(ls1.next, ls2))) : ls2);
18 } 20 }
19 21
22
23 // Embedding closures in XML strings
24
25 function cat(s1, s2) {
26 if (s1.length && s2.length)
27 return s1 + s2;
28 else
29 return {_1: s1, _2: s2};
30 }
31
32 var closures = [];
33
34 function newClosure(f) {
35 var n = closures.length;
36 closures[n] = f;
37 return n;
38 }
39
40 function cr(n) {
41 return closures[n]();
42 }
43
44 function flatten(tr) {
45 if (tr.length)
46 return tr;
47 else if (tr._1)
48 return cs(tr._1) + cs(tr._2);
49 else
50 return "cr(" + newClosure(tr) + ")";
51 }
52
53 function clearClosures() {
54 closures = [];
55 }
56
57
58 // Dynamic tree management
20 59
21 function populate(node) { 60 function populate(node) {
22 var s = node.signal; 61 var s = node.signal;
23 var oldSources = node.sources; 62 var oldSources = node.sources;
24 var sr = s(); 63 var sr = s();
83 var thisScript = null; 122 var thisScript = null;
84 123
85 function runScripts(node) { 124 function runScripts(node) {
86 var savedScript = thisScript; 125 var savedScript = thisScript;
87 126
88 var scripts = node.getElementsByTagName("script"), scriptsCopy = {}; 127 var scripts = node.getElementsByTagName("script"), scriptsCopy = [];
89 var len = scripts.length; 128 var len = scripts.length;
90 for (var i = 0; i < len; ++i) 129 for (var i = 0; i < len; ++i)
91 scriptsCopy[i] = scripts[i]; 130 scriptsCopy[i] = scripts[i];
92 for (var i = 0; i < len; ++i) { 131 for (var i = 0; i < len; ++i) {
93 thisScript = scriptsCopy[i]; 132 thisScript = scriptsCopy[i];
96 135
97 thisScript = savedScript; 136 thisScript = savedScript;
98 } 137 }
99 138
100 139
140 // Dynamic tree entry points
141
142 var dynDepth = 0;
143
101 function dyn(s) { 144 function dyn(s) {
102 var x = document.createElement("span"); 145 var x = document.createElement("span");
103 x.dead = false; 146 x.dead = false;
104 x.signal = s; 147 x.signal = s;
105 x.sources = null; 148 x.sources = null;
106 x.recreate = function(v) { 149 x.recreate = function(v) {
150 ++dynDepth;
151
107 var spans = x.getElementsByTagName("span"); 152 var spans = x.getElementsByTagName("span");
108 for (var i = 0; i < spans.length; ++i) { 153 for (var i = 0; i < spans.length; ++i) {
109 var span = spans[i]; 154 var span = spans[i];
110 span.dead = true; 155 span.dead = true;
111 for (var ls = span.sources; ls; ls = ls.next) 156 for (var ls = span.sources; ls; ls = ls.next)
112 ls.data.dyns = remove(span, ls.data.dyns); 157 ls.data.dyns = remove(span, ls.data.dyns);
113 } 158 }
114 159
115 x.innerHTML = v; 160 x.innerHTML = v;
116 runScripts(x); 161 runScripts(x);
162
163 if (--dynDepth == 0)
164 clearClosures();
117 }; 165 };
118 populate(x); 166 populate(x);
119 addNode(x); 167 addNode(x);
120 } 168 }
121 169
129 addNode(x); 177 addNode(x);
130 x.onkeyup = function() { sv(s, x.value) }; 178 x.onkeyup = function() { sv(s, x.value) };
131 return x; 179 return x;
132 } 180 }
133 181
182
183 // Basic string operations
184
134 function eh(x) { 185 function eh(x) {
135 return x.split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;"); 186 return x.split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;");
136 } 187 }
137 188
138 function ts(x) { return x.toString() } 189 function ts(x) { return x.toString() }
152 return r; 203 return r;
153 else 204 else
154 throw "Can't parse float: " + s; 205 throw "Can't parse float: " + s;
155 } 206 }
156 207
157 function cat(s1, s2) { 208 function uf(s) {
158 return s1 + s2; 209 return escape(s).replace(new RegExp ("/", "g"), "%2F");
159 } 210 }
211
212 function uu(s) {
213 return unescape(s).replace(new RegExp ("\\+", "g"), " ");
214 }
215
216
217 // Error handling
160 218
161 function whine(msg) { 219 function whine(msg) {
162 alert(msg); 220 alert(msg);
163 throw msg; 221 throw msg;
164 } 222 }
165 223
166 function pf() { 224 function pf() {
167 whine("Pattern match failure"); 225 whine("Pattern match failure");
168 } 226 }
169 227
170 var closures = []; 228
171 229 // Remote calls
172 function ca(f) {
173 var n = closures.length;
174 closures[n] = f;
175 return n;
176 }
177
178 function cr(n) {
179 return closures[n]();
180 }
181
182 230
183 var client_id = 0; 231 var client_id = 0;
184 var client_pass = 0; 232 var client_pass = 0;
185 var url_prefix = "/"; 233 var url_prefix = "/";
186 var timeout = 60; 234 var timeout = 60;
362 enqueue(ch.listeners, function(msg) { k(parse(msg))(null); }); 410 enqueue(ch.listeners, function(msg) { k(parse(msg))(null); });
363 } else { 411 } else {
364 k(parse(msg))(null); 412 k(parse(msg))(null);
365 } 413 }
366 } 414 }
367
368 function uf(s) {
369 return escape(s).replace(new RegExp ("/", "g"), "%2F");
370 }
371
372 function uu(s) {
373 return unescape(s).replace(new RegExp ("\\+", "g"), " ");
374 }