From 03165a41912aee11c5f82d822e347fcf9f674370 Mon Sep 17 00:00:00 2001 From: Danny Yoo Date: Thu, 14 Jul 2011 18:26:56 -0400 Subject: [PATCH] installing on-tick --- examples/counting-world-program.rkt | 4 +- .../runtime-src/baselib-exceptions.js | 45 ++++-- world/js-impl.js | 110 +++++++++++++ world/kernel.js | 150 ++++++++++++++++-- world/main.rkt | 4 +- 5 files changed, 283 insertions(+), 30 deletions(-) diff --git a/examples/counting-world-program.rkt b/examples/counting-world-program.rkt index 0c00577..38c595f 100644 --- a/examples/counting-world-program.rkt +++ b/examples/counting-world-program.rkt @@ -4,4 +4,6 @@ (circle 20 'solid 'blue) -;(big-bang 0 (on-tick add1 1)) \ No newline at end of file +(big-bang 0 (on-tick add1 1)) + +"all done" \ No newline at end of file diff --git a/js-assembler/runtime-src/baselib-exceptions.js b/js-assembler/runtime-src/baselib-exceptions.js index fbd00f5..f378886 100644 --- a/js-assembler/runtime-src/baselib-exceptions.js +++ b/js-assembler/runtime-src/baselib-exceptions.js @@ -85,7 +85,11 @@ var raiseUnboundToplevelError = function(MACHINE, name) { - raise(MACHINE, new Error("Not bound: " + name)); + raise(MACHINE, + new Error( + plt.baselib.format.foramt( + "Not bound: ~a", + [name]))); }; @@ -95,37 +99,54 @@ argumentOffset, actualValue) { raise(MACHINE, - new Error(callerName + ": expected " + expectedTypeName - + " as argument " + (argumentOffset + 1) - + " but received " + plt.baselib.format.toWrittenString(actualValue))); + new Error( + plt.baselib.format.format( + "~a: expected ~e as argument ~e but received ~e", + [callerName, + expectedTypeName, + (argumentOffset + 1), + actualValue]))); }; var raiseContextExpectedValuesError = function(MACHINE, expected) { raise(MACHINE, - new Error("expected " + expected + - " values, received " + - MACHINE.argcount + " values")); + new Error(plt.baselib.format.format( + "expected ~e values, received ~e values" + [expected, + MACHINE.argcount]))); }; var raiseArityMismatchError = function(MACHINE, proc, expected, received) { raise(MACHINE, - new Error(proc.displayName + ": " + "expected " + expected - + " value(s), received " + received + " value(s)")); + new Error(plt.baselib.format.format( + "~a: expected ~e value(s), received ~e value(s)", + [proc.displayName, + expected , + received]))) }; var raiseOperatorApplicationError = function(MACHINE, operator) { raise(MACHINE, - new Error("not a procedure: " + plt.baselib.format.toWrittenString(operator))); + new Error( + plt.baselib.format.format( + "not a procedure: ~e", + [operator]))); }; var raiseOperatorIsNotClosure = function(MACHINE, operator) { raise(MACHINE, - new Error("not a closure: " + plt.baselib.format.toWrittenString(operator))); + new Error( + plt.baselib.format.format( + "not a closure: ~e", + [operator]))); }; var raiseOperatorIsNotPrimitiveProcedure = function(MACHINE, operator) { raise(MACHINE, - new Error("not a primitive procedure: " + plt.baselib.format.toWrittenString(operator))); + new Error( + plt.baselib.format.format( + "not a primitive procedure: ~e", + [operator]))); }; diff --git a/world/js-impl.js b/world/js-impl.js index e69de29..609df98 100644 --- a/world/js-impl.js +++ b/world/js-impl.js @@ -0,0 +1,110 @@ +var PAUSE = plt.runtime.PAUSE; +var makeClosure = plt.baselib.functions.makeClosure; +var makeRational = plt.baselib.numbers.makeRational; +var finalizeClosureCall = plt.baselib.functions.finalizeClosureCall; +var makePrimitiveProcedure = plt.baselib.functions.makePrimitiveProcedure; + + + +var checkProcedure = plt.baselib.check.checkProcedure; +var checkNonNegativeReal = plt.baselib.check.checkNonNegativeReal; + + +// The default tick delay is 28 times a second. +var DEFAULT_TICK_DELAY = makeRational(1, 28); + + + +EXPORTS['big-bang'] = + makeClosure( + 'big-bang', + plt.baselib.arity.makeArityAtLeast(1), + function(MACHINE) { + var initialWorldValue = MACHINE.env[MACHINE.env.length - 1]; + var handlers = []; + for (var i = 1; i < MACHINE.argcount; i++) { + // FIXME: typecheck for configuration options + handlers.push(MACHINE.env[MACHINE.env.length - 1 - i]); + } + bigBang(initialWorldValue, handlers); + }); + + + +EXPORTS['on-tick'] = + makePrimitiveProcedure( + 'on-tick', + plt.baselib.lists.makeList(1, 2), + function(MACHINE) { + if (MACHINE.argcount === 1) { + var f = checkProcedure(MACHINE, "on-tick", 0); + return new OnTick(f, DEFAULT_TICK_DELAY); + } else if (MACHINE.argcount === 2) { + var f = checkProcedure(MACHINE, "on-tick", 0); + var delay = checkNonNegativeReal(MACHINE, "on-tick", 1); + return new OnTick(f, delay); + } + }); + + + + + + + + + + + + + + + + + +// EXPORTS['on-tick'] = +// new CasePrimitive( +// 'on-tick', +// [new PrimProc('on-tick', +// 1, +// false, false, +// function(f) { +// check(f, isFunction, "on-tick", "procedure", 1); +// return new OnTickBang(f, +// new PrimProc('', 1, false, false, +// function(w) { return types.effectDoNothing(); }), +// DEFAULT_TICK_DELAY); +// }), +// new PrimProc('on-tick', +// 2, +// false, false, +// function(f, aDelay) { +// check(f, isFunction, "on-tick", "procedure", 1, arguments); +// check(aDelay, isNumber, "on-tick", "number", 2, arguments); +// return new OnTickBang(f, +// new PrimProc('', 1, false, false, +// function(w) { return types.effectDoNothing(); }), +// aDelay); +// }) ]); + + + +// EXPORTS['on-tick!'] = +// new CasePrimitive('on-tick!', +// [new PrimProc('on-tick!', +// 2, +// false, false, +// function(handler, effectHandler) { +// check(handler, isFunction, "on-tick!", "procedure", 1, arguments); +// check(effectHandler, isFunction, "on-tick!","procedure", 2, arguments); +// return new OnTickBang(handler, effectHandler, DEFAULT_TICK_DELAY); +// }), +// new PrimProc('on-tick!', +// 3, +// false, false, +// function(handler, effectHandler, aDelay) { +// check(handler, isFunction, "on-tick!", "procedure", 1, arguments); +// check(effectHandler, isFunction, "on-tick!","procedure", 2, arguments); +// check(aDelay, isNumber, "on-tick!", "number", 3, arguments); +// return new OnTickBang(handler, effectHandler, aDelay); +// }) ]); diff --git a/world/kernel.js b/world/kernel.js index 56ee957..ef8f4db 100644 --- a/world/kernel.js +++ b/world/kernel.js @@ -1,26 +1,146 @@ var PAUSE = plt.runtime.PAUSE; +var EMPTY = plt.baselib.lists.EMPTY; +var isString = plt.baselib.strings.isString; +var isBoolean = function(x) { return x === true || x === false; } +var isSymbol = plt.baselib.symbols.isSymbol; +var makePair = plt.baselib.lists.makePair; +var makeList = plt.baselib.lists.makeList; +var makeRational = plt.baselib.numbers.makeRational; +var finalizeClosureCall = plt.baselib.functions.finalizeClosureCall; + + + + + +////////////////////////////////////////////////////////////////////// + var bigBang = function(MACHINE, initW, handlers) { PAUSE(function(restart) { - var bigBangController; - var onBreak = function() { - bigBangController.breaker(); - } - state.addBreakRequestedListener(onBreak); - bigBangController = rawJsworld.bigBang( - initW, - state.getToplevelNodeHook()(), - unwrappedConfigs, - caller, - function(v) { - state.removeBreakRequestedListener(onBreak); - restarter(v); - }, - onFail); + + var finalWorldValue = "not done yet"; + // Once we finally get a value back, we can call + // restart at this point and finish the call to + // big-bang. + restart(function(MACHINE) { + finalizeClosureCall( + MACHINE, + finalWorldValue); + }); + + + + // var onBreak = function() { + // bigBangController.breaker(); + // } + // state.addBreakRequestedListener(onBreak); + // var bigBangController = rawJsworld.bigBang( + // initW, + // state.getToplevelNodeHook()(), + // unwrappedConfigs, + // caller, + // function(v) { + // state.removeBreakRequestedListener(onBreak); + // restarter(v); + // }, + // onFail); + }); }; + +////////////////////////////////////////////////////////////////////// + +// Every world configuration function (on-tick, stop-when, ...) +// produces a WorldConfigOption instance. +var WorldConfigOption = function(name) { + this.name = name; +}; + +WorldConfigOption.prototype.configure = function(config) { + throw new Error('unimplemented WorldConfigOption'); +}; + + +WorldConfigOption.prototype.toDomNode = function(cache) { + var span = document.createElement('span'); + span.appendChild(document.createTextNode("(" + this.name + " ...)")); + return span; +}; + +WorldConfigOption.prototype.toWrittenString = function(cache) { + return "(" + this.name + " ...)"; +}; + +WorldConfigOption.prototype.toDisplayedString = function(cache) { + return "(" + this.name + " ...)"; +}; + +var isWorldConfigOption = function(x) { return x instanceof WorldConfigOption; }; + +////////////////////////////////////////////////////////////////////// + + +var convertAttribList = function(attribList) { + var nextElt; + var key, val; + var hash = {}; + while (attribList !== EMPTY) { + nextElt = attribList.first; + + key = nextElt.first; + val = nextElt.rest.first; + + key = String(key); + + if (isString(val)) { + val = String(val); + } else if (isBoolean(val)) { + // do nothing: the representation is the same. + } else if (isSymbol(val)) { + if (String(val) === 'true') { + val = true; + } else if (String(val) === 'false') { + val = false; + } else { + val = String(val); + } + } else { + // raise error: neither string nor boolean + throw new Error( + plt.baselib.format.format( + "attribute value ~s neither a string nor a boolean", + [val])); + } + hash[key] = val; + attribList = attribList.rest; + } + return hash; +} + + + + +////////////////////////////////////////////////////////////////////// + + +var OnTick = function(handler, aDelay) { + WorldConfigOption.call(this, 'on-tick'); + this.handler = handler; + this.aDelay = aDelay; +}; + +OnTick.prototype = plt.baselib.heir(WorldConfigOption.prototype); + +OnTick.prototype.configure = function(config) { + return config.updateAll( + { onTick: this.handler, + tickDelay: jsnums.toFixnum(jsnums.multiply(1000, this.aDelay)) + } + ); +}; + diff --git a/world/main.rkt b/world/main.rkt index 6cc31d9..ffdb97c 100644 --- a/world/main.rkt +++ b/world/main.rkt @@ -8,8 +8,8 @@ "private/raw-jsworld.js" ;; We add Whalesong-specific things here. - ;;"kernel.js" - ;;"js-impl.js" + "kernel.js" + "js-impl.js" ) #:provided-values (big-bang on-tick)) \ No newline at end of file