@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
296 lines (294 loc) • 15.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ObjectBindingHelper = 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 DiagnosticCode_1 = require("../../../DiagnosticCode");
const DiagnosticMessage_1 = require("../../../DiagnosticMessage");
const builtins_1 = require("../../builtins");
const types_1 = require("../types");
class ObjectBindingHelper extends types_1.TypedHelper {
constructor(options) {
super(options);
this.value = options.value;
}
emit(sb, node, optionsIn) {
const restElement = node.elements.find((element) => ts_utils_1.tsUtils.node.getDotDotDotToken(element) !== undefined);
const elements = restElement === undefined ? [...node.elements] : node.elements.slice(0, -1);
const throwTypeError = (innerOptions) => {
sb.emitOp(node, 'DROP');
sb.emitHelper(node, innerOptions, sb.helpers.throwTypeError);
};
const throwInnerTypeError = (innerOptions) => {
sb.emitOp(node, 'DROP');
throwTypeError(innerOptions);
};
const handleBuiltin = (member, element, innerOptions) => {
if (builtins_1.isBuiltinInstanceMemberValue(member)) {
member.emitValue(sb, element, innerOptions, true);
return;
}
if (builtins_1.isBuiltinMemberValue(member)) {
member.emitValue(sb, element, innerOptions);
return;
}
sb.context.reportError(element, DiagnosticCode_1.DiagnosticCode.InvalidBuiltinReference, DiagnosticMessage_1.DiagnosticMessage.CannotReferenceBuiltinProperty);
};
const createProcessBuiltin = (builtinName, isBuiltinValue = false) => (innerOptions) => {
if (restElement !== undefined) {
sb.context.reportUnsupportedEfficiency(restElement);
}
elements.forEach((element) => {
const nameNode = ts_utils_1.tsUtils.node.getNameNode(element);
const propertyName = ts_utils_1.tsUtils.node.getPropertyNameNode(element);
const initializer = ts_utils_1.tsUtils.initializer.getInitializer(element);
const elementType = sb.context.analysis.getType(nameNode);
if (typescript_1.default.isIdentifier(nameNode)) {
sb.scope.add(ts_utils_1.tsUtils.node.getText(nameNode));
}
if (!isBuiltinValue) {
sb.emitOp(element, 'DUP');
}
if (propertyName === undefined ||
typescript_1.default.isIdentifier(propertyName) ||
typescript_1.default.isStringLiteral(propertyName) ||
typescript_1.default.isNumericLiteral(propertyName)) {
const memberName = propertyName === undefined
? ts_utils_1.tsUtils.node.getNameOrThrow(element)
: typescript_1.default.isIdentifier(propertyName)
? ts_utils_1.tsUtils.node.getText(propertyName)
: typescript_1.default.isStringLiteral(propertyName)
? ts_utils_1.tsUtils.literal.getLiteralValue(propertyName)
: `${ts_utils_1.tsUtils.literal.getLiteralValue(propertyName)}`;
const member = sb.context.builtins.getOnlyMember(builtinName, memberName);
if (member === undefined) {
throwInnerTypeError(innerOptions);
}
else {
handleBuiltin(member, element, innerOptions);
}
}
else {
sb.context.reportUnsupported(element);
}
if (initializer !== undefined) {
sb.emitHelper(node, innerOptions, sb.helpers.if({
condition: () => {
sb.emitOp(node, 'DUP');
sb.emitHelper(node, innerOptions, sb.helpers.isUndefined);
},
whenTrue: () => {
sb.emitOp(node, 'DROP');
sb.visit(initializer, innerOptions);
},
}));
}
if (typescript_1.default.isIdentifier(nameNode)) {
sb.scope.set(sb, element, innerOptions, ts_utils_1.tsUtils.node.getText(nameNode));
}
else if (typescript_1.default.isArrayBindingPattern(nameNode)) {
sb.emitHelper(nameNode, innerOptions, sb.helpers.arrayBinding({ type: elementType }));
}
else {
sb.emitHelper(nameNode, innerOptions, sb.helpers.objectBinding({ type: elementType }));
}
});
if (!isBuiltinValue) {
sb.emitOp(node, 'DROP');
}
};
const processObject = (innerOptions) => {
let addSymbolProp = () => {
};
let addStringProp = () => {
};
if (restElement !== undefined) {
sb.emitPushInt(node, 0);
sb.emitOp(node, 'NEWARRAY');
sb.emitPushInt(node, 0);
sb.emitOp(node, 'NEWARRAY');
sb.emitOp(node, 'ROT');
addSymbolProp = () => {
sb.emitPushInt(restElement, 4);
sb.emitOp(restElement, 'PICK');
sb.emitOp(node, 'OVER');
sb.emitOp(node, 'APPEND');
};
addStringProp = () => {
sb.emitPushInt(restElement, 3);
sb.emitOp(restElement, 'PICK');
sb.emitOp(node, 'OVER');
sb.emitOp(node, 'APPEND');
};
}
elements.forEach((element) => {
const nameNode = ts_utils_1.tsUtils.node.getNameNode(element);
const propertyName = ts_utils_1.tsUtils.node.getPropertyNameNode(element);
const initializer = ts_utils_1.tsUtils.initializer.getInitializer(element);
const elementType = sb.context.analysis.getType(nameNode);
if (typescript_1.default.isIdentifier(nameNode)) {
sb.scope.add(ts_utils_1.tsUtils.node.getText(nameNode));
}
sb.emitOp(element, 'DUP');
if (propertyName === undefined) {
sb.emitPushString(element, ts_utils_1.tsUtils.node.getNameOrThrow(element));
addStringProp();
sb.emitHelper(element, innerOptions, sb.helpers.getPropertyObjectProperty);
}
else if (typescript_1.default.isIdentifier(propertyName)) {
sb.emitPushString(element, ts_utils_1.tsUtils.node.getText(propertyName));
addStringProp();
sb.emitHelper(element, innerOptions, sb.helpers.getPropertyObjectProperty);
}
else if (typescript_1.default.isComputedPropertyName(propertyName)) {
const expr = ts_utils_1.tsUtils.expression.getExpression(propertyName);
const propertyNameType = sb.context.analysis.getType(expr);
sb.visit(expr, innerOptions);
const handleSymbol = () => {
sb.emitHelper(element, innerOptions, sb.helpers.unwrapSymbol);
addSymbolProp();
sb.emitHelper(element, innerOptions, sb.helpers.getSymbolObjectProperty);
};
const handleStringBase = (innerInnerOptions) => {
addStringProp();
sb.emitHelper(element, innerInnerOptions, sb.helpers.getPropertyObjectProperty);
};
const handleString = (innerInnerOptions) => {
sb.emitHelper(node, innerInnerOptions, sb.helpers.unwrapString);
handleStringBase(innerInnerOptions);
};
const handleNumber = (innerInnerOptions) => {
sb.emitHelper(node, innerInnerOptions, sb.helpers.toString({ type: propertyNameType }));
handleStringBase(innerInnerOptions);
};
sb.emitHelper(element, innerOptions, sb.helpers.forBuiltinType({
type: propertyNameType,
array: throwInnerTypeError,
arrayStorage: throwInnerTypeError,
boolean: throwInnerTypeError,
buffer: throwInnerTypeError,
null: throwInnerTypeError,
number: handleNumber,
object: throwInnerTypeError,
string: handleString,
symbol: handleSymbol,
undefined: throwInnerTypeError,
map: throwInnerTypeError,
mapStorage: throwInnerTypeError,
set: throwInnerTypeError,
setStorage: throwInnerTypeError,
error: throwInnerTypeError,
forwardValue: throwInnerTypeError,
iteratorResult: throwInnerTypeError,
iterable: throwInnerTypeError,
iterableIterator: throwInnerTypeError,
transaction: throwInnerTypeError,
output: throwInnerTypeError,
attribute: throwInnerTypeError,
input: throwInnerTypeError,
account: throwInnerTypeError,
asset: throwInnerTypeError,
contract: throwInnerTypeError,
header: throwInnerTypeError,
block: throwInnerTypeError,
}));
}
else {
sb.emitPushString(propertyName, typescript_1.default.isStringLiteral(propertyName)
? ts_utils_1.tsUtils.literal.getLiteralValue(propertyName)
: `${ts_utils_1.tsUtils.literal.getLiteralValue(propertyName)}`);
addStringProp();
sb.emitHelper(element, innerOptions, sb.helpers.getPropertyObjectProperty);
}
if (initializer !== undefined) {
sb.emitHelper(node, innerOptions, sb.helpers.if({
condition: () => {
sb.emitOp(node, 'DUP');
sb.emitHelper(node, innerOptions, sb.helpers.isUndefined);
},
whenTrue: () => {
sb.emitOp(node, 'DROP');
sb.visit(initializer, innerOptions);
},
}));
}
if (typescript_1.default.isIdentifier(nameNode)) {
sb.scope.set(sb, element, innerOptions, ts_utils_1.tsUtils.node.getText(nameNode));
}
else if (typescript_1.default.isArrayBindingPattern(nameNode)) {
sb.emitHelper(nameNode, innerOptions, sb.helpers.arrayBinding({ type: elementType }));
}
else {
sb.emitHelper(nameNode, innerOptions, sb.helpers.objectBinding({ type: elementType }));
}
});
if (restElement === undefined) {
sb.emitOp(node, 'DROP');
}
else {
const name = ts_utils_1.tsUtils.node.getNameOrThrow(restElement);
sb.scope.add(name);
sb.emitOp(node, 'NEWMAP');
sb.emitOp(node, 'SWAP');
sb.emitOp(node, 'DUP');
sb.emitHelper(node, innerOptions, sb.helpers.getSymbolObject);
sb.emitOp(node, 'SWAP');
sb.emitHelper(node, innerOptions, sb.helpers.getPropertyObject);
sb.emitPushInt(node, 3);
sb.emitHelper(node, innerOptions, sb.helpers.packObject);
sb.emitPushInt(node, 3);
sb.emitOp(node, 'XTUCK');
sb.emitOp(restElement, 'ROT');
sb.emitOp(restElement, 'ROT');
sb.emitHelper(restElement, innerOptions, sb.helpers.omitObjectProperties);
sb.scope.set(sb, restElement, innerOptions, name);
}
};
const options = sb.pushValueOptions(optionsIn);
if (this.value !== undefined) {
const builtinInterface = sb.context.builtins.getValueInterface(this.value);
if (builtinInterface === undefined) {
sb.visit(this.value, options);
}
else {
createProcessBuiltin(builtinInterface, true)(options);
return;
}
}
sb.emitHelper(node, options, sb.helpers.forBuiltinType({
type: this.type,
knownType: this.knownType,
array: createProcessBuiltin('Array'),
arrayStorage: createProcessBuiltin('ArrayStorage'),
boolean: createProcessBuiltin('Boolean'),
buffer: createProcessBuiltin('Buffer'),
null: throwTypeError,
number: createProcessBuiltin('Number'),
object: processObject,
string: createProcessBuiltin('String'),
symbol: createProcessBuiltin('Symbol'),
undefined: throwTypeError,
map: createProcessBuiltin('Map'),
mapStorage: createProcessBuiltin('MapStorage'),
set: createProcessBuiltin('Set'),
setStorage: createProcessBuiltin('SetStorage'),
error: createProcessBuiltin('Error'),
forwardValue: createProcessBuiltin('ForwardValue'),
iteratorResult: createProcessBuiltin('IteratorResult'),
iterable: createProcessBuiltin('Iterable'),
iterableIterator: createProcessBuiltin('IterableIterator'),
transaction: createProcessBuiltin('TransactionBase'),
output: createProcessBuiltin('Output'),
attribute: createProcessBuiltin('AttributeBase'),
input: createProcessBuiltin('Input'),
account: createProcessBuiltin('Account'),
asset: createProcessBuiltin('Asset'),
contract: createProcessBuiltin('Contract'),
header: createProcessBuiltin('Header'),
block: createProcessBuiltin('Block'),
}));
}
}
exports.ObjectBindingHelper = ObjectBindingHelper;
//# sourceMappingURL=ObjectBindingHelper.js.map