// Type representations: // // number are numbers // // cons pairs are [first, rest] // // function closures are Closures // primitive procedures are regular functions. // No error trapping at the moment. var Frame = function(label, proc) { this.label = label; this.proc = proc; }; // 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; this.arity = arity; this.closedVals = closedVals; this.displayName = displayName; }; var Primitives = (function() { var NULL = []; return { 'display': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; MACHINE.params.currentDisplayer(firstArg); }, 'newline': function(arity, returnLabel) { MACHINE.params.currentDisplayer("\n"); }, 'displayln': function(arity, returnLabel){ var firstArg = MACHINE.env[MACHINE.env.length-1]; MACHINE.params.currentDisplayer(firstArg); MACHINE.params.currentDisplayer("\n"); }, 'pi' : Math.PI, 'e' : Math.E, '=': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; var secondArg = MACHINE.env[MACHINE.env.length-2]; return firstArg === secondArg; }, '<': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; var secondArg = MACHINE.env[MACHINE.env.length-2]; return firstArg < secondArg; }, '>': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; var secondArg = MACHINE.env[MACHINE.env.length-2]; return firstArg > secondArg; }, '<=': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; var secondArg = MACHINE.env[MACHINE.env.length-2]; return firstArg <= secondArg; }, '>=': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; var secondArg = MACHINE.env[MACHINE.env.length-2]; return firstArg >= secondArg; }, '+': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; var secondArg = MACHINE.env[MACHINE.env.length-2]; return firstArg + secondArg; }, '*': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; var secondArg = MACHINE.env[MACHINE.env.length-2]; return firstArg * secondArg; }, '-': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; var secondArg = MACHINE.env[MACHINE.env.length-2]; return firstArg - secondArg; }, '/': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; var secondArg = MACHINE.env[MACHINE.env.length-2]; return firstArg / secondArg; }, 'cons': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; var secondArg = MACHINE.env[MACHINE.env.length-2]; return [firstArg, secondArg]; }, 'list': function(arity, returnLabel) { var result = NULL; for (var i = 0; i < arity; i++) { result = [MACHINE.env[MACHINE.env.length - (arity - i)], result]; } return result; }, 'car': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; return firstArg[0]; }, 'cdr': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; return firstArg[1]; }, 'null' : NULL, 'null?': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; return firstArg === NULL; }, 'add1': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; return firstArg + 1; }, 'sub1': function(arity, returnLabel) { var firstArg = MACHINE.env[MACHINE.env.length-1]; return firstArg - 1; } , 'call/cc': new Closure(callCCEntry, 1, [], "call/cc") }; })(); // // adaptToJs: closure -> (array (X -> void) -> void) // // Converts closures to functions that can be called from the // // JavaScript toplevel. // Closure.prototype.adaptToJs = function() { // var that = this; // return function(args, success, fail) { // var oldEnv = MACHINE.env; // var oldCont = MACHINE.cont; // var oldProc = MACHINE.proc; // var oldArgl = MACHINE.argl; // var oldVal = MACHINE.val; // trampoline( // function() { // var proc = that; // MACHINE.proc = proc; // MACHINE.argl = undefined; // for(var i = args.length - 1; i >= 0; i--) { // MACHINE.argl = [args[i], MACHINE.argl]; // } // MACHINE.cont = function() { // var result = MACHINE.val; // MACHINE.env = oldEnv; // MACHINE.cont = oldCont; // MACHINE.proc = oldProc; // MACHINE.argl = oldArgl; // MACHINE.val = oldVal; // success(result); // }; // proc.label(); // }, // function() { // }, // function(e) { // return fail(e); // }); // } // }; var MACHINE={callsBeforeTrampoline: 100, val:undefined, proc:undefined, env: [], control : [], params: { currentDisplayer: function(v) {}, currentErrorHandler: function(e) {}, currentNamespace: {}}}; var trampoline = function(initialJump, success, fail) { var thunk = initialJump; MACHINE.callsBeforeTrampoline = 100; while(thunk) { try { thunk(); break; } catch (e) { if (typeof(e) === 'function') { thunk = e; MACHINE.callsBeforeTrampoline = 100; } else { return fail(e); } } } return success(); };