UNPKG

pasm

Version:

Piston X86-64 Assembler

1,437 lines (1,184 loc) 236 kB
// 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()