UNPKG

@neo-one/smart-contract-compiler

Version:

NEO•ONE TypeScript smart contract compiler.

196 lines (194 loc) 9.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EqualsEqualsHelper = void 0; const ts_utils_1 = require("@neo-one/ts-utils"); const constants_1 = require("../../constants"); const Helper_1 = require("../Helper"); class EqualsEqualsHelper extends Helper_1.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 (ts_utils_1.tsUtils.type_.isOnly(leftType) && ts_utils_1.tsUtils.type_.isOnly(rightType) && ts_utils_1.tsUtils.type_.isSame(leftType, rightType)) { sb.emitHelper(node, options, sb.helpers.equalsEqualsEquals({ leftType, rightType })); } else if ((ts_utils_1.tsUtils.type_.hasNull(leftType) || ts_utils_1.tsUtils.type_.hasUndefined(leftType)) && (ts_utils_1.tsUtils.type_.isOnlyUndefined(rightType) || ts_utils_1.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 (ts_utils_1.tsUtils.type_.isOnlyNumberish(leftType) && (ts_utils_1.tsUtils.type_.isOnlyStringish(rightType) || ts_utils_1.tsUtils.type_.isOnlyBooleanish(rightType))) { sb.visit(this.left, options); sb.visit(this.right, options); this.equalsEqualsLeftNumberRightBooleanOrString(sb, node, options); } else if (ts_utils_1.tsUtils.type_.isOnlyBooleanish(leftType) && (ts_utils_1.tsUtils.type_.isOnlyStringish(rightType) || ts_utils_1.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 ((ts_utils_1.tsUtils.type_.isOnlyStringish(leftType) || ts_utils_1.tsUtils.type_.isOnlyBooleanish(leftType)) && ts_utils_1.tsUtils.type_.isOnlyNumberish(rightType)) { sb.visit(this.left, options); sb.visit(this.right, options); this.equalsEqualsRightNumberLeftBooleanOrString(sb, node, options); } else if ((ts_utils_1.tsUtils.type_.isOnlyStringish(leftType) || ts_utils_1.tsUtils.type_.isOnlyBooleanish(leftType)) && ts_utils_1.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: constants_1.Types.Number, rightType: undefined, rightKnownType: constants_1.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: constants_1.Types.Number, rightType: undefined, rightKnownType: constants_1.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); })); })); } } exports.EqualsEqualsHelper = EqualsEqualsHelper; //# sourceMappingURL=EqualsEqualsHelper.js.map