@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
173 lines (171 loc) • 8.05 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ForOfStatementCompiler = void 0;
const tslib_1 = require("tslib");
const ts_utils_1 = require("@neo-one/ts-utils");
const typescript_1 = tslib_1.__importDefault(require("typescript"));
const entries_1 = require("../builtins/array/entries");
const constants_1 = require("../constants");
const NodeCompiler_1 = require("../NodeCompiler");
class ForOfStatementCompiler extends NodeCompiler_1.NodeCompiler {
constructor() {
super(...arguments);
this.kind = typescript_1.default.SyntaxKind.ForOfStatement;
}
visitNode(sb, node, optionsIn) {
const options = sb.pushValueOptions(optionsIn);
const initializer = ts_utils_1.tsUtils.statement.getInitializer(node);
if (!typescript_1.default.isVariableDeclarationList(initializer)) {
sb.context.reportUnsupported(initializer);
return;
}
const variables = ts_utils_1.tsUtils.variable.getDeclarations(initializer);
if (variables.length !== 1) {
sb.context.reportUnsupported(initializer);
return;
}
const variable = variables[0];
const nameNode = ts_utils_1.tsUtils.node.getNameNode(variable);
const variableType = sb.context.analysis.getType(nameNode);
const expression = ts_utils_1.tsUtils.expression.getExpression(node);
const statement = ts_utils_1.tsUtils.statement.getStatement(node);
const each = (innerOptions) => {
if (typescript_1.default.isIdentifier(nameNode)) {
sb.scope.add(ts_utils_1.tsUtils.node.getText(nameNode));
sb.scope.set(sb, nameNode, innerOptions, ts_utils_1.tsUtils.node.getText(nameNode));
}
else if (typescript_1.default.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: constants_1.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: constants_1.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: constants_1.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 (typescript_1.default.isCallExpression(expression)) {
const valueExpression = ts_utils_1.tsUtils.expression.getExpression(expression);
if (typescript_1.default.isPropertyAccessExpression(valueExpression)) {
const value = ts_utils_1.tsUtils.expression.getExpression(valueExpression);
const name = ts_utils_1.tsUtils.node.getNameNode(valueExpression);
const builtinProp = sb.context.builtins.getMember(value, name);
if (builtinProp !== undefined && builtinProp instanceof entries_1.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,
}));
}
}
exports.ForOfStatementCompiler = ForOfStatementCompiler;
//# sourceMappingURL=ForOfStatementCompiler.js.map