UNPKG

@neo-one/smart-contract-compiler

Version:

NEO•ONE TypeScript smart contract compiler.

136 lines (134 loc) 6.49 kB
import { tsUtils } from '@neo-one/ts-utils'; import { utils } from '@neo-one/utils'; import { BUILTIN_PROPERTIES, IGNORED_PROPERTIES } from '../../../constants'; import { getSetterName } from '../../../utils'; import { InternalObjectProperty } from '../../constants'; import { BuiltinMemberCall } from '../BuiltinMemberCall'; export class SmartContractForBase extends BuiltinMemberCall { emitCall(sb, func, node, optionsIn) { const options = sb.pushValueOptions(optionsIn); const returnType = sb.context.analysis.getType(node); if (returnType === undefined) { return; } const properties = tsUtils.type_.getProperties(returnType); const props = properties.map((prop) => { const propType = sb.context.analysis.getTypeOfSymbol(prop, node); if (propType === undefined) { return undefined; } const propName = tsUtils.symbol.getName(prop); if (IGNORED_PROPERTIES.has(propName)) { return undefined; } if (BUILTIN_PROPERTIES.has(propName)) { return undefined; } const propNode = tsUtils.symbol.getValueDeclarationOrThrow(prop); if (tsUtils.modifier.isStatic(propNode) || tsUtils.modifier.isProtected(propNode) || tsUtils.modifier.isPrivate(propNode)) { return undefined; } const result = sb.context.analysis.extractSignatureForType(propNode, propType, { error: true }); if (result === undefined) { return { paramDecls: [], paramTypes: new Map(), returnType: propType, prop: propNode, propName, accessor: true, isReadonly: tsUtils.modifier.isReadonly(propNode), }; } return { ...result, prop: propNode, propName, accessor: false, isReadonly: false }; }); const handleParams = (prop, paramDecls, paramTypes, innerOptions) => { sb.emitHelper(prop, innerOptions, sb.helpers.parameters({ params: paramDecls, asArgsArr: true, map: (param, innerInnerOptions, isRestElement) => { let type = paramTypes.get(param); if (type !== undefined && isRestElement) { type = tsUtils.type_.getArrayType(type); } sb.emitHelper(param, innerInnerOptions, sb.helpers.unwrapValRecursive({ type })); }, })); }; const addressName = sb.scope.addUnique(); this.emitInitial(sb, func, node, addressName, options); sb.emitHelper(node, options, sb.helpers.createObject); props .filter(utils.notNull) .forEach(({ prop, propName, paramDecls, paramTypes, returnType: propReturnType, accessor, isReadonly }) => { sb.emitOp(prop, 'DUP'); sb.emitPushString(prop, propName); if (accessor && !isReadonly) { sb.emitHelper(prop, options, sb.helpers.createFunctionArray({ body: (innerOptionsIn) => { const innerOptions = sb.pushValueOptions(innerOptionsIn); sb.emitPushInt(prop, 0); sb.emitOp(prop, 'PICKITEM'); sb.emitHelper(prop, innerOptions, sb.helpers.unwrapValRecursive({ type: propReturnType })); sb.emitPushInt(prop, 1); sb.emitOp(prop, 'PACK'); sb.emitPushString(prop, getSetterName(propName)); const callBuffer = Buffer.from([0, 2]); this.emitInvoke(sb, func, node, prop, addressName, callBuffer, sb.noPushValueOptions(innerOptions)); sb.emitHelper(prop, innerOptions, sb.helpers.wrapUndefined); sb.emitHelper(prop, innerOptions, sb.helpers.return); }, })); sb.emitHelper(prop, options, sb.helpers.createFunctionObject({ property: InternalObjectProperty.Call, })); } sb.emitHelper(prop, options, sb.helpers.createFunctionArray({ body: (innerOptionsIn) => { const innerOptions = sb.pushValueOptions(innerOptionsIn); if (accessor) { sb.emitOp(prop, 'DROP'); sb.emitPushInt(prop, 0); sb.emitOp(prop, 'NEWARRAY'); } else { handleParams(prop, paramDecls, paramTypes, innerOptions); } sb.emitPushString(prop, propName); const isVoidReturn = propReturnType !== undefined && tsUtils.type_.isVoid(propReturnType); const callBuffer = Buffer.from([isVoidReturn ? 0 : 1, 2]); this.emitInvoke(sb, func, node, prop, addressName, callBuffer, innerOptions); if (isVoidReturn) { sb.emitHelper(prop, innerOptions, sb.helpers.wrapUndefined); } else { sb.emitHelper(prop, innerOptions, sb.helpers.wrapValRecursive({ type: propReturnType, })); } sb.emitHelper(prop, innerOptions, sb.helpers.return); }, })); sb.emitHelper(prop, options, sb.helpers.createFunctionObject({ property: InternalObjectProperty.Call, })); if (accessor) { sb.emitHelper(prop, options, sb.helpers.setAccessorPropertyObjectProperty({ hasGet: true, hasSet: !isReadonly })); } else { sb.emitHelper(prop, options, sb.helpers.setDataPropertyObjectProperty); } }); this.emitAdditionalProperties(sb, func, node, options); if (!optionsIn.pushValue) { sb.emitOp(node, 'DROP'); } } emitInitial(_sb, _func, _node, _addressName, _options) { } emitAdditionalProperties(_sb, _func, _node, _options) { } } //# sourceMappingURL=SmartContractForBase.js.map