@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
117 lines (115 loc) • 5.33 kB
JavaScript
import { tsUtils } from '@neo-one/ts-utils';
import ts from 'typescript';
import { DiagnosticCode } from '../../DiagnosticCode';
import { DiagnosticMessage } from '../../DiagnosticMessage';
import { isBuiltinInstanceMemberValue, isBuiltinMemberValue } from '../builtins';
import { NodeCompiler } from '../NodeCompiler';
export class PropertyAccessExpressionCompiler extends NodeCompiler {
constructor() {
super(...arguments);
this.kind = ts.SyntaxKind.PropertyAccessExpression;
}
visitNode(sb, expr, optionsIn) {
const isOptionalChain = ts.isOptionalChain(expr);
const value = tsUtils.expression.getExpression(expr);
const valueType = sb.context.analysis.getType(value);
const name = tsUtils.node.getNameNode(expr);
const nameValue = tsUtils.node.getName(expr);
const handleBuiltin = (member, visited) => {
if (isBuiltinInstanceMemberValue(member)) {
member.emitValue(sb, expr, optionsIn, visited);
return;
}
if (isBuiltinMemberValue(member)) {
member.emitValue(sb, expr, optionsIn);
return;
}
if (optionsIn.setValue) {
sb.context.reportError(name, DiagnosticCode.InvalidBuiltinModify, DiagnosticMessage.CannotModifyBuiltin);
}
else {
sb.context.reportError(name, DiagnosticCode.InvalidBuiltinReference, DiagnosticMessage.CannotReferenceBuiltinProperty);
}
};
const builtin = sb.context.builtins.getMember(value, name);
if (builtin !== undefined) {
handleBuiltin(builtin, false);
return;
}
const throwTypeError = (innerOptions) => {
sb.emitOp(expr, 'DROP');
sb.emitHelper(expr, innerOptions, sb.helpers.throwTypeError);
};
const processUndefined = (innerOptions) => {
sb.emitOp(expr, 'DROP');
sb.emitHelper(expr, innerOptions, sb.helpers.wrapUndefined);
};
const throwTypeErrorUnlessOptionalChain = (innerOptions) => {
isOptionalChain ? processUndefined(innerOptions) : throwTypeError(innerOptions);
};
const createProcessBuiltin = (valueName) => {
const member = sb.context.builtins.getOnlyMember(valueName, nameValue);
if (member === undefined) {
return throwTypeError;
}
return () => {
handleBuiltin(member, true);
};
};
const processObject = (innerOptions) => {
sb.emitPushString(name, nameValue);
if (optionsIn.pushValue && optionsIn.setValue) {
sb.emitOp(expr, 'OVER');
sb.emitOp(expr, 'OVER');
sb.emitPushInt(expr, 4);
sb.emitOp(expr, 'ROLL');
sb.emitHelper(expr, innerOptions, sb.helpers.setPropertyObjectProperty);
sb.emitHelper(expr, innerOptions, sb.helpers.getPropertyObjectProperty);
}
else if (optionsIn.setValue) {
sb.emitOp(expr, 'ROT');
sb.emitHelper(expr, innerOptions, sb.helpers.setPropertyObjectProperty);
}
else {
sb.emitHelper(expr, innerOptions, sb.helpers.getPropertyObjectProperty);
if (!optionsIn.pushValue) {
sb.emitOp(expr, 'DROP');
}
}
};
const options = sb.pushValueOptions(sb.noSetValueOptions(optionsIn));
sb.visit(value, options);
sb.emitHelper(value, options, sb.helpers.forBuiltinType({
type: valueType,
array: createProcessBuiltin('Array'),
arrayStorage: createProcessBuiltin('ArrayStorage'),
boolean: createProcessBuiltin('Boolean'),
buffer: createProcessBuiltin('Buffer'),
null: throwTypeErrorUnlessOptionalChain,
number: createProcessBuiltin('Number'),
object: processObject,
string: createProcessBuiltin('String'),
symbol: createProcessBuiltin('Symbol'),
undefined: throwTypeErrorUnlessOptionalChain,
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'),
}));
}
}
//# sourceMappingURL=PropertyAccessExpressionCompiler.js.map