UNPKG

@powerlang/egg-js

Version:

A Smalltalk VM that runs on top of JavaScript

581 lines (528 loc) 14.7 kB
import JSNativeCode from './JSNativeCode.js'; import SMessage from './SMessage.js'; let JSSExpressionTranspiler = class { constructor() { this._runtime = nil; this._evaluator = nil; this._stream = nil; this._literals = nil; this._tabs = nil; this._currentBlock = nil; this._one = nil; this._plus = nil; this._greaterThan = nil; this._equalsEquals = nil; this._not = 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._repeat = nil; this._whileTrue = nil; this._whileFalse = nil; this._whileTrue_ = nil; this._whileFalse_ = nil; this._timesRepeat = nil; this._toDo = nil; this._toByDo = nil; this._andNot = nil; this._orNot = nil; } addLiteral_(anObject) { this._literals.add_(anObject); return this._literals.size(); } args() { this._stream.nextPutAll_("frame.__arguments"); return this; } argumentAt_(index) { _cascade(this, (_recv) => { _recv.args(); return _recv.index_(index);}); return this; } argumentAt_in_(index, environmentIndex) { if (nil === environmentIndex) { return this.argumentAt_(index) } ; _cascade(this, (_recv) => { _recv.loadEnvironmentFor_(environmentIndex); return _recv.index_(index);}); return this; } assign_(value) { _cascade(this._stream, (_recv) => { _recv.nextPutAll_(" = "); return _recv.print_(value);}); return this; } currentEnv() { this._stream.nextPutAll_("frame.env"); return this; } end() { _cascade(this._stream, (_recv) => { _recv.nextPutAll_("})"); return _recv.cr();}); return this; } evaluator_(aJSEggEvaluator) { this._evaluator = aJSEggEvaluator; this.runtime_(this._evaluator.runtime()); return this; } false() { this._stream.nextPutAll_("evaluator._falseObj"); return this; } index_(anInteger) { _cascade(this._stream, (_recv) => { _recv.nextPutAll_("["); _recv.print_((anInteger-1)); return _recv.nextPut_("]");}); return this; } initialize() { this._tabs = 2; this._stream = ("").writeStream(); this._literals = Array.new(); return this; } inline_binaryWhile_(anSMessage, aBoolean) { this._stream.nextPutAll_("( () => {while ("); if (aBoolean) { this._stream.nextPutAll_("evaluator._trueObj===") } else { this._stream.nextPutAll_("evaluator._falseObj===") } ; this._stream.nextPut_("("); this.visitStatements_(anSMessage.receiver().statements()); this._stream.nextPutAll_(")) {"); this.visitStatements_(anSMessage.arguments().first().statements()); this._stream.nextPutAll_("} })()"); return this; } inline_ifTrue_(anSMessage, aBoolean) { this._stream.nextPut_("("); if (aBoolean) { this._stream.nextPutAll_("evaluator._trueObj===") } else { this._stream.nextPutAll_("evaluator._falseObj===") } ; this._stream.nextPut_("("); anSMessage.receiver().acceptVisitor_(this); this._stream.nextPutAll_(") ? ("); this.visitStatements_(anSMessage.arguments().first().statements()); this._stream.nextPutAll_(") : evaluator._nilObj)"); return this; } inline_ifTrueIfFalse_(anSMessage, aBoolean) { this._stream.nextPut_("("); if (aBoolean) { this._stream.nextPutAll_("evaluator._trueObj===") } else { this._stream.nextPutAll_("evaluator._falseObj===") } ; this._stream.nextPut_("("); anSMessage.receiver().acceptVisitor_(this); this._stream.nextPutAll_(") ? ("); this.visitStatements_(anSMessage.arguments().first().statements()); this._stream.nextPutAll_(") : ("); this.visitStatements_(anSMessage.arguments().second().statements()); this._stream.nextPutAll_("))"); return this; } inlineToDo_(anSMessage) { let compare, cindex, increment, incindex, args, limit, block, ipos; compare = SMessage.new().selector_(this._greaterThan); cindex = this.addLiteral_(compare); increment = SMessage.new().selector_(this._plus); incindex = this.addLiteral_(increment); args = anSMessage.arguments(); limit = args.first(); block = args.second(); ipos = block.inlinedArgs().first(); this._stream.nextPutAll_("( () => { for ("); this._tabs = (this._tabs+1); this._stream.crtab_(this._tabs); _cascade(this, (_recv) => { _recv.temps(); return _recv.index_(ipos);}); this._stream.nextPutAll_(" = "); anSMessage.receiver().acceptVisitor_(this); _cascade(this._stream, (_recv) => { _recv.nextPut_(";"); _recv.crtab_(this._tabs); return _recv.nextPutAll_("evaluator._falseObj===evaluator.sendSuperToWith_(");}); this.literalAt_(cindex); this._stream.nextPutAll_(", false, "); this.stackTemporaryAt_(ipos); this._stream.nextPutAll_(", [("); limit.acceptVisitor_(this); _cascade(this._stream, (_recv) => { _recv.nextPutAll_(")]);"); return _recv.crtab_(this._tabs);}); _cascade(this, (_recv) => { _recv.temps(); return _recv.index_(ipos);}); this._stream.nextPutAll_(" = "); this._stream.nextPutAll_("evaluator.sendSuperToWith_("); this.literalAt_(incindex); this._stream.nextPutAll_(", false,"); this.stackTemporaryAt_(ipos); this._stream.nextPutAll_(", ["); this.loadLiteral_(this._one); _cascade(this._stream, (_recv) => { _recv.nextPutAll_("]))"); _recv.crtab_((this._tabs-1)); _recv.nextPutAll_("{"); return _recv.crtab_(this._tabs);}); this.visitStatements_(block.statements()); this._tabs = (this._tabs-1); _cascade(this._stream, (_recv) => { _recv.crtab_(this._tabs); return _recv.nextPutAll_("}}) ()");}); return this; } inlinedMessage_with_(anSMessage, nativizer) { let selector; selector = anSMessage.selector(); if (selector._equalEqual(this._ifTrueIfFalse)) { return this.inline_ifTrueIfFalse_(anSMessage, true) } ; if (selector._equalEqual(this._ifTrue)) { return this.inline_ifTrue_(anSMessage, true) } ; if (selector._equalEqual(this._ifFalse)) { return this.inline_ifTrue_(anSMessage, false) } ; if (selector._equalEqual(this._toDo)) { return this.inlineToDo_(anSMessage) } ; if (selector._equalEqual(this._whileTrue)) { return this.inline_unitaryWhile_(anSMessage, true) } ; if (selector._equalEqual(this._whileFalse)) { return this.inline_unitaryWhile_(anSMessage, true) } ; if (selector._equalEqual(this._whileTrue_)) { return this.inline_binaryWhile_(anSMessage, true) } ; if (selector._equalEqual(this._whileFalse_)) { return this.inline_binaryWhile_(anSMessage, true) } ; this.ASSERT_(false); return this; } literalAt_(index) { this._stream.nextPutAll_("literals"); this.index_(index); return this; } literals() { return this._literals; } loadEnvironmentFor_(anInteger) { if (anInteger._equal(0)) { return this.currentEnv() } ; if (anInteger._equal(-1)) { return this.temps() } ; return _cascade(this, (_recv) => { _recv.currentEnv(); return _recv.index_(anInteger);}); } loadLiteral_(value) { let index; if (value.isImmediate()) { return this.smallInteger_(value.value()) } ; index = this.addLiteral_(value); this.literalAt_(index); return this; } loadVMLiteral_(value) { let index; index = this.addLiteral_(value); this.literalAt_(index); return this; } message_super_(anSMessage, aBoolean) { let args; args = anSMessage.arguments(); this._stream.nextPutAll_("evaluator.sendSuperToWith"); this._stream.nextPutAll_("_("); this.loadVMLiteral_(anSMessage); _cascade(this._stream, (_recv) => { _recv.nextPutAll_(", "); _recv.print_(aBoolean); return _recv.nextPutAll_(", ");}); anSMessage.receiver().acceptVisitor_(this); this._stream.nextPutAll_(", ["); args.do_separatedBy_((code) => { return code.acceptVisitor_(this) }, () => { return this._stream.nextPutAll_(", ") }); this._stream.nextPutAll_("])"); return this; } nativize_(anSMethod) { this.visitMethod_(anSMethod); return _cascade(JSNativeCode.new(), (_recv) => { _recv.source_(this.result()); return _recv.literals_(this.literals());}); } nil() { this._stream.nextPutAll_("evaluator._nilObj"); return this; } receiver() { this._stream.nextPutAll_("frame.__self"); return this; } result() { return this._stream.contents(); } return() { this._stream.nextPutAll_("return "); return this; } returnSelf() { this._stream.return_(() => { return this._stream.nextPutAll_("frame.__self") }); return this; } runtime_(anEggRuntime) { this._runtime = anEggRuntime; this._one = this._runtime.newInteger_(1); 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; } smallInteger_(value) { _cascade(this._stream, (_recv) => { _recv.nextPutAll_("LMRSmallInteger.new().value_("); _recv.print_(value); return _recv.nextPut_(")");}); return this; } stackTemporaryAt_(index) { _cascade(this, (_recv) => { _recv.temps(); return _recv.index_(index);}); return this; } stackTemporaryAt_put_(index, value) { _cascade(this, (_recv) => { _recv.temps(); _recv.index_(index); return _recv.assign_(value);}); return this; } start() { _cascade(this._stream, (_recv) => { _recv.reset(); _recv.nextPutAll_("(function (evaluator, frame, literals) {"); return _recv.crtab();}); return this; } statementEnd() { _cascade(this._stream, (_recv) => { _recv.nextPut_(";"); return _recv.cr();}); return this; } stream_(aWriteStream) { this._stream = aWriteStream; return this; } temporaryAt_in_(index, environmentIndex) { if (nil === environmentIndex) { return this.stackTemporaryAt_(index) } ; _cascade(this, (_recv) => { _recv.loadEnvironmentFor_(environmentIndex); return _recv.index_(index);}); return this; } temporaryAt_in_put_(index, environmentIndex, value) { if (nil === environmentIndex) { return this.stackTemporaryAt_put_(index, value) } ; _cascade(this, (_recv) => { _recv.loadEnvironmentFor_(environmentIndex); return _recv.index_(index);}); _cascade(this._stream, (_recv) => { _recv.nextPutAll_(" = "); return _recv.nextPutAll_(value);}); return this; } temps() { this._stream.nextPutAll_("frame._temporaries"); return this; } true() { this._stream.nextPutAll_("evaluator._trueObj"); return this; } visitAssignment_(anSAssignment) { let result, assignees; result = this.collect_(() => { return anSAssignment.expression().acceptVisitor_(this) }); assignees = anSAssignment.assignees(); if (assignees.size()._equal(1)) { return assignees.first().binding().assign_within_(result, this) } ; this._stream.nextPutAll_("_cascade("); this._stream.nextPutAll_(", (__result) => {"); assignees.do_separatedBy_((identifier) => { return identifier.binding().assign_within_("__result", this) }, () => { return this._stream.nextPutAll_("; ") }); this._stream.nextPutAll_("})"); return this; } visitBlock_(anSBlock) { this._stream.nextPutAll_("frame.captureClosure_("); this.loadVMLiteral_(anSBlock); this._stream.nextPut_(")"); return this; } visitIdentifier_(anSIdentifier) { let binding; binding = anSIdentifier.binding(); if (binding.isDynamic()) { this.loadVMLiteral_(anSIdentifier); this._stream.nextPutAll_("._binding.valueWithin_(frame)") } else { binding.valueWithin_(this) } ; return this; } visitLiteral_(anSLiteral) { this.loadLiteral_(anSLiteral.value()); return this; } visitMessage_(anSMessage) { if (anSMessage.isInlined()) { this.inlinedMessage_with_(anSMessage, this) } else { this.message_super_(anSMessage, false) } ; return this; } visitMethod_(anSMethod) { let statements, primitive, index; this.start(); if (nil !== anSMethod.pragma()) { primitive = this._evaluator.primitiveFor_(anSMethod.primitive()); this._stream.nextPutAll_("return "); index = this.addLiteral_(primitive); this.literalAt_(index); this._stream.nextPutAll_("()"); return this.end() } ; statements = anSMethod.statements(); statements.do_((node) => { node.acceptVisitor_(this); return this.statementEnd() }); if (statements.isEmpty().orNot_(() => { return statements.last().isReturn() })) { this.returnSelf() } ; this.end(); return this; } visitReturn_(anSReturn) { this.return(); anSReturn.expression().acceptVisitor_(this); return this; } visitStatements_(aCollection) { aCollection.do_separatedBy_((sexpression) => { return sexpression.acceptVisitor_(this) }, () => { return _cascade(this._stream, (_recv) => { _recv.nextPutAll_(","); return _recv.crtab_(this._tabs);}) }); return this; } } export default JSSExpressionTranspiler