Как исправить ошибку компиляции при выполнении динамического кода через метод Выполнить() в 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке гибких систем согласования, обработок данных и настраиваемых бизнес-процессов разработчики часто сохраняют исполняемый программный код в базе данных (например, в строковых реквизитах справочников) и запускают его с помощью встроенной процедуры Выполнить(). Однако во время исполнения такого динамического кода платформа может выдать исключение: «Ошибка компиляции при вычислении выражения или выполнении фрагмента кода: {(строка, позиция)}: Ожидается символ...».

Разберем природу возникновения этой ошибки, выясним, как правильно интерпретировать координаты сбоя и как локализовать и устранить неполадку.

Анализ проблемы и диагностика координат ошибки

Посмотрим на типичный пример вызова динамического алгоритма:


ПараметрыВыполненияКода = Новый Структура("СсылкаДокумента, НовоеСостояниеДокумента, СтатусОбработкиДокумента");
ПараметрыВыполненияКода.СсылкаДокумента = СтрокаТабличнойЧасти.Ссылка; 
ПараметрыВыполненияКода.НовоеСостояниеДокумента = НовоеСостояниеТекущегоДокумента;
ПараметрыВыполненияКода.СтатусОбработкиДокумента = ""; 

Выполнить(КодПостОбработки);

Если во время вызова возникает ошибка вида {(37,96)}: Ожидается символ ')', важно понимать, что указанные координаты (37-я строка, 96-й символ) относятся не к тексту вызывающего модуля формы или общего модуля, а непосредственно к содержимому строковой переменной КодПостОбработки.

Часто разработчик сверяет текст в конфигураторе или тестовом модуле и не находит синтаксических ошибок, поскольку в саму переменную КодПостОбработки был передан другой фрагмент (например, неотредактированная версия алгоритма из другого элемента справочника или устаревший шаблон).

Основные причины синтаксических сбоев динамического кода

Проанализируем распространенные причины, приводящие к ошибкам компиляции при динамическом исполнении:

  1. Несоответствие исполняемого кода ожидаемому. Если алгоритм подтягивается из базы данных, необходимо убедиться, что из реквизита прочитана именно та строка, которая прошла тестирование, и в ней нет незакрытых скобок ) или пропущенных точек с запятой ;.
  2. Скрытые и неразрывные символы. При копировании кода из текстовых редакторов, веб-страниц или почтовых клиентов в текст могут попасть неразрывные пробелы (код 160 вместо стандартного пробела 32), которые платформа 1С воспринимает как синтаксическую ошибку.
  3. Недопустимые синтаксические конструкции. В строке, передаваемой в метод Выполнить(), запрещено объявлять процедуры и функции (конструкции Процедура ... КонецПроцедуры), а также использовать директивы препроцессора (#Если, #Иначе, #КонецЕсли).
  4. Экранирование строковых литералов. Если внутри динамического кода формируются строки с кавычками, их необходимо оформлять по правилам встроенного языка 1С (дублирование кавычек "" внутри строковых литералов).

Пошаговый алгоритм поиска и устранения ошибки

Разберем по шагам, как быстро обнаружить точное место сбоя в динамическом фрагменте.

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

Альтернативные архитектурные решения

Хранение исходного кода в строковых полях справочников несет в себе риски: конфигуратор не выполняет синтаксическую проверку таких строк при обновлении метаданных, а отладка становится затруднительной. Рассмотрим более надежные подходы:

  1. Хранение внешних обработок в базе данных. Вместо текста процедур в справочнике можно сохранять двоичные данные внешних обработок (файлов .epf). Это дает возможность отлаживать алгоритмы в стандартном конфигураторе и проверять их синтаксис.
  2. Использование паттерна «Стратегия». Создадим в конфигурации общий модуль с набором типовых обработчиков. В справочнике будем указывать лишь имя экспортной процедуры, которую платформа вызывает через Вычислить() или прямое ветвление по имени алгоритма.
  3. Применение механизмов БСП. Если в конфигурации подключена Библиотека стандартных подсистем, для выполнения произвольных внешних алгоритмов рекомендуется использовать подсистему «Дополнительные отчеты и обработки».
← На главную