michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* michael@0: * Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/licenses/publicdomain/ michael@0: */ michael@0: michael@0: michael@0: // The Worker constructor can take a relative URL, but different test runners michael@0: // run in different enough environments that it doesn't all just automatically michael@0: // work. For the shell, we use just a filename; for the browser, see browser.js. michael@0: var workerDir = ''; michael@0: michael@0: // explicitly turn on js185 michael@0: // XXX: The browser currently only supports up to version 1.8 michael@0: if (typeof version != 'undefined') michael@0: { michael@0: version(185); michael@0: } michael@0: michael@0: // A little pattern-matching library. michael@0: var Match = michael@0: michael@0: (function() { michael@0: michael@0: function Pattern(template) { michael@0: // act like a constructor even as a function michael@0: if (!(this instanceof Pattern)) michael@0: return new Pattern(template); michael@0: michael@0: this.template = template; michael@0: } michael@0: michael@0: Pattern.prototype = { michael@0: match: function(act) { michael@0: return match(act, this.template); michael@0: }, michael@0: michael@0: matches: function(act) { michael@0: try { michael@0: return this.match(act); michael@0: } michael@0: catch (e if e instanceof MatchError) { michael@0: return false; michael@0: } michael@0: }, michael@0: michael@0: assert: function(act, message) { michael@0: try { michael@0: return this.match(act); michael@0: } michael@0: catch (e if e instanceof MatchError) { michael@0: throw new Error((message || "failed match") + ": " + e.message); michael@0: } michael@0: }, michael@0: michael@0: toString: function() "[object Pattern]" michael@0: }; michael@0: michael@0: Pattern.ANY = new Pattern; michael@0: Pattern.ANY.template = Pattern.ANY; michael@0: michael@0: var quote = uneval; michael@0: michael@0: function MatchError(msg) { michael@0: this.message = msg; michael@0: } michael@0: michael@0: MatchError.prototype = { michael@0: toString: function() { michael@0: return "match error: " + this.message; michael@0: } michael@0: }; michael@0: michael@0: function isAtom(x) { michael@0: return (typeof x === "number") || michael@0: (typeof x === "string") || michael@0: (typeof x === "boolean") || michael@0: (x === null) || michael@0: (typeof x === "object" && x instanceof RegExp); michael@0: } michael@0: michael@0: function isObject(x) { michael@0: return (x !== null) && (typeof x === "object"); michael@0: } michael@0: michael@0: function isArrayLike(x) { michael@0: return isObject(x) && ("length" in x); michael@0: } michael@0: michael@0: function matchAtom(act, exp) { michael@0: if ((typeof exp) === "number" && isNaN(exp)) { michael@0: if ((typeof act) !== "number" || !isNaN(act)) michael@0: throw new MatchError("expected NaN, got: " + quote(act)); michael@0: return true; michael@0: } michael@0: michael@0: if (exp === null) { michael@0: if (act !== null) michael@0: throw new MatchError("expected null, got: " + quote(act)); michael@0: return true; michael@0: } michael@0: michael@0: if (exp instanceof RegExp) { michael@0: if (!(act instanceof RegExp) || exp.source !== act.source) michael@0: throw new MatchError("expected " + quote(exp) + ", got: " + quote(act)); michael@0: return true; michael@0: } michael@0: michael@0: switch (typeof exp) { michael@0: case "string": michael@0: if (act !== exp) michael@0: throw new MatchError("expected " + exp.quote() + ", got " + quote(act)); michael@0: return true; michael@0: case "boolean": michael@0: case "number": michael@0: if (exp !== act) michael@0: throw new MatchError("expected " + exp + ", got " + quote(act)); michael@0: return true; michael@0: } michael@0: michael@0: throw new Error("bad pattern: " + exp.toSource()); michael@0: } michael@0: michael@0: function matchObject(act, exp) { michael@0: if (!isObject(act)) michael@0: throw new MatchError("expected object, got " + quote(act)); michael@0: michael@0: for (var key in exp) { michael@0: if (!(key in act)) michael@0: throw new MatchError("expected property " + key.quote() + " not found in " + quote(act)); michael@0: match(act[key], exp[key]); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: function matchArray(act, exp) { michael@0: if (!isObject(act) || !("length" in act)) michael@0: throw new MatchError("expected array-like object, got " + quote(act)); michael@0: michael@0: var length = exp.length; michael@0: if (act.length !== exp.length) michael@0: throw new MatchError("expected array-like object of length " + length + ", got " + quote(act)); michael@0: michael@0: for (var i = 0; i < length; i++) { michael@0: if (i in exp) { michael@0: if (!(i in act)) michael@0: throw new MatchError("expected array property " + i + " not found in " + quote(act)); michael@0: match(act[i], exp[i]); michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: function match(act, exp) { michael@0: if (exp === Pattern.ANY) michael@0: return true; michael@0: michael@0: if (exp instanceof Pattern) michael@0: return exp.match(act); michael@0: michael@0: if (isAtom(exp)) michael@0: return matchAtom(act, exp); michael@0: michael@0: if (isArrayLike(exp)) michael@0: return matchArray(act, exp); michael@0: michael@0: return matchObject(act, exp); michael@0: } michael@0: michael@0: return { Pattern: Pattern, michael@0: MatchError: MatchError }; michael@0: michael@0: })(); michael@0: michael@0: function referencesVia(from, edge, to) { michael@0: edge = "edge: " + edge; michael@0: var edges = findReferences(to); michael@0: if (edge in edges && edges[edge].indexOf(from) != -1) michael@0: return true; michael@0: michael@0: // Be nice: make it easy to fix if the edge name has just changed. michael@0: var alternatives = []; michael@0: for (var e in edges) { michael@0: if (edges[e].indexOf(from) != -1) michael@0: alternatives.push(e); michael@0: } michael@0: if (alternatives.length == 0) { michael@0: print("referent not referred to by referrer after all"); michael@0: } else { michael@0: print("referent is not referenced via: " + uneval(edge)); michael@0: print("but it is referenced via: " + uneval(alternatives)); michael@0: } michael@0: print("all incoming edges, from any object:"); michael@0: for (var e in edges) michael@0: print(e); michael@0: return false; michael@0: } michael@0: michael@0: // Note that AsmJS ArrayBuffers have a minimum size, currently 4096 bytes. If a michael@0: // smaller size is given, a regular ArrayBuffer will be returned instead. michael@0: function AsmJSArrayBuffer(size) { michael@0: var ab = new ArrayBuffer(size); michael@0: (new Function('global', 'foreign', 'buffer', '' + michael@0: ' "use asm";' + michael@0: ' var i32 = new global.Int32Array(buffer);' + michael@0: ' function g() {};' + michael@0: ' return g;' + michael@0: ''))(Function("return this")(),null,ab); michael@0: return ab; michael@0: }