UNPKG

@powerlang/egg-js

Version:

A Smalltalk VM that runs on top of JavaScript

798 lines (740 loc) 20.8 kB
import SInlinerOperation from './SInlinerOperation.js'; import SLiteral from './SLiteral.js'; import SMessage from './SMessage.js'; import SOpAssign from './SOpAssign.js'; import SOpDispatchMessage from './SOpDispatchMessage.js'; import SOpDropToS from './SOpDropToS.js'; import SOpJump from './SOpJump.js'; import SOpJumpFalse from './SOpJumpFalse.js'; import SOpJumpTrue from './SOpJumpTrue.js'; import SOpLoadRfromFrame from './SOpLoadRfromFrame.js'; import SOpLoadRfromStack from './SOpLoadRfromStack.js'; import SOpLoadRwithNil from './SOpLoadRwithNil.js'; import SOpLoadRwithSelf from './SOpLoadRwithSelf.js'; import SOpNonLocalReturn from './SOpNonLocalReturn.js'; import SOpPopR from './SOpPopR.js'; import SOpPrimitive from './SOpPrimitive.js'; import SOpPushR from './SOpPushR.js'; import SOpReturn from './SOpReturn.js'; import SOpStoreRintoFrame from './SOpStoreRintoFrame.js'; let SExpressionLinearizer = class { constructor() { this._operations = nil; this._primitives = nil; this._inBlock = nil; this._runtime = nil; this._greaterThan = nil; this._one = nil; this._plus = nil; this._stackTop = nil; this._dropsArguments = nil; this._not = nil; this._equalsEquals = nil; this._ifTrue = nil; this._ifFalse = nil; this._ifTrueIfFalse = nil; this._ifFalseIfTrue = nil; this._ifNil = nil; this._ifNotNil = nil; this._ifNilIfNotNil = nil; this._ifNotNilIfNil = nil; this._whileTrue = nil; this._whileFalse = nil; this._whileTrue_ = nil; this._whileFalse_ = nil; this._toDo = nil; this._toByDo = nil; this._repeat = nil; this._timesRepeat = nil; this._andNot = nil; this._orNot = nil; } assign_(aCollection) { let op; op = SOpAssign.new().assignees_(aCollection); this._operations.add_(op); return this; } branchIf_(aBoolean) { let _class, op; if (aBoolean) { _class = SOpJumpTrue } else { _class = SOpJumpFalse } ; op = _class.new(); this._operations.add_(op); return op; } branchTargetOf_(branch) { branch.target_(this.currentPC()); return this; } currentPC() { return this._operations.size(); } dispatch_(message) { let op, count; op = SOpDispatchMessage.new().message_(message); this._operations.add_(op); if (this._dropsArguments) { return this } ; count = message.arguments().size(); if (count._greaterThan(0)) { count = (count+1) } ; this._stackTop = (this._stackTop-count); return this; } dropCascadeMessageArgs_(argsize) { if (argsize._equal(0).orNot_(() => { return this._dropsArguments })) { return this } ; this.dropToS_(argsize); return this; } dropMessageArgs_(argsize) { if (argsize._equal(0).orNot_(() => { return this._dropsArguments })) { return this } ; this.dropToS_((argsize+1)); return this; } dropToS() { return this.dropToS_(1); } dropToS_(anInteger) { let op; op = SOpDropToS.new().count_(anInteger); this._operations.add_(op); this._stackTop = (this._stackTop-anInteger); return this; } dropsArguments() { this._dropsArguments = true; return this; } initialize() { this._dropsArguments = false; return this; } inline_binaryWhile_(anSMessage, aBoolean) { let start, end; start = this.currentPC(); this.visitStatements_(anSMessage.receiver().statements()); end = this.branchIf_(aBoolean.not()); _cascade(this, (_recv) => { _recv.visitStatements_(anSMessage.arguments().first().statements()); _recv.jumpTo_(start); return _recv.branchTargetOf_(end);}); return this; } inline_if_(anSMessage, aBoolean) { let branch, end; anSMessage.receiver().acceptVisitor_(this); branch = this.branchIf_(aBoolean.not()); end = _cascade(this, (_recv) => { _recv.visitStatements_(anSMessage.arguments().first().statements()); return _recv.jump();}); _cascade(this, (_recv) => { _recv.branchTargetOf_(branch); _recv.loadRwithNil(); return _recv.branchTargetOf_(end);}); return this; } inline_ifNil_(anSMessage, aBoolean) { let nilObj, message, branch, end, arg, index; anSMessage.receiver().acceptVisitor_(this); arg = anSMessage.arguments().first(); if (arg.isBlock().and_(() => { return arg.inlinedArgs().size()._equal(1) })) { index = arg.inlinedArgs().first(); this.storeRintoFrameAt_(index) } ; this.pushR(); nilObj = SLiteral.new().value_(this._runtime.nil()); message = _cascade(SMessage.new(), (_recv) => { _recv.receiver_(SOpLoadRfromStack.new().index_(0)); _recv.arguments_([nilObj]); return _recv.selector_(this._equalsEquals);}); this.visitMessage_(message); branch = this.branchIf_(aBoolean.not()); if (arg.isBlock()) { this.visitStatements_(arg.statements()) } else { arg.acceptVisitor_(this) } ; end = _cascade(this, (_recv) => { _recv.dropToS(); return _recv.jump();}); _cascade(this, (_recv) => { _recv.branchTargetOf_(branch); _recv.popR(); return _recv.branchTargetOf_(end);}); return this; } inline_ifNilIfNotNil_(anSMessage, aBoolean) { let _arguments, nilObj, message, branch, end, arg, index; anSMessage.receiver().acceptVisitor_(this); _arguments = anSMessage.arguments(); if (aBoolean) { arg = _arguments.second() } else { arg = _arguments.first() } ; if (arg.isBlock().and_(() => { return arg.inlinedArgs().size()._equal(1) })) { index = arg.inlinedArgs().first(); this.storeRintoFrameAt_(index) } ; this.pushR(); nilObj = SLiteral.new().value_(this._runtime.nil()); message = _cascade(SMessage.new(), (_recv) => { _recv.receiver_(SOpLoadRfromStack.new().index_(0)); _recv.arguments_([nilObj]); return _recv.selector_(this._equalsEquals);}); this.visitMessage_(message); branch = this.branchIf_(aBoolean.not()); end = _cascade(this, (_recv) => { _recv.visitStatements_(_arguments.first().statements()); return _recv.jump();}); _cascade(this, (_recv) => { _recv.branchTargetOf_(branch); _recv.visitStatements_(_arguments.second().statements()); _recv.branchTargetOf_(end); return _recv.dropToS();}); return this; } inline_ifTrueIfFalse_(anSMessage, aBoolean) { let branch, end; anSMessage.receiver().acceptVisitor_(this); branch = this.branchIf_(aBoolean.not()); end = _cascade(this, (_recv) => { _recv.visitStatements_(anSMessage.arguments().first().statements()); return _recv.jump();}); _cascade(this, (_recv) => { _recv.branchTargetOf_(branch); _recv.visitStatements_(anSMessage.arguments().second().statements()); return _recv.branchTargetOf_(end);}); return this; } inline_unitaryWhile_(anSMessage, aBoolean) { let start, branch; start = this.currentPC(); this.visitStatements_(anSMessage.receiver().statements()); branch = this.branchIf_(aBoolean); branch.target_(start); return this; } inlineAnd_(anSMessage) { let branches; anSMessage.receiver().acceptVisitor_(this); branches = Array.new(); anSMessage.arguments().do_((block) => { branches.add_(this.branchIf_(false)); return this.visitStatements_(block.statements()) }); branches.do_((branch) => { return this.branchTargetOf_(branch) }); return this; } inlineAndNot_(anSMessage) { let branch, message; anSMessage.receiver().acceptVisitor_(this); branch = this.branchIf_(false); message = _cascade(SMessage.new(), (_recv) => { _recv.receiver_(SInlinerOperation.new()); _recv.selector_(this._not); return _recv.arguments_([]);}); _cascade(this, (_recv) => { _recv.visitStatements_(anSMessage.arguments().first().statements()); _recv.dispatch_(message); return _recv.branchTargetOf_(branch);}); return this; } inlineOr_(anSMessage) { let branches; anSMessage.receiver().acceptVisitor_(this); branches = Array.new(); anSMessage.arguments().do_((block) => { branches.add_(this.branchIf_(true)); return this.visitStatements_(block.statements()) }); branches.do_((branch) => { return this.branchTargetOf_(branch) }); return this; } inlineOrNot_(anSMessage) { let branch, message; anSMessage.receiver().acceptVisitor_(this); branch = this.branchIf_(true); message = _cascade(SMessage.new(), (_recv) => { _recv.receiver_(SInlinerOperation.new()); _recv.selector_(this._not); return _recv.arguments_([]);}); _cascade(this, (_recv) => { _recv.visitStatements_(anSMessage.arguments().first().statements()); _recv.dispatch_(message); return _recv.branchTargetOf_(branch);}); return this; } inlineRepeat_(anSMessage) { let start; start = this.currentPC(); _cascade(this, (_recv) => { _recv.visitStatements_(anSMessage.receiver().statements()); return _recv.jumpTo_(start);}); return this; } inlineTimesRepeat_(anSMessage) { let current, limit, start, end, compare, increment; this._operations.add_(this._one); this.pushR(); current = SOpLoadRfromFrame.new().index_(this._stackTop); anSMessage.receiver().acceptVisitor_(this); this.pushR(); limit = SOpLoadRfromFrame.new().index_(this._stackTop); start = this.currentPC(); compare = _cascade(SMessage.new(), (_recv) => { _recv.receiver_(current); _recv.selector_(this._greaterThan); return _recv.arguments_([limit]);}); this.visitMessage_(compare); end = this.branchIf_(true); this.visitStatements_(anSMessage.arguments().first().statements()); increment = _cascade(SMessage.new(), (_recv) => { _recv.receiver_(current); _recv.selector_(this._plus); return _recv.arguments_([this._one]);}); _cascade(this, (_recv) => { _recv.visitMessage_(increment); _recv.storeRintoFrameAt_(current.index()); _recv.jumpTo_(start); _recv.branchTargetOf_(end); return _recv.dropToS_(2);}); return this; } inlineToDo_(anSMessage) { let index, current, limit, start, end, compare, increment; anSMessage.receiver().acceptVisitor_(this); index = anSMessage.arguments().second().inlinedArgs().first(); current = SOpLoadRfromFrame.new().index_(index); this.storeRintoFrameAt_(index); anSMessage.arguments().first().acceptVisitor_(this); this.pushR(); limit = SOpLoadRfromFrame.new().index_(this._stackTop); start = this.currentPC(); compare = _cascade(SMessage.new(), (_recv) => { _recv.receiver_(current); _recv.selector_(this._greaterThan); return _recv.arguments_([limit]);}); this.visitMessage_(compare); end = this.branchIf_(true); this.visitStatements_(anSMessage.arguments().second().statements()); increment = _cascade(SMessage.new(), (_recv) => { _recv.receiver_(current); _recv.selector_(this._plus); return _recv.arguments_([this._one]);}); _cascade(this, (_recv) => { _recv.visitMessage_(increment); _recv.storeRintoFrameAt_(index); _recv.jumpTo_(start); _recv.branchTargetOf_(end); return _recv.dropToS_(1);}); return this; } jump() { let op; op = SOpJump.new(); this._operations.add_(op); return op; } jumpTo_(anInteger) { let op; op = SOpJump.new().target_(anInteger); this._operations.add_(op); return this; } loadRfromStack_(anInteger) { let op; op = SOpLoadRfromStack.new().index_(anInteger); this._operations.add_(op); return this; } loadRwithNil() { this._operations.add_(SOpLoadRwithNil.new()); return this; } loadRwithSelf() { this._operations.add_(SOpLoadRwithSelf.new()); return this; } operations() { return this._operations; } popR() { this._operations.add_(SOpPopR.new()); this._stackTop = (this._stackTop-1); return this; } primitive_(aClosure) { this._operations.add_(SOpPrimitive.new().block_(aClosure)); return this; } primitives_(aCollection) { this._primitives = aCollection; return this; } pushR() { this._operations.add_(SOpPushR.new()); this._stackTop = (this._stackTop+1); return this; } reset() { this._operations = Array.new(); this._inBlock = false; return this; } return() { this._operations.add_(SOpReturn.new()); return this; } return_(isLocal) { let _class; if (isLocal.andNot_(() => { return this._inBlock })) { _class = SOpReturn } else { _class = SOpNonLocalReturn } ; this._operations.add_(_class.new()); return this; } runtime_(anEggRuntime) { let literal; this._runtime = anEggRuntime; literal = this._runtime.newInteger_(1); this._one = SLiteral.new().value_(literal); this._plus = this._runtime.symbolFromLocal_("+"); this._greaterThan = this._runtime.symbolFromLocal_(">"); this._equalsEquals = this._runtime.symbolFromLocal_("=="); this._not = this._runtime.symbolFromLocal_("not"); this._ifTrue = this._runtime.symbolFromLocal_("ifTrue:"); this._ifFalse = this._runtime.symbolFromLocal_("ifFalse:"); this._ifTrueIfFalse = this._runtime.symbolFromLocal_("ifTrue:ifFalse:"); this._ifFalseIfTrue = this._runtime.symbolFromLocal_("ifFalse:ifTrue:"); this._ifNil = this._runtime.symbolFromLocal_("ifNil:"); this._ifNotNil = this._runtime.symbolFromLocal_("ifNotNil:"); this._ifNilIfNotNil = this._runtime.symbolFromLocal_("ifNil:ifNotNil:"); this._ifNotNilIfNil = this._runtime.symbolFromLocal_("ifNotNil:ifNil:"); this._repeat = this._runtime.symbolFromLocal_("repeat"); this._whileTrue = this._runtime.symbolFromLocal_("whileTrue"); this._whileFalse = this._runtime.symbolFromLocal_("whileFalse"); this._whileTrue_ = this._runtime.symbolFromLocal_("whileTrue:"); this._whileFalse_ = this._runtime.symbolFromLocal_("whileFalse:"); this._timesRepeat = this._runtime.symbolFromLocal_("timesRepeat:"); this._toDo = this._runtime.symbolFromLocal_("to:do:"); this._toByDo = this._runtime.symbolFromLocal_("to:by:do:"); this._andNot = this._runtime.symbolFromLocal_("andNot:"); this._orNot = this._runtime.symbolFromLocal_("orNot:"); return this; } storeRintoFrameAt_(anInteger) { let op; op = SOpStoreRintoFrame.new().index_(anInteger); this._operations.add_(op); return this; } visitAssignment_(anSAssignment) { anSAssignment.expression().acceptVisitor_(this); this.assign_(anSAssignment.assignees()); return this; } visitBlock_(anSBlock) { let prevInBlock, prevOperations, prevStackTop, statements, code, _retval; this._operations.add_(anSBlock); prevInBlock = this._inBlock; prevOperations = this._operations; prevStackTop = this._stackTop; this._stackTop = this._runtime.blockTempCount_(anSBlock.compiledCode()); this._inBlock = true; this._operations = Array.new(); statements = anSBlock.statements(); statements.do_((node) => { return node.acceptVisitor_(this) }); if (statements.isEmpty()) { this.loadRwithNil() } else { _retval = nil; if (!statements.last().isReturn()) { _retval = this.return() } ; _retval } ; if (!anSBlock.isInlined()) { code = this._runtime.newExecutableCodeFor_(this._operations.asArray()); this._runtime.blockExecutableCode_put_(anSBlock.compiledCode(), code) } ; this._stackTop = prevStackTop; this._operations = prevOperations; this._inBlock = prevInBlock; return this; } visitCascade_(anSCascade) { let args, argsize; anSCascade.receiver().acceptVisitor_(this); this.pushR(); anSCascade.messages().do_((msg) => { args = msg.arguments(); argsize = args.size(); args.do_((arg) => { arg.acceptVisitor_(this); return this.pushR() }); return _cascade(this, (_recv) => { _recv.loadRfromStack_(argsize); _recv.dispatch_(msg); return _recv.dropCascadeMessageArgs_(argsize);}) }); this.dropToS(); return this; } visitFFIMethod_(anSMethod) { let handler; this.reset(); handler = this._primitives.at_("FFICall"); return _cascade(this, (_recv) => { _recv.primitive_(handler); return _recv.return();}); } visitIdentifier_(anSIdentifier) { this._operations.add_(anSIdentifier); return this; } visitInlinedMessage_(anSMessage) { let selector; selector = anSMessage.selector(); if (selector._equalEqual(this._ifTrue)) { return this.inline_if_(anSMessage, true) } ; if (selector._equalEqual(this._ifFalse)) { return this.inline_if_(anSMessage, false) } ; if (selector._equalEqual(this._ifNil)) { return this.inline_ifNil_(anSMessage, true) } ; if (selector._equalEqual(this._ifNotNil)) { return this.inline_ifNil_(anSMessage, false) } ; if (selector._equalEqual(this._ifNilIfNotNil)) { return this.inline_ifNilIfNotNil_(anSMessage, true) } ; if (selector._equalEqual(this._ifNotNilIfNil)) { return this.inline_ifNilIfNotNil_(anSMessage, false) } ; if (selector._equalEqual(this._ifTrueIfFalse)) { return this.inline_ifTrueIfFalse_(anSMessage, true) } ; if (selector._equalEqual(this._ifFalseIfTrue)) { return this.inline_ifTrueIfFalse_(anSMessage, false) } ; if (selector._equalEqual(this._whileTrue)) { return this.inline_unitaryWhile_(anSMessage, true) } ; if (selector._equalEqual(this._whileFalse)) { return this.inline_unitaryWhile_(anSMessage, false) } ; if (selector._equalEqual(this._whileTrue_)) { return this.inline_binaryWhile_(anSMessage, true) } ; if (selector._equalEqual(this._whileFalse_)) { return this.inline_binaryWhile_(anSMessage, false) } ; if (selector._equalEqual(this._repeat)) { return this.inlineRepeat_(anSMessage) } ; if (selector._equalEqual(this._toDo)) { return this.inlineToDo_(anSMessage) } ; if (selector._equalEqual(this._toByDo)) { return this.inlineToByDo_(anSMessage) } ; if (selector._equalEqual(this._timesRepeat)) { return this.inlineTimesRepeat_(anSMessage) } ; if (selector._equalEqual(this._andNot)) { return this.inlineAndNot_(anSMessage) } ; if (selector._equalEqual(this._orNot)) { return this.inlineOrNot_(anSMessage) } ; selector = this._runtime.localSymbolFrom_(selector); if (selector.beginsWith_("or:")) { return this.inlineOr_(anSMessage) } ; if (selector.beginsWith_("and:")) { return this.inlineAnd_(anSMessage) } ; this.ASSERT_(false); return this; } visitLiteral_(anSLiteral) { this._operations.add_(anSLiteral); return this; } visitMessage_(anSMessage) { let args, argsize; if (anSMessage.isInlined()) { return this.visitInlinedMessage_(anSMessage) } ; anSMessage.receiver().acceptVisitor_(this); args = anSMessage.arguments(); argsize = args.size(); if (argsize._greaterThan(0)) { this.pushR() } ; args.do_((arg) => { arg.acceptVisitor_(this); return this.pushR() }); if (argsize._greaterThan(0)) { this.loadRfromStack_(argsize) } ; _cascade(this, (_recv) => { _recv.dispatch_(anSMessage); return _recv.dropMessageArgs_(argsize);}); return this; } visitMethod_(anSMethod) { let primitive, statements, symbol, descriptor, handler; this.reset(); primitive = anSMethod.pragma(); if (nil !== primitive) { symbol = this._runtime.localSymbolFrom_(anSMethod.primitive()); handler = this._primitives.at_(symbol); return _cascade(this, (_recv) => { _recv.primitive_(handler); return _recv.return();}) } ; this._stackTop = this._runtime.methodTempCount_(anSMethod.compiledCode()); statements = anSMethod.statements(); statements.do_((node) => { return node.acceptVisitor_(this) }); if (statements.isEmpty().orNot_(() => { return statements.last().isReturn() })) { _cascade(this, (_recv) => { _recv.loadRwithSelf(); return _recv.return();}) } ; return this; } visitOpLoadRfromFrame_(anSOpLoadRfromFrame) { this._operations.add_(anSOpLoadRfromFrame); return this; } visitOpLoadRfromStack_(anSOpLoadRfromStack) { this.loadRfromStack_(anSOpLoadRfromStack.index()); return this; } visitReturn_(anSReturn) { anSReturn.expression().acceptVisitor_(this); this.return_(anSReturn.local()); return this; } visitStatements_(aCollection) { aCollection.do_((sexpression) => { return sexpression.acceptVisitor_(this) }); return this; } } export default SExpressionLinearizer