@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
151 lines (149 loc) • 6.98 kB
JavaScript
import { tsUtils } from '@neo-one/ts-utils';
import _ from 'lodash';
import ts from 'typescript';
import { DiagnosticCode } from '../../../DiagnosticCode';
import { DiagnosticMessage } from '../../../DiagnosticMessage';
import { Types } from '../../constants';
import { Helper } from '../Helper';
import { getHasBuiltins } from '../types';
export class ArgumentsHelper extends Helper {
emit(sb, node, optionsIn) {
const options = sb.pushValueOptions(optionsIn);
const args = ts.isArrayLiteralExpression(node)
? tsUtils.expression.getElements(node)
: tsUtils.argumented.getArgumentsArray(node);
if (!ts.isArrayLiteralExpression(node) && args.length > 0) {
const signatureTypes = sb.context.analysis.extractSignaturesForCall(node, { error: true });
if (signatureTypes !== undefined) {
args.forEach((arg, idx) => {
const argType = sb.context.analysis.getType(arg);
if (argType !== undefined) {
const mismatch = signatureTypes.some(({ paramDecls, paramTypes }) => {
const paramDecl = paramDecls[Math.min(idx, paramDecls.length - 1)];
let paramTypeIn = paramTypes.get(paramDecl);
if (paramTypeIn !== undefined && tsUtils.parameter.isRestParameter(paramDecl)) {
paramTypeIn = tsUtils.type_.getArrayType(paramTypeIn);
}
const paramType = paramTypeIn;
const hasBuiltins = getHasBuiltins(sb.context, arg, argType);
return (paramType === undefined ||
hasBuiltins.some((hasBuiltin) => !hasBuiltin(sb.context, paramDecl, paramType)));
});
if (mismatch) {
sb.context.reportError(arg, DiagnosticCode.InvalidBuiltinUsage, DiagnosticMessage.InvalidBuiltinCallArgument);
}
}
});
}
}
if (args.some((arg) => ts.isSpreadElement(arg))) {
sb.emitPushInt(node, 0);
sb.emitOp(node, 'NEWARRAY');
args.forEach((arg) => {
const handleArrayLike = () => {
sb.emitOp(arg, 'TUCK');
sb.emitOp(arg, 'SWAP');
sb.emitOp(arg, 'APPEND');
};
const handleArray = (innerOptions) => {
sb.emitHelper(arg, innerOptions, sb.helpers.unwrapArray);
sb.emitOp(arg, 'SWAP');
sb.emitHelper(arg, innerOptions, sb.helpers.arrReduce({
each: handleArrayLike,
}));
};
const handleMapLike = (innerOption) => {
sb.emitOp(arg, 'ROT');
sb.emitOp(arg, 'ROT');
sb.emitPushInt(arg, 2);
sb.emitOp(arg, 'PACK');
sb.emitHelper(arg, innerOption, sb.helpers.wrapArray);
sb.emitOp(arg, 'OVER');
sb.emitOp(arg, 'SWAP');
sb.emitOp(arg, 'APPEND');
};
const handleMap = (innerOptions) => {
sb.emitHelper(arg, innerOptions, sb.helpers.unwrapMap);
sb.emitOp(arg, 'SWAP');
sb.emitHelper(arg, innerOptions, sb.helpers.mapReduce({
deserializeKey: true,
each: handleMapLike,
}));
};
const handleSetLike = () => {
sb.emitOp(arg, 'ROT');
sb.emitOp(arg, 'DROP');
sb.emitOp(arg, 'TUCK');
sb.emitOp(arg, 'SWAP');
sb.emitOp(arg, 'APPEND');
};
const handleSet = (innerOptions) => {
sb.emitHelper(arg, innerOptions, sb.helpers.unwrapSet);
sb.emitOp(arg, 'SWAP');
sb.emitHelper(arg, innerOptions, sb.helpers.mapReduce({
deserializeKey: true,
each: handleSetLike,
}));
};
const handleArrayStorage = (innerOptions) => {
sb.emitOp(arg, 'SWAP');
sb.emitHelper(arg, innerOptions, sb.helpers.structuredStorageReduceVal({
type: Types.ArrayStorage,
each: handleArrayLike,
}));
};
const handleMapStorage = (innerOptions) => {
sb.emitOp(arg, 'SWAP');
sb.emitHelper(arg, innerOptions, sb.helpers.structuredStorageReduce({
type: Types.MapStorage,
each: handleMapLike,
}));
};
const handleSetStorage = (innerOptions) => {
sb.emitOp(arg, 'SWAP');
sb.emitHelper(arg, innerOptions, sb.helpers.structuredStorageReduce({
type: Types.SetStorage,
each: handleSetLike,
}));
};
const handleIterableIterator = (innerOptions) => {
sb.emitOp(arg, 'SWAP');
sb.emitHelper(arg, innerOptions, sb.helpers.iterableIteratorReduce({
each: handleArrayLike,
}));
};
if (ts.isSpreadElement(arg)) {
const expr = tsUtils.expression.getExpression(arg);
sb.visit(expr, options);
sb.emitHelper(arg, options, sb.helpers.forIterableType({
type: sb.context.analysis.getType(expr),
array: handleArray,
map: handleMap,
set: handleSet,
arrayStorage: handleArrayStorage,
mapStorage: handleMapStorage,
setStorage: handleSetStorage,
iterableIterator: handleIterableIterator,
}));
}
else {
sb.emitOp(node, 'DUP');
sb.visit(arg, options);
sb.emitOp(node, 'APPEND');
}
});
}
else {
const reversedElements = _.reverse([...args]);
reversedElements.forEach((arg) => {
sb.visit(arg, options);
});
sb.emitPushInt(node, args.length);
sb.emitOp(node, 'PACK');
}
if (!optionsIn.pushValue) {
sb.emitOp(node, 'DROP');
}
}
}
//# sourceMappingURL=ArgumentsHelper.js.map