@powerlang/egg-js
Version:
A Smalltalk VM that runs on top of JavaScript
293 lines (260 loc) • 7.58 kB
JavaScript
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