UNPKG

@powerlang/egg-js

Version:

A Smalltalk VM that runs on top of JavaScript

293 lines (260 loc) 7.58 kB
import EggIterativeInterpreter from './EggIterativeInterpreter.js'; import SExpressionLinearizer from './SExpressionLinearizer.js'; import SLiteral from './SLiteral.js'; import SMessage from './SMessage.js'; import SOpDispatchMessage from './SOpDispatchMessage.js'; import StackedEvaluationContext from './StackedEvaluationContext.js'; let EggIterativeStackedInterpreter = class extends EggIterativeInterpreter { constructor() { super(); this._linearizer = nil; this._work = nil; } contextFor_(vmStack) { return this._stacks.at_(vmStack); } contextForProcess_(process) { let stack; stack = process.slotAt_(2); return this._stacks.at_(stack); } contextSwitchTo_(vmStack) { let sp; this._context = this._stacks.at_(vmStack); sp = this._runtime.processStackSP_(vmStack); this._context.regSP_(sp.value()); _cascade(this._context, (_recv) => { _recv.environment_(this._context.pop()); return _recv.regBP_(this._context.regSP());}); this.popFrameAndPrepare(); return this._trueObj; } evaluate() { let operation; (() => { operation = this.nextOperation(); return operation.notNil() }).whileTrue_(() => { return operation.acceptVisitor_(this) }); return this._regR; } evaluateClosure_withArgs_(closure, _arguments) { let block, code, receiver; block = this._runtime.closureBlock_(closure); code = this.prepareBlockExecutableCode_(block); this._work = this._runtime.executableCodeWork_(code); if (this._runtime.blockCapturesSelf_(block)) { receiver = closure.at_(1) } else { receiver = this._nilObj } ; _cascade(this._context, (_recv) => { _recv.popFrame(); return _recv.buildClosureFrameFor_code_environment_(receiver, block, closure);}); return this._regR; } evaluateUndermessage_with_(message, block) { let argcount, _arguments; argcount = message.argumentCount(); _arguments = this._context.popOperands_(argcount); this._regR = block.value_value_(this._regR, _arguments); this._context.reserveStackSlots_(argcount); return this; } initialize() { super.initialize(); this._linearizer = SExpressionLinearizer.new(); return this; } initializeExecutableCodeOf_(method) { return this.initializeLinearExecutableCodeOf_(method); } initializePrimitives() { super.initializePrimitives(); this._linearizer.primitives_(this._primitives); return this; } invoke_with_(method, receiver) { let size, environment; if (this._runtime.methodNeedsEnvironment_(method)) { size = this._runtime.methodEnvironmentSize_(method); environment = this._runtime.newEnvironmentSized_(size) } else { environment = this._nilObj } ; this._work = this.prepareForExecuting_(method); this._context.buildMethodFrameFor_code_environment_(receiver, method, environment); return this._regR; } linearizer() { return this._linearizer; } messageNotUnderstood_(anSMessage) { let count, args, array, dnu; count = anSMessage.arguments().size(); args = (1).to_(count).collect_((i) => { return this._context.operandAt_((count-i)) }); array = this._runtime.newArray_(args); _cascade(this._context, (_recv) => { _recv.push_(anSMessage.selector()); return _recv.push_(array);}); dnu = this._runtime.doesNotUnderstandMethod(); this.invoke_with_(dnu, this._regR); return this; } newEvaluationContext() { return StackedEvaluationContext.new().runtime_(this._runtime); } nextOperation() { let pc; pc = this._context.incRegPC(); if (!pc._lessEqualThan(this._work.size())) { return nil } ; return this._work.at_(pc); } popFrameAndPrepare() { let code; this._context.popFrame(); code = this._runtime.methodExecutableCode_(this._context.regM()); this._work = this._runtime.executableCodeWork_(code); return this; } prepareBlockExecutableCode_(block) { let code, method; code = this._runtime.blockExecutableCode_(block); if (this._runtime.isExecutableCode_(code)) { return code } ; method = this._runtime.blockMethod_(block); this.initializeExecutableCodeOf_(method); code = this._runtime.blockExecutableCode_(block); this.ASSERT_(this._runtime.isExecutableCode_(code)); return code; } runtime_(anEggRuntime) { super.runtime_(anEggRuntime); _cascade(this._linearizer, (_recv) => { _recv.runtime_(anEggRuntime); return _recv.dropsArguments();}); this._context = this.newEvaluationContext(); return this; } sendLocal_to_with_(aSymbol, receiver, anArray) { let symbol, literal, dummy, message, dispatch, prevWork, prevPC, prevRegE; symbol = this._runtime.symbolFromLocal_(aSymbol); literal = SLiteral.new().value_(this._nilObj); dummy = Array.new_withAll_(anArray.size(), nil); message = _cascade(SMessage.new(), (_recv) => { _recv.selector_(symbol); _recv.receiver_(literal); return _recv.arguments_(dummy);}); dispatch = SOpDispatchMessage.new().message_(message); prevWork = this._work; prevPC = this._context.regPC(); prevRegE = this._context.environment(); this._context.buildLaunchFrame(); this._regR = receiver; if (!anArray.isEmpty()) { this._context.pushOperand_(receiver) } ; anArray.do_((arg) => { return this._context.pushOperand_(arg) }); this._work = [dispatch]; this._context.regPC_(0); this.evaluate(); this._context.popLaunchFrame_(prevRegE); this._work = prevWork; this._context.regPC_(prevPC); return this._regR; } underprimitiveRestart() { return (receiver, _arguments) => { return this._context.restart() }; } visitOpDispatchMessage_(anSOpDispatchMessage) { let message, behavior, method, _condition; message = anSOpDispatchMessage.message(); _condition = message.cachedUndermessage(); if (nil !== _condition) { let block; block = _condition; return this.evaluateUndermessage_with_(message, block) } ; if (message.receiver().isSuper()) { behavior = this._runtime.superBehaviorOf_(this._context.classBinding()) } else { behavior = this._runtime.behaviorOf_(this._regR) } ; method = this.lookup_startingAt_sendSite_(message.selector(), behavior, message); if (nil === method) { return this.messageNotUnderstood_(message) } ; if (method.isBlock()) { return this.evaluateUndermessage_with_(message, method) } ; return this.invoke_with_(method, this._regR); } visitOpJump_(anSOpJump) { this._context.regPC_(anSOpJump.target()); return this; } visitOpJumpFalse_(anSOpJumpFalse) { if (this._regR._equalEqual(this._falseObj)) { this._context.regPC_(anSOpJumpFalse.target()) } ; return this; } visitOpJumpTrue_(anSOpJumpTrue) { if (this._regR._equalEqual(this._trueObj)) { this._context.regPC_(anSOpJumpTrue.target()) } ; return this; } visitOpNonLocalReturn_(anSOpReturn) { let code; this._context.unwind(); code = this._runtime.methodExecutableCode_(this._context.regM()); this._work = this._runtime.executableCodeWork_(code); return this; } visitOpPopR_(anSOpPopR) { this._regR = this._context.pop(); return this; } visitOpPrimitive_(anSOpPrimtive) { this._regR = anSOpPrimtive.block().value(); return this; } visitOpReturn_(anSOpReturn) { this.popFrameAndPrepare(); return this; } } export default EggIterativeStackedInterpreter