Mercurial > urweb
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("&").split("<").join("<").split(">").join(">"); | 186 return x.split("&").join("&").split("<").join("<").split(">").join(">"); |
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 } |