diff --git a/image/private/js-impl.js b/image/private/js-impl.js index e15e98e..b21d4c3 100644 --- a/image/private/js-impl.js +++ b/image/private/js-impl.js @@ -1,21 +1,21 @@ -var checkString = plt.runtime.makeCheckArgumentType( - plt.runtime.strings.isString, +var checkString = plt.baselib.check.makeCheckArgumentType( + plt.baselib.strings.isString, 'string'); -var checkByte = plt.runtime.makeCheckArgumentType( - plt.runtime.numbers.isByte, +var checkByte = plt.baselib.check.makeCheckArgumentType( + plt.baselib.numbers.isByte, 'byte'); -var checkColor = plt.runtime.makeCheckArgumentType( +var checkColor = plt.baselib.check.makeCheckArgumentType( isColorOrColorString, 'color'); -var checkImage = plt.runtime.makeCheckArgumentType( +var checkImage = plt.baselib.check.makeCheckArgumentType( isImage, 'image'); -var checkReal = plt.runtime.makeCheckArgumentType( - plt.runtime.numbers.isReal, +var checkReal = plt.baselib.check.makeCheckArgumentType( + plt.baselib.numbers.isReal, 'real'); @@ -24,7 +24,7 @@ var checkReal = plt.runtime.makeCheckArgumentType( EXPORTS['image-color?'] = - plt.runtime.makePrimitiveProcedure( + plt.baselib.functions.makePrimitiveProcedure( 'image-color?', 1, function(MACHINE) { @@ -36,7 +36,7 @@ EXPORTS['image-color?'] = EXPORTS['text'] = - plt.runtime.makePrimitiveProcedure( + plt.baselib.functions.makePrimitiveProcedure( 'text', 3, function(MACHINE) { @@ -53,7 +53,7 @@ EXPORTS['text'] = // FIXME // EXPORTS['text/font'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'text/font', // ???, // function(MACHINE) { @@ -62,7 +62,7 @@ EXPORTS['text'] = // FIXME // EXPORTS['image-url'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'image-url', // ???, // function(MACHINE) { @@ -71,7 +71,7 @@ EXPORTS['text'] = // FIXME // EXPORTS['open-image-url'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'open-image-url', // ???, // function(MACHINE) { @@ -79,7 +79,7 @@ EXPORTS['text'] = // }); EXPORTS['overlay'] = - plt.runtime.makePrimitiveProcedure( + plt.baselib.functions.makePrimitiveProcedure( 'overlay', plt.baselib.arity.makeArityAtLeast(2), function(MACHINE) { @@ -99,7 +99,7 @@ EXPORTS['overlay'] = }); EXPORTS['overlay/xy'] = - plt.runtime.makePrimitiveProcedure( + plt.baselib.functions.makePrimitiveProcedure( 'overlay/xy', 4, function(MACHINE) { @@ -115,7 +115,7 @@ EXPORTS['overlay/xy'] = // FIXME // EXPORTS['overlay/align'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'overlay/align', // ???, // function(MACHINE) { @@ -123,7 +123,7 @@ EXPORTS['overlay/xy'] = // }); EXPORTS['underlay'] = - plt.runtime.makePrimitiveProcedure( + plt.baselib.functions.makePrimitiveProcedure( 'underlay', plt.baselib.arity.makeArityAtLeast(2), function(MACHINE) { @@ -142,7 +142,7 @@ EXPORTS['underlay'] = }); EXPORTS['underlay/xy'] = - plt.runtime.makePrimitiveProcedure( + plt.baselib.functions.makePrimitiveProcedure( 'underlay/xy', 4, function(MACHINE) { @@ -157,7 +157,7 @@ EXPORTS['underlay/xy'] = }); // EXPORTS['underlay/align'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'underlay/align', // ???, // function(MACHINE) { @@ -165,7 +165,7 @@ EXPORTS['underlay/xy'] = // }); // EXPORTS['beside'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'beside', // ???, // function(MACHINE) { @@ -173,7 +173,7 @@ EXPORTS['underlay/xy'] = // }); // EXPORTS['beside/align'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'beside/align', // ???, // function(MACHINE) { @@ -181,7 +181,7 @@ EXPORTS['underlay/xy'] = // }); // EXPORTS['above'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'above', // ???, // function(MACHINE) { @@ -189,7 +189,7 @@ EXPORTS['underlay/xy'] = // }); // EXPORTS['above/align'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'above/align', // ???, // function(MACHINE) { @@ -197,7 +197,7 @@ EXPORTS['underlay/xy'] = // }); // EXPORTS['place-image/align'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'place-image/align', // ???, // function(MACHINE) { @@ -205,7 +205,7 @@ EXPORTS['underlay/xy'] = // }); EXPORTS['rotate'] = - plt.runtime.makePrimitiveProcedure( + plt.baselib.functions.makePrimitiveProcedure( 'rotate', 2, function(MACHINE) { @@ -215,7 +215,7 @@ EXPORTS['rotate'] = }); EXPORTS['scale'] = - plt.runtime.makePrimitiveProcedure( + plt.baselib.functions.makePrimitiveProcedure( 'scale', 2, function(MACHINE) { @@ -227,7 +227,7 @@ EXPORTS['scale'] = }); EXPORTS['scale/xy'] = - plt.runtime.makePrimitiveProcedure( + plt.baselib.functions.makePrimitiveProcedure( 'scale/xy', 3, function(MACHINE) { @@ -241,7 +241,7 @@ EXPORTS['scale/xy'] = }); // EXPORTS['flip-horizontal'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'flip-horizontal', // ???, // function(MACHINE) { @@ -249,7 +249,7 @@ EXPORTS['scale/xy'] = // }); // EXPORTS['flip-vertical'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'flip-vertical', // ???, // function(MACHINE) { @@ -257,7 +257,7 @@ EXPORTS['scale/xy'] = // }); // EXPORTS['frame'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'frame', // ???, // function(MACHINE) { @@ -265,7 +265,7 @@ EXPORTS['scale/xy'] = // }); // EXPORTS['crop'] = -// plt.runtime.makePrimitiveProcedure( +// plt.baselib.functions.makePrimitiveProcedure( // 'crop', // ???, // function(MACHINE) { @@ -273,7 +273,7 @@ EXPORTS['scale/xy'] = // }); EXPORTS['line'] = - plt.runtime.makePrimitiveProcedure( + plt.baselib.functions.makePrimitiveProcedure( 'line', 3, function(MACHINE) { @@ -289,233 +289,266 @@ EXPORTS['line'] = return line; }); -EXPORTS['add-line'] = - plt.runtime.makePrimitiveProcedure( - 'add-line', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['scene+line'] = - plt.runtime.makePrimitiveProcedure( - 'scene+line', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['circle'] = - plt.runtime.makePrimitiveProcedure( - 'circle', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['square'] = - plt.runtime.makePrimitiveProcedure( - 'square', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['rectangle'] = - plt.runtime.makePrimitiveProcedure( - 'rectangle', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['regular-polygon'] = - plt.runtime.makePrimitiveProcedure( - 'regular-polygon', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['ellipse'] = - plt.runtime.makePrimitiveProcedure( - 'ellipse', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['triangle'] = - plt.runtime.makePrimitiveProcedure( - 'triangle', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['right-triangle'] = - plt.runtime.makePrimitiveProcedure( - 'right-triangle', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['isosceles-triangle'] = - plt.runtime.makePrimitiveProcedure( - 'isosceles-triangle', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['star'] = - plt.runtime.makePrimitiveProcedure( - 'star', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['radial-star'] = - plt.runtime.makePrimitiveProcedure( - 'radial-star', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['star-polygon'] = - plt.runtime.makePrimitiveProcedure( - 'star-polygon', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['rhombus'] = - plt.runtime.makePrimitiveProcedure( - 'rhombus', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['image->color-list'] = - plt.runtime.makePrimitiveProcedure( - 'image->color-list', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['color-list->image'] = - plt.runtime.makePrimitiveProcedure( - 'color-list->image', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['image-width'] = - plt.runtime.makePrimitiveProcedure( - 'image-width', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['image-height'] = - plt.runtime.makePrimitiveProcedure( - 'image-height', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['image-baseline'] = - plt.runtime.makePrimitiveProcedure( - 'image-baseline', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['image-color?'] = - plt.runtime.makePrimitiveProcedure( - 'image-color?', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['mode?'] = - plt.runtime.makePrimitiveProcedure( - 'mode?', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['x-place?'] = - plt.runtime.makePrimitiveProcedure( - 'x-place?', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['y-place?'] = - plt.runtime.makePrimitiveProcedure( - 'y-place?', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['angle?'] = - plt.runtime.makePrimitiveProcedure( - 'angle?', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['side-count?'] = - plt.runtime.makePrimitiveProcedure( - 'side-count?', - ???, - function(MACHINE) { - ... - }); - -EXPORTS['image-url'] = - plt.runtime.makePrimitiveProcedure( - 'image-url', - ???, - function(MACHINE) { - ... - }); -EXPORTS['open-image-url'] = - plt.runtime.makePrimitiveProcedure( - 'open-image-url', - ???, - function(MACHINE) { - ... - }); -EXPORTS['color-list->image'] = - plt.runtime.makePrimitiveProcedure( - 'color-list->image', - ???, - function(MACHINE) { - ... - }); -EXPORTS['step-count?'] = - plt.runtime.makePrimitiveProcedure( - 'step-count?', - ???, - function(MACHINE) { - ... - }); \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// EXPORTS['add-line'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'add-line', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['scene+line'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'scene+line', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['circle'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'circle', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['square'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'square', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['rectangle'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'rectangle', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['regular-polygon'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'regular-polygon', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['ellipse'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'ellipse', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['triangle'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'triangle', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['right-triangle'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'right-triangle', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['isosceles-triangle'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'isosceles-triangle', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['star'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'star', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['radial-star'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'radial-star', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['star-polygon'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'star-polygon', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['rhombus'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'rhombus', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['image->color-list'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'image->color-list', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['color-list->image'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'color-list->image', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['image-width'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'image-width', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['image-height'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'image-height', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['image-baseline'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'image-baseline', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['image-color?'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'image-color?', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['mode?'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'mode?', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['x-place?'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'x-place?', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['y-place?'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'y-place?', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['angle?'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'angle?', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['side-count?'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'side-count?', +// ???, +// function(MACHINE) { +// ... +// }); + +// EXPORTS['image-url'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'image-url', +// ???, +// function(MACHINE) { +// ... +// }); +// EXPORTS['open-image-url'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'open-image-url', +// ???, +// function(MACHINE) { +// ... +// }); +// EXPORTS['color-list->image'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'color-list->image', +// ???, +// function(MACHINE) { +// ... +// }); + + +// EXPORTS['step-count?'] = +// plt.baselib.functions.makePrimitiveProcedure( +// 'step-count?', +// ???, +// function(MACHINE) { +// ... +// }); diff --git a/image/private/racket-impl.rkt b/image/private/racket-impl.rkt index 9be555a..c444cb0 100644 --- a/image/private/racket-impl.rkt +++ b/image/private/racket-impl.rkt @@ -51,15 +51,13 @@ y-place? angle? side-count? + image-color? ;; Something funky is happening on the Racket side of things with regards ;; to step-count? See: http://bugs.racket-lang.org/query/?cmd=view&pr=12031 ;; step-count? ) -(define (is-color? x) - true) - (define-syntax (define-stubs stx) diff --git a/js-assembler/get-runtime.rkt b/js-assembler/get-runtime.rkt index 775b6fb..9fc6868 100644 --- a/js-assembler/get-runtime.rkt +++ b/js-assembler/get-runtime.rkt @@ -63,6 +63,8 @@ baselib-keywords.js baselib-structs.js baselib-ports.js + baselib-functions.js + baselib-modules.js baselib-arity.js baselib-inspectors.js diff --git a/js-assembler/runtime-src/baselib-check.js b/js-assembler/runtime-src/baselib-check.js index c882743..b29f607 100644 --- a/js-assembler/runtime-src/baselib-check.js +++ b/js-assembler/runtime-src/baselib-check.js @@ -38,6 +38,22 @@ } }; + var testArity = function(callerName, observed, minimum, maximum) { + if (observed < minimum || observed > maximum) { + plt.baselib.exceptions.raise( + MACHINE, new Error(callerName + ": expected at least " + minimum + + " arguments " + + " but received " + observed)); + + } + }; + + + + + + + //var checkOutputPort = makeCheckArgumentType() @@ -48,7 +64,9 @@ exports.testArgument = testArgument; + exports.testArity = testArity; exports.makeCheckArgumentType = makeCheckArgumentType; + //exports.checkOutputPort = checkOutputPort; diff --git a/js-assembler/runtime-src/baselib-functions.js b/js-assembler/runtime-src/baselib-functions.js new file mode 100644 index 0000000..7a6d1c2 --- /dev/null +++ b/js-assembler/runtime-src/baselib-functions.js @@ -0,0 +1,95 @@ +// Functions +(function(baselib) { + var exports = {}; + baselib.functions = exports; + + // Function types: a function is either a Primitive or a Closure. + + // A Primitive is a function that's expected to return. It is not + // allowed to call into Closures. Its caller is expected to pop off + // its argument stack space. + // + + + + + + // A Closure is a function that takes on more responsibilities: it is + // responsible for popping off stack space before it finishes, and it + // is also explicitly responsible for continuing the computation by + // popping off the control stack and doing the jump. Because of this, + // closures can do pretty much anything to the machine. + + // 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.arity = 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. + // + // If used in the body of a Closure, it must be in tail + // position. This finishes the closure call, and does the following: + // + // * Clears out the existing arguments off the stack frame + // * Sets up the return value + // * Jumps either to the single-value return point, or the multiple-value + // return point. + // + // I'd personally love for this to be a macro and avoid the + // extra function call here. + var finalizeClosureCall = function(MACHINE) { + MACHINE.callsBeforeTrampoline--; + var frame, i, returnArgs = [].slice.call(arguments, 1); + + // clear out stack space + // TODO: replace with a splice. + for(i = 0; i < MACHINE.argcount; i++) { + MACHINE.env.pop(); + } + + if (returnArgs.length === 1) { + MACHINE.val = returnArgs[0]; + frame = MACHINE.control.pop(); + return frame.label(MACHINE); + } else if (returnArgs.length === 0) { + MACHINE.argcount = 0; + frame = MACHINE.control.pop(); + return frame.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++) { + MACHINE.env.push(returnArgs.pop()); + } + frame = MACHINE.control.pop(); + return frame.label.multipleValueReturn(MACHINE); + } + }; + + + + + var makePrimitiveProcedure = function(name, arity, f) { + f.arity = arity; + f.displayName = name; + return f; + }; + + + + + + ////////////////////////////////////////////////////////////////////// + exports.Closure = Closure; + exports.finalizeClosureCall = finalizeClosureCall; + exports.makePrimitiveProcedure = makePrimitiveProcedure; + +})(this['plt'].baselib); \ No newline at end of file diff --git a/js-assembler/runtime-src/baselib-modules.js b/js-assembler/runtime-src/baselib-modules.js new file mode 100644 index 0000000..2418b2a --- /dev/null +++ b/js-assembler/runtime-src/baselib-modules.js @@ -0,0 +1,63 @@ +(function(baselib) { + var exports = {}; + baselib.modules = exports; + + + var ModuleRecord = function(name, label) { + this.name = name; + this.label = label; + this.isInvoked = false; + this.prefix = false; + this.namespace = {}; + }; + + // Returns access to the names defined in the module. + ModuleRecord.prototype.getNamespace = function() { + return this.namespace; + }; + + ModuleRecord.prototype.finalizeModuleInvokation = function() { + var i, len = this.prefix.names.length; + for (i=0; i < len; i++) { + this.namespace[this.prefix.names[i]] = this.prefix[i]; + } + }; + + + // External invokation of a module. + ModuleRecord.prototype.invoke = function(MACHINE, succ, fail) { + MACHINE = MACHINE || plt.runtime.currentMachine; + succ = succ || function(){}; + fail = fail || function(){}; + + var oldErrorHandler = MACHINE.params['currentErrorHandler']; + var afterGoodInvoke = function(MACHINE) { + MACHINE.params['currentErrorHandler'] = oldErrorHandler; + setTimeout(succ, 0); + }; + + if (this.isInvoked) { + setTimeout(succ, 0); + } else { + MACHINE.params['currentErrorHandler'] = function(MACHINE, anError) { + MACHINE.params['currentErrorHandler'] = oldErrorHandler; + setTimeout( + function() { + fail(MACHINE, anError) + }, + 0); + }; + MACHINE.control.push(new plt.baselib.frames.CallFrame(afterGoodInvoke, null)); + plt.runtime.trampoline(MACHINE, this.label); + } + }; + + + + + + + exports.ModuleRecord = ModuleRecord; + + +})(this['plt'].baselib); \ No newline at end of file diff --git a/js-assembler/runtime-src/baselib.js b/js-assembler/runtime-src/baselib.js index d2a0a18..f03a6d8 100644 --- a/js-assembler/runtime-src/baselib.js +++ b/js-assembler/runtime-src/baselib.js @@ -39,9 +39,37 @@ if (! this['plt']) { this['plt'] = {}; } }; + + // Helper to deal with the argument-passing of primitives. Call f + // with arguments bound from MACHINE.env, assuming + // MACHINE.argcount has been initialized with the number of + // arguments on the stack. vs provides optional values for the + // arguments that go beyond those of the mandatoryArgCount. + var withArguments = function(MACHINE, + mandatoryArgCount, + vs, + f) { + var args = []; + for (var i = 0; i < MACHINE.argcount; i++) { + if (i < mandatoryArgCount) { + args.push(MACHINE.env[MACHINE.env.length - 1 - i]); + } else { + if (i < MACHINE.argcount) { + args.push(MACHINE.env[MACHINE.env.length - 1 - i]); + } else { + args.push(vs[mandatoryArgCount - i]); + } + } + } + return f.apply(null, args); + }; + + + baselib.heir = heir; baselib.clone = clone; baselib.makeClassPredicate = makeClassPredicate; + baselib.withArguments = withArguments; })(this['plt']); diff --git a/js-assembler/runtime-src/runtime.js b/js-assembler/runtime-src/runtime.js index ec6456f..0608469 100644 --- a/js-assembler/runtime-src/runtime.js +++ b/js-assembler/runtime-src/runtime.js @@ -9,11 +9,6 @@ if(this['plt'] === undefined) { this['plt'] = {}; } var runtime = {}; scope['runtime'] = runtime; - var types = plt.types; - - - var makeClassPredicate = plt.baselib.makeClassPredicate; - ////////////////////////////////////////////////////////////////////// @@ -28,6 +23,7 @@ if(this['plt'] === undefined) { this['plt'] = {}; } var isList = plt.baselib.lists.isList; var isVector = plt.baselib.vectors.isVector; var isString = plt.baselib.strings.isString; + var isNonNegativeReal = plt.baselib.numbers.isNonNegativeReal; var equals = plt.baselib.equality.equals; var NULL = plt.baselib.lists.EMPTY; @@ -44,26 +40,38 @@ if(this['plt'] === undefined) { this['plt'] = {}; } var makeBignum = plt.baselib.numbers.makeBignum; var makeComplex = plt.baselib.numbers.makeComplex; + var makeBox = plt.baselib.boxes.makeBox; + var isBox = plt.baselib.boxes.isBox; var makeVector = plt.baselib.vectors.makeVector; var makeList = plt.baselib.lists.makeList; var makePair = plt.baselib.lists.makePair; + + var Closure = plt.baselib.functions.Closure; + var finalizeClosureCall = plt.baselib.functions.finalizeClosureCall; + var makePrimitiveProcedure = plt.baselib.functions.makePrimitiveProcedure; + + + // Other helpers + var withArguments = plt.baselib.withArguments; var heir = plt.baselib.heir; + var makeClassPredicate = plt.baselib.makeClassPredicate; var toDomNode = plt.baselib.format.toDomNode; var toWrittenString = plt.baselib.format.toWrittenString; var toDisplayedString = plt.baselib.format.toDisplayedString; - var makeBox = plt.baselib.boxes.makeBox; - var isBox = plt.baselib.boxes.isBox; - // Frame structures. var Frame = plt.baselib.frames.Frame; var CallFrame = plt.baselib.frames.CallFrame; var PromptFrame = plt.baselib.frames.PromptFrame; + // Module structure + var ModuleRecord = plt.baselib.modules.ModuleRecord; + + // Ports var OutputPort = plt.baselib.ports.OutputPort; @@ -76,14 +84,29 @@ if(this['plt'] === undefined) { this['plt'] = {}; } + // Exceptions and error handling. + var raise = plt.baselib.exceptions.raise; + var raiseUnboundToplevelError = plt.baselib.exceptions.raiseUnboundToplevelError; + var raiseArgumentTypeError = plt.baselib.exceptions.raiseArgumentTypeError; + var raiseContextExpectedValuesError = plt.baselib.exceptions.raiseContextExpectedValuesError; + var raiseArityMismatchError = plt.baselib.exceptions.raiseArityMismatchError; + var raiseOperatorApplicationError = plt.baselib.exceptions.raiseOperatorApplicationError; + var raiseOperatorIsNotPrimitiveProcedure = plt.baselib.exceptions.raiseOperatorIsNotPrimitiveProcedure; + var raiseOperatorIsNotClosure = plt.baselib.exceptions.raiseOperatorIsNotClosure; + var raiseUnimplementedPrimitiveError = plt.baselib.exceptions.raiseUnimplementedPrimitiveError; + + var testArgument = plt.baselib.check.testArgument; + var testArity = plt.baselib.check.testArity; + var makeCheckArgumentType = plt.baselib.check.makeCheckArgumentType; + + + + //////////////////////////////////////////////////////////////////////] - var isNonNegativeReal = plt.baselib.numbers.isNonNegativeReal; - - @@ -145,21 +168,7 @@ if(this['plt'] === undefined) { this['plt'] = {}; } 'numBouncesBeforeYield': 2000, // self-adjusting 'maxNumBouncesBeforeYield': 2000, // self-adjusting - 'currentPrint': new Closure( - function(MACHINE) { - if(--MACHINE.callsBeforeTrampoline<0) { throw arguments.callee; } - var elt = MACHINE.env[MACHINE.env.length - 1]; - var outputPort = - MACHINE.params.currentOutputPort; - if (elt !== VOID) { - outputPort.writeDomNode(MACHINE, toDomNode(elt, 'print')); - outputPort.writeDomNode(MACHINE, toDomNode("\n", 'display')); - } - return finalizeClosureCall(MACHINE, VOID); - }, - 1, - [], - "printer") + 'currentPrint': defaultCurrentPrint }; @@ -168,192 +177,55 @@ if(this['plt'] === undefined) { this['plt'] = {}; } - // Finalize the return from a closure. This is a helper function - // for those who implement Closures by hand. - // - // If used in the body of a Closure, it must be in tail - // position. This finishes the closure call, and does the following: - // - // * Clears out the existing arguments off the stack frame - // * Sets up the return value - // * Jumps either to the single-value return point, or the multiple-value - // return point. - // - // I'd personally love for this to be a macro and avoid the - // extra function call here. - var finalizeClosureCall = function(MACHINE) { - MACHINE.callsBeforeTrampoline--; - var frame, i, returnArgs = [].slice.call(arguments, 1); - // clear out stack space - // TODO: replace with a splice. - for(i = 0; i < MACHINE.argcount; i++) { - MACHINE.env.pop(); - } - - if (returnArgs.length === 1) { - MACHINE.val = returnArgs[0]; - frame = MACHINE.control.pop(); - return frame.label(MACHINE); - } else if (returnArgs.length === 0) { - MACHINE.argcount = 0; - frame = MACHINE.control.pop(); - return frame.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++) { - MACHINE.env.push(returnArgs.pop()); - } - frame = MACHINE.control.pop(); - return frame.label.multipleValueReturn(MACHINE); - } - }; - - - - - var ModuleRecord = function(name, label) { - this.name = name; - this.label = label; - this.isInvoked = false; - this.prefix = false; - this.namespace = {}; - }; - - // Returns access to the names defined in the module. - ModuleRecord.prototype.getNamespace = function() { - return this.namespace; - }; - - ModuleRecord.prototype.finalizeModuleInvokation = function() { - var i, len = this.prefix.names.length; - for (i=0; i < len; i++) { - this.namespace[this.prefix.names[i]] = this.prefix[i]; + // Approximately find the stack limit. + // This function assumes, on average, five variables or + // temporaries per stack frame. + // This will never report a number greater than MAXIMUM_CAP. + var findStackLimit = function(after) { + var MAXIMUM_CAP = 100000; + var n = 1; + var limitDiscovered = false; + setTimeout( + function() { + if(! limitDiscovered) { + limitDiscovered = true; + after(n); + } + }, + 0); + var loop1 = function(x, y, z, w, k) { + // Ensure termination, just in case JavaScript ever + // does eliminate stack limits. + if (n >= MAXIMUM_CAP) { return; } + n++; + return 1 + loop2(y, z, w, k, x); + }; + var loop2 = function(x, y, z, w, k) { + n++; + return 1 + loop1(y, z, w, k, x); + }; + try { + var dontCare = 1 + loop1(2, "seven", [1], {number: 8}, 2); + } catch (e) { + // ignore exceptions. } - }; - - - // External invokation of a module. - ModuleRecord.prototype.invoke = function(MACHINE, succ, fail) { - MACHINE = MACHINE || plt.runtime.currentMachine; - succ = succ || function(){}; - fail = fail || function(){}; - - var oldErrorHandler = MACHINE.params['currentErrorHandler']; - var afterGoodInvoke = function(MACHINE) { - MACHINE.params['currentErrorHandler'] = oldErrorHandler; - setTimeout(succ, 0); - }; - - if (this.isInvoked) { - setTimeout(succ, 0); - } else { - MACHINE.params['currentErrorHandler'] = function(MACHINE, anError) { - MACHINE.params['currentErrorHandler'] = oldErrorHandler; - setTimeout( - function() { - fail(MACHINE, anError) - }, - 0); - }; - MACHINE.control.push(new CallFrame(afterGoodInvoke, null)); - trampoline(MACHINE, this.label); - } - }; - - - - - - - - - - - - // Function types: a function is either a Primitive or a Closure. - - // A Primitive is a function that's expected to return. It is not - // allowed to call into Closures. Its caller is expected to pop off - // its argument stack space. - // - // - - - // A Closure is a function that takes on more responsibilities: it is - // responsible for popping off stack space before it finishes, and it - // is also explicitly responsible for continuing the computation by - // popping off the control stack and doing the jump. Because of this, - // closures can do pretty much anything to the machine. - - // 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.arity = arity; // number - this.closedVals = closedVals; // arrayof number - this.displayName = displayName; // string - }; - - - - var VariableReference = function(prefix, pos) { - this.prefix = prefix; - this.pos = pos; - }; - - - - - - - // A continuation prompt tag labels a prompt frame. - var ContinuationPromptTag = function(name) { - this.name = name; - }; - - - - // There is a single, distinguished default continuation prompt tag - // that's used to wrap around toplevel prompts. - var DEFAULT_CONTINUATION_PROMPT_TAG = - new ContinuationPromptTag("default-continuation-prompt-tag"); - - - - var raise = plt.baselib.exceptions.raise; - - var raiseUnboundToplevelError = plt.baselib.exceptions.raiseUnboundToplevelError; - var raiseArgumentTypeError = plt.baselib.exceptions.raiseArgumentTypeError; - var raiseContextExpectedValuesError = plt.baselib.exceptions.raiseContextExpectedValuesError; - var raiseArityMismatchError = plt.baselib.exceptions.raiseArityMismatchError; - var raiseOperatorApplicationError = plt.baselib.exceptions.raiseOperatorApplicationError; - var raiseOperatorIsNotPrimitiveProcedure = plt.baselib.exceptions.raiseOperatorIsNotPrimitiveProcedure; - var raiseOperatorIsNotClosure = plt.baselib.exceptions.raiseOperatorIsNotClosure; - var raiseUnimplementedPrimitiveError = plt.baselib.exceptions.raiseUnimplementedPrimitiveError; - - - var testArgument = plt.baselib.check.testArgument; - var makeCheckArgumentType = plt.baselib.check.makeCheckArgumentType; - - - - - - var testArity = function(callerName, observed, minimum, maximum) { - if (observed < minimum || observed > maximum) { - raise(MACHINE, new Error(callerName + ": expected at least " + minimum - + " arguments " - + " but received " + observed)); - + if (! limitDiscovered) { + limitDiscovered = true; + after(n); } }; - - + // Schedule a stack limit estimation. If it fails, no harm, no + // foul (hopefully!) + setTimeout(function() { + findStackLimit(function(v) { + // Trying to be a little conservative. + STACK_LIMIT_ESTIMATE = Math.floor(v / 10); + }); + }, + 0); // captureControl implements the continuation-capturing part of @@ -407,6 +279,7 @@ if(this['plt'] === undefined) { this['plt'] = {}; } }; + // Unsplices a list from the MACHINE stack. var unspliceRestFromStack = function(MACHINE, depth, length) { var lst = NULL; var i; @@ -426,30 +299,57 @@ if(this['plt'] === undefined) { this['plt'] = {}; } - // Helper to deal with the argument-passing of primitives. Call f - // with arguments bound from MACHINE.env, assuming - // MACHINE.argcount has been initialized with the number of - // arguments on the stack. vs provides optional values for the - // arguments that go beyond those of the mandatoryArgCount. - var withArguments = function(MACHINE, - mandatoryArgCount, - vs, - f) { - var args = []; - for (var i = 0; i < MACHINE.argcount; i++) { - if (i < mandatoryArgCount) { - args.push(MACHINE.env[MACHINE.env.length - 1 - i]); - } else { - if (i < MACHINE.argcount) { - args.push(MACHINE.env[MACHINE.env.length - 1 - i]); - } else { - args.push(vs[mandatoryArgCount - i]); - } + + var defaultCurrentPrint = new Closure( + function(MACHINE) { + if(--MACHINE.callsBeforeTrampoline < 0) { + throw arguments.callee; } - } - return f.apply(null, args); + var elt = MACHINE.env[MACHINE.env.length - 1]; + var outputPort = + MACHINE.params.currentOutputPort; + if (elt !== VOID) { + outputPort.writeDomNode(MACHINE, toDomNode(elt, 'print')); + outputPort.writeDomNode(MACHINE, toDomNode("\n", 'display')); + } + return finalizeClosureCall(MACHINE, VOID); + }, + 1, + [], + "printer"); + + + + + + + + + + + + + var VariableReference = function(prefix, pos) { + this.prefix = prefix; + this.pos = pos; }; - + + + + // A continuation prompt tag labels a prompt frame. + var ContinuationPromptTag = function(name) { + this.name = name; + }; + + + + // There is a single, distinguished default continuation prompt tag + // that's used to wrap around toplevel prompts. + var DEFAULT_CONTINUATION_PROMPT_TAG = + new ContinuationPromptTag("default-continuation-prompt-tag"); + + + @@ -473,12 +373,6 @@ if(this['plt'] === undefined) { this['plt'] = {}; } }; - var makePrimitiveProcedure = function(name, arity, f) { - f.arity = arity; - f.displayName = name; - return f; - }; - var installPrimitiveConstant = function(name, v) { Primitives[name] = v; }; @@ -2324,62 +2218,15 @@ if(this['plt'] === undefined) { this['plt'] = {}; } - // Approximately find the stack limit. - // This function assumes, on average, five variables or - // temporaries per stack frame. - // This will never report a number greater than MAXIMUM_CAP. - var findStackLimit = function(after) { - var MAXIMUM_CAP = 100000; - var n = 1; - var limitDiscovered = false; - setTimeout( - function() { - if(! limitDiscovered) { - limitDiscovered = true; - after(n); - } - }, - 0); - var loop1 = function(x, y, z, w, k) { - // Ensure termination, just in case JavaScript ever - // does eliminate stack limits. - if (n >= MAXIMUM_CAP) { return; } - n++; - return 1 + loop2(y, z, w, k, x); - }; - var loop2 = function(x, y, z, w, k) { - n++; - return 1 + loop1(y, z, w, k, x); - }; - try { - var dontCare = 1 + loop1(2, "seven", [1], {number: 8}, 2); - } catch (e) { - // ignore exceptions. - } - if (! limitDiscovered) { - limitDiscovered = true; - after(n); - } - }; - - - // Schedule a stack limit estimation. If it fails, no harm, no - // foul (hopefully!) - setTimeout(function() { - findStackLimit(function(v) { - // Trying to be a little conservative. - STACK_LIMIT_ESTIMATE = Math.floor(v / 10); - }); - }, - 0); - - ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// + // Implementation of the ready function. This will fire off when + // setReadyTrue is called. + (function(scope) { scope.ready = function(f) { if (runtimeIsReady) { @@ -2404,6 +2251,7 @@ if(this['plt'] === undefined) { this['plt'] = {}; } }; })(this); + ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// diff --git a/tests/browser-harness.rkt b/tests/browser-harness.rkt index 87fd5e1..d50332e 100644 --- a/tests/browser-harness.rkt +++ b/tests/browser-harness.rkt @@ -83,6 +83,7 @@ EOF (quasisyntax/loc #'stx (begin (printf "running test on ~s..." original-source-file-path) + (flush-output (current-output-port)) (let* ([src-path source-file-path] [result (evaluate (make-MainModuleSource (make-ModuleSource src-path)))] [output (evaluated-stdout result)]) diff --git a/tests/more-tests/images.rkt b/tests/more-tests/images.rkt index 99edd27..f3a5aac 100644 --- a/tests/more-tests/images.rkt +++ b/tests/more-tests/images.rkt @@ -1,9 +1,9 @@ #lang planet dyoo/whalesong (require (planet dyoo/whalesong/image)) -(is-color? "red") -(is-color? "blue") -(is-color? 42) +(image-color? "red") +(image-color? "blue") +(image-color? 42) -(is-color? (make-color 3 4 5 0)) -(is-color? "color") +(image-color? (make-color 3 4 5 0)) +(image-color? "color")