@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
289 lines (287 loc) • 14.3 kB
JavaScript
;
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