открыть: Синтаксис 2Syntax 1

Обработка исключений

Пока не реализовано в интерпретаторе.

Механизм исключений позволяет, чтобы исключение могло быть брошено в одной функции, а поймано в другой функции (или в блоке `plain), где происходит вызов первой функции. Или может быть сложная цепочка вызовов. Непойманное исключение в ksi является ошибкой и прекращает работу программы.

Специальный тип данных

Исключения хранятся в объекте класса $exception, который имеет следующий вид:

-- Псевдокод $exception ~ fn -- Указатель на функцию, откуда было брошено исключение module -- Указатель на модуль, из которого было брошено исключение line -- Номер строки, откуда было брошено исключение column -- Номер колонки trace -- Вся цепочка вызовов функций (массив или null) value -- Брошенное значение msg -- Сообщение (message) `static need_trace -- Если true, то поле trace будет заполнено при бросании исключения ;

Если статическое поле need_trace равно true #1, то поле trace будет заполнено массивом при бросании исключения. А иначе trace будет null #. Значение по-умолчанию статического поля need_trace равно false #0.

`plain -- Нам нужен trace $exception.need_trace = #1

Как бросать исключения

Чтобы бросить исключение используется оператор `throw, котоый формирует объект класса $exception.

n = 100 n > 10 ? n `throw 'Переменная n больше десяти.' ;

Выражение слева от `throw – это бросаемое значение, а справа – текст сообщения. Бросаемое значение попадает в поле value, а сообщение – в поле msg.

Обычно сообщение (поле msg) имеет тип $text, однако в ksi нет жёстких ограничений, и это может быть любое значение (например null #).

Как ловить исключения

Для ловли исключений используется конструкция `try.

`try e ~ /* Проверяемый фрагмент программы, потенциально бросающий исключение. */ 1 `throw 'Ошибка!' \ $int: ~ -- Блок catch, перегруженный для бросаемого значения, имеющего тип $int e.msg `echo ' e.value = ', e.value; -- выдаст: Ошибка! e.value = 1 ;

`try e ~ означает, что если исключение брошено и найден соответствующий блок catch, то переменная e в качестве значения примет объект типа $exception, заполненный при вызове оператора `throw.

Перегрузка блоков catch работает по принципу перегрузки функций. И статическая перегрузка тоже допустима.

`try e ~ $int `throw # \ $int ~ -- Блок catch, статически перегруженный для бросаемого значения, равного $int 'Вы бросили $int' `echo; ;

Чтобы назначить блок catch для любых бросаемых значений – тип не указывается.

`try e ~ # `throw # \ ~ -- Блок catch, перегруженный для любого бросаемого значения. 'Исключение поймано.' `echo ' Оно было брошено на строке: ', e.line; ;

Конструкция `try может содержать несколько блоков catch. Кроме того один блок catch может быть перегружен для разных типов бросаемого значения.

`try e ~ -- Проверяемый фрагмент \ $int: \ $float: ~ -- Обработка исключения 1 \ $null \ $null: ~ -- Обработка исключения 2 \ ~ -- Обработка исключения 3 ;

Рассмотрим пример, где исключение может быть брошено из функции &at, а поймано в блоке `plain.

&at $array: items index ~ -- Проверка типа и диапазона index #is_not $int `or index < 0 `or index >= items #count # ? index `throw 'Ошибка: index лежит за границами массива.' ; ret = items[index] ; `plain `try e ~ [0 1 2] &at 3 `echo; \ $int: ~ -- Блок catch, перегруженный для бросаемого значения, имеющего тип $int e #dump #1 ;

Возможный результат работы:

$exception{ %fn : &at& %module : @1 %line : 4 %column : 9 %trace : # %value : 3 %msg : "Ошибка: index лежит за границами массива." }

Блоки `try могут быть вложены и исключение, непойманное во внутреннем блоке будет передано внешнему блоку `try. Кроме того исключение может быть брошено из блока catch.

Блок try как часть большего выражения

Блок `try возвращает значение типа $bool в зависимости от того было ли исключение брошено и поймано. Если да, то блок `try вернёт true #1, иначе false #0.

was_catch = `try v ~ 'Привет.' `echo; \ ~ 'Ошибка!' `echo; ; "\n" `echo 'was_catch = '; was_catch #dump #0 -- выдаст: #0