UNPKG

@powerlang/egg-js

Version:

A Smalltalk VM that runs on top of JavaScript

523 lines (453 loc) 11.2 kB
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