whalesong/runtime.js
2011-03-10 15:11:08 -05:00

221 lines
5.6 KiB
JavaScript

// 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 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;
}
};
})();
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;
};
// // 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();
};