@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
192 lines (190 loc) • 9.04 kB
JavaScript
import { tsUtils } from '@neo-one/ts-utils';
import { Types } from '../../constants';
import { Helper } from '../Helper';
export class EqualsEqualsHelper extends Helper {
constructor(options) {
super();
this.left = options.left;
this.right = options.right;
}
emit(sb, node, options) {
if (!options.pushValue) {
sb.visit(this.left, options);
sb.visit(this.right, options);
return;
}
const leftType = sb.context.analysis.getType(this.left);
const rightType = sb.context.analysis.getType(this.right);
if (leftType !== undefined && rightType !== undefined) {
this.equalsEqualsType(sb, node, options, leftType, rightType);
}
else {
this.equalsEqualsUnknown(sb, node, options);
}
}
equalsEqualsType(sb, node, options, leftType, rightType) {
if (tsUtils.type_.isOnly(leftType) &&
tsUtils.type_.isOnly(rightType) &&
tsUtils.type_.isSame(leftType, rightType)) {
sb.emitHelper(node, options, sb.helpers.equalsEqualsEquals({ leftType, rightType }));
}
else if ((tsUtils.type_.hasNull(leftType) || tsUtils.type_.hasUndefined(leftType)) &&
(tsUtils.type_.isOnlyUndefined(rightType) || tsUtils.type_.isOnlyNull(rightType))) {
sb.visit(this.left, options);
sb.visit(this.right, sb.noPushValueOptions(options));
sb.emitHelper(node, options, sb.helpers.isNullOrUndefined({ type: rightType }));
}
else if (tsUtils.type_.isOnlyNumberish(leftType) &&
(tsUtils.type_.isOnlyStringish(rightType) || tsUtils.type_.isOnlyBooleanish(rightType))) {
sb.visit(this.left, options);
sb.visit(this.right, options);
this.equalsEqualsLeftNumberRightBooleanOrString(sb, node, options);
}
else if (tsUtils.type_.isOnlyBooleanish(leftType) &&
(tsUtils.type_.isOnlyStringish(rightType) || tsUtils.type_.isOnlyBooleanish(rightType))) {
sb.visit(this.left, options);
sb.emitHelper(this.left, options, sb.helpers.toNumber({ type: sb.context.analysis.getType(this.left) }));
sb.emitHelper(this.left, options, sb.helpers.wrapNumber);
sb.visit(this.right, options);
this.equalsEqualsLeftNumberRightBooleanOrString(sb, node, options);
}
else if ((tsUtils.type_.isOnlyStringish(leftType) || tsUtils.type_.isOnlyBooleanish(leftType)) &&
tsUtils.type_.isOnlyNumberish(rightType)) {
sb.visit(this.left, options);
sb.visit(this.right, options);
this.equalsEqualsRightNumberLeftBooleanOrString(sb, node, options);
}
else if ((tsUtils.type_.isOnlyStringish(leftType) || tsUtils.type_.isOnlyBooleanish(leftType)) &&
tsUtils.type_.isOnlyBooleanish(rightType)) {
sb.visit(this.left, options);
sb.visit(this.right, options);
sb.emitHelper(this.right, options, sb.helpers.toNumber({ type: sb.context.analysis.getType(this.right) }));
sb.emitHelper(this.right, options, sb.helpers.wrapNumber);
this.equalsEqualsRightNumberLeftBooleanOrString(sb, node, options);
}
else {
this.equalsEqualsUnknown(sb, node, options);
}
}
equalsEqualsLeftNumberRightBooleanOrString(sb, node, options) {
sb.emitHelper(this.right, options, sb.helpers.toNumber({ type: sb.context.analysis.getType(this.right) }));
sb.emitHelper(this.right, options, sb.helpers.wrapNumber);
sb.emitHelper(node, options, sb.helpers.equalsEqualsEquals({
leftType: undefined,
leftKnownType: Types.Number,
rightType: undefined,
rightKnownType: Types.Number,
}));
}
equalsEqualsRightNumberLeftBooleanOrString(sb, node, options) {
sb.emitOp(node, 'SWAP');
sb.emitHelper(this.left, options, sb.helpers.toNumber({ type: sb.context.analysis.getType(this.left) }));
sb.emitHelper(this.left, options, sb.helpers.wrapNumber);
sb.emitOp(node, 'SWAP');
sb.emitHelper(node, options, sb.helpers.equalsEqualsEquals({
leftType: undefined,
leftKnownType: Types.Number,
rightType: undefined,
rightKnownType: Types.Number,
}));
}
equalsEqualsUnknown(sb, node, options) {
const copy = () => {
sb.emitOp(this.right, 'SWAP');
sb.emitOp(this.right, 'TUCK');
sb.emitOp(this.right, 'OVER');
};
sb.visit(this.left, options);
sb.visit(this.right, options);
const cases = [
{
condition: () => {
copy();
sb.emitHelper(node, options, sb.helpers.equalsEqualsEquals({
leftType: undefined,
rightType: undefined,
}));
},
whenTrue: () => {
sb.emitOp(node, 'DROP');
sb.emitOp(node, 'DROP');
sb.emitPushBoolean(node, true);
},
},
{
condition: () => {
copy();
sb.emitHelper(node, options, sb.helpers.isNullOrUndefined({ type: undefined }));
sb.emitOp(node, 'SWAP');
sb.emitHelper(node, options, sb.helpers.isNullOrUndefined({ type: undefined }));
sb.emitOp(node, 'BOOLOR');
},
whenTrue: () => {
sb.emitHelper(node, options, sb.helpers.isNullOrUndefined({ type: undefined }));
sb.emitOp(node, 'SWAP');
sb.emitHelper(node, options, sb.helpers.isNullOrUndefined({ type: undefined }));
sb.emitOp(node, 'EQUAL');
},
},
{
condition: () => {
copy();
sb.emitOp(node, 'DUP');
sb.emitHelper(this.right, options, sb.helpers.isString);
sb.emitOp(node, 'SWAP');
sb.emitHelper(this.right, options, sb.helpers.isBoolean);
sb.emitOp(node, 'BOOLOR');
sb.emitOp(node, 'SWAP');
sb.emitOp(node, 'DUP');
sb.emitHelper(this.right, options, sb.helpers.isNumber);
sb.emitOp(node, 'SWAP');
sb.emitHelper(this.right, options, sb.helpers.isBoolean);
sb.emitOp(node, 'BOOLOR');
sb.emitOp(node, 'BOOLAND');
},
whenTrue: () => {
sb.emitOp(node, 'SWAP');
sb.emitHelper(node, options, sb.helpers.toNumber({ type: sb.context.analysis.getType(this.left) }));
sb.emitHelper(node, options, sb.helpers.wrapNumber);
sb.emitOp(node, 'SWAP');
this.equalsEqualsLeftNumberRightBooleanOrString(sb, node, options);
},
},
{
condition: () => {
copy();
sb.emitOp(node, 'SWAP');
sb.emitOp(node, 'DUP');
sb.emitHelper(this.right, options, sb.helpers.isString);
sb.emitOp(node, 'SWAP');
sb.emitHelper(this.right, options, sb.helpers.isBoolean);
sb.emitOp(node, 'BOOLOR');
sb.emitOp(node, 'SWAP');
sb.emitOp(node, 'DUP');
sb.emitHelper(this.right, options, sb.helpers.isNumber);
sb.emitOp(node, 'SWAP');
sb.emitHelper(this.right, options, sb.helpers.isBoolean);
sb.emitOp(node, 'BOOLOR');
sb.emitOp(node, 'BOOLAND');
},
whenTrue: () => {
sb.emitHelper(node, options, sb.helpers.toNumber({ type: sb.context.analysis.getType(this.right) }));
sb.emitHelper(node, options, sb.helpers.wrapNumber);
this.equalsEqualsRightNumberLeftBooleanOrString(sb, node, options);
},
},
];
sb.emitHelper(node, options, sb.helpers.case(cases, () => {
sb.emitHelper(node, options, sb.helpers.toPrimitive({ type: sb.context.analysis.getType(this.right) }));
sb.emitOp(node, 'SWAP');
sb.emitHelper(node, options, sb.helpers.toPrimitive({ type: sb.context.analysis.getType(this.left) }));
sb.emitOp(node, 'SWAP');
sb.emitHelper(node, options, sb.helpers.case(cases, () => {
sb.emitOp(node, 'DROP');
sb.emitOp(node, 'DROP');
sb.emitPushBoolean(node, false);
}));
}));
}
}
//# sourceMappingURL=EqualsEqualsHelper.js.map