@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
145 lines (143 loc) • 6.4 kB
JavaScript
import { tsUtils } from '@neo-one/ts-utils';
import ts from 'typescript';
import { TypedHelper } from '../types';
export class ArrayBindingHelper extends TypedHelper {
constructor(options) {
super(options);
this.value = options.value;
}
emit(sb, node, optionsIn) {
const options = sb.pushValueOptions(optionsIn);
const restElement = node.elements.find((element) => tsUtils.node.getDotDotDotToken(element) !== undefined);
const elements = restElement === undefined ? [...node.elements] : node.elements.slice(0, -1);
const handleCommon = (setup, getNext, getRemaining) => (innerOptions) => {
setup(innerOptions);
elements.forEach((element, idx) => {
if (ts.isOmittedExpression(element)) {
return;
}
const name = tsUtils.node.getNameNode(element);
const initializer = tsUtils.initializer.getInitializer(element);
const elementType = sb.context.analysis.getType(name);
if (ts.isIdentifier(name)) {
sb.scope.add(tsUtils.node.getText(name));
}
sb.emitOp(element, 'DUP');
getNext(element, innerOptions, idx);
if (initializer !== undefined) {
sb.emitHelper(node, options, sb.helpers.if({
condition: () => {
sb.emitOp(node, 'DUP');
sb.emitHelper(node, options, sb.helpers.isUndefined);
},
whenTrue: () => {
sb.emitOp(node, 'DROP');
sb.visit(initializer, options);
},
}));
}
if (ts.isIdentifier(name)) {
sb.scope.set(sb, node, options, tsUtils.node.getText(name));
}
else if (ts.isArrayBindingPattern(name)) {
sb.emitHelper(name, options, sb.helpers.arrayBinding({ type: elementType }));
}
else {
sb.emitHelper(name, options, sb.helpers.objectBinding({ type: elementType }));
}
});
if (restElement === undefined) {
sb.emitOp(node, 'DROP');
}
else {
sb.scope.add(tsUtils.node.getNameOrThrow(restElement));
getRemaining(restElement, innerOptions);
sb.emitHelper(node, options, sb.helpers.wrapArray);
sb.scope.set(sb, node, options, tsUtils.node.getNameOrThrow(restElement));
}
};
const handleArray = handleCommon(() => {
}, (element, innerOptions, idx) => {
sb.emitPushInt(element, idx);
sb.emitHelper(element, innerOptions, sb.helpers.getArrayIndex);
}, (element, innerOptions) => {
sb.emitHelper(element, innerOptions, sb.helpers.unwrapArray);
sb.emitPushInt(element, elements.length);
sb.emitHelper(element, innerOptions, sb.helpers.arrSlice({ hasEnd: false }));
});
const handleMapLike = (element) => (innerOption) => {
sb.emitOp(element, 'ROT');
sb.emitOp(element, 'ROT');
sb.emitPushInt(element, 2);
sb.emitOp(element, 'PACK');
sb.emitHelper(element, innerOption, sb.helpers.wrapArray);
sb.emitOp(element, 'OVER');
sb.emitOp(element, 'SWAP');
sb.emitOp(element, 'APPEND');
};
const handleMap = handleCommon((innerOptions) => {
sb.emitHelper(node, innerOptions, sb.helpers.unwrapMap);
sb.emitSysCall(node, 'Neo.Iterator.Create');
}, (element, innerOptions) => {
sb.emitOp(element, 'DUP');
sb.emitSysCall(element, 'Neo.Enumerator.Next');
sb.emitOp(element, 'DROP');
sb.emitOp(element, 'DUP');
sb.emitSysCall(element, 'Neo.Enumerator.Value');
sb.emitOp(element, 'SWAP');
sb.emitSysCall(element, 'Neo.Iterator.Key');
sb.emitSysCall(element, 'Neo.Runtime.Deserialize');
sb.emitPushInt(element, 2);
sb.emitOp(element, 'PACK');
sb.emitHelper(element, innerOptions, sb.helpers.wrapArray);
}, (element, innerOptions) => {
sb.emitPushInt(element, 0);
sb.emitOp(element, 'NEWARRAY');
sb.emitHelper(element, innerOptions, sb.helpers.rawIteratorReduce({
deserializeKey: true,
each: handleMapLike(element),
}));
});
const handleSetLike = (element) => () => {
sb.emitOp(element, 'ROT');
sb.emitOp(element, 'DROP');
sb.emitOp(element, 'TUCK');
sb.emitOp(element, 'SWAP');
sb.emitOp(element, 'APPEND');
};
const handleSet = handleCommon((innerOptions) => {
sb.emitHelper(node, innerOptions, sb.helpers.unwrapSet);
sb.emitSysCall(node, 'Neo.Iterator.Create');
}, (element) => {
sb.emitOp(element, 'DUP');
sb.emitSysCall(element, 'Neo.Enumerator.Next');
sb.emitOp(element, 'DROP');
sb.emitSysCall(element, 'Neo.Iterator.Key');
sb.emitSysCall(element, 'Neo.Runtime.Deserialize');
}, (element, innerOptions) => {
sb.emitPushInt(element, 0);
sb.emitOp(element, 'NEWARRAY');
sb.emitHelper(element, innerOptions, sb.helpers.rawIteratorReduce({
deserializeKey: true,
each: handleSetLike(element),
}));
});
const handleUnsupported = () => {
sb.context.reportUnsupported(node);
};
if (this.value !== undefined) {
sb.visit(this.value, options);
}
sb.emitHelper(node, options, sb.helpers.forIterableType({
type: this.type,
array: handleArray,
map: handleMap,
set: handleSet,
arrayStorage: handleUnsupported,
mapStorage: handleUnsupported,
setStorage: handleUnsupported,
iterableIterator: handleUnsupported,
}));
}
}
//# sourceMappingURL=ArrayBindingHelper.js.map