@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
108 lines (106 loc) • 4.96 kB
JavaScript
import { tsUtils } from '@neo-one/ts-utils';
import { utils } from '@neo-one/utils';
import ts from 'typescript';
import * as constants from '../../constants';
import { NodeCompiler } from '../NodeCompiler';
export class TryStatementCompiler extends NodeCompiler {
constructor() {
super(...arguments);
this.kind = ts.SyntaxKind.TryStatement;
}
visitNode(sb, node, options) {
const catchClause = tsUtils.statement.getCatchClause(node);
const finallyBlock = tsUtils.statement.getFinallyBlock(node);
const pushFinally = () => {
if (finallyBlock !== undefined) {
sb.emitPushInt(node, constants.FINALLY_COMPLETION);
sb.emitPushInt(node, constants.FINALLY_COMPLETION);
sb.emitPushInt(node, constants.FINALLY_COMPLETION);
}
};
sb.withProgramCounter((finallyPC) => {
sb.withProgramCounter((catchPC) => {
let pcOptions = catchClause === undefined ? sb.noCatchPCOptions(options) : sb.catchPCOptions(options, catchPC.getLast());
pcOptions = finallyBlock === undefined ? pcOptions : sb.finallyPCOptions(pcOptions, finallyPC.getLast());
sb.visit(tsUtils.statement.getTryBlock(node), pcOptions);
pushFinally();
sb.emitJmp(node, 'JMP', finallyPC.getLast());
});
const finallyOptions = finallyBlock === undefined ? options : sb.finallyPCOptions(options, finallyPC.getLast());
if (catchClause !== undefined) {
const variable = tsUtils.statement.getOnlyVariableDeclaration(catchClause);
sb.emitOp(node, 'DROP');
if (variable === undefined) {
sb.emitOp(node, 'DROP');
sb.visit(tsUtils.statement.getBlock(catchClause), finallyOptions);
}
else {
sb.withScope(node, finallyOptions, (innerOptions) => {
sb.visit(variable, sb.setValueOptions(innerOptions));
sb.visit(tsUtils.statement.getBlock(catchClause), innerOptions);
});
}
pushFinally();
}
});
if (finallyBlock !== undefined) {
const completion = sb.scope.addUnique();
const val = sb.scope.addUnique();
sb.emitOp(finallyBlock, 'DROP');
sb.scope.set(sb, finallyBlock, options, completion);
sb.scope.set(sb, finallyBlock, options, val);
sb.visit(finallyBlock, options);
sb.scope.get(sb, finallyBlock, options, completion);
const condition = (value) => () => {
sb.emitOp(finallyBlock, 'DUP');
sb.emitPushInt(finallyBlock, value);
sb.emitOp(finallyBlock, 'NUMEQUAL');
};
sb.emitHelper(finallyBlock, options, sb.helpers.case([
{
condition: condition(constants.FINALLY_COMPLETION),
whenTrue: () => {
sb.emitOp(finallyBlock, 'DROP');
},
},
{
condition: condition(constants.THROW_COMPLETION),
whenTrue: () => {
sb.emitOp(finallyBlock, 'DROP');
sb.scope.get(sb, finallyBlock, options, val);
sb.emitHelper(finallyBlock, options, sb.helpers.throwCompletionBase);
},
},
{
condition: condition(constants.NORMAL_COMPLETION),
whenTrue: () => {
sb.emitOp(finallyBlock, 'DROP');
sb.scope.get(sb, finallyBlock, options, val);
sb.emitHelper(finallyBlock, options, sb.helpers.return);
},
},
options.breakPC === undefined
? undefined
: {
condition: condition(constants.BREAK_COMPLETION),
whenTrue: () => {
sb.emitOp(finallyBlock, 'DROP');
sb.emitHelper(finallyBlock, options, sb.helpers.break);
},
},
options.continuePC === undefined
? undefined
: {
condition: condition(constants.CONTINUE_COMPLETION),
whenTrue: () => {
sb.emitOp(finallyBlock, 'DROP');
sb.emitHelper(finallyBlock, options, sb.helpers.continue);
},
},
].filter(utils.notNull), () => {
sb.emitOp(finallyBlock, 'DROP');
}));
}
}
}
//# sourceMappingURL=TryStatementCompiler.js.map