При разработке гибких систем согласования, обработок данных и настраиваемых бизнес-процессов разработчики часто сохраняют исполняемый программный код в базе данных (например, в строковых реквизитах справочников) и запускают его с помощью встроенной процедуры Выполнить(). Однако во время исполнения такого динамического кода платформа может выдать исключение: «Ошибка компиляции при вычислении выражения или выполнении фрагмента кода: {(строка, позиция)}: Ожидается символ...».
Разберем природу возникновения этой ошибки, выясним, как правильно интерпретировать координаты сбоя и как локализовать и устранить неполадку.
Посмотрим на типичный пример вызова динамического алгоритма:
ПараметрыВыполненияКода = Новый Структура("СсылкаДокумента, НовоеСостояниеДокумента, СтатусОбработкиДокумента");
ПараметрыВыполненияКода.СсылкаДокумента = СтрокаТабличнойЧасти.Ссылка;
ПараметрыВыполненияКода.НовоеСостояниеДокумента = НовоеСостояниеТекущегоДокумента;
ПараметрыВыполненияКода.СтатусОбработкиДокумента = "";
Выполнить(КодПостОбработки);
Если во время вызова возникает ошибка вида {(37,96)}: Ожидается символ ')', важно понимать, что указанные координаты (37-я строка, 96-й символ) относятся не к тексту вызывающего модуля формы или общего модуля, а непосредственно к содержимому строковой переменной КодПостОбработки.
Часто разработчик сверяет текст в конфигураторе или тестовом модуле и не находит синтаксических ошибок, поскольку в саму переменную КодПостОбработки был передан другой фрагмент (например, неотредактированная версия алгоритма из другого элемента справочника или устаревший шаблон).
Проанализируем распространенные причины, приводящие к ошибкам компиляции при динамическом исполнении:
) или пропущенных точек с запятой ;.160 вместо стандартного пробела 32), которые платформа 1С воспринимает как синтаксическую ошибку.Выполнить(), запрещено объявлять процедуры и функции (конструкции Процедура ... КонецПроцедуры), а также использовать директивы препроцессора (#Если, #Иначе, #КонецЕсли)."" внутри строковых литералов).Разберем по шагам, как быстро обнаружить точное место сбоя в динамическом фрагменте.
{(37,96)} с реальным кодом, используем объект ТекстовыйДокумент:
ТекстДляПроверки = Новый ТекстовыйДокумент;
ТекстДляПроверки.УстановитьТекст(КодПостОбработки);
// Проверяем строку под номером 37
СтрокаСОшибкой = ТекстДляПроверки.ПолучитьСтроку(37);
Сообщить("Проблемная строка: " + СтрокаСОшибкой);
Попытка ... Исключение с получением подробного описания через ИнформацияОбОшибке():
Попытка
Выполнить(КодПостОбработки);
Исключение
Инфо = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации(
"ДинамическийКод.Ошибка",
УровеньЖурналаРегистрации.Ошибка,,,
"Ошибка: " + Инфо.Описание + Символы.ПС + "Исходный код: " + Символы.ПС + КодПостОбработки
);
ВызватьИсключение;
КонецПопытки;
Если Не ГМЗ_СогласованиеДокументов.ТребоватьПроверкуРасценкиЗаказногоЛимита(ПараметрыВыполненияКода.СсылкаДокумента) Тогда
Если (ПараметрыВыполненияКода.НовоеСостояниеДокумента = Перечисления.ГМЗ_СостоянияДокументов.Согласован)
Или (ПараметрыВыполненияКода.НовоеСостояниеДокумента = Перечисления.ГМЗ_СостоянияДокументов.Утвержден) Тогда
прм_Запрос = Новый Запрос;
прм_Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ГМЗ_УстановкаЦенМатериаловЛимитов.Ссылка
|ИЗ
| Документ.ГМЗ_УстановкаЦенМатериаловЛимитов КАК ГМЗ_УстановкаЦенМатериаловЛимитов
|ГДЕ
| ГМЗ_УстановкаЦенМатериаловЛимитов.Проведен = ИСТИНА
| И ГМЗ_УстановкаЦенМатериаловЛимитов.ДокументЛимитов = &ДокументЛимитов";
прм_Запрос.УстановитьПараметр("ДокументЛимитов", ПараметрыВыполненияКода.СсылкаДокумента);
прм_РезультатЗапроса = прм_Запрос.Выполнить();
прм_Выб = прм_РезультатЗапроса.Выбрать();
прм_НовоеСостояние = Перечисления.ГМЗ_СостоянияДокументов.Утвержден;
прм_Комментарий = "Утвержден при утверждении документа лимита";
прм_РезОперации = "";
Пока прм_Выб.Следующий() Цикл
прм_СтрК = Новый Структура("Состояние, Комментарий", прм_НовоеСостояние, прм_Комментарий);
прм_Рез = ГМЗ_СогласованиеДокументов.УстановитьНовоеСостояниеДокумента(прм_Выб.Ссылка, прм_СтрК);
СтрокаСтатуса = ?(прм_Рез = "", "ОК", "ОШИБКА!!! " + прм_Рез);
прм_РезОперации = ?(прм_РезОперации = "", "", прм_РезОперации + Символы.ПС)
+ "Утверждение " + СокрЛП(прм_Выб.Ссылка) + ": " + СтрокаСтатуса;
КонецЦикла;
ПараметрыВыполненияКода.СтатусОбработкиДокумента = прм_РезОперации;
КонецЕсли;
КонецЕсли;
Хранение исходного кода в строковых полях справочников несет в себе риски: конфигуратор не выполняет синтаксическую проверку таких строк при обновлении метаданных, а отладка становится затруднительной. Рассмотрим более надежные подходы:
.epf). Это дает возможность отлаживать алгоритмы в стандартном конфигураторе и проверять их синтаксис.Вычислить() или прямое ветвление по имени алгоритма.