Skip to content
113 changes: 105 additions & 8 deletions src/internal/Модули/Десериализатор.os
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

// Состояние парсинга
Перем ТекущиеТАГДирективы; // Хранилище TAG директив

Перем ВстречалаYAMLДиректива; // Флаг встречи YAML директивы в текущем документе

Перем Якоря; // Соответствие для хранения якорей

Expand Down Expand Up @@ -121,6 +121,9 @@
// Очищаем TAG директивы перед началом парсинга
ТекущиеТАГДирективы.Очистить();

// Сбрасываем флаг YAML директивы
ВстречалаYAMLДиректива = Ложь;

// Очищаем якоря перед началом парсинга
Якоря.Очистить();

Expand Down Expand Up @@ -172,6 +175,9 @@

Если Не Документ = Неопределено Тогда
МассивСтрокДокументов.Добавить(Документ);
ИначеЕсли ВстречалаYAMLДиректива Тогда
// Если была YAML директива, но нет документа - это ошибка
ВызватьИсключение "YAML директива без последующего документа";
КонецЕсли;

Лог.Отладка("Разбиение на документы завершено, найдено " + МассивСтрокДокументов.Количество() + " документов");
Expand Down Expand Up @@ -223,6 +229,8 @@
МассивСтрокДокументов.Добавить(Документ);
// Очищаем TAG директивы только после обработки предыдущего документа
ТекущиеТАГДирективы.Очистить();
// Сбрасываем флаг YAML директивы для нового документа
ВстречалаYAMLДиректива = Ложь;
КонецЕсли;

Документ = Новый Массив();
Expand All @@ -246,11 +254,20 @@
//
Функция ОбработатьТерминаторДокумента(Документ, МассивСтрокДокументов)

// Проверяем наличие директивы без документа
Если Документ = Неопределено И ВстречалаYAMLДиректива Тогда
// Если была директива, но документ не был начат (нет ---), это ошибка
ВызватьИсключение "YAML директива без последующего документа";
КонецЕсли;

// Конец текущего документа
Если Документ <> Неопределено И Документ.Количество() > 0 Тогда
МассивСтрокДокументов.Добавить(Документ);
КонецЕсли;

Документ = Неопределено; // Переходим в состояние вне документа
// Сбрасываем флаг YAML директивы
ВстречалаYAMLДиректива = Ложь;

Возврат Документ;

Expand Down Expand Up @@ -339,8 +356,42 @@
Функция ОбработатьСтрокуВнеДокумента(СтрокаБезПробелов, ПолнаяСтрока, Документ)
// Мы вне документа - здесь можем обрабатывать YAML директивы
Если СтрНачинаетсяС(СтрокаБезПробелов, "%YAML") Тогда
Лог.Отладка("Обработка YAML директивы (игнорируем): " + СтрокаБезПробелов);
// YAML директивы игнорируем, но не добавляем в документ
Лог.Отладка("Обработка YAML директивы: " + СтрокаБезПробелов);

// Проверяем, не была ли уже YAML директива
Если ВстречалаYAMLДиректива Тогда
ВызватьИсключение "Дублирование YAML директивы не допускается";
КонецЕсли;

// Удаляем комментарий из строки для валидации
ПозицияКомментария = СтрНайти(СтрокаБезПробелов, "#");
Если ПозицияКомментария > 0 Тогда
СтрокаБезКомментария = СокрЛП(Лев(СтрокаБезПробелов, ПозицияКомментария - 1));
Иначе
СтрокаБезКомментария = СтрокаБезПробелов;
КонецЕсли;

// Валидируем формат YAML директивы
ЧастиДирективы = СтрРазделить(СтрокаБезКомментария, " ", Истина);
Если ЧастиДирективы.Количество() > 2 Тогда
ВызватьИсключение "YAML директива содержит лишние слова: " + СтрокаБезКомментария;
ИначеЕсли ЧастиДирективы.Количество() < 2 Тогда
ВызватьИсключение "YAML директива должна содержать версию";
КонецЕсли;

// Проверяем формат версии (должно быть x.y)
Версия = ЧастиДирективы[1];

// Проверяем, нет ли комментария без пробела (например, "1.1#comment")
Если СтрНайти(Версия, "#") > 0 Тогда
ВызватьИсключение "Комментарий в YAML директиве должен быть отделен пробелом";
КонецЕсли;

Если НЕ СтрНайти(Версия, ".") > 0 Тогда
ВызватьИсключение "Неверный формат версии YAML директивы: " + Версия;
КонецЕсли;

ВстречалаYAMLДиректива = Истина;
Возврат Документ;
ИначеЕсли СтрНачинаетсяС(СтрокаБезПробелов, "%") И НЕ СтрНачинаетсяС(СтрокаБезПробелов, "%TAG") Тогда
// Неизвестные директивы (как %FOO) должны игнорироваться с предупреждением
Expand Down Expand Up @@ -4243,6 +4294,10 @@
КонецЕсли;

УправляющийПодсимвол = ПолучитьУправляющийПодсимвол(Строка, ДанныеУправляющегоСимвола.Позиция + 1);

// Валидация управляющего подсимвола
ПроверитьУправляющийПодсимвол(УправляющийПодсимвол);

Лог.Отладка("Найден управляющий символ: %1 с подсимволом: %2",
ДанныеУправляющегоСимвола.Символ,
УправляющийПодсимвол);
Expand Down Expand Up @@ -4458,6 +4513,40 @@

КонецФункции

// Проверяет корректность управляющего подсимвола блочного скаляра
//
// Параметры:
// УправляющийПодсимвол - Строка - подсимвол после | или > (например, "2-", "+", "10")
//
Процедура ПроверитьУправляющийПодсимвол(УправляющийПодсимвол)
Если ПустаяСтрока(УправляющийПодсимвол) Тогда
Возврат; // Пустой подсимвол допустим
КонецЕсли;

// Удаляем допустимые chomping модификаторы
ПодсимволБезChomping = СтрЗаменить(УправляющийПодсимвол, "+", "");
ПодсимволБезChomping = СтрЗаменить(ПодсимволБезChomping, "-", "");
ПодсимволБезChomping = СокрЛП(ПодсимволБезChomping);

// Если после удаления chomping символов что-то осталось
Если НЕ ПустаяСтрока(ПодсимволБезChomping) Тогда
// Это должен быть индикатор отступа - единственная цифра от 1 до 9
Если СтрДлина(ПодсимволБезChomping) > 1 Тогда
ВызватьИсключение "Индикатор отступа блочного скаляра должен быть единственной цифрой (1-9): " + УправляющийПодсимвол;
КонецЕсли;

// Проверяем, что это цифра
Попытка
Цифра = Число(ПодсимволБезChomping);
Если Цифра < 1 ИЛИ Цифра > 9 Тогда
ВызватьИсключение "Индикатор отступа блочного скаляра должен быть цифрой от 1 до 9: " + УправляющийПодсимвол;
КонецЕсли;
Исключение
ВызватьИсключение "Индикатор отступа блочного скаляра должен быть цифрой от 1 до 9: " + УправляющийПодсимвол;
КонецПопытки;
КонецЕсли;
КонецПроцедуры

Функция ПолучитьУправляющийПодсимвол(Строка, Позиция)
Если СтрДлина(Строка) < Позиция Тогда
Возврат ""; // Нет подсимвола, возвращаем пустую строку
Expand Down Expand Up @@ -5733,12 +5822,17 @@
Возврат Ложь;
КонецЕсли;

// В YAML ... должно быть в отдельной строке или с пробелом после
// В YAML ... должно быть в отдельной строке или только с пробелами/комментариями после
ОстаткСтроки = Сред(СокращеннаяСтрока, СтрДлина(YAML_ТЕРМИНАТОР_ДОКУМЕНТА) + 1);

// Если есть остаток, он должен начинаться с пробела или быть пустым
Если НЕ ПустаяСтрока(ОстаткСтроки) И НЕ СтрНачинаетсяС(ОстаткСтроки, " ") И НЕ СтрНачинаетсяС(ОстаткСтроки, Символы.Таб) Тогда
Возврат Ложь;
ОстаткСтрокиБезПробелов = СокрЛП(ОстаткСтроки);

// Проверяем остаток строки
Если НЕ ПустаяСтрока(ОстаткСтрокиБезПробелов) Тогда
// Если есть непробельное содержимое, оно должно быть комментарием
Если НЕ СтрНачинаетсяС(ОстаткСтрокиБезПробелов, "#") Тогда
// Если это не комментарий, то это ошибка
ВызватьИсключение "Недопустимое содержимое после маркера конца документа: " + СокращеннаяСтрока;
КонецЕсли;
КонецЕсли;

Возврат Истина;
Expand Down Expand Up @@ -5886,6 +5980,9 @@ YAML_ТЕРМИНАТОР_ДОКУМЕНТА = "...";
// Хранилище TAG директив для текущего документа
ТекущиеТАГДирективы = Новый Соответствие();

// Флаг наличия YAML директивы в текущем документе
ВстречалаYAMLДиректива = Ложь;

// Инициализация кэша якорей
Якоря = Новый Соответствие;

Expand Down
Loading
Loading