|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* |
|
3 * Any copyright is dedicated to the Public Domain. |
|
4 * http://creativecommons.org/licenses/publicdomain/ |
|
5 */ |
|
6 |
|
7 |
|
8 // The Worker constructor can take a relative URL, but different test runners |
|
9 // run in different enough environments that it doesn't all just automatically |
|
10 // work. For the shell, we use just a filename; for the browser, see browser.js. |
|
11 var workerDir = ''; |
|
12 |
|
13 // explicitly turn on js185 |
|
14 // XXX: The browser currently only supports up to version 1.8 |
|
15 if (typeof version != 'undefined') |
|
16 { |
|
17 version(185); |
|
18 } |
|
19 |
|
20 // A little pattern-matching library. |
|
21 var Match = |
|
22 |
|
23 (function() { |
|
24 |
|
25 function Pattern(template) { |
|
26 // act like a constructor even as a function |
|
27 if (!(this instanceof Pattern)) |
|
28 return new Pattern(template); |
|
29 |
|
30 this.template = template; |
|
31 } |
|
32 |
|
33 Pattern.prototype = { |
|
34 match: function(act) { |
|
35 return match(act, this.template); |
|
36 }, |
|
37 |
|
38 matches: function(act) { |
|
39 try { |
|
40 return this.match(act); |
|
41 } |
|
42 catch (e if e instanceof MatchError) { |
|
43 return false; |
|
44 } |
|
45 }, |
|
46 |
|
47 assert: function(act, message) { |
|
48 try { |
|
49 return this.match(act); |
|
50 } |
|
51 catch (e if e instanceof MatchError) { |
|
52 throw new Error((message || "failed match") + ": " + e.message); |
|
53 } |
|
54 }, |
|
55 |
|
56 toString: function() "[object Pattern]" |
|
57 }; |
|
58 |
|
59 Pattern.ANY = new Pattern; |
|
60 Pattern.ANY.template = Pattern.ANY; |
|
61 |
|
62 var quote = uneval; |
|
63 |
|
64 function MatchError(msg) { |
|
65 this.message = msg; |
|
66 } |
|
67 |
|
68 MatchError.prototype = { |
|
69 toString: function() { |
|
70 return "match error: " + this.message; |
|
71 } |
|
72 }; |
|
73 |
|
74 function isAtom(x) { |
|
75 return (typeof x === "number") || |
|
76 (typeof x === "string") || |
|
77 (typeof x === "boolean") || |
|
78 (x === null) || |
|
79 (typeof x === "object" && x instanceof RegExp); |
|
80 } |
|
81 |
|
82 function isObject(x) { |
|
83 return (x !== null) && (typeof x === "object"); |
|
84 } |
|
85 |
|
86 function isArrayLike(x) { |
|
87 return isObject(x) && ("length" in x); |
|
88 } |
|
89 |
|
90 function matchAtom(act, exp) { |
|
91 if ((typeof exp) === "number" && isNaN(exp)) { |
|
92 if ((typeof act) !== "number" || !isNaN(act)) |
|
93 throw new MatchError("expected NaN, got: " + quote(act)); |
|
94 return true; |
|
95 } |
|
96 |
|
97 if (exp === null) { |
|
98 if (act !== null) |
|
99 throw new MatchError("expected null, got: " + quote(act)); |
|
100 return true; |
|
101 } |
|
102 |
|
103 if (exp instanceof RegExp) { |
|
104 if (!(act instanceof RegExp) || exp.source !== act.source) |
|
105 throw new MatchError("expected " + quote(exp) + ", got: " + quote(act)); |
|
106 return true; |
|
107 } |
|
108 |
|
109 switch (typeof exp) { |
|
110 case "string": |
|
111 if (act !== exp) |
|
112 throw new MatchError("expected " + exp.quote() + ", got " + quote(act)); |
|
113 return true; |
|
114 case "boolean": |
|
115 case "number": |
|
116 if (exp !== act) |
|
117 throw new MatchError("expected " + exp + ", got " + quote(act)); |
|
118 return true; |
|
119 } |
|
120 |
|
121 throw new Error("bad pattern: " + exp.toSource()); |
|
122 } |
|
123 |
|
124 function matchObject(act, exp) { |
|
125 if (!isObject(act)) |
|
126 throw new MatchError("expected object, got " + quote(act)); |
|
127 |
|
128 for (var key in exp) { |
|
129 if (!(key in act)) |
|
130 throw new MatchError("expected property " + key.quote() + " not found in " + quote(act)); |
|
131 match(act[key], exp[key]); |
|
132 } |
|
133 |
|
134 return true; |
|
135 } |
|
136 |
|
137 function matchArray(act, exp) { |
|
138 if (!isObject(act) || !("length" in act)) |
|
139 throw new MatchError("expected array-like object, got " + quote(act)); |
|
140 |
|
141 var length = exp.length; |
|
142 if (act.length !== exp.length) |
|
143 throw new MatchError("expected array-like object of length " + length + ", got " + quote(act)); |
|
144 |
|
145 for (var i = 0; i < length; i++) { |
|
146 if (i in exp) { |
|
147 if (!(i in act)) |
|
148 throw new MatchError("expected array property " + i + " not found in " + quote(act)); |
|
149 match(act[i], exp[i]); |
|
150 } |
|
151 } |
|
152 |
|
153 return true; |
|
154 } |
|
155 |
|
156 function match(act, exp) { |
|
157 if (exp === Pattern.ANY) |
|
158 return true; |
|
159 |
|
160 if (exp instanceof Pattern) |
|
161 return exp.match(act); |
|
162 |
|
163 if (isAtom(exp)) |
|
164 return matchAtom(act, exp); |
|
165 |
|
166 if (isArrayLike(exp)) |
|
167 return matchArray(act, exp); |
|
168 |
|
169 return matchObject(act, exp); |
|
170 } |
|
171 |
|
172 return { Pattern: Pattern, |
|
173 MatchError: MatchError }; |
|
174 |
|
175 })(); |
|
176 |
|
177 function referencesVia(from, edge, to) { |
|
178 edge = "edge: " + edge; |
|
179 var edges = findReferences(to); |
|
180 if (edge in edges && edges[edge].indexOf(from) != -1) |
|
181 return true; |
|
182 |
|
183 // Be nice: make it easy to fix if the edge name has just changed. |
|
184 var alternatives = []; |
|
185 for (var e in edges) { |
|
186 if (edges[e].indexOf(from) != -1) |
|
187 alternatives.push(e); |
|
188 } |
|
189 if (alternatives.length == 0) { |
|
190 print("referent not referred to by referrer after all"); |
|
191 } else { |
|
192 print("referent is not referenced via: " + uneval(edge)); |
|
193 print("but it is referenced via: " + uneval(alternatives)); |
|
194 } |
|
195 print("all incoming edges, from any object:"); |
|
196 for (var e in edges) |
|
197 print(e); |
|
198 return false; |
|
199 } |
|
200 |
|
201 // Note that AsmJS ArrayBuffers have a minimum size, currently 4096 bytes. If a |
|
202 // smaller size is given, a regular ArrayBuffer will be returned instead. |
|
203 function AsmJSArrayBuffer(size) { |
|
204 var ab = new ArrayBuffer(size); |
|
205 (new Function('global', 'foreign', 'buffer', '' + |
|
206 ' "use asm";' + |
|
207 ' var i32 = new global.Int32Array(buffer);' + |
|
208 ' function g() {};' + |
|
209 ' return g;' + |
|
210 ''))(Function("return this")(),null,ab); |
|
211 return ab; |
|
212 } |