@powerlang/egg-js
Version:
A Smalltalk VM that runs on top of JavaScript
523 lines (453 loc) • 11.2 kB
JavaScript
import EvaluationContext from './EvaluationContext.js';
let StackedEvaluationContext = class extends EvaluationContext {
constructor() {
super();
this._stack = nil;
this._regSP = nil;
this._regBP = nil;
this._regM = nil;
this._regS = nil;
this._regE = nil;
this._pc = nil;
}
argumentAt_(anInteger) {
return this.argumentAt_frameIndex_(anInteger, 1);
}
argumentAt_frame_(anInteger, bp) {
let code, count;
code = this._stack.at_((bp-2));
count = this._runtime.argumentCountOf_(code);
return this._stack.at_(((bp+1)+((count-anInteger)+1)));
}
argumentAt_frameIndex_(anInteger, anotherInteger) {
let bp;
bp = this.bpForFrameAt_(anotherInteger);
return this.argumentAt_frame_(anInteger, bp);
}
argumentAt_in_(index, environmentIndex) {
if (nil === environmentIndex)
{
return this.argumentAt_(index)
}
;
return this.environment_at_(environmentIndex, index);
}
arguments() {
let count;
count = this._runtime.argumentCountOf_(this._regM);
return count.to_by_(1, -1).collect_((i) => {
return this.argumentAt_(i)
});
}
backtrace() {
let result, bp, code, receiver, argcount, args, tempcount, temps, envcount, envtemps;
result = Array.new();
bp = this._regBP;
(() => {
return bp._notEqual(0)
}).whileTrue_(() => {
code = this._stack.at_((bp-2));
receiver = this._stack.at_((bp-1));
argcount = this._runtime.argumentCountOf_(code);
args = (1).to_(argcount).collect_((i) => {
return this.argumentAt_frame_(i, bp)
});
tempcount = this._runtime.temporaryCountOf_(code);
temps = (1).to_(tempcount).collect_((i) => {
return this.stackTemporaryAt_frame_(i, bp)
});
if (this._runtime.isBlock_(code))
{
envcount = 0
} else {
envcount = this._runtime.methodEnvironmentSize_(code)
}
;
envtemps = (1).to_(envcount).collect_((i) => {
return this.environmentAt_frame_(i, bp)
});
result.add_([code, receiver, args, temps, envtemps]);
return bp = this._stack.at_(bp)
});
return result;
}
bpForFrameAt_(anInteger) {
let bp;
const _home = {};
try {
bp = this._regBP;
(anInteger-1).timesRepeat_(() => {
if (bp._equal(0))
{
throw [_home, nil]
}
;
return bp = this._stack.at_(bp)
});
return bp;
} catch(e) { if (e[0] == _home) return e[1]; else throw(e); }
}
buildClosureFrameFor_code_environment_(receiver, code, environment) {
let temps;
temps = this._runtime.blockTempCount_(code);
this.buildFrameFor_code_environment_temps_(receiver, code, environment, temps);
return this;
}
buildFrameFor_code_environment_temps_(receiver, code, environment, temps) {
this._regS = receiver;
this._regM = code;
_cascade(this, (_recv) => {
_recv.push_(this._pc);
return _recv.push_(this._regBP);});
this._regBP = this._regSP;
if (this._regBP._lessThan(100))
{
this.error_("stack overflow")
}
;
_cascade(this, (_recv) => {
_recv.push_(receiver);
_recv.push_(code);
_recv.push_(this._regE);
return _recv.push_(environment);});
this._regE = environment;
this._pc = 0;
temps.timesRepeat_(() => {
return this.push_(this.nil())
});
return this;
}
buildLaunchFrame() {
let launcher, code, executable;
launcher = this._runtime.newCompiledMethod();
code = this._runtime.newArraySized_(0);
executable = this._runtime.newExecutableCodeFor_(code);
this._runtime.methodExecutableCode_put_(launcher, executable);
this.buildMethodFrameFor_code_environment_(this._runtime.nil(), launcher, this._runtime.nil());
return this;
}
buildMethodFrameFor_code_environment_(receiver, code, environment) {
let temps;
temps = this._runtime.methodTempCount_(code);
this.buildFrameFor_code_environment_temps_(receiver, code, environment, temps);
return this;
}
contextSwitchTo_sp_environment_(anotherStack, anotherSP, env) {
this._stack = anotherStack;
this._regSP = anotherSP;
this._regE = env;
return this;
}
dropOperands_(anInteger) {
this._regSP = (this._regSP+anInteger);
return this;
}
environment() {
return this._regE;
}
environment_(array) {
this._regE = array;
return this;
}
environment_at_(environmentIndex, index) {
let env;
if (environmentIndex._equal(-1))
{
return this.stackTemporaryAt_(index)
}
;
if (environmentIndex._equal(0))
{
env = this._regE
} else {
env = this._regE.at_(environmentIndex)
}
;
return env.at_(index);
}
environment_at_put_(environmentIndex, index, value) {
let env;
if (environmentIndex._equal(-1))
{
return this.stackTemporaryAt_put_(index, value)
}
;
if (environmentIndex._equal(0))
{
env = this._regE
} else {
env = this._regE.at_(environmentIndex)
}
;
return env.at_put_(index, value);
}
environmentAt_frame_(anInteger, bp) {
return this._stack.at_((bp-this.tempOffset())).slotAt_(anInteger);
}
firstArgument() {
return this.argumentAt_(1);
}
fourthArgument() {
return this.argumentAt_(4);
}
hasFinished() {
return this._regBP._equal(0).and_(() => {
return this._regSP._equal((this._stack.size()+1))
});
}
incRegPC() {
return this._pc = (this._pc+1);
}
initialize() {
super.initialize();
this._stack = Array.new_((64*1024));
this._regSP = (this._stack.size()+1);
this._regBP = 0;
this._pc = 0;
return this;
}
isBlock() {
return this._runtime.isBlock_(this._regM);
}
method() {
let _retval;
if (this.isBlock())
{
_retval = this._runtime.blockMethod_(this._regM)
} else {
_retval = this._regM
}
;
return _retval;
}
method_(aMethod) {
this._regM = aMethod;
return this;
}
methodArguments() {
let count;
count = this._runtime.methodArgumentCount_(this._regM);
return count.to_by_(1, -1).collect_((i) => {
return this.argumentAt_(i)
});
}
operandAt_(anInteger) {
return this._stack.at_((this._regSP+anInteger));
}
pop() {
let result;
result = this._stack.at_(this._regSP);
this._regSP = (this._regSP+1);
return result;
}
popFrame() {
this._regSP = this._regBP;
this._regBP = this.pop();
this._pc = this.pop();
this._regE = this._stack.at_((this._regBP-4));
this._regM = this._stack.at_((this._regBP-2));
this._regS = this._stack.at_((this._regBP-1));
return this;
}
popLaunchFrame() {
this._regSP = this._regBP;
this._regE = this._stack.at_((this._regBP-3));
this._regBP = this.pop();
this._pc = this.pop();
if (this._regBP._equal(0))
{
return this
}
;
this._regM = this._stack.at_((this._regBP-2));
this._regS = this._stack.at_((this._regBP-1));
return this;
}
popLaunchFrame_(prevRegE) {
this._regSP = this._regBP;
this._regE = prevRegE;
this._regBP = this.pop();
this._pc = this.pop();
if (this._regBP._equal(0))
{
return this
}
;
this._regM = this._stack.at_((this._regBP-2));
this._regS = this._stack.at_((this._regBP-1));
return this;
}
popOperand() {
return this.pop();
}
popOperands_(anInteger) {
let result;
if (anInteger._equal(0))
{
return []
}
;
result = Array.new_(anInteger);
anInteger.to_by_do_(1, -1, (i) => {
return result.at_put_(i, this.pop())
});
return result;
}
push_(anObject) {
if (nil === anObject)
{
this.halt()
}
;
this._regSP = (this._regSP-1);
this._stack.at_put_(this._regSP, anObject);
return this;
}
pushOperand_(anObject) {
if (nil === anObject)
{
this.halt()
}
;
this._regSP = (this._regSP-1);
this._stack.at_put_(this._regSP, anObject);
return this;
}
receiver() {
return this._regS;
}
receiver_(object) {
this._regS = object;
return this;
}
regBP() {
return this._regBP;
}
regBP_(integer) {
this._regBP = integer;
return this;
}
regM() {
return this._regM;
}
regPC() {
return this._pc;
}
regPC_(anInteger) {
this._pc = anInteger;
return this;
}
regSP() {
return this._regSP;
}
regSP_(integer) {
this._regSP = integer;
return this;
}
reserveStackSlots_(anInteger) {
this._regSP = (this._regSP-anInteger);
return this;
}
restart() {
let nilObj;
nilObj = this._runtime.nil();
(this._regBP-this.tempOffset()).to_by_do_(this._regSP, -1, (i) => {
return this._stack.at_put_(i, nilObj)
});
this._pc = 1;
return this;
}
runtime_(anEggRuntime) {
super.runtime_(anEggRuntime);
this._regE = this._regS = this._runtime.nil();
return this;
}
secondArgument() {
return this.argumentAt_(2);
}
self() {
return this._regS;
}
stack() {
return this._stack;
}
stack_(array) {
this._stack = array;
return this;
}
stackSize() {
return this._stack.size();
}
stackTemporaryAt_(anInteger) {
return this.stackTemporaryAt_frame_(anInteger, this._regBP);
}
stackTemporaryAt_frame_(anInteger, bp) {
return this._stack.at_(((bp-this.tempOffset())-anInteger));
}
stackTemporaryAt_frame_put_(anInteger, bp, anObject) {
return this._stack.at_put_(((bp-this.tempOffset())-anInteger), anObject);
}
stackTemporaryAt_frameIndex_(anInteger, anotherInteger) {
let bp;
bp = this.bpForFrameAt_(anotherInteger);
return this.stackTemporaryAt_frame_(anInteger, bp);
}
stackTemporaryAt_frameIndex_put_(anInteger, anotherInteger, anObject) {
let bp;
bp = this.bpForFrameAt_(anotherInteger);
return this.stackTemporaryAt_frame_put_(anInteger, bp, anObject);
}
stackTemporaryAt_put_(anInteger, anObject) {
return this.stackTemporaryAt_frameIndex_put_(anInteger, 1, anObject);
}
tempOffset() {
return 4;
}
temporaryAt_in_(index, environmentIndex) {
if (nil === environmentIndex)
{
return this.stackTemporaryAt_(index)
}
;
return this.environment_at_(environmentIndex, index);
}
temporaryAt_in_put_(index, environmentIndex, value) {
if (nil === environmentIndex)
{
return this.stackTemporaryAt_put_(index, value)
}
;
return this.environment_at_put_(environmentIndex, index, value);
}
thirdArgument() {
return this.argumentAt_(3);
}
unwind() {
let home, bp, environment;
const _home = {};
try {
home = this._runtime.closureHome_(this.environment());
if (home._equalEqual(this._runtime.nil()))
{
this.error_("cannot return because closure has no home")
}
;
bp = this._regBP;
(() => {
return bp._notEqual(0)
}).whileTrue_(() => {
environment = this._stack.at_((bp-4));
if (environment._equalEqual(home))
{
this._regBP = bp;
throw [_home, this.popFrame()]
}
;
return bp = this._stack.at_(bp)
});
this.error_("cannot return from this closure");
return this;
} catch(e) { if (e[0] == _home) return e[1]; else throw(e); }
}
}
export default StackedEvaluationContext