You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
5.1 KiB
183 lines
5.1 KiB
/* |
|
Copyright (c) 2007-2010 Alessandro Warth <awarth@cs.ucla.edu> |
|
|
|
Permission is hereby granted, free of charge, to any person |
|
obtaining a copy of this software and associated documentation |
|
files (the "Software"), to deal in the Software without |
|
restriction, including without limitation the rights to use, |
|
copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the |
|
Software is furnished to do so, subject to the following |
|
conditions: |
|
|
|
The above copyright notice and this permission notice shall be |
|
included in all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|
OTHER DEALINGS IN THE SOFTWARE. |
|
*/ |
|
|
|
// try to use StringBuffer instead of string concatenation to improve performance |
|
|
|
function StringBuffer() { |
|
this.strings = [] |
|
for (var idx = 0; idx < arguments.length; idx++) |
|
this.nextPutAll(arguments[idx]) |
|
} |
|
StringBuffer.prototype.nextPutAll = function(s) { this.strings.push(s) } |
|
StringBuffer.prototype.contents = function() { return this.strings.join("") } |
|
String.prototype.writeStream = function() { return new StringBuffer(this) } |
|
|
|
// make Arrays print themselves sensibly |
|
|
|
printOn = function(x, ws) { |
|
if (x === undefined || x === null) |
|
ws.nextPutAll("" + x) |
|
else if (x.constructor === Array) { |
|
ws.nextPutAll("[") |
|
for (var idx = 0; idx < x.length; idx++) { |
|
if (idx > 0) |
|
ws.nextPutAll(", ") |
|
printOn(x[idx], ws) |
|
} |
|
ws.nextPutAll("]") |
|
} |
|
else |
|
ws.nextPutAll(x.toString()) |
|
} |
|
|
|
Array.prototype.toString = function() { var ws = "".writeStream(); printOn(this, ws); return ws.contents() } |
|
|
|
// delegation |
|
|
|
objectThatDelegatesTo = function(x, props) { |
|
var f = function() { } |
|
f.prototype = x |
|
var r = new f() |
|
for (var p in props) |
|
if (props.hasOwnProperty(p)) |
|
r[p] = props[p] |
|
return r |
|
} |
|
|
|
// some reflective stuff |
|
|
|
ownPropertyNames = function(x) { |
|
var r = [] |
|
for (name in x) |
|
if (x.hasOwnProperty(name)) |
|
r.push(name) |
|
return r |
|
} |
|
|
|
isImmutable = function(x) { |
|
return x === null || x === undefined || typeof x === "boolean" || typeof x === "number" || typeof x === "string" |
|
} |
|
|
|
String.prototype.digitValue = function() { return this.charCodeAt(0) - "0".charCodeAt(0) } |
|
|
|
isSequenceable = function(x) { return typeof x == "string" || x.constructor === Array } |
|
|
|
// some functional programming stuff |
|
|
|
if(!Array.prototype.map) { |
|
Array.prototype.map = function(f) { |
|
var r = [] |
|
for (var idx = 0; idx < this.length; idx++) |
|
r[idx] = f(this[idx]) |
|
return r |
|
} |
|
} |
|
|
|
Array.prototype.reduce = function(f, z) { |
|
var r = z |
|
for (var idx = 0; idx < this.length; idx++) |
|
r = f(r, this[idx]) |
|
return r |
|
} |
|
|
|
Array.prototype.delimWith = function(d) { |
|
return this.reduce( |
|
function(xs, x) { |
|
if (xs.length > 0) |
|
xs.push(d) |
|
xs.push(x) |
|
return xs |
|
}, |
|
[]) |
|
} |
|
|
|
// Squeak's ReadStream, kind of |
|
|
|
function ReadStream(anArrayOrString) { |
|
this.src = anArrayOrString |
|
this.pos = 0 |
|
} |
|
ReadStream.prototype.atEnd = function() { return this.pos >= this.src.length } |
|
ReadStream.prototype.next = function() { return this.src.at(this.pos++) } |
|
|
|
// escape characters |
|
|
|
escapeStringFor = new Object() |
|
for (var c = 0; c < 256; c++) |
|
escapeStringFor[c] = String.fromCharCode(c) |
|
escapeStringFor["\\".charCodeAt(0)] = "\\\\" |
|
escapeStringFor['"'.charCodeAt(0)] = '\\"' |
|
escapeStringFor["'".charCodeAt(0)] = "\\'" |
|
escapeStringFor["\r".charCodeAt(0)] = "\\r" |
|
escapeStringFor["\n".charCodeAt(0)] = "\\n" |
|
escapeStringFor["\t".charCodeAt(0)] = "\\t" |
|
escapeChar = function(c) { |
|
var charCode = c.charCodeAt(0) |
|
return charCode > 255 ? String.fromCharCode(charCode) : escapeStringFor[charCode] |
|
} |
|
|
|
function unescape(s) { |
|
if (s.charAt(0) == '\\') |
|
switch (s.charAt(1)) { |
|
case '\\': return '\\' |
|
case 'r': return '\r' |
|
case 'n': return '\n' |
|
case 't': return '\t' |
|
default: return s.charAt(1) |
|
} |
|
else |
|
return s |
|
} |
|
|
|
String.prototype.toProgramString = function() { |
|
var ws = "\"".writeStream() |
|
for (var idx = 0; idx < this.length; idx++) |
|
ws.nextPutAll(escapeChar(this.charAt(idx))) |
|
ws.nextPutAll("\"") |
|
return ws.contents() |
|
} |
|
|
|
// C-style tempnam function |
|
|
|
function tempnam(s) { return (s ? s : "_tmpnam_") + tempnam.n++ } |
|
tempnam.n = 0 |
|
|
|
// unique tags for objects (useful for making "hash tables") |
|
|
|
getTag = (function() { |
|
var numIdx = 0 |
|
return function(x) { |
|
if (x === null || x === undefined) |
|
return x |
|
switch (typeof x) { |
|
case "boolean": return x == true ? "Btrue" : "Bfalse" |
|
case "string": return "S" + x |
|
case "number": return "N" + x |
|
default: return x.hasOwnProperty("_id_") ? x._id_ : x._id_ = "R" + numIdx++ |
|
} |
|
} |
|
})() |
|
|
|
module.exports.StringBuffer = StringBuffer;
|
|
|