UNPKG

@neo-one/smart-contract-compiler

Version:

NEO•ONE TypeScript smart contract compiler.

289 lines (287 loc) 14.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ClassDeclarationCompiler = 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 constants_1 = require("../constants"); const NodeCompiler_1 = require("../NodeCompiler"); class ClassDeclarationCompiler extends NodeCompiler_1.NodeCompiler { constructor() { super(...arguments); this.kind = typescript_1.default.SyntaxKind.ClassDeclaration; } visitNode(sb, decl, optionsIn) { if (sb.context.analysis.isSmartContract(decl)) { return; } let options = sb.pushValueOptions(sb.noSuperClassOptions(optionsIn)); const name = sb.scope.add(ts_utils_1.tsUtils.node.getNameOrThrow(decl)); const extendsExpr = ts_utils_1.tsUtils.class_.getExtends(decl); let superClassIn; if (extendsExpr !== undefined) { superClassIn = sb.scope.addUnique(); options = sb.superClassOptions(options, superClassIn); sb.visit(ts_utils_1.tsUtils.expression.getExpression(extendsExpr), options); sb.scope.set(sb, extendsExpr, options, superClassIn); } const superClass = superClassIn; const switchProperty = (node, innerOptions, handleString, handleSymbol) => { const nameNode = ts_utils_1.tsUtils.node.getNameNode(node); if (typescript_1.default.isComputedPropertyName(nameNode)) { const expr = ts_utils_1.tsUtils.expression.getExpression(nameNode); const throwTypeError = (innerInnerOptions) => { sb.emitOp(node, 'DROP'); sb.emitHelper(node, innerInnerOptions, sb.helpers.throwTypeError); }; const processString = (innerInnerOptions) => { sb.emitHelper(node, innerInnerOptions, sb.helpers.unwrapString); handleString(innerInnerOptions); }; const processSymbol = (innerInnerOptions) => { sb.emitHelper(node, innerInnerOptions, sb.helpers.unwrapSymbol); handleSymbol(innerInnerOptions); }; sb.visit(expr, sb.pushValueOptions(innerOptions)); sb.emitHelper(expr, innerOptions, sb.helpers.forBuiltinType({ type: sb.context.analysis.getType(expr), array: throwTypeError, arrayStorage: throwTypeError, boolean: throwTypeError, buffer: throwTypeError, null: throwTypeError, number: throwTypeError, object: throwTypeError, string: processString, symbol: processSymbol, undefined: throwTypeError, map: throwTypeError, mapStorage: throwTypeError, set: throwTypeError, setStorage: throwTypeError, error: throwTypeError, forwardValue: throwTypeError, iteratorResult: throwTypeError, iterable: throwTypeError, iterableIterator: throwTypeError, transaction: throwTypeError, output: throwTypeError, attribute: throwTypeError, input: throwTypeError, account: throwTypeError, asset: throwTypeError, contract: throwTypeError, header: throwTypeError, block: throwTypeError, })); } else { sb.emitPushString(node, ts_utils_1.tsUtils.node.getName(node)); handleString(innerOptions); } }; const addProperty = (property, innerOptions) => { const initializer = ts_utils_1.tsUtils.initializer.getInitializer(property); const propNode = initializer === undefined ? property : initializer; sb.emitOp(propNode, 'DUP'); switchProperty(property, innerOptions, (innerInnerOptions) => { if (initializer === undefined) { sb.emitHelper(propNode, sb.pushValueOptions(innerInnerOptions), sb.helpers.wrapUndefined); } else { sb.visit(initializer, sb.pushValueOptions(innerInnerOptions)); } sb.emitHelper(propNode, innerOptions, sb.helpers.setDataPropertyObjectProperty); }, (innerInnerOptions) => { if (initializer === undefined) { sb.emitHelper(propNode, sb.pushValueOptions(innerInnerOptions), sb.helpers.wrapUndefined); } else { sb.visit(initializer, sb.pushValueOptions(innerInnerOptions)); } sb.emitHelper(propNode, innerOptions, sb.helpers.setDataSymbolObjectProperty); }); }; sb.emitHelper(decl, options, sb.helpers.createConstructArray({ withScope: true, body: (innerOptionsIn) => { const innerOptions = sb.pushValueOptions(innerOptionsIn); const ctorImpl = ts_utils_1.tsUtils.class_.getConcreteConstructor(decl); const ctorNode = ctorImpl === undefined ? decl : ctorImpl; if (ctorImpl !== undefined) { sb.emitHelper(ctorImpl, innerOptions, sb.helpers.parameters({ params: ts_utils_1.tsUtils.parametered.getParameters(ctorImpl) })); } else if (superClass !== undefined && extendsExpr !== undefined) { sb.scope.getThis(sb, extendsExpr, innerOptions); sb.scope.get(sb, extendsExpr, innerOptions, superClass); sb.emitHelper(extendsExpr, sb.noPushValueOptions(innerOptions), sb.helpers.invokeConstruct()); } else { sb.emitOp(decl, 'DROP'); } sb.scope.getThis(sb, ctorNode, innerOptions); ts_utils_1.tsUtils.class_ .getConcreteInstanceProperties(decl) .filter(typescript_1.default.isPropertyDeclaration) .forEach((property) => { addProperty(property, innerOptions); }); sb.emitOp(ctorNode, 'DROP'); if (ctorImpl !== undefined) { sb.visit(ts_utils_1.tsUtils.body.getBodyOrThrow(ctorImpl), sb.noPushValueOptions(innerOptions)); } }, })); sb.emitHelper(decl, options, sb.helpers.createFunctionObject({ property: constants_1.InternalObjectProperty.Construct, })); sb.emitOp(decl, 'DUP'); sb.emitPushString(decl, 'prototype'); sb.emitOp(decl, 'OVER'); sb.emitHelper(decl, options, sb.helpers.createObject); sb.emitOp(decl, 'TUCK'); sb.emitPushString(decl, 'constructor'); sb.emitOp(decl, 'ROT'); sb.emitHelper(decl, options, sb.helpers.setDataPropertyObjectProperty); const addMethod = (method) => { const visit = (innerOptions) => { sb.emitHelper(method, innerOptions, sb.helpers.createCallArray); sb.emitHelper(method, innerOptions, sb.helpers.createFunctionObject({ property: constants_1.InternalObjectProperty.Call, })); }; sb.emitOp(method, 'DUP'); switchProperty(method, options, (innerOptions) => { visit(innerOptions); sb.emitHelper(method, innerOptions, sb.helpers.setDataPropertyObjectProperty); }, (innerOptions) => { visit(innerOptions); sb.emitHelper(method, innerOptions, sb.helpers.setDataSymbolObjectProperty); }); }; ts_utils_1.tsUtils.class_.getConcreteInstanceMethods(decl).forEach((method) => { addMethod(method); }); ts_utils_1.tsUtils.class_.getConcreteMembers(decl).forEach((member) => { const decorators = ts_utils_1.tsUtils.decoratable.getDecoratorsArray(member); if (decorators.length > 0) { sb.context.reportError(decorators[0], DiagnosticCode_1.DiagnosticCode.UnsupportedSyntax, DiagnosticMessage_1.DiagnosticMessage.UnsupportedDecorator); } }); const addSetAccessor = (accessor) => { const visit = (innerOptions) => { sb.emitHelper(accessor, innerOptions, sb.helpers.createCallArray); sb.emitHelper(accessor, innerOptions, sb.helpers.createFunctionObject({ property: constants_1.InternalObjectProperty.Call, })); const getAccessor = ts_utils_1.tsUtils.accessor.getGetAccessor(accessor); const hasGet = getAccessor !== undefined; if (getAccessor !== undefined) { sb.emitHelper(getAccessor, innerOptions, sb.helpers.createCallArray); sb.emitHelper(getAccessor, innerOptions, sb.helpers.createFunctionObject({ property: constants_1.InternalObjectProperty.Call, })); } return hasGet; }; sb.emitOp(accessor, 'DUP'); switchProperty(accessor, options, (innerOptions) => { const hasGet = visit(innerOptions); sb.emitHelper(accessor, options, sb.helpers.setAccessorPropertyObjectProperty({ hasSet: true, hasGet, })); }, (innerOptions) => { const hasGet = visit(innerOptions); sb.emitHelper(accessor, options, sb.helpers.setAccessorSymbolObjectProperty({ hasSet: true, hasGet, })); }); }; ts_utils_1.tsUtils.class_ .getConcreteInstanceMembers(decl) .filter(typescript_1.default.isSetAccessor) .forEach((accessor) => { addSetAccessor(accessor); }); const addGetAccessor = (accessor) => { const visit = (innerOptions) => { sb.emitHelper(accessor, innerOptions, sb.helpers.createCallArray); sb.emitHelper(accessor, innerOptions, sb.helpers.createFunctionObject({ property: constants_1.InternalObjectProperty.Call, })); }; sb.emitOp(accessor, 'DUP'); switchProperty(accessor, options, (innerOptions) => { visit(innerOptions); sb.emitHelper(accessor, options, sb.helpers.setAccessorPropertyObjectProperty({ hasSet: false, hasGet: true, })); }, (innerOptions) => { visit(innerOptions); sb.emitHelper(accessor, options, sb.helpers.setAccessorSymbolObjectProperty({ hasSet: false, hasGet: true, })); }); }; ts_utils_1.tsUtils.class_ .getConcreteInstanceMembers(decl) .filter(typescript_1.default.isGetAccessor) .filter((accessor) => ts_utils_1.tsUtils.accessor.getSetAccessor(accessor) === undefined) .forEach((accessor) => { addGetAccessor(accessor); }); if (superClass !== undefined && extendsExpr !== undefined) { sb.emitOp(extendsExpr, 'DUP'); sb.emitPushString(extendsExpr, '__proto__'); sb.scope.get(sb, extendsExpr, options, superClass); sb.emitPushString(extendsExpr, 'prototype'); sb.emitHelper(extendsExpr, options, sb.helpers.getPropertyObjectProperty); sb.emitHelper(extendsExpr, options, sb.helpers.setDataPropertyObjectProperty); } sb.emitHelper(decl, options, sb.helpers.setDataPropertyObjectProperty); ts_utils_1.tsUtils.class_ .getConcreteStaticProperties(decl) .filter(typescript_1.default.isPropertyDeclaration) .forEach((property) => { addProperty(property, options); }); ts_utils_1.tsUtils.class_.getConcreteStaticMethods(decl).forEach((method) => { addMethod(method); }); ts_utils_1.tsUtils.class_ .getConcreteStaticMembers(decl) .filter(typescript_1.default.isSetAccessor) .forEach((accessor) => { addSetAccessor(accessor); }); ts_utils_1.tsUtils.class_ .getConcreteStaticMembers(decl) .filter(typescript_1.default.isGetAccessor) .filter((accessor) => ts_utils_1.tsUtils.accessor.getSetAccessor(accessor) === undefined) .forEach((accessor) => { addGetAccessor(accessor); }); if (superClass !== undefined && extendsExpr !== undefined) { sb.emitOp(extendsExpr, 'DUP'); sb.emitPushString(extendsExpr, '__proto__'); sb.scope.get(sb, extendsExpr, options, superClass); sb.emitHelper(extendsExpr, options, sb.helpers.setDataPropertyObjectProperty); } if (ts_utils_1.tsUtils.modifier.isNamedExport(decl) || ts_utils_1.tsUtils.modifier.isDefaultExport(decl)) { sb.emitOp(decl, 'DUP'); sb.emitHelper(decl, options, sb.helpers.exportSingle({ name: ts_utils_1.tsUtils.modifier.isNamedExport(decl) ? ts_utils_1.tsUtils.node.getNameOrThrow(decl) : undefined, defaultExport: ts_utils_1.tsUtils.modifier.isDefaultExport(decl), })); } sb.scope.set(sb, decl, options, name); } } exports.ClassDeclarationCompiler = ClassDeclarationCompiler; //# sourceMappingURL=ClassDeclarationCompiler.js.map