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