diff --git a/js-assembler/runtime-src/baselib-functions.js b/js-assembler/runtime-src/baselib-functions.js index 469e893..0390f1c 100644 --- a/js-assembler/runtime-src/baselib-functions.js +++ b/js-assembler/runtime-src/baselib-functions.js @@ -1,9 +1,14 @@ +/*jslint unparam: true, sub: true, vars: true, white: true, plusplus: true, maxerr: 50, indent: 4 */ + // Procedures // For historical reasons, this module is called 'functions' instead of 'procedures'. // This may change soon. -(function(baselib) { +/*global plt*/ + +(function (baselib) { + 'use strict'; var exports = {}; baselib.functions = exports; @@ -16,195 +21,8 @@ - - - // coerseToJavaScript: racket function -> JavaScript function - // Given a closure or primitive, produces an - // asynchronous JavaScript function. - // The function will run on the provided MACHINE. - // - // It assumes that it must begin its own trampoline. - var asJavaScriptFunction = function(v, MACHINE) { - MACHINE = MACHINE || plt.runtime.currentMachine; - if (isPrimitiveProcedure(v)) { - return coersePrimitiveToJavaScript(v, MACHINE); - } else if (isClosure(v)) { - return coerseClosureToJavaScript(v, MACHINE); - } else { - plt.baselib.exceptions.raise(MACHINE, - plt.baselib.exceptions.makeExnFail( - plt.baselib.format.format( - "Not a procedure: ~e", - v))); - } - }; - - var coersePrimitiveToJavaScript = function(v, MACHINE) { - return function(succ, fail) { - try { - succ = succ || function(){}; - fail = fail || function(){}; - - var oldArgcount = MACHINE.argcount; - MACHINE.argcount = arguments.length - 2; - for (var i = 0; i < arguments.length - 2; i++) { - MACHINE.env.push(arguments[arguments.length - 1 - i]); - } - - if (! plt.baselib.arity.isArityMatching(v.racketArity, MACHINE.argcount)) { - fail(new Error(plt.baselib.format.format( - "arity mismatch: expected ~s arguments, but received ~s", - [v.racketArity, MACHINE.argcount]))); - return; - } - - var result = v(MACHINE); - MACHINE.argcount = oldArgcount; - for (var i = 0; i < arguments.length - 2; i++) { - MACHINE.env.pop(); - } - succ(result); - } catch (e) { - fail(e); - } - } - }; - - - var coerseClosureToJavaScript = function(v, MACHINE) { - var f = function(succ, fail) { - succ = succ || function(){}; - fail = fail || function(){}; - - if (! plt.baselib.arity.isArityMatching(v.racketArity, arguments.length - 2)) { - fail(new Error( - plt.baselib.format.format( - "arity mismatch: expected ~s argument(s) but received ~s", - [v.racketArity, arguments.length - 2]))); - return; - } - - var oldVal = MACHINE.val; - var oldArgcount = MACHINE.argcount; - var oldProc = MACHINE.proc; - - var oldErrorHandler = MACHINE.params['currentErrorHandler']; - var afterGoodInvoke = function(MACHINE) { - plt.runtime.PAUSE( - function(restart) { - MACHINE.params['currentErrorHandler'] = oldErrorHandler; - var returnValue = MACHINE.val; - MACHINE.val = oldVal; - MACHINE.argcount = oldArgcount; - MACHINE.proc = oldProc; - succ(returnValue); - }); - }; - afterGoodInvoke.multipleValueReturn = function(MACHINE) { - plt.runtime.PAUSE( - function(restart) { - MACHINE.params['currentErrorHandler'] = oldErrorHandler; - var returnValues = [MACHINE.val]; - for (var i = 0; i < MACHINE.argcount - 1; i++) { - returnValues.push(MACHINE.env.pop()); - } - MACHINE.val = oldVal; - MACHINE.argcount = oldArgcount; - MACHINE.proc = oldProc; - succ.apply(null, returnValues); - }); - }; - - MACHINE.control.push( - new plt.baselib.frames.CallFrame(afterGoodInvoke, null)); - MACHINE.argcount = arguments.length - 2; - for (var i = 0; i < arguments.length - 2; i++) { - MACHINE.env.push(arguments[arguments.length - 1 - i]); - } - MACHINE.proc = v; - MACHINE.params['currentErrorHandler'] = function(MACHINE, e) { - MACHINE.params['currentErrorHandler'] = oldErrorHandler; - MACHINE.val = oldVal; - MACHINE.argcount = oldArgcount; - MACHINE.proc = oldProc; - fail(e); - }; - MACHINE.trampoline(v.label); - }; - return f; - }; - - - - // internallCallDuringPause: call a Racket procedure and get its results. - // The use assumes the machine is in a running-but-paused state. - var internalCallDuringPause = function(MACHINE, proc, success, fail) { - if (! plt.baselib.arity.isArityMatching(proc.racketArity, arguments.length - 4)) { - return fail(plt.baselib.exceptions.makeExnFailContractArity("arity mismatch")); - } - - if (isPrimitiveProcedure(proc)) { - var oldArgcount = MACHINE.argcount; - MACHINE.argcount = arguments.length - 4; - for (var i = 0; i < arguments.length - 4; i++) { - MACHINE.env.push(arguments[arguments.length - 1 - i]); - } - var result = proc(MACHINE); - for (var i = 0; i < arguments.length - 4; i++) { - MACHINE.env.pop(); - } - success(result); - } else if (isClosure(proc)) { - var oldVal = MACHINE.val; - var oldArgcount = MACHINE.argcount; - var oldProc = MACHINE.proc; - - var oldErrorHandler = MACHINE.params['currentErrorHandler']; - var afterGoodInvoke = function(MACHINE) { - plt.runtime.PAUSE(function(restart) { - MACHINE.params['currentErrorHandler'] = oldErrorHandler; - var returnValue = MACHINE.val; - MACHINE.val = oldVal; - MACHINE.argcount = oldArgcount; - MACHINE.proc = oldProc; - success(returnValue); - }); - }; - afterGoodInvoke.multipleValueReturn = function(MACHINE) { - plt.runtime.PAUSE(function(restart) { - MACHINE.params['currentErrorHandler'] = oldErrorHandler; - var returnValues = [MACHINE.val]; - for (var i = 0; i < MACHINE.argcount - 1; i++) { - returnValues.push(MACHINE.env.pop()); - } - MACHINE.val = oldVal; - MACHINE.argcount = oldArgcount; - MACHINE.proc = oldProc; - success.apply(null, returnValues); - }); - }; - - MACHINE.control.push( - new plt.baselib.frames.CallFrame(afterGoodInvoke, null)); - MACHINE.argcount = arguments.length - 4; - for (var i = 0; i < arguments.length - 4; i++) { - MACHINE.env.push(arguments[arguments.length - 1 - i]); - } - MACHINE.proc = proc; - MACHINE.params['currentErrorHandler'] = function(MACHINE, e) { - MACHINE.params['currentErrorHandler'] = oldErrorHandler; - MACHINE.val = oldVal; - MACHINE.argcount = oldArgcount; - MACHINE.proc = oldProc; - fail(e); - }; - MACHINE.trampoline(proc.label); - } else { - fail(plt.baselib.exceptions.makeExnFail( - plt.baselib.format.format( - "Not a procedure: ~e", - proc))); - } + var isPrimitiveProcedure = function (x) { + return typeof (x) === 'function'; }; @@ -221,15 +39,14 @@ // A closure consists of its free variables as well as a label // into its text segment. - var Closure = function(label, arity, closedVals, displayName) { - this.label = label; // (MACHINE -> void) - this.racketArity = arity; // number - this.closedVals = closedVals; // arrayof number - this.displayName = displayName; // string + var Closure = function (label, arity, closedVals, displayName) { + this.label = label; // (MACHINE -> void) + this.racketArity = arity; // number + this.closedVals = closedVals; // arrayof number + this.displayName = displayName; // string }; - // Finalize the return from a closure. This is a helper function // for those who implement Closures by hand. // @@ -243,28 +60,237 @@ // // I'd personally love for this to be a macro and avoid the // extra function call here. - var finalizeClosureCall = function(MACHINE) { + var finalizeClosureCall = function (MACHINE) { MACHINE.callsBeforeTrampoline--; var i, returnArgs = [].slice.call(arguments, 1); // clear out stack space // TODO: replace with a splice. - MACHINE.env.length = MACHINE.env.length - MACHINE.argcount; + MACHINE.env.length = MACHINE.env.length - MACHINE.argcount; if (returnArgs.length === 1) { MACHINE.val = returnArgs[0]; - return MACHINE.control.pop().label(MACHINE); + return MACHINE.control.pop().label(MACHINE); } else if (returnArgs.length === 0) { MACHINE.argcount = 0; - return MACHINE.control.pop().label.multipleValueReturn(MACHINE); + return MACHINE.control.pop().label.multipleValueReturn(MACHINE); } else { MACHINE.argcount = returnArgs.length; MACHINE.val = returnArgs.shift(); // TODO: replace with a splice. - for(i = 0; i < MACHINE.argcount - 1; i++) { + for (i = 0; i < MACHINE.argcount - 1; i++) { MACHINE.env.push(returnArgs.pop()); } - return MACHINE.control.pop().label.multipleValueReturn(MACHINE); + return MACHINE.control.pop().label.multipleValueReturn(MACHINE); + } + }; + + + var isClosure = function (x) { + return x instanceof Closure; + }; + + + var isProcedure = function (x) { + return (typeof (x) === 'function' || + x instanceof Closure); + }; + + + + + + + + + + var coersePrimitiveToJavaScript = function (v, MACHINE) { + return function (succ, fail) { + try { + succ = succ || function () {}; + fail = fail || function () {}; + + var oldArgcount = MACHINE.argcount, i; + MACHINE.argcount = arguments.length - 2; + for (i = 0; i < arguments.length - 2; i++) { + MACHINE.env.push(arguments[arguments.length - 1 - i]); + } + + if (!(baselib.arity.isArityMatching(v.racketArity, MACHINE.argcount))) { + fail(new Error(baselib.format.format("arity mismatch: expected ~s arguments, but received ~s", + [v.racketArity, MACHINE.argcount]))); + return; + } + + var result = v(MACHINE); + MACHINE.argcount = oldArgcount; + for (i = 0; i < arguments.length - 2; i++) { + MACHINE.env.pop(); + } + succ(result); + } catch (e) { + fail(e); + } + }; + }; + + var coerseClosureToJavaScript = function (v, MACHINE) { + var f = function (succ, fail) { + succ = succ || function () {}; + fail = fail || function () {}; + + if (!(baselib.arity.isArityMatching(v.racketArity, arguments.length - 2))) { + fail(new Error( + baselib.format.format( + "arity mismatch: expected ~s argument(s) but received ~s", + [v.racketArity, arguments.length - 2]))); + return; + } + + var oldVal = MACHINE.val; + var oldArgcount = MACHINE.argcount; + var oldProc = MACHINE.proc; + + var oldErrorHandler = MACHINE.params['currentErrorHandler']; + var afterGoodInvoke = function (MACHINE) { + plt.runtime.PAUSE( + function (restart) { + MACHINE.params['currentErrorHandler'] = oldErrorHandler; + var returnValue = MACHINE.val; + MACHINE.val = oldVal; + MACHINE.argcount = oldArgcount; + MACHINE.proc = oldProc; + succ(returnValue); + }); + }; + afterGoodInvoke.multipleValueReturn = function (MACHINE) { + plt.runtime.PAUSE( + function (restart) { + MACHINE.params['currentErrorHandler'] = oldErrorHandler; + var returnValues = [MACHINE.val], i; + for (i = 0; i < MACHINE.argcount - 1; i++) { + returnValues.push(MACHINE.env.pop()); + } + MACHINE.val = oldVal; + MACHINE.argcount = oldArgcount; + MACHINE.proc = oldProc; + succ.apply(null, returnValues); + }); + }; + + MACHINE.control.push( + new baselib.frames.CallFrame(afterGoodInvoke, null)); + MACHINE.argcount = arguments.length - 2; + var i; + for (i = 0; i < arguments.length - 2; i++) { + MACHINE.env.push(arguments[arguments.length - 1 - i]); + } + MACHINE.proc = v; + MACHINE.params['currentErrorHandler'] = function (MACHINE, e) { + MACHINE.params['currentErrorHandler'] = oldErrorHandler; + MACHINE.val = oldVal; + MACHINE.argcount = oldArgcount; + MACHINE.proc = oldProc; + fail(e); + }; + MACHINE.trampoline(v.label); + }; + return f; + }; + + // coerseToJavaScript: racket function -> JavaScript function + // Given a closure or primitive, produces an + // asynchronous JavaScript function. + // The function will run on the provided MACHINE. + // + // It assumes that it must begin its own trampoline. + var asJavaScriptFunction = function (v, MACHINE) { + MACHINE = MACHINE || plt.runtime.currentMachine; + if (isPrimitiveProcedure(v)) { + return coersePrimitiveToJavaScript(v, MACHINE); + } else if (isClosure(v)) { + return coerseClosureToJavaScript(v, MACHINE); + } else { + baselib.exceptions.raise(MACHINE, + baselib.exceptions.makeExnFail( + baselib.format.format( + "Not a procedure: ~e", + v))); + } + }; + + + // internallCallDuringPause: call a Racket procedure and get its results. + // The use assumes the machine is in a running-but-paused state. + var internalCallDuringPause = function (MACHINE, proc, success, fail) { + var i; + var oldArgcount, oldVal, oldProc, oldErrorHandler; + if (! baselib.arity.isArityMatching(proc.racketArity, arguments.length - 4)) { + return fail(baselib.exceptions.makeExnFailContractArity("arity mismatch")); + } + + if (isPrimitiveProcedure(proc)) { + oldArgcount = MACHINE.argcount; + MACHINE.argcount = arguments.length - 4; + for (i = 0; i < arguments.length - 4; i++) { + MACHINE.env.push(arguments[arguments.length - 1 - i]); + } + var result = proc(MACHINE); + for (i = 0; i < arguments.length - 4; i++) { + MACHINE.env.pop(); + } + success(result); + } else if (isClosure(proc)) { + oldVal = MACHINE.val; + oldArgcount = MACHINE.argcount; + oldProc = MACHINE.proc; + + oldErrorHandler = MACHINE.params['currentErrorHandler']; + var afterGoodInvoke = function (MACHINE) { + plt.runtime.PAUSE(function (restart) { + MACHINE.params['currentErrorHandler'] = oldErrorHandler; + var returnValue = MACHINE.val; + MACHINE.val = oldVal; + MACHINE.argcount = oldArgcount; + MACHINE.proc = oldProc; + success(returnValue); + }); + }; + afterGoodInvoke.multipleValueReturn = function (MACHINE) { + plt.runtime.PAUSE(function (restart) { + MACHINE.params['currentErrorHandler'] = oldErrorHandler; + var returnValues = [MACHINE.val]; + var i; + for (i = 0; i < MACHINE.argcount - 1; i++) { + returnValues.push(MACHINE.env.pop()); + } + MACHINE.val = oldVal; + MACHINE.argcount = oldArgcount; + MACHINE.proc = oldProc; + success.apply(null, returnValues); + }); + }; + + MACHINE.control.push( + new baselib.frames.CallFrame(afterGoodInvoke, null)); + MACHINE.argcount = arguments.length - 4; + for (i = 0; i < arguments.length - 4; i++) { + MACHINE.env.push(arguments[arguments.length - 1 - i]); + } + MACHINE.proc = proc; + MACHINE.params['currentErrorHandler'] = function (MACHINE, e) { + MACHINE.params['currentErrorHandler'] = oldErrorHandler; + MACHINE.val = oldVal; + MACHINE.argcount = oldArgcount; + MACHINE.proc = oldProc; + fail(e); + }; + MACHINE.trampoline(proc.label); + } else { + fail(baselib.exceptions.makeExnFail( + baselib.format.format( + "Not a procedure: ~e", + proc))); } }; @@ -273,13 +299,18 @@ - var makePrimitiveProcedure = function(name, arity, f) { + + + + + + var makePrimitiveProcedure = function (name, arity, f) { f.racketArity = arity; f.displayName = name; return f; }; - var makeClosure = function(name, arity, f, closureArgs) { + var makeClosure = function (name, arity, f, closureArgs) { if (! closureArgs) { closureArgs = []; } return new Closure(f, arity, @@ -290,28 +321,15 @@ - var isPrimitiveProcedure = function(x) { - return typeof(x) === 'function'; - }; - - var isClosure = function(x) { - return x instanceof Closure; - }; - - - var isProcedure = function(x) { - return (typeof(x) === 'function' || - x instanceof Closure); - }; - var renameProcedure = function(f, name) { + var renameProcedure = function (f, name) { if (isPrimitiveProcedure(f)) { return makePrimitiveProcedure( name, f.racketArity, - function() { + function () { return f.apply(null, arguments); }); } else { @@ -346,4 +364,4 @@ exports.asJavaScriptFunction = asJavaScriptFunction; -})(this['plt'].baselib); \ No newline at end of file +}(this.plt.baselib)); \ No newline at end of file