UNPKG

@neo-one/smart-contract-compiler

Version:

NEO•ONE TypeScript smart contract compiler.

151 lines (149 loc) 6.98 kB
import { tsUtils } from '@neo-one/ts-utils'; import _ from 'lodash'; import ts from 'typescript'; import { DiagnosticCode } from '../../../DiagnosticCode'; import { DiagnosticMessage } from '../../../DiagnosticMessage'; import { Types } from '../../constants'; import { Helper } from '../Helper'; import { getHasBuiltins } from '../types'; export class ArgumentsHelper extends Helper { emit(sb, node, optionsIn) { const options = sb.pushValueOptions(optionsIn); const args = ts.isArrayLiteralExpression(node) ? tsUtils.expression.getElements(node) : tsUtils.argumented.getArgumentsArray(node); if (!ts.isArrayLiteralExpression(node) && args.length > 0) { const signatureTypes = sb.context.analysis.extractSignaturesForCall(node, { error: true }); if (signatureTypes !== undefined) { args.forEach((arg, idx) => { const argType = sb.context.analysis.getType(arg); if (argType !== undefined) { const mismatch = signatureTypes.some(({ paramDecls, paramTypes }) => { const paramDecl = paramDecls[Math.min(idx, paramDecls.length - 1)]; let paramTypeIn = paramTypes.get(paramDecl); if (paramTypeIn !== undefined && tsUtils.parameter.isRestParameter(paramDecl)) { paramTypeIn = tsUtils.type_.getArrayType(paramTypeIn); } const paramType = paramTypeIn; const hasBuiltins = getHasBuiltins(sb.context, arg, argType); return (paramType === undefined || hasBuiltins.some((hasBuiltin) => !hasBuiltin(sb.context, paramDecl, paramType))); }); if (mismatch) { sb.context.reportError(arg, DiagnosticCode.InvalidBuiltinUsage, DiagnosticMessage.InvalidBuiltinCallArgument); } } }); } } if (args.some((arg) => ts.isSpreadElement(arg))) { sb.emitPushInt(node, 0); sb.emitOp(node, 'NEWARRAY'); args.forEach((arg) => { const handleArrayLike = () => { sb.emitOp(arg, 'TUCK'); sb.emitOp(arg, 'SWAP'); sb.emitOp(arg, 'APPEND'); }; const handleArray = (innerOptions) => { sb.emitHelper(arg, innerOptions, sb.helpers.unwrapArray); sb.emitOp(arg, 'SWAP'); sb.emitHelper(arg, innerOptions, sb.helpers.arrReduce({ each: handleArrayLike, })); }; const handleMapLike = (innerOption) => { sb.emitOp(arg, 'ROT'); sb.emitOp(arg, 'ROT'); sb.emitPushInt(arg, 2); sb.emitOp(arg, 'PACK'); sb.emitHelper(arg, innerOption, sb.helpers.wrapArray); sb.emitOp(arg, 'OVER'); sb.emitOp(arg, 'SWAP'); sb.emitOp(arg, 'APPEND'); }; const handleMap = (innerOptions) => { sb.emitHelper(arg, innerOptions, sb.helpers.unwrapMap); sb.emitOp(arg, 'SWAP'); sb.emitHelper(arg, innerOptions, sb.helpers.mapReduce({ deserializeKey: true, each: handleMapLike, })); }; const handleSetLike = () => { sb.emitOp(arg, 'ROT'); sb.emitOp(arg, 'DROP'); sb.emitOp(arg, 'TUCK'); sb.emitOp(arg, 'SWAP'); sb.emitOp(arg, 'APPEND'); }; const handleSet = (innerOptions) => { sb.emitHelper(arg, innerOptions, sb.helpers.unwrapSet); sb.emitOp(arg, 'SWAP'); sb.emitHelper(arg, innerOptions, sb.helpers.mapReduce({ deserializeKey: true, each: handleSetLike, })); }; const handleArrayStorage = (innerOptions) => { sb.emitOp(arg, 'SWAP'); sb.emitHelper(arg, innerOptions, sb.helpers.structuredStorageReduceVal({ type: Types.ArrayStorage, each: handleArrayLike, })); }; const handleMapStorage = (innerOptions) => { sb.emitOp(arg, 'SWAP'); sb.emitHelper(arg, innerOptions, sb.helpers.structuredStorageReduce({ type: Types.MapStorage, each: handleMapLike, })); }; const handleSetStorage = (innerOptions) => { sb.emitOp(arg, 'SWAP'); sb.emitHelper(arg, innerOptions, sb.helpers.structuredStorageReduce({ type: Types.SetStorage, each: handleSetLike, })); }; const handleIterableIterator = (innerOptions) => { sb.emitOp(arg, 'SWAP'); sb.emitHelper(arg, innerOptions, sb.helpers.iterableIteratorReduce({ each: handleArrayLike, })); }; if (ts.isSpreadElement(arg)) { const expr = tsUtils.expression.getExpression(arg); sb.visit(expr, options); sb.emitHelper(arg, options, sb.helpers.forIterableType({ type: sb.context.analysis.getType(expr), array: handleArray, map: handleMap, set: handleSet, arrayStorage: handleArrayStorage, mapStorage: handleMapStorage, setStorage: handleSetStorage, iterableIterator: handleIterableIterator, })); } else { sb.emitOp(node, 'DUP'); sb.visit(arg, options); sb.emitOp(node, 'APPEND'); } }); } else { const reversedElements = _.reverse([...args]); reversedElements.forEach((arg) => { sb.visit(arg, options); }); sb.emitPushInt(node, args.length); sb.emitOp(node, 'PACK'); } if (!optionsIn.pushValue) { sb.emitOp(node, 'DROP'); } } } //# sourceMappingURL=ArgumentsHelper.js.map