more cleanup

This commit is contained in:
Danny Yoo 2011-04-02 18:36:08 -04:00
parent 13484d7cca
commit 6e920dd7ca
2 changed files with 471 additions and 326 deletions

8
NOTES
View File

@ -63,3 +63,11 @@ primitive as well as:
}; };
Is this completely unrealistic? I have to see how Rabbit and Orbit do this. Is this completely unrealistic? I have to see how Rabbit and Orbit do this.
----------------------------------------------------------------------
Runtime values and types are in in the plt.runtime namespace. I need
to move types from WeScheme into here.

View File

@ -1,6 +1,6 @@
if(this['plt'] === undefined) { if(this['plt'] === undefined) {
this['plt'] = {}; this['plt'] = {};
} }
// All of the values here are namespaced under "plt.runtime". // All of the values here are namespaced under "plt.runtime".
@ -10,6 +10,29 @@ if(this['plt'] === undefined) {
var exports = this['plt']['runtime']; var exports = this['plt']['runtime'];
// Type helpers
//
// Defines inheritance between prototypes.
var heir = function(parentPrototype) {
var f = function() {}
f.prototype = parentPrototype;
return new f();
};
// Consumes a class and creates a predicate that recognizes subclasses.
var makeClassPredicate = function(aClass) {
return function(x) { return x instanceof aClass; };
};
var isNumber = function(x) { return typeof(x) === 'number'; };
var isPair = function(x) { return (typeof(x) == 'object' &&
x.length === 2) }
var isVector = function(x) { return (typeof(x) == 'object' &&
x.length !== undefined) }
var Machine = function() { var Machine = function() {
this.callsBeforeTrampoline = 100; this.callsBeforeTrampoline = 100;
this.val = undefined; this.val = undefined;
@ -19,6 +42,7 @@ if(this['plt'] === undefined) {
this.running = false; this.running = false;
this.params = { currentDisplayer: function(v) {}, this.params = { currentDisplayer: function(v) {},
currentOutputPort: new StandardOutputPort(),
currentSuccessHandler: function(MACHINE) {}, currentSuccessHandler: function(MACHINE) {},
currentErrorHandler: function(MACHINE, exn) {}, currentErrorHandler: function(MACHINE, exn) {},
@ -43,6 +67,8 @@ if(this['plt'] === undefined) {
}; };
var Frame = function() {};
// Control stack elements: // Control stack elements:
// A CallFrame represents a call stack frame. // A CallFrame represents a call stack frame.
@ -50,12 +76,45 @@ if(this['plt'] === undefined) {
this.label = label; this.label = label;
this.proc = proc; this.proc = proc;
}; };
CallFrame.prototype = heir(Frame.prototype);
// PromptFrame represents a prompt frame. // PromptFrame represents a prompt frame.
var PromptFrame = function(label, tag) { var PromptFrame = function(label, tag) {
this.label = label; this.label = label;
this.tag = tag; // ContinuationPromptTag this.tag = tag; // ContinuationPromptTag
}; };
PromptFrame.prototype = heir(Frame.prototype);
var OutputPort = function() {};
var isOutputPort = makeClassPredicate(OutputPort);
var StandardOutputPort = function() {};
StandardOutputPort.prototype = heir(OutputPort.prototype);
StandardOutputPort.prototype.write = function(MACHINE, v) {
MACHINE.params.currentDisplayer(v);
};
var OutputStringPort = function() {
this.buf = [];
};
OutputStringPort.prototype = heir(OutputPort.prototype);
OutputStringPort.prototype.write = function(MACHINE, v) {
this.buf.push(String(v));
};
OutputStringPort.prototype.getOutputString = function() {
return this.buf.join('');
};
var isOutputStringPort = makeClassPredicate(OutputStringPort);
@ -86,6 +145,11 @@ if(this['plt'] === undefined) {
// A continuation prompt tag labels a prompt frame. // A continuation prompt tag labels a prompt frame.
var ContinuationPromptTag = function(name) { var ContinuationPromptTag = function(name) {
this.name = name; this.name = name;
@ -102,8 +166,6 @@ if(this['plt'] === undefined) {
var NULL = []; var NULL = [];
var raise = function(e) { throw e; } var raise = function(e) { throw e; }
@ -126,6 +188,15 @@ if(this['plt'] === undefined) {
} }
}; };
var testArity = function(callerName, observed, minimum, maximum) {
if (observed < minimum || observed > maximum) {
raise(new Error(callerName + ": expected at least " + minimum
+ " arguments "
+ " but received " + observer));
}
};
// captureControl implements the continuation-capturing part of // captureControl implements the continuation-capturing part of
@ -165,7 +236,6 @@ if(this['plt'] === undefined) {
var isNumber = function(x) { return typeof(x) === 'number'; };
@ -173,68 +243,82 @@ if(this['plt'] === undefined) {
// Primtitives are the set of primitive values. Not all primitives // Primtitives are the set of primitive values. Not all primitives
// are coded here; several of them (including call/cc) are injected by // are coded here; several of them (including call/cc) are injected by
// the bootstrapping code. // the bootstrapping code.
var Primitives = (function() { var Primitives = {};
return { Primitives['display'] = function(MACHINE, arity) {
'display': function(MACHINE, arity) { testArity('display', arity, 1, 2);
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
MACHINE.params.currentDisplayer(firstArg); var outputPort = MACHINE.params.currentOutputPort;
}, if (arity == 2) {
outputPort = MACHINE.env[MACHINE.env.length-2];
}
outputPort.write(MACHINE, firstArg);
};
'newline': function(MACHINE, arity) { Primitives['newline'] = function(MACHINE, arity) {
MACHINE.params.currentDisplayer("\n"); testArity('newline', arity, 0, 1);
}, var outputPort = MACHINE.params.currentOutputPort;
if (arity == 1) {
outputPort = MACHINE.env[MACHINE.env.length-1];
}
outputPort.write(MACHINE, "\n");
};
'displayln': function(MACHINE, arity){ Primitives['displayln'] = function(MACHINE, arity){
testArity('displayln', arity, 1, 2);
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
MACHINE.params.currentDisplayer(firstArg); var outputPort = MACHINE.params.currentOutputPort;
MACHINE.params.currentDisplayer("\n"); if (arity == 2) {
}, outputPort = MACHINE.env[MACHINE.env.length-2];
}
outputPort.write(MACHINE, firstArg);
outputPort.write(MACHINE, "\n");
};
'pi' : Math.PI, Primitives['pi'] = Math.PI;
'e' : Math.E, Primitives['e'] = Math.E;
'=': function(MACHINE, arity) { Primitives['='] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
testArgument('number', isNumber, firstArg, 0, '='); testArgument('number', isNumber, firstArg, 0, '=');
testArgument('number', isNumber, secondArg, 1, '='); testArgument('number', isNumber, secondArg, 1, '=');
return firstArg === secondArg; return firstArg === secondArg;
}, };
'<': function(MACHINE, arity) { Primitives['<'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
testArgument('number', isNumber, firstArg, 0, '<'); testArgument('number', isNumber, firstArg, 0, '<');
testArgument('number', isNumber, secondArg, 1, '<'); testArgument('number', isNumber, secondArg, 1, '<');
return firstArg < secondArg; return firstArg < secondArg;
}, };
'>': function(MACHINE, arity) { Primitives['>'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
testArgument('number', isNumber, firstArg, 0, '>'); testArgument('number', isNumber, firstArg, 0, '>');
testArgument('number', isNumber, secondArg, 1, '>'); testArgument('number', isNumber, secondArg, 1, '>');
return firstArg > secondArg; return firstArg > secondArg;
}, };
'<=': function(MACHINE, arity) { Primitives['<='] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
testArgument('number', isNumber, firstArg, 0, '<='); testArgument('number', isNumber, firstArg, 0, '<=');
testArgument('number', isNumber, secondArg, 1, '<='); testArgument('number', isNumber, secondArg, 1, '<=');
return firstArg <= secondArg; return firstArg <= secondArg;
}, };
'>=': function(MACHINE, arity) { Primitives['>='] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
testArgument('number', isNumber, firstArg, 0, '>='); testArgument('number', isNumber, firstArg, 0, '>=');
testArgument('number', isNumber, secondArg, 1, '>='); testArgument('number', isNumber, secondArg, 1, '>=');
return firstArg >= secondArg; return firstArg >= secondArg;
}, };
'+': function(MACHINE, arity) { Primitives['+'] = function(MACHINE, arity) {
var result = 0; var result = 0;
var i = 0; var i = 0;
for (i=0; i < arity; i++) { for (i=0; i < arity; i++) {
@ -247,9 +331,9 @@ if(this['plt'] === undefined) {
result += MACHINE.env[MACHINE.env.length - 1 - i]; result += MACHINE.env[MACHINE.env.length - 1 - i];
}; };
return result; return result;
}, };
'*': function(MACHINE, arity) { Primitives['*'] = function(MACHINE, arity) {
var result = 1; var result = 1;
var i = 0; var i = 0;
for (i=0; i < arity; i++) { for (i=0; i < arity; i++) {
@ -262,9 +346,9 @@ if(this['plt'] === undefined) {
result *= MACHINE.env[MACHINE.env.length - 1 - i]; result *= MACHINE.env[MACHINE.env.length - 1 - i];
} }
return result; return result;
}, };
'-': function(MACHINE, arity) { Primitives['-'] = function(MACHINE, arity) {
if (arity === 0) { raise(new Error()); } if (arity === 0) { raise(new Error()); }
if (arity === 1) { if (arity === 1) {
testArgument('number', testArgument('number',
@ -284,9 +368,9 @@ if(this['plt'] === undefined) {
result -= MACHINE.env[MACHINE.env.length - 1 - i]; result -= MACHINE.env[MACHINE.env.length - 1 - i];
} }
return result; return result;
}, };
'/': function(MACHINE, arity) { Primitives['/'] = function(MACHINE, arity) {
if (arity === 0) { raise(new Error()); } if (arity === 0) { raise(new Error()); }
testArgument('number', testArgument('number',
isNumber, isNumber,
@ -298,88 +382,122 @@ if(this['plt'] === undefined) {
result /= MACHINE.env[MACHINE.env.length - 1 - i]; result /= MACHINE.env[MACHINE.env.length - 1 - i];
} }
return result; return result;
}, };
'cons': function(MACHINE, arity) { Primitives['cons'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
return [firstArg, secondArg]; return [firstArg, secondArg];
}, };
'list': function(MACHINE, arity) { Primitives['list'] = function(MACHINE, arity) {
var result = NULL; var result = NULL;
for (var i = 0; i < arity; i++) { for (var i = 0; i < arity; i++) {
result = [MACHINE.env[MACHINE.env.length - (arity - i)], result = [MACHINE.env[MACHINE.env.length - (arity - i)],
result]; result];
} }
return result; return result;
}, };
'car': function(MACHINE, arity) { Primitives['car'] = function(MACHINE, arity) {
testArgument('pair',
isPair,
MACHINE.env[MACHINE.env.length - 1],
0,
'car');
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg[0]; return firstArg[0];
}, };
'cdr': function(MACHINE, arity) { Primitives['cdr'] = function(MACHINE, arity) {
testArgument('pair',
isPair,
MACHINE.env[MACHINE.env.length - 1],
0,
'cdr');
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg[1]; return firstArg[1];
}, };
'pair?': function(MACHINE, arity) { Primitives['pair?'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return (typeof(firstArg) == 'object' && return isPair(firstArg);
firstArg.length === 2); };
},
'set-car!': function(MACHINE, arity) { Primitives['set-car!'] = function(MACHINE, arity) {
testArgument('pair',
isPair,
MACHINE.env[MACHINE.env.length - 1],
0,
'set-car!');
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
firstArg[0] = secondArg; firstArg[0] = secondArg;
}, };
'set-cdr!': function(MACHINE, arity) { Primitives['set-cdr!'] = function(MACHINE, arity) {
testArgument('pair',
isPair,
MACHINE.env[MACHINE.env.length - 1],
0,
'set-cdr!');
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
firstArg[1] = secondArg; firstArg[1] = secondArg;
}, };
'not': function(MACHINE, arity) { Primitives['not'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return (!firstArg); return (!firstArg);
}, };
'null' : NULL, Primitives['null'] = NULL;
'null?': function(MACHINE, arity) { Primitives['null?'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg === NULL; return firstArg === NULL;
}, };
'add1': function(MACHINE, arity) { Primitives['add1'] = function(MACHINE, arity) {
testArgument('number',
isNumber,
MACHINE.env[MACHINE.env.length - 1],
0,
'add1');
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg + 1; return firstArg + 1;
}, };
'sub1': function(MACHINE, arity) { Primitives['sub1'] = function(MACHINE, arity) {
testArgument('number',
isNumber,
MACHINE.env[MACHINE.env.length - 1],
0,
'sub1');
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg - 1; return firstArg - 1;
}, };
'zero?': function(MACHINE, arity) { Primitives['zero?'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg === 0; return firstArg === 0;
}, };
'vector': function(MACHINE, arity) { Primitives['vector'] = function(MACHINE, arity) {
var i; var i;
var result = []; var result = [];
for (i = 0; i < arity; i++) { for (i = 0; i < arity; i++) {
result.push(MACHINE.env[MACHINE.env.length-1-i]); result.push(MACHINE.env[MACHINE.env.length-1-i]);
} }
return result; return result;
}, };
'vector->list': function(MACHINE, arity) { Primitives['vector->list'] = function(MACHINE, arity) {
testArgument('vector',
isVector,
MACHINE.env[MACHINE.env.length - 1],
0,
'vector->list');
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var i; var i;
var result = NULL; var result = NULL;
@ -387,9 +505,9 @@ if(this['plt'] === undefined) {
result = [firstArg[firstArg.length - 1 - i], result]; result = [firstArg[firstArg.length - 1 - i], result];
} }
return result; return result;
}, };
'list->vector': function(MACHINE, arity) { Primitives['list->vector'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var result = []; var result = [];
while (firstArg !== NULL) { while (firstArg !== NULL) {
@ -397,76 +515,85 @@ if(this['plt'] === undefined) {
firstArg = firstArg[1]; firstArg = firstArg[1];
} }
return result; return result;
}, };
'vector-ref': function(MACHINE, arity) { Primitives['vector-ref'] = function(MACHINE, arity) {
testArgument('vector',
isVector,
MACHINE.env[MACHINE.env.length - 1],
0,
'vector-ref');
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
return firstArg[secondArg]; return firstArg[secondArg];
}, };
'vector-set!': function(MACHINE, arity) { Primitives['vector-set!'] = function(MACHINE, arity) {
testArgument('vector',
isVector,
MACHINE.env[MACHINE.env.length - 1],
0,
'vector-set!');
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
var thirdArg = MACHINE.env[MACHINE.env.length-3]; var thirdArg = MACHINE.env[MACHINE.env.length-3];
firstArg[secondArg] = thirdArg; firstArg[secondArg] = thirdArg;
return null; return null;
}, };
'symbol?': function(MACHINE, arity) { Primitives['symbol?'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return typeof(firstArg) === 'string'; return typeof(firstArg) === 'string';
}, };
'symbol->string': function(MACHINE, arity) { Primitives['symbol->string'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg; return firstArg;
}, };
'string-append': function(MACHINE, arity) { Primitives['string-append'] = function(MACHINE, arity) {
var buffer = []; var buffer = [];
var i; var i;
for (i = 0; i < arity; i++) { for (i = 0; i < arity; i++) {
buffer.push(MACHINE.env[MACHINE.env.length - 1 - i]); buffer.push(MACHINE.env[MACHINE.env.length - 1 - i]);
} }
return buffer.join(''); return buffer.join('');
}, };
'string-length': function(MACHINE, arity) { Primitives['string-length'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg.length; return firstArg.length;
}, };
'box': function(MACHINE, arity) { Primitives['box'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var result = [firstArg]; var result = [firstArg];
return result; return result;
}, };
'unbox': function(MACHINE, arity) { Primitives['unbox'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg[0]; return firstArg[0];
}, };
'set-box!': function(MACHINE, arity) { Primitives['set-box!'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
firstArg[0] = secondArg; firstArg[0] = secondArg;
return; return;
}, };
'void': function(MACHINE, arity) { Primitives['void'] = function(MACHINE, arity) {
return; return;
}, };
Primitives['eq?'] = function(MACHINE, arity) {
'eq?': function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
return firstArg === secondArg; return firstArg === secondArg;
}, };
'equal?': function(MACHINE, arity) { Primitives['equal?'] = function(MACHINE, arity) {
var firstArg = MACHINE.env[MACHINE.env.length-1]; var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2]; var secondArg = MACHINE.env[MACHINE.env.length-2];
var lset = [firstArg], rset = [secondArg]; var lset = [firstArg], rset = [secondArg];
@ -487,10 +614,7 @@ if(this['plt'] === undefined) {
} }
} }
return true; return true;
}
}; };
})();
@ -554,18 +678,31 @@ if(this['plt'] === undefined) {
// Exports // Exports
exports.Machine = Machine; exports['Machine'] = Machine;
exports.CallFrame = CallFrame; exports['CallFrame'] = CallFrame;
exports.PromptFrame = PromptFrame; exports['PromptFrame'] = PromptFrame;
exports.Closure = Closure; exports['Closure'] = Closure;
exports.ContinuationPromptTag = ContinuationPromptTag; exports['ContinuationPromptTag'] = ContinuationPromptTag;
exports.DEFAULT_CONTINUATION_PROMPT_TAG = DEFAULT_CONTINUATION_PROMPT_TAG; exports['DEFAULT_CONTINUATION_PROMPT_TAG'] =
exports.testArgument = testArgument; DEFAULT_CONTINUATION_PROMPT_TAG;
exports.captureControl = captureControl; exports['NULL'] = NULL;
exports.restoreControl = restoreControl;
exports.isNumber = isNumber; exports['testArgument'] = testArgument;
exports.raise = raise; exports['testArity'] = testArity;
exports.NULL = NULL; exports['raise'] = raise;
exports.trampoline = trampoline;
exports['captureControl'] = captureControl;
exports['restoreControl'] = restoreControl;
exports['isNumber'] = isNumber;
exports['isPair'] = isPair;
exports['isVector'] = isVector;
exports['isOutputPort'] = isOutputPort;
exports['isOutputStringPort'] = isOutputStringPort;
exports['heir'] = heir;
exports['makeClassPredicate'] = makeClassPredicate;
exports['trampoline'] = trampoline;
}).call(this); }).call(this);