@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
140 lines (138 loc) • 6.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SmartContractForBase = void 0;
const ts_utils_1 = require("@neo-one/ts-utils");
const utils_1 = require("@neo-one/utils");
const constants_1 = require("../../../constants");
const utils_2 = require("../../../utils");
const constants_2 = require("../../constants");
const BuiltinMemberCall_1 = require("../BuiltinMemberCall");
class SmartContractForBase extends BuiltinMemberCall_1.BuiltinMemberCall {
emitCall(sb, func, node, optionsIn) {
const options = sb.pushValueOptions(optionsIn);
const returnType = sb.context.analysis.getType(node);
if (returnType === undefined) {
return;
}
const properties = ts_utils_1.tsUtils.type_.getProperties(returnType);
const props = properties.map((prop) => {
const propType = sb.context.analysis.getTypeOfSymbol(prop, node);
if (propType === undefined) {
return undefined;
}
const propName = ts_utils_1.tsUtils.symbol.getName(prop);
if (constants_1.IGNORED_PROPERTIES.has(propName)) {
return undefined;
}
if (constants_1.BUILTIN_PROPERTIES.has(propName)) {
return undefined;
}
const propNode = ts_utils_1.tsUtils.symbol.getValueDeclarationOrThrow(prop);
if (ts_utils_1.tsUtils.modifier.isStatic(propNode) ||
ts_utils_1.tsUtils.modifier.isProtected(propNode) ||
ts_utils_1.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: ts_utils_1.tsUtils.modifier.isReadonly(propNode),
};
}
return Object.assign(Object.assign({}, 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 = ts_utils_1.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_1.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, utils_2.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: constants_2.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 && ts_utils_1.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: constants_2.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) {
}
}
exports.SmartContractForBase = SmartContractForBase;
//# sourceMappingURL=SmartContractForBase.js.map