UNPKG

@neo-one/smart-contract-compiler

Version:

NEO•ONE TypeScript smart contract compiler.

192 lines (190 loc) 9.04 kB
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