UNPKG

@neo-one/smart-contract-compiler-esnext-esm

Version:

NEO•ONE TypeScript smart contract compiler.

134 lines (132 loc) 5.64 kB
import { tsUtils } from '@neo-one/ts-utils-esnext-esm'; import _ from 'lodash'; import { DiagnosticCode } from '../../../DiagnosticCode'; import { DiagnosticMessage } from '../../../DiagnosticMessage'; import { Helper } from '../Helper'; import { hasBooleanFalse, isBooleanFalse } from './boolean'; import { hasUndefined } from './undefined'; export class ForTypeHelper extends Helper { constructor({ type, types, single, singleUndefined, singleFalse, defaultCase, optional = false, }) { super(); this.type = type; this.types = types; this.single = single === undefined ? false : single; this.singleUndefined = singleUndefined; this.singleFalse = singleFalse; this.optional = optional; this.defaultCase = defaultCase; } emit(sb, node, optionsIn) { const noCastOptions = sb.noCastOptions(optionsIn); const options = sb.pushValueOptions(sb.noCastOptions(optionsIn)); let typeIn = this.type === undefined ? optionsIn.cast : this.type; let checkUndefinedSingle = false; let checkFalseSingle = false; if (typeIn !== undefined && this.single && (this.optional || hasUndefined(sb.context, node, typeIn)) && this.singleUndefined !== undefined) { typeIn = tsUtils.type_.getNonNullableType(typeIn); checkUndefinedSingle = true; } if (typeIn !== undefined && this.single && hasBooleanFalse(sb.context, node, typeIn) && this.singleFalse !== undefined) { typeIn = tsUtils.type_.filterUnion(sb.context.typeChecker, typeIn, (tpe) => !isBooleanFalse(sb.context, node, tpe)); checkFalseSingle = true; } const type = typeIn; const types = type === undefined ? this.types : this.types.filter((testType) => testType.hasType(type)); const groupedTypes = new Map(); for (const forType of types) { const mutableTypes = groupedTypes.get(forType.process); if (mutableTypes === undefined) { groupedTypes.set(forType.process, [forType]); } else { mutableTypes.push(forType); } } let defaultCase = this.defaultCase === undefined ? (innerOptions) => { sb.emitOp(node, 'DROP'); sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError); } : this.defaultCase; if (this.single && (types.length !== 1 || (checkUndefinedSingle && checkFalseSingle))) { sb.context.reportError(node, DiagnosticCode.UnknownType, DiagnosticMessage.ResolveOneType); return; } if (types.length === 0) { defaultCase(noCastOptions); } else if (groupedTypes.size === 1) { const singleUndefined = this.singleUndefined; const singleFalse = this.singleFalse; if (checkUndefinedSingle && singleUndefined !== undefined) { sb.emitHelper(node, options, sb.helpers.if({ condition: () => { sb.emitOp(node, 'DUP'); sb.emitOp(node, 'SIZE'); sb.emitPushInt(node, 0); sb.emitOp(node, 'NUMEQUAL'); }, whenTrue: () => { singleUndefined(options); }, whenFalse: () => { types[0].process(noCastOptions); }, })); } else if (checkFalseSingle && singleFalse !== undefined) { sb.emitHelper(node, options, sb.helpers.if({ condition: () => { sb.emitOp(node, 'DUP'); sb.emitOp(node, 'SIZE'); sb.emitPushInt(node, 0); sb.emitOp(node, 'NUMEQUAL'); }, whenTrue: () => { singleFalse(options); }, whenFalse: () => { types[0].process(noCastOptions); }, })); } else { types[0].process(noCastOptions); } } else { const groupedTypesOrdered = _.sortBy([...groupedTypes.entries()], [(value) => value[1].length]); let caseTypes = groupedTypesOrdered; if (this.defaultCase === undefined) { caseTypes = groupedTypesOrdered.slice(0, -1); defaultCase = (innerOptions) => { const [processType] = groupedTypesOrdered[groupedTypesOrdered.length - 1]; processType(innerOptions); }; } sb.emitHelper(node, options, sb.helpers.case(caseTypes.map(([processType, forTypes]) => ({ condition: () => { sb.emitOp(node, 'DUP'); forTypes[0].isRuntimeType(options); forTypes.slice(1).forEach((forType) => { sb.emitOp(node, 'OVER'); forType.isRuntimeType(options); sb.emitOp(node, 'BOOLOR'); }); }, whenTrue: () => { processType(noCastOptions); }, })), () => { defaultCase(noCastOptions); })); } } } //# sourceMappingURL=ForTypeHelper.js.map