pasm
Version:
Piston X86-64 Assembler
1,437 lines (1,184 loc) • 236 kB
JavaScript
// Scheme numerical tower in JavaScript.
// Copyright (c) 2011,2012 by John Tobey <John.Tobey@gmail.com>
/*
File: schemeNumber.js
Exports:
<SchemeNumber>
Depends:
<biginteger.js> for <BigInteger>
*/
/*
Class: SchemeNumber
A number object as <defined by the Scheme language at
http://www.r6rs.org/>.
Scheme supports *exact* arithmetic and mixing exact with standard
(*inexact*) numbers. Several basic operations, including
addition, subtraction, multiplication, and division, when given
only exact arguments, must return an exact, numerically correct
result.
These operations are allowed to fail due to running out of memory,
but they are not allowed to return approximations the way
ECMAScript operators may, unless given one or more inexact
arguments.
For example, adding exact *1/100* to exact *0* one hundred times
produces exactly *1*, not 1.0000000000000007 as in JavaScript.
Raising exact *2* to the power of exact *1024* returns a 308-digit
integer with complete precision, not *Infinity* as in ECMAScript.
This implementation provides all functions listed in the <R6RS
Scheme specification at http://www.r6rs.org/>, Section 11.7, along
with <eqv?> from Section 11.5. (<eqv?> uses JavaScript's *===* to
compare non-numbers.)
Exact numbers support the standard ECMA Number formatting methods
(toFixed, toExponential, and toPrecision) without a fixed upper
limit to precision.
The schemeNumber.js file exports an object <SchemeNumber>. It
contains a property <fn>, which in turn contains the functions
implementing the numeric types.
The <SchemeNumber> object is in fact a function that converts its
argument to a Scheme number: similar to a constructor, but it may
not always return an object, let alone a unique object.
Parameters:
obj - Object to be converted to a Scheme number.
*obj* may have any of the following
types:
Scheme number - returned unchanged.
String - converted as if by *string->number*.
Native ECMAScript number - treated as an inexact real.
Returns:
A Scheme number.
Exceptions:
If *obj* can not be parsed, <SchemeNumber> will <raise> an
exception with condition type *&assertion*.
See Also:
<fn>, <raise>, <R6RS Chapter 3: Numbers at http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-6.html#node_chap_3>
*/
var SchemeNumber = (function() {
//
// Multiple dispatch support.
//
var DispatchJs = (function() {
"use strict";
/*
Multiple dispatch for JavaScript functions of fixed arity. Example:
// B and C inherit from A. D inherits from C.
var A = disp.defClass("A", {ctor: function(x) { this.x = x }});
var B = disp.defClass("B", {base: "A"});
var C = disp.defClass("C", {base: "A"});
// Classes may be defined after their superclass methods.
//var D = disp.defClass("D", {base: "C"});
// Or you can declare existing classes:
//var disp = DispatchJs;
//function A(){} A.prototype = {};
//disp.defClass("A", {ctor: A});
//function B(){} B.prototype = new A();
//disp.defClass("B", {ctor: B, base "A"});
//function C(){} C.prototype = new A();
//disp.defClass("C", {ctor: C, base "A"});
//function D(){} D.prototype = new C();
//disp.defClass("D", {ctor: D, base "C"});
// This creates a function of 2 arguments:
var frob = disp.defGeneric("frob", 2);
// Define methods. Methods receive frob's first argument as "this" and
// the rest as method arguments.
frob.def("A", "A", function(a1) { return "A A" });
frob.def("A", "B", function(a1) { return "A B" });
frob.def("B", "A", function(a1) { return "B A" });
frob.def("B", "B", function(a1) { return "B B" });
frob.def("A", "C", function(a1) { return "A C" });
var D = disp.defClass("D", function(x) { this.x = x }, "C");
frob.def("D", "D", function(a1) { return "D D" });
// Create some arguments:
var a = new A();
var b = new B();
var c = new C();
var d = new D();
// Call the function:
frob(a,a); // "A A"
frob(a,b); // "A B"
frob(a,c); // "A C"
frob(a,d); // "A C"
frob(b,a); // "B A"
frob(b,b); // "B B"
frob(b,c); // "B A" or "A C"
frob(b,d); // "B A" or "A C"
frob(c,a); // "A A"
frob(c,b); // "A B"
frob(c,c); // "A C"
frob(c,d); // "A C"
frob(d,a); // "A A"
frob(d,b); // "A B"
frob(d,c); // "A C"
frob(d,d); // "D D"
Ambiguous calls such as frob(b,c) and frob(b,d) above use whichever of
the best candidates was defined first: the method for types B,A or the
one for A,C.
*/
function short_fn(f) {
return String(f).replace(/(?:.|\n)*(function .*?\(.*?\))(?:.|\n)*/, "$1");
}
var Formals = [];
function makeContext(opts) {
var g = opts.globals;
var _Function = (g ? g.Function : Function);
var uncurry = _Function.prototype.bind.bind(_Function.prototype.call);
var _Object = (g ? g.Object : Object);
var _String = (g ? g.String : String);
var _Array = (g ? g.Array : Array);
var _Error = (g ? g.Error : Error);
var _apply = uncurry(_Function.prototype.apply);
var _slice = uncurry(_Array.prototype.slice);
var _join = uncurry(_Array.prototype.join);
var _push = uncurry(_Array.prototype.push);
var _unshift = uncurry(_Array.prototype.unshift);
var _forEach = uncurry(_Array.prototype.forEach);
var _concat = uncurry(_Array.prototype.concat);
var _replace = uncurry(_String.prototype.replace);
var _split = uncurry(_String.prototype.split);
var _create = _Object.create;
var _hasOwnProperty = uncurry(_Object.prototype.hasOwnProperty);
var String_indexOf = uncurry(_String.prototype.indexOf);
var Array_indexOf = uncurry(_Array.prototype.indexOf);
var prefix = opts.methodNamePrefix || "_jsmd";
var ePrefix = _replace(prefix, /([\"\\])/g, "\\$1");
var sep = opts.methodNameSeparator || " ";
var classes = _create(null);
function classToName(cl) {
if (cl != null) {
var name = cl[prefix];
if (typeof name === "string")
if (classes[name] && classes[name].ctor === cl)
return name;
else
for (name in classes)
if (classes[name] && classes[name].ctor === cl)
return name;
}
}
function assertClassToName(cl) {
if ("string" === typeof cl)
return cl;
var ret = classToName(cl);
if (ret)
return ret;
throw _Error("Class not defined: " + cl);
}
function pureVirtual() {
var msg = "Abstract method not overridden for ";
try {
msg += this;
}
catch (e) {
try {
msg += _Object.prototype.toString.call(this);
}
catch (e) {
msg += "object";
}
}
throw new _Error(msg);
}
var ret = {
getConstructor: function(name) {
return classes[name] && classes[name].ctor;
},
defClass: function(name, opts) {
var ctor, base;
var bctor, proto, key, sub, sepBase, cname, c;
var ometh, meth, func, array, doit, i, indices;
opts.debug && console.log("defClass: ", name);
if (opts) {
ctor = opts.ctor;
if (opts.base)
base = assertClassToName(opts.base);
}
if (typeof base === "undefined" && ctor && ctor.prototype != null) {
base = classToName(ctor.prototype.constructor);
}
//opts.debug && console.log("base:", base);
if (typeof base !== "undefined") {
bctor = classes[base].ctor;
}
ctor = ctor || function(){}
if (typeof name !== "string") {
throw _Error("Usage: defClass(NAME, [OPTS])");
}
if (classes[name]) {
if (classes[name].ctor !== ctor || classes[name].base !== base)
{
throw _Error("Can't redefine class " + name);
}
return ctor;
}
if (String_indexOf(name, sep) != -1) {
throw _Error((sep == " " ? "Space" : "Separator") +
" in class name: " + name);
}
if (typeof (ctor[prefix]) !== "undefined") {
if (ctor[prefix] !== name)
throw _Error("Cannot define constructor as " + name +
", it was previously defined as " +
ctor[prefix]);
}
else {
ctor[prefix] = name;
}
//opts.debug && console.log("checking prototype constructor");
if (ctor.prototype) {
if (_hasOwnProperty(ctor.prototype, "constructor")) {
if (ctor.prototype.constructor !== ctor)
throw _Error("ctor.prototype.constructor is not ctor");
}
else {
ctor.prototype.constructor = ctor;
}
}
//opts.debug && console.log("ok")
if (!ctor.prototype ||
(bctor && !(ctor.prototype instanceof bctor)))
{
proto = (bctor ? new bctor() : _create(null));
//opts.debug && console.log("proto.constructor[prefix]", proto.constructor[prefix]);
if (ctor.prototype) {
// XXX Used for BigInteger; too hacky?
for (key in ctor.prototype) {
proto[key] = ctor.prototype[key];
}
}
proto.constructor = ctor;
ctor.prototype = proto;
}
classes[name] = {
ctor: ctor,
base: base,
sub: [],
ename: _replace(sep + name, /([\"\\])/g, "\\$1"),
};
//opts.debug && console.log("defClass:", name, "base:", base);
if (typeof base !== "undefined") {
sub = classes[base].sub;
if (Array_indexOf(sub, name) === -1)
_push(sub, name);
sepBase = sep + base;
for (cname in classes) {
proto = classes[cname].ctor.prototype;
for (ometh in proto) {
if (!_hasOwnProperty(proto, ometh))
continue;
if (!String_indexOf(ometh, sepBase))
continue;
array = _split(ometh, sep);
if (array[0] !== prefix)
continue;
func = proto[ometh];
indices = [];
for (i = Array_indexOf(array, base, 2); i !== -1;
i = Array_indexOf(array, base, i + 1)) {
_push(indices, i);
}
doit = function(i) {
if (i === indices.length) {
meth = _join(array, sep);
if (meth !== ometh) {
opts.debug && console.log(cname + '["'+meth+'"] propagated -> ' + short_fn(func));
proto[meth] = func;
}
return;
}
array[indices[i]] = base;
doit(i + 1);
array[indices[i]] = name;
doit(i + 1);
}
doit(0);
}
}
}
return ctor;
},
defGeneric: function (fnName, ndisp, nargs) {
if (String_indexOf(fnName, sep) != -1)
throw _Error((sep == " " ? "Space" : "Separator") +
" in function name: " + fnName);
nargs = nargs || ndisp;
if (fnName == ""
|| ndisp < 1 || ndisp != (ndisp | 0)
|| nargs < 1 || nargs != (nargs | 0))
throw Error("Usage: defGeneric(NAME, NDISP [, NARGS])");
var eName = _replace(sep + fnName, /([\"\\])/g, "\\$1");
var eTopMethod = ePrefix + eName;
for (var i = Formals.length; i < nargs; i++)
Formals[i] = "a" + i;
var array = _slice(Formals, 0, nargs);
// e.g., function(a0,a1,a2,a3){return a3["_jsmd frob"](a0,a1,a2)}
_push(array,
"return " + Formals[ndisp-1] + '["' + eTopMethod + '"](' +
_join(_concat(_slice(array, 0, ndisp-1),
_slice(array, ndisp, nargs)), ",") + ')')
var ret = _apply(_Function, null, array);
var func_cache = _create(null);
function get_func(i, etypes) {
var suffix = _join(_slice(etypes, i), "");
if (!func_cache[suffix]) {
var method = ePrefix + eName + suffix;
var array = _concat(_slice(Formals, 0,i),
_slice(Formals, i+1, nargs));
_push(array, "return " + Formals[i-1] +
'["' + method + '"](' +
_join(_concat(_slice(Formals, 0, i-1), "this",
_slice(Formals, i+1, nargs)), ",") +
')');
func_cache[suffix] = _apply(_Function, null, array);
}
return func_cache[suffix];
}
// For error message.
function usageArgs() {
switch (ndisp) {
case 1: return "TYPE";
case 2: return "TYPE1, TYPE2";
case 3: return "TYPE1, TYPE2, TYPE3";
default: return "TYPE1, ..., TYPE" + ndisp;
}
}
// def(TYPE1, ..., TYPEn, FUNCTION)
// Defines FUNCTION as this method's specialization for the
// given types. Each TYPEi must have been passed as the
// NAME argument in a successful call to defClass.
function def() {
var fn = arguments[ndisp] || pureVirtual;
if (typeof fn !== "function") {
throw _Error("Not a function. Usage: " + fnName +
".def(" + usageArgs() + ", FUNCTION)");
}
var types = _slice(arguments, 0, ndisp);
//opts.debug && console.log("def", fnName, types, short_fn(fn));
for (i = 0; i < ndisp; i++) {
// Throw error if not registered.
// XXX Could add def() arguments to a list to be
// defined during defClass.
types[i] = assertClassToName(types[i]);
}
//opts.debug && console.log("def");
do_def(types, fn, _create(null));
}
function do_def(types, fn, inherited) {
var cs = new _Array(ndisp);
var eTypes = new _Array(ndisp);
var i, suffix, oldm, newm;
for (i = 0; i < ndisp; i++) {
cs[i] = classes[types[i]];
//opts.debug && console.log("cs[" + i + "]=classes[", types[i], "]");
eTypes[i] = cs[i].ename;
}
opts.debug && console.log("do_def", fnName, eTypes);
oldm = new Array(ndisp);
for (i = ndisp-1, suffix = ""; ; i--) {
oldm[i] = cs[i].ctor.prototype[
prefix + sep + fnName + suffix];
//opts.debug && console.log("oldm[" + i + "]" + oldm[i]);
if (i === 0)
break;
suffix = eTypes[i] + suffix;
}
newm = new _Array(ndisp);
newm[0] = fn;
for (i=1; i<ndisp; i++)
newm[i] = get_func(i, eTypes);
function doit(i, method) {
var key;
var proto = cs[i].ctor.prototype;
if (proto[method] && proto[method] !== oldm[i]) {
opts.debug && console.log("Skipping " + i + " " + types[i] + '["' + method + '"] ' + short_fn(proto[method]) + "!=" + short_fn(oldm[i]));
return; // already more specialized in an argument.
}
//console.log("doit("+i+","+method+") "+cs[i].ename);
if (proto === Object.prototype) // sanity check.
throw Error("BUG: code would modify Object.prototype.");
if (proto[method] !== newm[i]) {
key = types[i] + sep + method;
if ((key in inherited) && newm[i] === inherited[key]) {
opts.debug && console.log(eTypes[i] + '["'+method+'"] ' + short_fn(proto[method]) + " -> DELETED");
delete(proto[method]);
}
else {
opts.debug && console.log(eTypes[i] + '["'+method+'"] ' + short_fn(proto[method]) + " -> " + short_fn(newm[i]));
if (!_hasOwnProperty(proto, method)) {
inherited[key] = proto[method];
}
proto[method] = newm[i];
}
}
if (i === 0)
return;
function doit2(k) {
doit(i - 1, method + sep + k);
_forEach(classes[k].sub, doit2);
}
doit2(types[i]);
}
doit(ndisp-1, prefix + sep + fnName);
}
ret.def = def;
return ret;
},
// lookup: TO DO
};
if (opts.debug)
ret.classes = classes;
return ret;
}
var ret = makeContext(Object.create(null));
ret.makeContext = makeContext;
return ret;
})();
//if (typeof exports !== "undefined") {
// exports.DispatchJs = DispatchJs;
// exports.makeContext = DispatchJs.makeContext;
// exports.defClass = DispatchJs.defClass;
// exports.defGeneric = DispatchJs.defGeneric;
//}
/*
Constructor: PluginContainer(plugins)
A PluginContainer is just a set of properties, referred to as
"plugins", with an interface to change them and subscribe to
notification of such changes.
If *plugins* is passed, it is stored as if via <extend> as the
initial set of plugins.
*/
function PluginContainer(init) {
"use strict";
// XXX use of globals via Array and Function methods, Object,
// Error, and undefined: should virtualize.
if (!(this instanceof PluginContainer))
throw Error("Usage: new PluginContainer()");
var t = this, listeners = [], plugins = Object.create(null);
function mergeChanges(from, to, changed) {
var ret = false;
for (var i in from) {
if (to[i] !== undefined && to[i] !== from[i])
throw Error("Conflicting changes to " + i);
if (changed)
changed[i] = from[i];
to[i] = from[i];
ret = true;
}
return ret;
}
/*
Property: onChange
Event used to publish changes to plugins.
> plugins.onChange.subscribe(listener);
After <extend> changes one or more plugin values, it calls
*listener* with two arguments: the <PluginContainer> and an object
whose properties are the changed plugins.
No call results from passing <extend> an empty object or one whose
values all equal the current corresponding plugins.
> plugins.onChange.unsubscribe(listener);
Reverses the effect of an earlier *subscribe* call.
*/
var onChange = {
fire: function(changes) {
function notify(listener) {
listener.call(listener, t, changes);
}
listeners.forEach(notify);
},
subscribe: function(listener) {
listeners.push(listener);
},
unsubscribe: function(listener) {
function isNotIt(l) { return l !== listener; }
listeners = listeners.filter(isNotIt);
},
};
t.onChange = onChange;
/*
Method: extend(newPlugins)
Adds or replaces plugins in the container.
*newPlugins* must be an object. All of its properties
(technically, its own, enumerable properties) are stored as new or
replacement plugins. If this results in any actual changes, all
of the container's <onChange> listeners are notified.
Method: extend(name1, plugin1, name2, plugin2, ...)
Like extend({ *name1* : *plugin1*, *name2* : *plugin2*, ... })
*/
t.extend = function() {
var changes = Object.create(null);
var newPlugins = arguments[0], i;
if (typeof newPlugins !== "object") {
if (arguments.length & 1)
throw Error("extend: Wrong argument types");
newPlugins = Object.create(null);
for (i = 0; i < arguments.length; i += 2) {
if (arguments[i] in newPlugins)
throw Error("extend: " + arguments[i] +
" given more than once");
newPlugins[arguments[i]] = arguments[i+1];
}
}
if (mergeChanges(newPlugins, plugins, changes))
onChange.fire(changes);
};
/*
Method: get(pluginName)
Returns the plugin named *pluginName*, or *undefined* if none
exists by that name.
*/
t.get = function(pluginName) {
return plugins[pluginName];
};
t.list = function() {
return Object.keys(plugins);
};
if (init) {
t.extend(init);
}
}
//
// Uncomment "assert(...)" to use this:
//
function assert(x) { if (!x) throw new Error("assertion failed"); }
function getEs5Globals() {
// Package the ECMAScript 5 Global Object properties so that
// careful users can provide a safer-seeming copy of them. XXX If
// you want to use this, consider auditing PluginContainer and
// JsDispatch, too.
return {
NaN : NaN,
Infinity : Infinity,
undefined : undefined,
eval : eval,
parseInt : parseInt,
parseFloat : parseFloat,
isNaN : isNaN,
isFinite : isFinite,
decodeURI : decodeURI,
decodeURIComponent : decodeURIComponent,
encodeURI : encodeURI,
encodeURIComponent : encodeURIComponent,
Object : Object,
Function : Function,
Array : Array,
String : String,
Boolean : Boolean,
Number : Number,
Date : Date,
RegExp : RegExp,
Error : Error,
EvalError : EvalError,
RangeError : RangeError,
ReferenceError : ReferenceError,
SyntaxError : SyntaxError,
TypeError : TypeError,
URIError : URIError,
Math : Math,
JSON : JSON,
};
}
function implementUncurry(plugins) {
var g = plugins.get("es5globals");
var api = g.Object.create(null);
/*
uncurry(func) returns a function equivalent to
> function(arg...) { return func.call(arg...); }
but not relying on func or its prototype having a "call"
property. The point is to make library code behave the same
after arbitrary code runs, possibly improving security and
performance.
http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
*/
api.uncurry = g.Function.prototype.bind.bind(g.Function.prototype.call);
return api;
}
/*
Function: defineGenericFunctions(plugins)
Creates the generic functions of number subtypes called by
higher-level library code.
The bulk of the internal/plugin API consists of these functions.
Their interfaces are optimized for ease of implementation and for
use in implementing the library. By contrast, the Scheme library
strives more for interface stability and convenience of use.
For example, the public subtraction function, <fn["-"]>, accepts
one or more arguments, converts them from native types if
necessary, and subtracts all but the first from the first, unless
there is only one, in which case it negates it. The library
converts all that into calls to <subtract>, with exactly two
arguments, both guaranteed to be Scheme numbers, or <negate> as
the case may be.
Input:
*plugins* shall be a <PluginContainer> containing *Dispatch*, a
<JsDispatch> object. <defineGenericFunctions> calls the
*defGeneric* method of *Dispatch* to create each generic function.
Functions:
toSchemeNumber - see <implementSchemeNumber>
numberToString - generic function(schemeNumber, radix, precision)
Equivalent to <fn["number->string"]> but with *radix* and
*precision* as native numbers.
isExact - generic function(schemeNumber)
"exact?"
isInexact - generic function(schemeNumber)
"inexact?"
isComplex - generic function(schemeNumber)
"complex?"
isReal - generic function(schemeNumber)
"real?"
isRational - generic function(schemeNumber)
"rational?"
isInteger - generic function(schemeNumber)
"integer?"
isZero - generic function(schemeNumber)
"zero?"
toExact - generic function(schemeNumber)
"exact"
toInexact - generic function(schemeNumber)
"inexact"
negate - generic function(schemeNumber)
Returns the argument's additive inverse, -*schemeNumber*.
reciprocal - generic function(schemeNumber)
Return the argument's multiplicative inverse, 1 / *schemeNumber*.
eq - generic function(schemeNumber, schemeNumber)
"="
ne - generic function(schemeNumber, schemeNumber)
Returns true if, and only if, the arguments are *not* equal in the
sense of Scheme's "=".
add - generic function(schemeNumber, schemeNumber)
Returns the sum of the two arguments.
subtract - generic function(schemeNumber1, schemeNumber2)
Returns the difference *schemeNumber1* - *schemeNumber2*.
multiply - generic function(schemeNumber, schemeNumber)
Returns the product of the two arguments.
divide - generic function(schemeNumber1, schemeNumber2)
Returns the quotient *schemeNumber1* / *schemeNumber2*.
square - generic function(schemeNumber)
Returns the argument's square.
realPart - generic function(complex)
"real-part"
imagPart - generic function(complex)
"imag-part"
expt - generic function(schemeNumber, integer)
As in Scheme.
expt - generic function(complex, complex)
As in Scheme.
exp - generic function(complex)
As in Scheme.
magnitude - generic function(complex)
As in Scheme.
angle - generic function(complex)
As in Scheme.
sqrt - generic function(complex)
As in Scheme.
log - generic function(complex)
Single-argument *log* as in Scheme.
asin - generic function(complex)
As in Scheme.
acos - generic function(complex)
As in Scheme.
atan - generic function(complex)
Single-argument *atan* as in Scheme.
sin - generic function(complex)
As in Scheme.
cos - generic function(complex)
As in Scheme.
tan - generic function(complex)
As in Scheme.
SN_isFinite - generic function(real)
"finite?"
SN_isInfinite - generic function(real)
"infinite?"
SN_isNaN - generic function(real)
"nan?"
isUnit - generic function(real)
Returns true if its argument equals 1 or -1.
abs - generic function(real)
As in Scheme.
isPositive - generic function(real)
"positive?"
isNegative - generic function(real)
"negative?"
sign - generic function(real)
Returns native -1 if *real* is negative, 0 if zero, or 1 if positive.
floor - generic function(real)
As in Scheme.
ceiling - generic function(real)
As in Scheme.
truncate - generic function(real)
As in Scheme.
round - generic function(real)
As in Scheme.
compare - generic function(real1, real2)
Returns the <sign> of the difference <real1 - real2>.
gt - generic function(real, real)
">"
lt - generic function(real, real)
"<"
ge - generic function(real, real)
">="
le - generic function(real, real)
"<="
divAndMod - generic function(real, real)
"div-and-mod"
div - generic function(real, real)
As in Scheme.
mod - generic function(real, real)
As in Scheme.
atan2 - generic function(real, real)
Equivalent to *atan* with two arguments in Scheme.
numerator - generic function(rational)
As in Scheme.
denominator - generic function(rational)
As in Scheme.
isEven - generic function(exactInteger)
"even?"
isOdd - generic function(exactInteger)
"odd?"
exp10 - generic function(significand, exponent)
Both arguments are exact integers. Returns an exact integer equal
to the *significand* times ten to the *exponent*.
gcdNonnegative - generic function(exactInteger, exactInteger)
Both arguments are non-negative, exact integers. <gcdNonnegative>
returns their greatest common divisor (GCD).
divideReduced - generic function(numerator, denominator)
Both arguments are exact, relatively prime integers, and
*denominator* is greater than zero. <divideReduced> returns an
exact rational equal to *numerator* divided by *denominator*.
*/
function defineGenericFunctions(plugins) {
"use strict";
var g = plugins.get("es5globals");
var disp = plugins.get("Dispatch");
var api = g.Object.create(null);
function def(name, ndisp, nargs) {
api[name] = disp.defGeneric(name, ndisp, nargs);
}
def("toSchemeNumber", 1);
def("numberToString", 1, 3); // 2nd and 3rd args native
def("isExact", 1);
def("isInexact", 1);
def("isComplex", 1);
def("isReal", 1);
def("isRational", 1);
def("isInteger", 1);
def("isZero", 1);
def("toExact", 1);
def("toInexact", 1);
def("negate", 1);
def("reciprocal", 1);
def("eq", 2);
def("ne", 2);
def("add", 2);
def("subtract", 2);
def("multiply", 2);
def("divide", 2);
def("square", 1);
def("realPart", 1);
def("imagPart", 1);
def("magnitude", 1);
def("angle", 1);
def("conjugate", 1);
def("expt", 2);
def("exp", 1);
def("sqrt", 1);
def("log", 1);
def("asin", 1);
def("acos", 1);
def("atan", 1);
def("sin", 1);
def("cos", 1);
def("tan", 1);
def("SN_isFinite", 1);
def("SN_isInfinite", 1);
def("SN_isNaN", 1);
def("isUnit", 1);
def("abs", 1);
def("isPositive", 1);
def("isNegative", 1);
def("sign", 1);
def("floor", 1);
def("ceiling", 1);
def("truncate", 1);
def("round", 1);
def("compare", 2);
def("gt", 2);
def("lt", 2);
def("ge", 2);
def("le", 2);
def("divAndMod", 2);
def("div", 2);
def("mod", 2);
def("atan2", 2);
def("numerator", 1);
def("denominator", 1);
def("numeratorAndDenominator", 1);
def("isEven", 1);
def("isOdd", 1);
def("exactIntegerSqrt", 1);
def("exp10", 1, 2); // 2nd arg exact integer
def("gcdNonnegative", 2);
def("divideReduced", 2);
def("bitwiseNot", 1);
def("bitwiseAnd", 2);
def("bitwiseIor", 2);
def("bitwiseXor", 2);
def("bitCount", 1);
def("bitLength", 1);
def("firstBitSet", 1);
def("isBitSet", 1, 2); // 2nd arg convertible to index
def("copyBit", 1, 3); // 2nd arg convertible to index; 3rd arg boolean
def("bitField", 1, 3);
def("copyBitField", 2, 4);
def("bitShift", 1, 2);
def("rotateBitField", 1, 4);
def("reverseBitField", 1, 3);
return api;
}
function defineSchemeNumberType(plugins) {
"use strict";
var g = plugins.get("es5globals");
var _NaN = g.NaN;
var api = g.Object.create(null);
var numberToString = plugins.get("numberToString");
var disp = plugins.get("Dispatch");
function SchemeNumberType(){}
// Inherit from Number so that "x instanceof Number" holds.
// But then override the standard methods, which are compatible
// only with native Number objects.
SchemeNumberType.prototype = new Number();
// Good defaults.
function genericToString(radix) {
if (numberToString)
return numberToString(this, radix);
return "[object SchemeNumber]";
}
function genericToLocaleString() {
return genericToString();
}
function retNaN() {
return _NaN;
}
// Bad default.
function genericFormatter() {
if (numberToString)
return numberToString(this);
return "SchemeNumber";
}
SchemeNumberType.prototype.toFixed = genericFormatter;
SchemeNumberType.prototype.toExponential = genericFormatter;
SchemeNumberType.prototype.toPrecision = genericFormatter;
SchemeNumberType.prototype.toString = genericToString;
SchemeNumberType.prototype.toLocaleString = genericToLocaleString;
SchemeNumberType.prototype.valueOf = retNaN;
disp.defClass("SchemeNumber", { ctor: SchemeNumberType });
api.SchemeNumberType = SchemeNumberType;
return api;
}
/*
Function: defineDebugFunction(plugins)
Creates a generic function, *debug*, for inspecting number objects.
Input:
*plugins* shall be a <PluginContainer> containing the following
element.
Dispatch - a <JsDispatch> object.
<defineDebugFunction> calls the *Dispatch* object's *defGeneric*
method to create the *debug* function, and calls the resulting
function's *def* method with class name "SchemeNumber" to define a
generic implementation of *debug*.
Output:
debug - generic function(schemeNumber) -> string
Applications must not rely on the returned string's format.
Number implementations should specialize this function to provide
internal details of use during development. Developers may obtain
this function via *SchemeNumber.plugins.get("debug")*. Example:
> SchemeNumber.plugins.get("debug")(SchemeNumber(10)) // "EINative(10)"
See Also: <JsDispatch>
*/
function defineDebugFunction(plugins) {
"use strict";
var g = plugins.get("es5globals");
var uncurry = plugins.get("uncurry");
var disp = plugins.get("Dispatch");
var SchemeNumberType = plugins.get("SchemeNumberType");
var Object_toString = uncurry(g.Object.prototype.toString);
var api = g.Object.create(null);
// Generic default for classes that don't specialize debug.
function SchemeNumber_debug() {
var t;
try { t = this.toString(); }
catch (e) {
try { t = Object_toString(this); }
catch (e) { t = "?"; }
}
return "SchemeNumber(" + t + ")";
}
api.debug = disp.defGeneric("debug", 1);
api.debug.def(SchemeNumberType, SchemeNumber_debug);
return api;
}
/*
Function: implementCoreLibrary(plugins)
Creates the plugins required by Scheme functions and a few others.
Input:
*plugins* shall be a <PluginContainer> containing the items listed
below. All may be added after the call to <implementCoreLibrary>
but before any use of its results. When changes to plugins
produce changes in non-function results (such as *ZERO* and
*ONE*), the library broadcasts the changes via the
<PluginContainer.onChange> event.
SchemeNumber - function(any)
The <SchemeNumber> object as returned by
<implementSchemeNumber(plugins)>.
nativeToExactInteger - function(integer)
*integer* is a native ECMAScript number of integer value.
<nativeToExactInteger> returns an exact Scheme number whose value
equals *integer*.
nativeToInexact - function(number)
*number* is a native ECMAScript number, possibly infinite or
*NaN*. <nativeToInexact> returns an inexact Scheme number
approximating its argument.
parseExactInteger - function(sign, string, radix)
*sign* is the native number 1 or -1. *radix* is the native number
2, 8, 10, or 16. <parseExactInteger> must be a function returning
a Scheme number equal to *sign* times the result of parsing
*string* as a positive, unprefixed, exact integer in the given
radix.
parseInexact - function(sign, string)
*sign* is the native number 1 or -1. <parseExact> must be a
function returning a Scheme number equal to *sign* times the
result of parsing *string* as a positive, unprefixed, decimal,
inexact, real number.
exactRectangular - function(x, y)
*x* and *y* are exact reals, *y* non-zero. <exactRectangular>
returns an exact complex equal to *x* + (i * *y*).
inexactRectangular - function(x, y)
*x* and *y* are inexact reals. <inexactRectangular> returns an
inexact complex equal to *x* + (i * *y*).
exactPolar - function(r, theta)
*r* and *theta* are exact reals. <exactPolar> returns an exact
complex equal to *r* * exp(i * *theta*).
inexactPolar - function(r, theta)
*r* and *theta* are inexact reals. <inexactPolar> returns an
inexact complex equal to *r* * exp(i * *theta*).
Output:
<implementCoreLibrary> returns an object with the following
properties.
ZERO - the exact integer *0*.
ONE - the exact integer *1*.
TWO - the exact integer *2*.
MINUS_ONE - the exact integer *-1*.
INEXACT_ZERO - the inexact integer *0.0*.
INEXACT_ONE - the inexact integer *1.0*.
PI - the inexact real number pi.
INFINITY - the inexact real number *+inf.0*.
MINUS_INFINITY - the inexact real number *-inf.0*.
NAN - the inexact real number *+nan.0*.
I - the exact complex unit *i*.
MINUS_I - the exact complex unit *-i*.
raise - function(conditionType, message, irritant...)
This *raise* simply calls the user-overridable
<SchemeNumber.raise> but enforces the contract not to return.
defaultRaise - function(conditionType, message, irritant...)
Throws an Error describing the arguments.
raiseDivisionByExactZero - function()
Raises an exception as specified by Scheme to report division by
exact zero.
isNumber - function(x)
Returns true if *x* is a Scheme number.
assertReal - function(x)
Returns *x* if *x* is a real Scheme number, otherwise raises an
exception as specified by Scheme for invalid argument type.
toReal - function(x)
Converts *x* to a Scheme number and behaves as if by returning
*assertReal(x)*.
assertInteger - function(x)
Returns *x* if *x* is a Scheme integer, otherwise raises an
exception as specified by Scheme for invalid argument type.
toInteger - function(x)
Converts *x* to a Scheme number and behaves as if by returning
*assertInteger(x)*.
assertExact - function(x)
Returns *x* if *x* is an exact Scheme number, otherwise raises an
exception as specified by Scheme for invalid argument type.
stringToNumber - function(string, radix, exact)
<stringToNumber> returns the Scheme number whose external
representation is *string* with added prefixes corresponding to
either or both of *radix* and *exact*, if defined.
*s* should be the external representation of a Scheme number, such
as "2/3" or "#e1.1@-2d19". If *s* does not represent a Scheme
number, <stringToNumber> returns *false*.
If *radix* is given, it must be either 2, 8, 10, or 16, and *s*
must not contain a radix prefix. The function behaves as if *s*
did contain the prefix corresponding to *radix*.
If *exact* is given, it must have type "boolean", and *s* must not
contain an exactness prefix. The function behaves as if *s*
contained the corresponding prefix ("#e" if *exact* is true, "#i"
if false).
truncateToPrecision -
XXX documentation incomplete.
*/
function implementCoreLibrary(plugins) {
"use strict";
// Abstract types, generic functions, and the SchemeNumber object.
// XXX Could remove unused items.
var SchemeNumber, toSchemeNumber, SchemeNumberType, Complex, Real,
InexactReal, ExactReal, ExactRational, ExactInteger,
numberToString, isExact, isInexact, isComplex, isReal,
isRational, isInteger, isZero, toExact, toInexact, negate,
reciprocal, eq, ne, add, subtract, multiply, divide, square,
realPart, imagPart, expt, expt, exp, magnitude, angle, sqrt,
log, asin, acos, atan, sin, cos, tan, SN_isFinite,
SN_isInfinite, SN_isNaN, isUnit, abs, isPositive, isNegative,
sign, floor, ceiling, truncate, round, compare, gt, lt, ge,
le, divAndMod, div, mod, atan2, numerator, denominator,
numeratorAndDenominator,
isEven, isOdd, exp10, gcdNonnegative, divideReduced;
SchemeNumber = plugins.get("SchemeNumber");
SchemeNumberType = plugins.get("SchemeNumberType");
Complex = plugins.get("Complex");
Real = plugins.get("Real");
InexactReal = plugins.get("InexactReal");
ExactReal = plugins.get("ExactReal");
ExactRational = plugins.get("ExactRational");
ExactInteger = plugins.get("ExactInteger");
toSchemeNumber = plugins.get("toSchemeNumber");
numberToString = plugins.get("numberToString");
isExact = plugins.get("isExact");
isInexact = plugins.get("isInexact");
isComplex = plugins.get("isComplex");
isReal = plugins.get("isReal");
isRational = plugins.get("isRational");
isInteger = plugins.get("isInteger");
isZero = plugins.get("isZero");
toExact = plugins.get("toExact");
toInexact = plugins.get("toInexact");
negate = plugins.get("negate");
reciprocal = plugins.get("reciprocal");
eq = plugins.get("eq");
ne = plugins.get("ne");
add = plugins.get("add");
subtract = plugins.get("subtract");
multiply = plugins.get("multiply");
divide = plugins.get("divide");
square = plugins.get("square");
realPart = plugins.get("realPart");
imagPart = plugins.get("imagPart");
expt = plugins.get("expt");
expt = plugins.get("expt");
exp = plugins.get("exp");
magnitude = plugins.get("magnitude");
angle = plugins.get("angle");
sqrt = plugins.get("sqrt");
log = plugins.get("log");
asin = plugins.get("asin");
acos = plugins.get("acos");
atan = plugins.get("atan");
sin = plugins.get("sin");
cos = plugins.get("cos");
tan = plugins.get("tan");
SN_isFinite = plugins.get("SN_isFinite");
SN_isInfinite = plugins.get("SN_isInfinite");
SN_isNaN = plugins.get("SN_isNaN");
isUnit = plugins.get("isUnit");
abs = plugins.get("abs");
isPositive = plugins.get("isPositive");
isNegative = plugins.get("isNegative");
sign = plugins.get("sign");
floor = plugins.get("floor");
ceiling = plugins.get("ceiling");
truncate = plugins.get("truncate");
round = plugins.get("round");
compare = plugins.get("compare");
gt = plugins.get("gt");
lt = plugins.get("lt");
ge = plugins.get("ge");
le = plugins.get("le");
divAndMod = plugins.get("divAndMod");
div = plugins.get("div");
mod = plugins.get("mod");
atan2 = plugins.get("atan2");
numerator = plugins.get("numerator");
denominator = plugins.get("denominator");
numeratorAndDenominator = plugins.get("numeratorAndDenominator");
isEven = plugins.get("isEven");
isOdd = plugins.get("isOdd");
exp10 = plugins.get("exp10");
gcdNonnegative = plugins.get("gcdNonnegative");
divideReduced = plugins.get("divideReduced");
// Functions to be provided by number implementations.
var nativeToInexact, parseInexact;
var parseExactInteger, nativeToExactInteger;
var divideReducedNotByOne;
var exactRectangular, inexactRectangular, exactPolar, inexactPolar;
// Constants to be defined here once we have the necessaries.
var ZERO, ONE, TWO, MINUS_ONE, I, MINUS_I;
var INEXACT_ZERO, INEXACT_ONE, PI, INFINITY, MINUS_INFINITY, NAN;
// Imports from ECMAScript.
var g = plugins.get("es5globals");
var uncurry = plugins.get("uncurry");
var Array_slice = uncurry(g.Array.prototype.slice);
var Array_join = uncurry(g.Array.prototype.join);
var Number_toString = uncurry(g.Number.prototype.toString);
var String_indexOf = uncurry(g.String.prototype.indexOf);
var String_substring = uncurry(g.String.prototype.substring);
var String_replace = uncurry(g.String.prototype.replace);
var RegExp_test = uncurry(g.RegExp.prototype.test);
var Math_LN10 = g.Math.LN10;
var Math_LN2 = g.Math.LN2;
var Math_PI = g.Math.PI;
var Math_abs = g.Math.abs;
var Math_floor = g.Math.floor;
var Math_pow = g.Math.pow;
var _LN2 = g.Math.LN2;
var _LN10 = g.Math.LN10;
var _PI = g.Math.PI;
var _undefined = g.undefined;
var _Infinity = g.Infinity;
var _NaN = g.NaN;
var _parseInt = g.parseInt;
var _isNaN = g.isNaN;
var _isFinite = g.isFinite;
var api = g.Object.create(null);
function onPluginsChanged(plugins, changed) {
nativeToExactInteger = plugins.get("nativeToExactInteger");
parseExactInteger = plugins.get("parseExactInteger");
nativeToInexact = plugins.get("nativeToInexact");
parseInexact = plugins.get("parseInexact");
divideReducedNotByOne = plugins.get("divideReducedNotByOne");
exactRectangular = plugins.get("exactRectangular");
inexactRectangular = plugins.get("inexactRectangular");
exactPolar = plugins.get("exactPolar");
inexactPolar = plugins.get("inexactPolar");
function getComplexConstant(x, y) {
try {
return exactRectangular(nativeToExactInteger(x),
nativeToExactInteger(y));
}
catch (e) {
return _undefined;
}
}
var exts = g.Object.create(null);
if (changed.nativeToExactInteger || changed.exactRectangular) {
I = exts.I = getComplexConstant(0, 1);
MINUS_I = exts.MINUS_I = getComplexConstant(0, -1);
}
if (changed.nativeToExactInteger) {
ZERO = exts.ZERO = nativeToExactInteger(0);
ONE = exts.ONE = nativeToExactInteger(1);
TWO = exts.TWO = nativeToExactInteger(2);
MINUS_ONE = exts.MINUS_ONE = nativeToExactInteger(-1);
}
if (changed.nativeToInexact) {
INEXACT_ZERO = exts.INEXACT_ZERO = nativeToInexact(0);
INEXACT_ONE = exts.INEXACT_ONE = nativeToInexact(1);
PI = exts.PI = nativeToInexact(Math_PI);
INFINITY = exts.INFINITY = nativeToInexact(_Infinity);
MINUS_INFINITY = exts.MINUS_INFINITY = nativeToInexact(-_Infinity);
NAN = exts.NAN = nativeToInexact(_NaN);
}
// XXX should not recurse into extend(). Should return exts
// here and make extend() loop.
plugins.extend(exts);
}
plugins.onChange.subscribe(onPluginsChanged);
onPluginsChanged(plugins, {});
function retFalse() { return false; }
function retTrue()