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