@Override
    StatementResult execute0(ScriptScope scope) throws SynsException {
        try {
            StatementResult tryResult = synTryStatement.execute(scope);
            return tryResult;
        } catch (ThrowSynsException e) {
            //Exception thrown by a script "throw" statement. The original exception must be
            //passed to the catch block, but if there is no catch block, the wrapped exception has
            //to be thrown.
            return handleException(scope, e.getCause(), e);
        } catch (SynsException e) {
            //Script runtime exception. Has to be passed to the catch block directly, and thrown,
            //if there is no catch block.
            return handleException(scope, e, e);
        } catch (RuntimeException | Error e) {
            //Arbitrary Java exception. To be passed to the catch block directly, but if there is no
            //one, a new wrapped exception has to be thrown.
            return handleException(scope, e, new SynsException(e));
        } finally {
            //Execute the finally statement.
            if (synFinallyStatement != null) {
                StatementResult finallyResult = synFinallyStatement.execute(scope);
                if (finallyResult.isReturn() || finallyResult.isBreak() || finallyResult.isContinue()) {
                    //If the finally statement finished with a break, continue or return, the
                    //whole try-catch statement have to finish in the same way, overriding the
                    //result of the try and catch blocks. E. g. if the try statement finishes with
                    //return, but finally statement finishes with break, the result of the
                    //try-catch-finally statement will be break, not return.
                    return finallyResult;
                }
            }
        }
    }