@neo-one/smart-contract-compiler-esnext-esm
Version:
NEO•ONE TypeScript smart contract compiler.
134 lines (132 loc) • 5.64 kB
JavaScript
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