201 lines
5.1 KiB
JavaScript
201 lines
5.1 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;
|
|
},
|
|
|
|
'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();
|
|
};
|