UNPKG

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

Version:

NEO•ONE TypeScript smart contract compiler.

227 lines (225 loc) 11.5 kB
import { common } from '@neo-one/client-common-esnext-esm'; import { tsUtils } from '@neo-one/ts-utils-esnext-esm'; import _ from 'lodash'; import { Helper } from '../Helper'; import { isAddress, isHash256, isPublicKey } from './buffer'; import { isOnlyMap } from './map'; export class WrapValRecursiveHelper extends Helper { constructor(options) { super(); this.checkValue = options.checkValue === undefined ? false : options.checkValue; this.type = options.type; this.optional = options.optional; } emit(sb, node, options) { if (this.type === undefined) { return; } const createHandleValue = (hasValue, body) => (innerOptions) => { if (!innerOptions.pushValue) { if (hasValue) { sb.emitOp(node, 'DROP'); } return; } body(innerOptions); }; const handleUndefined = createHandleValue(false, (innerOptions) => { sb.emitOp(node, 'DROP'); sb.emitHelper(node, innerOptions, sb.helpers.wrapUndefined); }); const handleBoolean = createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapBoolean); }); const type = tsUtils.type_.getNonNullableType(this.type); sb.emitHelper(node, options, sb.helpers.forBuiltinType({ type: this.type, single: true, singleUndefined: handleUndefined, singleFalse: handleBoolean, optional: this.optional, array: createHandleValue(true, (innerOptions) => { const elements = tsUtils.type_.getTupleElements(type); if (elements === undefined) { sb.emitHelper(node, innerOptions, sb.helpers.arrMap({ map: (innerInnerOptions) => { sb.emitHelper(node, innerInnerOptions, sb.helpers.wrapValRecursive({ checkValue: this.checkValue, type: sb.context.analysis.getNotAnyType(node, tsUtils.type_.getArrayType(type)), })); }, })); } else { const tupleElements = elements.map((element) => { const constraintType = tsUtils.type_.getConstraint(element); return sb.context.analysis.getNotAnyType(node, constraintType === undefined ? element : constraintType); }); _.reverse([...tupleElements]).forEach((element, idx) => { sb.emitOp(node, 'DUP'); sb.emitPushInt(node, elements.length - idx - 1); sb.emitOp(node, 'PICKITEM'); sb.emitHelper(node, innerOptions, sb.helpers.wrapValRecursive({ checkValue: this.checkValue, type: element })); sb.emitOp(node, 'SWAP'); }); sb.emitOp(node, 'DROP'); sb.emitPushInt(node, elements.length); sb.emitOp(node, 'PACK'); } sb.emitHelper(node, innerOptions, sb.helpers.wrapArray); }), arrayStorage: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError); }), boolean: handleBoolean, buffer: createHandleValue(true, (innerOptions) => { if (this.checkValue && (isAddress(sb.context, node, type) || isHash256(sb.context, node, type) || isPublicKey(sb.context, node, type))) { sb.emitOp(node, 'DUP'); sb.emitOp(node, 'SIZE'); sb.emitHelper(node, innerOptions, sb.helpers.if({ condition: () => { const expectedSize = isAddress(sb.context, node, type) ? common.UINT160_BUFFER_BYTES : isHash256(sb.context, node, type) ? common.UINT256_BUFFER_BYTES : common.ECPOINT_BUFFER_BYTES; sb.emitPushInt(node, expectedSize); sb.emitOp(node, 'NUMEQUAL'); }, whenFalse: () => { sb.emitOp(node, 'DROP'); sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError); }, })); } sb.emitHelper(node, innerOptions, sb.helpers.wrapBuffer); }), null: createHandleValue(false, (innerOptions) => { sb.emitOp(node, 'DROP'); sb.emitHelper(node, innerOptions, sb.helpers.wrapNull); }), number: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapNumber); }), object: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, options, sb.helpers.createObject); tsUtils.type_.getProperties(type).forEach((prop) => { const propType = sb.context.analysis.getTypeOfSymbol(prop, node); sb.emitOp(node, 'TUCK'); sb.emitOp(node, 'OVER'); sb.emitPushString(node, tsUtils.symbol.getName(prop)); sb.emitOp(node, 'OVER'); sb.emitOp(node, 'OVER'); sb.emitHelper(node, innerOptions, sb.helpers.if({ condition: () => { sb.emitOp(node, 'HASKEY'); }, whenTrue: () => { sb.emitOp(node, 'PICKITEM'); sb.emitHelper(node, innerOptions, sb.helpers.wrapValRecursive({ type: propType })); }, whenFalse: () => { sb.emitOp(node, 'DROP'); sb.emitOp(node, 'DROP'); sb.emitHelper(node, innerOptions, sb.helpers.wrapUndefined); }, })); sb.emitPushString(node, tsUtils.symbol.getName(prop)); sb.emitOp(node, 'SWAP'); sb.emitHelper(node, innerOptions, sb.helpers.setDataPropertyObjectProperty); sb.emitOp(node, 'SWAP'); }); sb.emitOp(node, 'NIP'); }), string: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapString); }), symbol: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapSymbol); }), undefined: handleUndefined, map: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.mapMap({ map: (innerInnerOptions) => { let keyType; let valueType; if (isOnlyMap(sb.context, node, type)) { const localKeyType = tsUtils.type_.getTypeArgumentsArray(type)[0]; keyType = localKeyType === undefined ? undefined : sb.context.analysis.getNotAnyType(node, localKeyType); const localValueType = tsUtils.type_.getTypeArgumentsArray(type)[1]; valueType = localValueType === undefined ? undefined : sb.context.analysis.getNotAnyType(node, localValueType); } sb.emitHelper(node, innerInnerOptions, sb.helpers.wrapValRecursive({ checkValue: this.checkValue, type: keyType, })); sb.emitOp(node, 'SWAP'); sb.emitHelper(node, innerInnerOptions, sb.helpers.wrapValRecursive({ checkValue: this.checkValue, type: valueType, })); sb.emitOp(node, 'SWAP'); }, })); sb.emitHelper(node, innerOptions, sb.helpers.wrapMap); }), mapStorage: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError); }), set: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError); }), setStorage: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError); }), error: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError); }), forwardValue: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapForwardValue); }), iteratorResult: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError); }), iterable: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError); }), iterableIterator: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError); }), transaction: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapTransaction); }), output: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapOutput); }), attribute: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapAttribute); }), input: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapInput); }), account: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapAccount); }), asset: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapAsset); }), contract: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapContract); }), header: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapHeader); }), block: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapBlock); }), })); } } //# sourceMappingURL=WrapValRecursiveHelper.js.map