Обратное отслеживание по стеку
Интерпретация сообщений об ошибках
В ответ на выполнение сценария в MAXScript формируются сообщения об ошибках, помогающие определить вид ошибки и место ее возникновения. Примеры сообщений об ошибках уже приводились в предыдущем разделе, посвященном видам ошибок, в частности следующее сообщение:
for i = 1 to 10 print i
-- Syntax error: at end, expected "do" or "collect"
В этом сообщении указывается, что синтаксическая ошибка произошла в конце сценария, где предполагалось обнаружить зарезервированное слово do или collect.
А теперь рассмотрим пример сообщения об ошибке периода выполнения:
arr = #(1); arr[0]
-- Runtime error: array index must be +ve number, got: 0
В этом сообщении указывается, что ошибка времени выполнения возникла в связи с тем, что индекс массива должен быть положительным целым числом, которое больше нуля, однако он оказался равным нулю.
Приложение
Далее рассмотрим пример ошибки времени компиляции:
(
y = (1/(х as float)
)
-- Compile error: Unexpected end-of-script
В этом сообщении указывается, что произошла ошибка времени компиляции. В частности, обнаружено неожиданное окончание сценария. Это произошло из-за пропуска круглой скобки в строке line y = (1/(х as float).
Системное исключение Unknown указывает на серьезную ошибку, которая может привести к нарушению устойчивой работы 3dsMax.
Сообщения об ошибках помогают отнюдь не всегда и могут даже ввести в заблуждение. Ведь сообщение об ошибке — это всего лишь попытка MAXScript распознать и обнаружить ошибку. Решению этой задачи препятствуют присущие данному процессу ограничения. Иногда MAXScript просто не в состоянии правильно распознать и обнаружить ошибку. Поэтому сообщение об ошибке может быть неопределенным, а место ошибки — указанным неверно. Но несмотря на подобные ограничения, сообщения об ошибках являются важным элементом отладки сценариев.
Сообщения об ошибках появляются в приемнике команд, а иногда и в перемещаемом диалоговом окне предупреждения. Текст сообщения в приемнике команд включает в себя информацию из окна предупреждения, а также результаты обратного отслеживания по стеку. В таком стеке отслеживается вся предыстория вызовов функций, обработчиков ошибок и выполнения циклов, включая ошибки, к которым это привело. Подобные сведения приводятся в обратном порядке по отношению к происходившим событиям, причем самое последнее из них находится в начале отслеживаемой предыстории. Помимо этого, выводятся локальные переменные, параметры функций и их значения. Тщательный анализ подобной информации позволяет выявить подозрительные переменные и определить место возникновения ошибки.
Ниже приведен пример сценария, выполнение которого приводит к ошибке и появлению окна предупреждения вместе с результатами обратного отслеживания по стеку. В данном сценарии создается простое окно с единственной кнопкой. В обработчике событий данной кнопки вызывается простая функция, воспринимающая один параметр. Эта функция содержит цикл, индекс которого умножается на параметр функции и неопределенную локальную переменную. Именно эта переменная дает ошибку.
Откройте приемник команд и выполните приведенный ниже сценарий в окне редактора MAXScript Editor. Щелкните на кнопке Click Me (Щелкни на мне).
fn testFunction n = (
for i = 1 to 10 do x = i * n * undefinedLocalVariable
)
try destroyDialog rol_test catch()
rollout rol_test "Test"
(
Приложение
button but_test "Click Me!"
on but_test pressed do
(
clearListener()
testFunction 123
)
)
createDialog rol_test
После того как вы щелкнете на кнопке ClickMe, появится приведенное ниже предупреждающее окно, в котором указывается ошибка несовместимости типов данных.
Эта ошибка возникла из-за того, что обработчик событий кнопки вызвал функцию и передал ей числовое значение 123 в качестве параметра. Затем в цикле данной функции была предпринята попытка умножить неопределенную переменную на 123.
Ниже приведены результаты обратного отслеживания по стеку, выводимые в окне приемника команд. В этом окне красным выделено место возникновения ошибки и само сообщение об ошибке, а синим, выделены параметры и локальные переменные с соответствующими значениями.
-- Error occurred in i loop
-- Frame:
-- undefinedLocalVariable: undefined
-- i: 1
-- x: undefined
-- called in testFunction()
-- Frame:
-- n: 123
-- called in but_test.pressed()
-- Frame:
>> MAXScript Rollout Handler Exception:
-- Incompatible types: 123, and undefined <<
Предыстория выполнения сценария отображается в обратном порядке. В первой строке указывается, что ошибка произошла в цикле. В строках, которые следуют после строки "Frame", перечислены локальные переменные цикла и их значения (обратите внимание на то, что индекс цикла i считается локальной переменной). В связи с тем что i = 1, ошибка возникла на первом же шаге цикла. Затем в предыстории указывается на то, что ошибка произошла в функции. В информации под заголовком "Frame" также перечисляются параметр функции и его значение. И наконец, обратите внимание, что ошибка началась с обработчика событий кнопки, а в последней строке содержатся заголовок предупреждающего окна и сообщение об ошибке.
Приложение
Кроме того, курсор помещается рядом с ошибочной строкой кода. В данном случае он находится рядом с закрывающей круглой скобкой, следующей сразу же после цикла, в котором произошла ошибка. Иногда MAXScript не в состоянии точно определить ошибочную строку кода, но, как правило, результат оказывается достаточно близким к истине, чтобы начать отладку кода сценария.
Обратное отслеживание по стеку может показаться поначалу не очень удобным средством обнаружения ошибок, хотя оно не очень сложное. В то же время оно дает немало важной и полезной информации для отладки. Если уделить немного времени, чтобы научиться правильно интерпретировать обратно отслеживаемую предысторию, это позволит значительно упростить отладку сценариев.