@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
168 lines (166 loc) • 7.51 kB
JavaScript
import { tsUtils } from '@neo-one/ts-utils';
import ts from 'typescript';
import { ArrayEntries } from '../builtins/array/entries';
import { Types } from '../constants';
import { NodeCompiler } from '../NodeCompiler';
export class ForOfStatementCompiler extends NodeCompiler {
constructor() {
super(...arguments);
this.kind = ts.SyntaxKind.ForOfStatement;
}
visitNode(sb, node, optionsIn) {
const options = sb.pushValueOptions(optionsIn);
const initializer = tsUtils.statement.getInitializer(node);
if (!ts.isVariableDeclarationList(initializer)) {
sb.context.reportUnsupported(initializer);
return;
}
const variables = tsUtils.variable.getDeclarations(initializer);
if (variables.length !== 1) {
sb.context.reportUnsupported(initializer);
return;
}
const variable = variables[0];
const nameNode = tsUtils.node.getNameNode(variable);
const variableType = sb.context.analysis.getType(nameNode);
const expression = tsUtils.expression.getExpression(node);
const statement = tsUtils.statement.getStatement(node);
const each = (innerOptions) => {
if (ts.isIdentifier(nameNode)) {
sb.scope.add(tsUtils.node.getText(nameNode));
sb.scope.set(sb, nameNode, innerOptions, tsUtils.node.getText(nameNode));
}
else if (ts.isArrayBindingPattern(nameNode)) {
sb.emitHelper(nameNode, innerOptions, sb.helpers.arrayBinding({ type: variableType }));
}
else {
sb.emitHelper(nameNode, innerOptions, sb.helpers.objectBinding({ type: variableType }));
}
sb.visit(statement, sb.noPushValueOptions(innerOptions));
};
const handleOther = (innerOptions) => {
sb.emitOp(node, 'DROP');
sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError);
};
const handleArray = (innerOptions, withIndex = false, arrEach = each) => {
sb.emitHelper(expression, innerOptions, sb.helpers.unwrapArray);
sb.emitHelper(node, innerOptions, sb.helpers.arrForEach({
withIndex,
each: arrEach,
}));
};
const handleArrayStorage = (innerOptions) => {
sb.emitHelper(node, sb.noPushValueOptions(innerOptions), sb.helpers.forEachValStructuredStorage({
type: Types.ArrayStorage,
each,
}));
};
const handleMap = (innerOptions) => {
sb.emitHelper(expression, innerOptions, sb.helpers.unwrapMap);
sb.emitSysCall(expression, 'Neo.Iterator.Create');
sb.emitHelper(node, innerOptions, sb.helpers.rawIteratorForEach({
deserializeKey: true,
each: (innerInnerOptionsIn) => {
const innerInnerOptions = sb.pushValueOptions(innerInnerOptionsIn);
sb.emitPushInt(node, 2);
sb.emitOp(node, 'PACK');
sb.emitHelper(node, innerInnerOptions, sb.helpers.wrapArray);
each(innerInnerOptions);
},
}));
};
const handleMapStorage = (innerOptions) => {
sb.emitHelper(node, sb.noPushValueOptions(innerOptions), sb.helpers.forEachStructuredStorage({
type: Types.MapStorage,
each: (innerInnerOptionsIn) => {
const innerInnerOptions = sb.pushValueOptions(innerInnerOptionsIn);
sb.emitPushInt(node, 2);
sb.emitOp(node, 'PACK');
sb.emitHelper(node, innerInnerOptions, sb.helpers.wrapArray);
each(innerInnerOptions);
},
}));
};
const handleSet = (innerOptions) => {
sb.emitHelper(expression, innerOptions, sb.helpers.unwrapSet);
sb.emitSysCall(expression, 'Neo.Iterator.Create');
sb.emitHelper(node, innerOptions, sb.helpers.rawIteratorForEachKey({ each, deserializeKey: true }));
};
const handleSetStorage = (innerOptions) => {
sb.emitHelper(node, sb.noPushValueOptions(innerOptions), sb.helpers.forEachKeyStructuredStorage({
type: Types.SetStorage,
each,
}));
};
const handleIterableIterator = (innerOptions) => {
sb.emitHelper(node, sb.noPushValueOptions(innerOptions), sb.helpers.iterableIteratorForEach({
each,
}));
};
const handleIterable = (innerOptions) => {
sb.emitHelper(node, innerOptions, sb.helpers.forIterableType({
array: handleArray,
map: handleMap,
set: handleSet,
arrayStorage: handleArrayStorage,
mapStorage: handleMapStorage,
setStorage: handleSetStorage,
iterableIterator: handleIterableIterator,
defaultCase: handleOther,
}));
};
if (ts.isCallExpression(expression)) {
const valueExpression = tsUtils.expression.getExpression(expression);
if (ts.isPropertyAccessExpression(valueExpression)) {
const value = tsUtils.expression.getExpression(valueExpression);
const name = tsUtils.node.getNameNode(valueExpression);
const builtinProp = sb.context.builtins.getMember(value, name);
if (builtinProp !== undefined && builtinProp instanceof ArrayEntries) {
sb.visit(value, options);
handleArray(options, true, (innerOptions) => {
sb.emitOp(variable, 'SWAP');
sb.emitHelper(variable, sb.pushValueOptions(innerOptions), sb.helpers.wrapNumber);
sb.emitPushInt(variable, 2);
sb.emitOp(variable, 'PACK');
sb.emitHelper(variable, sb.pushValueOptions(innerOptions), sb.helpers.wrapArray);
each(innerOptions);
});
return;
}
}
}
sb.visit(expression, options);
sb.emitHelper(node, options, sb.helpers.forBuiltinType({
type: sb.context.analysis.getType(expression),
array: handleArray,
arrayStorage: handleArrayStorage,
boolean: handleOther,
buffer: handleOther,
null: handleOther,
number: handleOther,
object: handleOther,
string: handleOther,
symbol: handleOther,
undefined: handleOther,
map: handleMap,
mapStorage: handleMapStorage,
set: handleSet,
setStorage: handleSetStorage,
error: handleOther,
forwardValue: handleOther,
iteratorResult: handleOther,
iterable: handleIterable,
iterableIterator: handleIterableIterator,
transaction: handleOther,
output: handleOther,
attribute: handleOther,
input: handleOther,
account: handleOther,
asset: handleOther,
contract: handleOther,
header: handleOther,
block: handleOther,
}));
}
}
//# sourceMappingURL=ForOfStatementCompiler.js.map