From e6e5bb0997f79f206a972f71d296749c9a8dd240 Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Thu, 27 Aug 2026 00:00:26 +0200 Subject: [PATCH 1/4] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=81=D0=B8=D0=BD=D1=82=D0=B0=D0=BA=D1=81=D0=B8?= =?UTF-8?q?=D1=81=D0=B0=20OneScript?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Парсер разбирал 65% корпуса реального кода OneScript (2732 файла всех установленных opm-библиотек). Основная причина - аннотации: имя аннотации проверялось по списку аннотаций 1С:Предприятие, а разбор ждал единственную форму &Перед("ИмяМетода"). Добавлено: - аннотации с произвольным именем, позиционными и именованными параметрами, вложенными аннотациями и аннотациями параметров метода; - асинхронные методы: признак Асинхронный в сигнатуре, узлы ВыражениеЖдать и ОператорЖдать; - имена библиотек с дефисами, слэшами, точками и цифрами в #Использовать; - директивы режима выполнения #Native и #Stack, строка запуска скрипта #!; - обращение к членам результата скобочного выражения и созданного объекта: (Новый Файл(Путь)).ПолноеИмя, Новый Рефлектор.МетодСуществует(Объект, "Имя"). Разбирается 99% корпуса; оставшиеся файлы - намеренно синтаксически ошибочная фикстура из тестов 1bdd в нескольких копиях. Добавлены тесты на OneUnit: 39 тестов на новый синтаксис и регрессию общих конструкций. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CP3TEtTKWGE2wxRjEDwVRV --- .gitignore | 4 +- README.md | 64 ++- oscript.cfg | 1 + packagedef | 7 +- ...20\257\320\267\321\213\320\272\320\260.os" | 445 +++++++++++++++--- ...21\202\320\260\321\206\320\270\320\270.os" | 268 +++++++++++ ...0\272\321\201\320\270\321\201OneScript.os" | 348 ++++++++++++++ 7 files changed, 1074 insertions(+), 63 deletions(-) create mode 100644 oscript.cfg create mode 100644 "tests/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\320\270.os" create mode 100644 "tests/\320\241\320\270\320\275\321\202\320\260\320\272\321\201\320\270\321\201OneScript.os" diff --git a/.gitignore b/.gitignore index c4bca14..8072f6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.txt -sandbox \ No newline at end of file +sandbox +oscript_modules +*.ospx diff --git a/README.md b/README.md index 0aea92a..0f48cec 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # osparser (oscript parser) -## Парсер встроенного языка платформы 1С:Предприятие 8 +## Парсер встроенного языка платформы 1С:Предприятие 8 и OneScript Документация: [Книга Джедая](book.md) @@ -19,9 +19,11 @@ ## Содержание 1. [Введение](#введение) -2. [Структура репозитория](#структура-репозитория) -3. [Принцип работы](#принцип-работы) -4. [Благодарности](#благодарности) +2. [Синтаксис OneScript](#синтаксис-onescript) +3. [Структура репозитория](#структура-репозитория) +4. [Принцип работы](#принцип-работы) +5. [Разработка](#разработка) +6. [Благодарности](#благодарности) ## Введение @@ -71,6 +73,51 @@ Пример выгрузки ошибок в [SonarQube](https://www.sonarqube.org/): [test7.os](./examples/test7.os) +## Синтаксис OneScript + +Помимо встроенного языка 1С:Предприятие парсер разбирает конструкции, которые есть только в OneScript. + +**Аннотации с произвольным именем.** Имя аннотации не ограничено списком аннотаций 1С:Предприятие, +поддерживаются позиционные и именованные параметры, вложенные аннотации и аннотации параметров метода: + +```bsl +&Деталька("OneUnit.Таймаут", ЗначениеПоУмолчанию = 500) +&Напильник(ПрименяетсяТолькоНа = &Прозвище("Желудь")) +Процедура ПриСозданииОбъекта(&Пластилин Сервис, Знач Обычный = 1) +``` + +Аннотация хранится в узле `ОбъявлениеАннотации`: `Имя` - имя аннотации, `Параметры` - массив узлов +`ПараметрАннотации`, у каждого есть `Имя` (пустое у позиционного), `Значение` (узел-выражение) +и `Литерал` - готовое значение, если параметр задан константой. Для аннотаций 1С:Предприятие +по-прежнему заполняются поля `Аннотация` и `ИмяМетода`. + +**Асинхронные методы.** Признак асинхронности метода доступен в поле `Асинхронный` его сигнатуры, +ожидание результата разбирается в узлы `ВыражениеЖдать` и `ОператорЖдать`: + +```bsl +Асинх Функция Прочитать() + Возврат Ждать ПолучитьДанные(); +КонецФункции +``` + +**Имена библиотек с дефисами и слэшами** в инструкции `#Использовать`: + +```bsl +#Использовать autumn-collections +#Использовать oint/api/grpc +``` + +**Директивы режима выполнения** `#Native` и `#Stack` разбираются в узел +`ИнструкцияПрепроцессораРежимВыполнения` с полем `Режим`, а строка запуска скрипта (`#!/usr/bin/env oscript`) +пропускается как не относящаяся к коду модуля. + +**Обращение к членам результата выражения** - скобочного и созданного объекта: + +```bsl +ПолноеИмя = (Новый Файл(Путь)).ПолноеИмя; +Если Новый Рефлектор.МетодСуществует(Объект, "Имя") Тогда +``` + ## Структура репозитория * /docs - файлы веб-страницы проекта @@ -86,6 +133,15 @@ Состояние плагина (в переменных модуля) сохраняется между вызовами до самого конца обхода дерева, а подписки на каждый узел возможны две: перед обходом узла и после обхода. Это существенно упрощает реализацию многих алгоритмов анализа. Плюс к этому, некоторую информацию предоставляет сам механизм обхода. Например, плагинам доступна статистика по родительским узлам (количество каждого вида). +## Разработка + +Установка окружения и запуск тестов: + +```sh +opm install -l oneunit +./oscript_modules/bin/oneunit e -d tests +``` + ## Благодарности Спасибо всем кто так или иначе повлиял на этот проект. diff --git a/oscript.cfg b/oscript.cfg new file mode 100644 index 0000000..39e1188 --- /dev/null +++ b/oscript.cfg @@ -0,0 +1 @@ +lib.additional=./oscript_modules diff --git a/packagedef b/packagedef index eb37d2c..2560d8d 100644 --- a/packagedef +++ b/packagedef @@ -3,11 +3,14 @@ // Полную документацию см. на hub.oscript.io/packaging Описание.Имя("osparser") - .Версия("0.0.3") + .Версия("0.1.0") .ВерсияСреды("1.0.21") .ВключитьФайл("src") .ВключитьФайл("examples") .ВключитьФайл("docs") .ОпределяетКласс("ПарсерВстроенногоЯзыка", "src/Классы/ПарсерВстроенногоЯзыка.os") .ВключитьФайл("README.md") - .ВключитьФайл("LICENSE") \ No newline at end of file + .ВключитьФайл("LICENSE") + + .РазработкаЗависитОт("oneunit", "0.4.1") + .РазработкаЗависитОт("asserts", "1.6.2") diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\321\201\320\265\321\200\320\222\321\201\321\202\321\200\320\276\320\265\320\275\320\275\320\276\320\263\320\276\320\257\320\267\321\213\320\272\320\260.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\321\201\320\265\321\200\320\222\321\201\321\202\321\200\320\276\320\265\320\275\320\275\320\276\320\263\320\276\320\257\320\267\321\213\320\272\320\260.os" index 4172d16..db5b1fa 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\321\201\320\265\321\200\320\222\321\201\321\202\321\200\320\276\320\265\320\275\320\275\320\276\320\263\320\276\320\257\320\267\321\213\320\272\320\260.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\321\201\320\265\321\200\320\222\321\201\321\202\321\200\320\276\320\265\320\275\320\275\320\276\320\263\320\276\320\257\320\267\321\213\320\272\320\260.os" @@ -79,6 +79,7 @@ Перем Парсер_ДанныеТекущегоТокена; // один из ТаблицаТокенов Перем Парсер_ДанныеПредыдущегоТокена; // один из ТаблицаТокенов Перем Парсер_Узлы; // структура как соответствие[строка] (таблица значений) +Перем Парсер_ИмяБиблиотеки; // строка, имя библиотеки последней инструкции #Использовать #КонецОбласти // СостояниеПарсера @@ -305,14 +306,35 @@ Парсер_Узлы.Вставить("ОбъявлениеАннотации", Новый ТаблицаЗначений); // Хранит информацию об объявлении аннотации. - // Пример: + // Имя аннотации произвольное: кроме аннотаций встроенного языка 1С:Предприятие + // поддерживаются аннотации OneScript. + // Примеры: //
 	// &Перед("ЗаполнитьТовары")
+	// &Тест
+	// &Деталька("OneUnit.Таймаут", ЗначениеПоУмолчанию = 500)
 	// 
Поля = Парсер_Узлы.ОбъявлениеАннотации.Колонки; Поля.Добавить("Тип"); // строка (один из Типы) - Поля.Добавить("Аннотация"); // строка (один из Аннотации) - Поля.Добавить("ИмяМетода"); // строка + Поля.Добавить("Имя"); // строка + Поля.Добавить("Аннотация"); // строка (один из Аннотации) или неопределено для аннотаций OneScript + Поля.Добавить("ИмяМетода"); // строка, заполняется для аннотаций 1С вида &Перед("ИмяМетода") + Поля.Добавить("Параметры"); // массив (ПараметрАннотации) + Поля.Добавить("Начало"); // один из ТаблицаТокенов + Поля.Добавить("Конец"); // один из ТаблицаТокенов + + Парсер_Узлы.Вставить("ПараметрАннотации", Новый ТаблицаЗначений); + // Хранит информацию о параметре аннотации. + // Пример: + // Параметры аннотации заключены в скобки {...} + //
+	// &Деталька({"OneUnit.Таймаут"}, {ЗначениеПоУмолчанию = 500})
+	// 
+ Поля = Парсер_Узлы.ПараметрАннотации.Колонки; + Поля.Добавить("Тип"); // строка (один из Типы) + Поля.Добавить("Имя"); // строка, пустая для позиционного параметра + Поля.Добавить("Значение"); // структура (ВыражениеЛитерал, ВыражениеСтроковое, ВыражениеУнарное, ОбъявлениеАннотации) + Поля.Добавить("Литерал"); // значение параметра, если он задан литералом, иначе неопределено Поля.Добавить("Начало"); // один из ТаблицаТокенов Поля.Добавить("Конец"); // один из ТаблицаТокенов @@ -326,6 +348,7 @@ Поля = Парсер_Узлы.ОбъявлениеСпискаПеременныхМодуля.Колонки; Поля.Добавить("Тип"); // строка (один из Типы) Поля.Добавить("Директивы"); // массив (ОбъявлениеДирективы) + Поля.Добавить("Аннотации"); // массив (ОбъявлениеАннотации) Поля.Добавить("Объявления"); // массив (ОбъявлениеПеременнойМодуля) Поля.Добавить("Начало"); // один из ТаблицаТокенов Поля.Добавить("Конец"); // один из ТаблицаТокенов @@ -402,6 +425,7 @@ Поля = Парсер_Узлы.ОбъявлениеПараметра.Колонки; Поля.Добавить("Тип"); // строка (один из Типы) Поля.Добавить("Имя"); // строка + Поля.Добавить("Аннотации"); // массив (ОбъявлениеАннотации) Поля.Добавить("ПоЗначению"); // булево Поля.Добавить("Значение"); // неопределено, структура (ВыражениеУнарное, ВыражениеЛитерал) Поля.Добавить("Начало"); // один из ТаблицаТокенов @@ -442,6 +466,7 @@ Поля.Добавить("Директивы"); // массив (ОбъявлениеДирективы) Поля.Добавить("Аннотации"); // массив (ОбъявлениеАннотации) Поля.Добавить("Параметры"); // массив (ОбъявлениеПараметра) + Поля.Добавить("Асинхронный"); // булево Поля.Добавить("Экспорт"); // булево Поля.Добавить("Начало"); // один из ТаблицаТокенов Поля.Добавить("Конец"); // один из ТаблицаТокенов @@ -459,6 +484,7 @@ Поля.Добавить("Директивы"); // массив (ОбъявлениеДирективы) Поля.Добавить("Аннотации"); // массив (ОбъявлениеАннотации) Поля.Добавить("Параметры"); // массив (ОбъявлениеПараметра) + Поля.Добавить("Асинхронный"); // булево Поля.Добавить("Экспорт"); // булево Поля.Добавить("Начало"); // один из ТаблицаТокенов Поля.Добавить("Конец"); // один из ТаблицаТокенов @@ -635,6 +661,20 @@ Поля = Парсер_Узлы.ВыражениеСкобочное.Колонки; Поля.Добавить("Тип"); // строка (один из Типы) Поля.Добавить("Выражение"); // структура (один из #Выражения) + Поля.Добавить("Хвост"); // массив (ВыражениеПоле, ВыражениеИндекс) + Поля.Добавить("Начало"); // один из ТаблицаТокенов + Поля.Добавить("Конец"); // один из ТаблицаТокенов + + Парсер_Узлы.Вставить("ВыражениеЖдать", Новый ТаблицаЗначений); + // Хранит выражение ожидания результата асинхронного метода. + // Пример: + //
+	// // выражение ожидания заключено в скобки {...}
+	// Результат = {Ждать ПрочитатьДанные()};
+	// 
+ Поля = Парсер_Узлы.ВыражениеЖдать.Колонки; + Поля.Добавить("Тип"); // строка (один из Типы) + Поля.Добавить("Выражение"); // структура (один из #Выражения) Поля.Добавить("Начало"); // один из ТаблицаТокенов Поля.Добавить("Конец"); // один из ТаблицаТокенов @@ -715,6 +755,18 @@ Поля.Добавить("Начало"); // один из ТаблицаТокенов Поля.Добавить("Конец"); // один из ТаблицаТокенов + Парсер_Узлы.Вставить("ОператорЖдать", Новый ТаблицаЗначений); + // Хранит оператор ожидания результата асинхронного метода. + // Пример: + //
+	// Ждать Сохранить();
+	// 
+ Поля = Парсер_Узлы.ОператорЖдать.Колонки; + Поля.Добавить("Тип"); // строка (один из Типы) + Поля.Добавить("Выражение"); // структура (один из #Выражения) + Поля.Добавить("Начало"); // один из ТаблицаТокенов + Поля.Добавить("Конец"); // один из ТаблицаТокенов + Парсер_Узлы.Вставить("ОператорВыполнить", Новый ТаблицаЗначений); // Хранит оператор "Выполнить". Поля = Парсер_Узлы.ОператорВыполнить.Колонки; @@ -947,6 +999,19 @@ Поля.Добавить("Начало"); // один из ТаблицаТокенов Поля.Добавить("Конец"); // один из ТаблицаТокенов + Парсер_Узлы.Вставить("ИнструкцияПрепроцессораРежимВыполнения", Новый ТаблицаЗначений); + // Хранит информацию о директиве режима выполнения OneScript. + // Пример: + //
+	//#Native
+	// ...
+	// 
+ Поля = Парсер_Узлы.ИнструкцияПрепроцессораРежимВыполнения.Колонки; + Поля.Добавить("Тип"); // строка (один из Типы) + Поля.Добавить("Режим"); // строка ("Native" или "Stack") + Поля.Добавить("Начало"); // один из ТаблицаТокенов + Поля.Добавить("Конец"); // один из ТаблицаТокенов + Парсер_Узлы.Вставить("ИнструкцияПрепроцессораКонецОбласти", Новый ТаблицаЗначений); // Хранит информацию об инструкции препроцессора #КонецОбласти, // Пример: @@ -1105,6 +1170,7 @@ |И.And, Или.Or, Не.Not, ДобавитьОбработчик.AddHandler, УдалитьОбработчик.RemoveHandler, |Попытка.Try, Исключение.Except, ВызватьИсключение.Raise, КонецПопытки.EndTry, |Новый.New, Выполнить.Execute, Экспорт.Export, Перейти.Goto, + |Асинх.Async, Ждать.Await, |Истина.True, Ложь.False, Неопределено.Undefined, Null" ); КонецФункции // КлючевыеСлова() @@ -1140,6 +1206,7 @@ // ИнструкцииПрепроцессора |_Если, _ИначеЕсли, _Иначе, _КонецЕсли, _Область, _КонецОбласти, |_Вставка, _КонецВставки, _Удаление, _КонецУдаления, _Использовать, + |_Native, _Stack, // Другие @@ -1154,19 +1221,20 @@ Функция Типы() Экспорт Возврат Перечисление(Новый Структура, "Модуль, ЭлементОкружения, ОбъявлениеГлобальногоОбъекта, ОбъявлениеГлобальногоМетода, - |ОбъявлениеДирективы, ОбъявлениеАннотации, ОбъявлениеПеременнойМодуля, ОбъявлениеСпискаПеременныхМодуля, + |ОбъявлениеДирективы, ОбъявлениеАннотации, ПараметрАннотации, ОбъявлениеПеременнойМодуля, ОбъявлениеСпискаПеременныхМодуля, |ОбъявлениеСпискаЛокальныхПеременных, ОбъявлениеЛокальнойПеременной, ОбъявлениеАвтоПеременной, |ОбъявлениеПараметра, ОбъявлениеМетода, ОбъявлениеСигнатурыПроцедуры, ОбъявлениеСигнатурыФункции, |ВыражениеЛитерал, ВыражениеПоле, ВыражениеИндекс, ВыражениеИдентификатор, |ВыражениеУнарное, ВыражениеБинарное, ВыражениеНовый, ВыражениеТернарное, - |ВыражениеСкобочное, ВыражениеНе, ВыражениеСтроковое, + |ВыражениеСкобочное, ВыражениеНе, ВыражениеСтроковое, ВыражениеЖдать, |ОператорПрисваивания, ОператорВозврат, ОператорПрервать, ОператорПродолжить, - |ОператорВызватьИсключение, ОператорВыполнить, ОператорПока, ОператорДля, ОператорДляКаждого, + |ОператорВызватьИсключение, ОператорВыполнить, ОператорЖдать, ОператорПока, ОператорДля, ОператорДляКаждого, |ОператорПопытка, ОператорИсключение, ОператорПерейти, ОператорМетка, |ОператорВызоваПроцедуры, ОператорЕсли, ОператорИначеЕсли, ОператорИначе, |ОператорДобавитьОбработчик, ОператорУдалитьОбработчик, |ИнструкцияПрепроцессораЕсли, ИнструкцияПрепроцессораИначеЕсли, ИнструкцияПрепроцессораИначе, |ИнструкцияПрепроцессораКонецЕсли, ИнструкцияПрепроцессораОбласть, ИнструкцияПрепроцессораКонецОбласти, + |ИнструкцияПрепроцессораРежимВыполнения, |ИнструкцияПрепроцессораВставка, ИнструкцияПрепроцессораКонецВставки, |ИнструкцияПрепроцессораУдаление, ИнструкцияПрепроцессораКонецУдаления, |ИнструкцияПрепроцессораИспользовать, @@ -1207,6 +1275,9 @@ "Удаление.Delete," "КонецУдаления.EndDelete," "Использовать.Use," + // директивы режима выполнения OneScript, русских синонимов не имеют + "Native," + "Stack," ); КонецФункции // ИнструкцииПрепроцессора() @@ -1450,16 +1521,24 @@ Парсер_Литерал = Сред(Парсер_Исходник, Начало, Парсер_ТекущаяПозиция - Начало); Если Директивы.Свойство(Парсер_Литерал) Тогда - Парсер_Токен = Токены.Директива; - ИначеЕсли Аннотации.Свойство(Парсер_Литерал) Тогда - Парсер_Токен = Токены.Аннотация; - Иначе - Ошибка(3, Парсер_Литерал, Ложь); Парсер_Токен = Токены.Директива; + Иначе + // Имя аннотации произвольное: помимо аннотаций встроенного языка 1С:Предприятие + // так объявляются аннотации OneScript, состав которых заранее неизвестен. + Парсер_Токен = Токены.Аннотация; КонецЕсли; ИначеЕсли ПредыдущийСимвол = "#" Тогда + Если Парсер_Символ = "!" Тогда + // строка запуска скрипта (#!/usr/bin/env oscript) - не часть кода модуля + Пока Парсер_Символ <> Символы_ПС И Парсер_Символ <> "" Цикл + Парсер_ТекущаяПозиция = Парсер_ТекущаяПозиция + 1; + Парсер_Символ = Сред(Парсер_Исходник, Парсер_ТекущаяПозиция, 1); + КонецЦикла; + Продолжить; + КонецЕсли; + // пропуск невидимых символов Пока ПустаяСтрока(Парсер_Символ) И Парсер_Символ <> "" Цикл Если Парсер_Символ = Символы_ПС Тогда @@ -1486,6 +1565,11 @@ // сопоставление токена Если ИнструкцииПрепроцессора.Свойство(Парсер_Литерал, Парсер_Токен) Тогда Парсер_Токен = "_" + Парсер_Токен; + Если Парсер_Токен = Токены._Использовать Тогда + // Имя библиотеки в OneScript может содержать дефисы, точки и слэши + // (autumn-collections, oint/api/grpc), поэтому читается целиком, а не по токенам. + Парсер_ИмяБиблиотеки = ПрочитатьИмяБиблиотеки(); + КонецЕсли; Иначе Ошибка(5, Парсер_Литерал, Истина); КонецЕсли; @@ -1553,6 +1637,41 @@ КонецФункции // СледующийТокен() +// Читает имя библиотеки инструкции #Использовать до конца строки. +// Возвращает неопределено, если путь записан строковым литералом - +// такой путь разбирается обычным образом как строка. +Функция ПрочитатьИмяБиблиотеки() + Перем Начало, Символ; + + // пропуск пробелов до имени, оставаясь на строке инструкции + Пока Истина Цикл + Символ = Сред(Парсер_Исходник, Парсер_ТекущаяПозиция, 1); + Если Символ <> " " И Символ <> Символы.Таб Тогда + Прервать; + КонецЕсли; + Парсер_ТекущаяПозиция = Парсер_ТекущаяПозиция + 1; + КонецЦикла; + + Если Символ = """" Или Символ = "" Или Символ = Символы.ВК Или Символ = Символы_ПС Тогда + Парсер_Символ = Символ; + Возврат Неопределено; + КонецЕсли; + + Начало = Парсер_ТекущаяПозиция; + Пока Истина Цикл + Символ = Сред(Парсер_Исходник, Парсер_ТекущаяПозиция, 1); + Если Символ = "" Или Символ = Символы_ПС Или Символ = Символы.ВК + Или Символ = " " Или Символ = Символы.Таб Тогда + Прервать; + КонецЕсли; + Парсер_ТекущаяПозиция = Парсер_ТекущаяПозиция + 1; + КонецЦикла; + + Парсер_Символ = Символ; + + Возврат Сред(Парсер_Исходник, Начало, Парсер_ТекущаяПозиция - Начало); +КонецФункции // ПрочитатьИмяБиблиотеки() + Функция Окружение(ВнешнееОкружение = Неопределено) Экспорт Возврат Новый Структура( "ВнешнееОкружение," // неопределено, структура (Окружение) @@ -1929,12 +2048,26 @@ Операнд = РазобратьВыражениеНовый(); ИначеЕсли Парсер_Токен = Токены.ЗнакВопроса Тогда Операнд = РазобратьВыражениеТернарное(); + ИначеЕсли Парсер_Токен = Токены.Ждать Тогда + Операнд = РазобратьВыражениеЖдать(); Иначе Ошибка(7, Неопределено, Истина, Парсер_ДанныеТекущегоТокена); КонецЕсли; Возврат Операнд; КонецФункции // РазобратьОперанд() +Функция РазобратьВыражениеЖдать() + Перем Узел, Начало; + Начало = Парсер_ДанныеТекущегоТокена; + СледующийТокен(); + Узел = Парсер_Узлы.ВыражениеЖдать.Добавить(); + Узел.Тип = Типы.ВыражениеЖдать; + Узел.Выражение = РазобратьОперанд(); + Узел.Начало = Начало; + Узел.Конец = Парсер_ДанныеПредыдущегоТокена; + Возврат Узел; +КонецФункции // РазобратьВыражениеЖдать() + Функция РазобратьВыражениеСтроковое() Перем СписокВыражений, Начало; Начало = Парсер_ДанныеТекущегоТокена; @@ -2018,9 +2151,11 @@ Ожидать(Токены.ПраваяКруглаяСкобка); КонецЕсли; СледующийТокен(); - Если Парсер_Токен = Токены.Точка Тогда - Хвост = РазобратьХвост(); - КонецЕсли; + КонецЕсли; + // Обращение к членам созданного объекта возможно и без скобок конструктора: + // Новый Рефлектор.МетодСуществует(Объект, "Имя") + Если Парсер_Токен = Токены.Точка Или Парсер_Токен = Токены.ЛеваяКвадратнаяСкобка Тогда + Хвост = РазобратьХвост(); КонецЕсли; Если Имя = Неопределено Тогда Если Аргументы = Неопределено Тогда @@ -2211,15 +2346,22 @@ КонецФункции // РазобратьВыражениеТернарное() Функция РазобратьВыражениеСкобочное() - Перем Выражение, Начало; + Перем Выражение, Хвост, Начало; Начало = Парсер_ДанныеТекущегоТокена; СледующийТокен(); Выражение = РазобратьВыражение(); Ожидать(Токены.ПраваяКруглаяСкобка); СледующийТокен(); + // Обращение к членам результата выражения: (Новый Файл(Путь)).ПолноеИмя + Если Парсер_Токен = Токены.Точка Или Парсер_Токен = Токены.ЛеваяКвадратнаяСкобка Тогда + Хвост = РазобратьХвост(); + Иначе + Хвост = ПустойМассив; + КонецЕсли; Узел = Парсер_Узлы.ВыражениеСкобочное.Добавить(); Узел.Тип = Типы.ВыражениеСкобочное; Узел.Выражение = Выражение; + Узел.Хвост = Хвост; Узел.Начало = Начало; Узел.Конец = Парсер_ДанныеПредыдущегоТокена; Возврат Узел; @@ -2230,11 +2372,12 @@ #Область РазборОбъявлений Функция РазобратьОбъявленияМодуля(Переменные) - Перем Объявления, ОбъявлениеДирективы; + Перем Объявления, ОбъявлениеДирективы, НачалоАсинхронного; Объявления = Новый Массив; Пока Истина Цикл Парсер_СписокДиректив = Новый Массив; Парсер_СписокАннотаций = Новый Массив; + НачалоАсинхронного = Неопределено; Пока Истина Цикл Если Парсер_Токен = Токены.Директива Тогда ОбъявлениеДирективы = Парсер_Узлы.ОбъявлениеДирективы.Добавить(); @@ -2245,36 +2388,27 @@ Парсер_СписокДиректив.Добавить(ОбъявлениеДирективы); СледующийТокен(); ИначеЕсли Парсер_Токен = Токены.Аннотация Тогда - Аннотация = Аннотации[Парсер_Литерал]; - НачалоАннотации = Парсер_ДанныеТекущегоТокена; - СледующийТокен(); - Ожидать(Токены.ЛеваяКруглаяСкобка); - СледующийТокен(); - Ожидать(Токены.Строка); - ИмяМетода = Парсер_Значение; - СледующийТокен(); - Ожидать(Токены.ПраваяКруглаяСкобка); - ОбъявлениеАннотации = Парсер_Узлы.ОбъявлениеАннотации.Добавить(); - ОбъявлениеАннотации.Тип = Типы.ОбъявлениеАннотации; - ОбъявлениеАннотации.Аннотация = Аннотация; - ОбъявлениеАннотации.ИмяМетода = ИмяМетода; - ОбъявлениеАннотации.Начало = НачалоАннотации; - ОбъявлениеАннотации.Конец = Парсер_ДанныеТекущегоТокена; - Парсер_СписокАннотаций.Добавить(ОбъявлениеАннотации); - СледующийТокен(); + Парсер_СписокАннотаций.Добавить(РазобратьОбъявлениеАннотации()); Иначе Прервать; КонецЕсли; КонецЦикла; + Если Парсер_Токен = Токены.Асинх Тогда + НачалоАсинхронного = Парсер_ДанныеТекущегоТокена; + СледующийТокен(); + Если Парсер_Токен <> Токены.Функция И Парсер_Токен <> Токены.Процедура Тогда + Ошибка(6, Неопределено, Истина, Парсер_ДанныеТекущегоТокена); + КонецЕсли; + КонецЕсли; Если Парсер_Токен = Токены.Перем И Парсер_ПеременныеРазрешены Тогда Объявления.Добавить(РазобратьОбъявлениеСпискаПеременныхМодуля(Переменные)); ИначеЕсли Парсер_Токен = Токены.Функция Тогда Парсер_ЭтоФункция = Истина; - Объявления.Добавить(РазобратьОбъявлениеМетода()); + Объявления.Добавить(РазобратьОбъявлениеМетода(НачалоАсинхронного)); Парсер_ЭтоФункция = Ложь; Парсер_ПеременныеРазрешены = Ложь; ИначеЕсли Парсер_Токен = Токены.Процедура Тогда - Объявления.Добавить(РазобратьОбъявлениеМетода()); + Объявления.Добавить(РазобратьОбъявлениеМетода(НачалоАсинхронного)); Парсер_ПеременныеРазрешены = Ложь; ИначеЕсли Парсер_Токен = Токены._Область Тогда Объявления.Добавить(РазобратьИнструкциюПрепроцессораОбласть()); @@ -2296,7 +2430,10 @@ СледующийТокен(); ИначеЕсли Парсер_Токен = Токены._Использовать Тогда Объявления.Добавить(РазобратьИнструкциюПрепроцессораИспользовать()); - СледующийТокен(); + СледующийТокен(); + ИначеЕсли Парсер_Токен = Токены._Native Или Парсер_Токен = Токены._Stack Тогда + Объявления.Добавить(РазобратьИнструкциюПрепроцессораРежимВыполнения()); + СледующийТокен(); Иначе Прервать; КонецЕсли; @@ -2304,6 +2441,113 @@ Возврат Объявления; КонецФункции // РазобратьОбъявленияМодуля() +// Разбирает объявление аннотации вместе с параметрами. +// Текущий токен на входе - Токены.Аннотация, на выходе - следующий за аннотацией токен. +Функция РазобратьОбъявлениеАннотации() + Перем ОбъявлениеАннотации, Начало, Имя, Параметры; + Начало = Парсер_ДанныеТекущегоТокена; + Имя = Парсер_Литерал; + СледующийТокен(); + Если Парсер_Токен = Токены.ЛеваяКруглаяСкобка Тогда + Параметры = РазобратьПараметрыАннотации(); + Иначе + Параметры = Новый Массив; + КонецЕсли; + ОбъявлениеАннотации = Парсер_Узлы.ОбъявлениеАннотации.Добавить(); + ОбъявлениеАннотации.Тип = Типы.ОбъявлениеАннотации; + ОбъявлениеАннотации.Имя = Имя; + Если Аннотации.Свойство(Имя) Тогда + ОбъявлениеАннотации.Аннотация = Аннотации[Имя]; + КонецЕсли; + ОбъявлениеАннотации.ИмяМетода = ИмяМетодаАннотации(Параметры); + ОбъявлениеАннотации.Параметры = Параметры; + ОбъявлениеАннотации.Начало = Начало; + ОбъявлениеАннотации.Конец = Парсер_ДанныеПредыдущегоТокена; + Возврат ОбъявлениеАннотации; +КонецФункции // РазобратьОбъявлениеАннотации() + +// Возвращает имя метода для аннотаций встроенного языка 1С:Предприятие вида &Перед("ИмяМетода"). +Функция ИмяМетодаАннотации(Параметры) + Перем Параметр; + Если Параметры.Количество() = 0 Тогда + Возврат Неопределено; + КонецЕсли; + Параметр = Параметры[0]; + Если ПустаяСтрока(Параметр.Имя) И ТипЗнч(Параметр.Литерал) = Тип("Строка") Тогда + Возврат Параметр.Литерал; + КонецЕсли; + Возврат Неопределено; +КонецФункции // ИмяМетодаАннотации() + +// Возвращает значение выражения, если оно задано литералом, иначе неопределено. +// Строковое выражение из нескольких частей возвращается склеенным. +Функция ЗначениеЛитерала(Выражение) + Перем Части, Элемент, Значение; + Если Выражение = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + Если Выражение.Тип = Типы.ВыражениеЛитерал Тогда + Возврат Выражение.Значение; + ИначеЕсли Выражение.Тип = Типы.ВыражениеСтроковое Тогда + Части = Новый Массив; + Для Каждого Элемент Из Выражение.Элементы Цикл + Части.Добавить(Элемент.Значение); + КонецЦикла; + Возврат СтрСоединить(Части, ""); + ИначеЕсли Выражение.Тип = Типы.ВыражениеУнарное Тогда + Значение = ЗначениеЛитерала(Выражение.Операнд); + Если ТипЗнч(Значение) = Тип("Число") И Выражение.Операция.Токен = Токены.ЗнакВычитания Тогда + Возврат -Значение; + КонецЕсли; + Возврат Значение; + КонецЕсли; + Возврат Неопределено; +КонецФункции // ЗначениеЛитерала() + +// Текущий токен на входе - Токены.ЛеваяКруглаяСкобка, на выходе - следующий за закрывающей скобкой токен. +Функция РазобратьПараметрыАннотации() + Перем Параметры; + Параметры = Новый Массив; + СледующийТокен(); + Если Парсер_Токен = Токены.ПраваяКруглаяСкобка Тогда + СледующийТокен(); + Возврат Параметры; + КонецЕсли; + Параметры.Добавить(РазобратьПараметрАннотации()); + Пока Парсер_Токен = Токены.Запятая Цикл + СледующийТокен(); + Параметры.Добавить(РазобратьПараметрАннотации()); + КонецЦикла; + Ожидать(Токены.ПраваяКруглаяСкобка); + СледующийТокен(); + Возврат Параметры; +КонецФункции // РазобратьПараметрыАннотации() + +Функция РазобратьПараметрАннотации() + Перем ПараметрАннотации, Начало, Имя, Значение; + Начало = Парсер_ДанныеТекущегоТокена; + Имя = ""; + Если Парсер_Токен = Токены.Идентификатор Тогда + Имя = Парсер_Литерал; + СледующийТокен(); + Ожидать(Токены.ЗнакРавно); + СледующийТокен(); + КонецЕсли; + Если Парсер_Токен = Токены.Аннотация Тогда + Значение = РазобратьОбъявлениеАннотации(); + Иначе + Значение = РазобратьВыражениеУнарное(); + КонецЕсли; + ПараметрАннотации = Парсер_Узлы.ПараметрАннотации.Добавить(); + ПараметрАннотации.Тип = Типы.ПараметрАннотации; + ПараметрАннотации.Имя = Имя; + ПараметрАннотации.Значение = Значение; + ПараметрАннотации.Литерал = ЗначениеЛитерала(Значение); + ПараметрАннотации.Начало = Начало; + ПараметрАннотации.Конец = Парсер_ДанныеПредыдущегоТокена; + Возврат ПараметрАннотации; +КонецФункции // РазобратьПараметрАннотации() + Функция РазобратьОбъявлениеСпискаПеременныхМодуля(Переменные) Перем ОбъявленияПеременных, ОбъявлениеПеременной, Объявление, Начало; Начало = Парсер_ДанныеТекущегоТокена; @@ -2321,6 +2565,7 @@ Объявление = Парсер_Узлы.ОбъявлениеСпискаПеременныхМодуля.Добавить(); Объявление.Тип = Типы.ОбъявлениеСпискаПеременныхМодуля; Объявление.Директивы = Парсер_СписокДиректив; + Объявление.Аннотации = Парсер_СписокАннотаций; Объявление.Объявления = ОбъявленияПеременных; Объявление.Начало = Начало; Объявление.Конец = Парсер_ДанныеПредыдущегоТокена; @@ -2413,9 +2658,10 @@ Возврат ОбъявлениеЛокальнойПеременной; КонецФункции // РазобратьОбъявлениеЛокальнойПеременной() -Функция РазобратьОбъявлениеМетода() - Перем Сигнатура, ЭлементОкружения, Имя, Переменные, Параметры, ЕстьЭкспорт, Операторы, Объявления, ОбъявлениеАвтоПеременной, Начало; - Начало = Парсер_ДанныеТекущегоТокена; +Функция РазобратьОбъявлениеМетода(НачалоАсинхронного = Неопределено) + Перем Сигнатура, ЭлементОкружения, Имя, Переменные, Параметры, ЕстьЭкспорт, Операторы, Объявления, ОбъявлениеАвтоПеременной, Начало, Асинхронный; + Асинхронный = (НачалоАсинхронного <> Неопределено); + Начало = ?(Асинхронный, НачалоАсинхронного, Парсер_ДанныеТекущегоТокена); ЕстьЭкспорт = Ложь; СледующийТокен(); Ожидать(Токены.Идентификатор); @@ -2434,6 +2680,7 @@ Сигнатура.Директивы = Парсер_СписокДиректив; Сигнатура.Аннотации = Парсер_СписокАннотаций; Сигнатура.Параметры = Параметры; + Сигнатура.Асинхронный = Асинхронный; Сигнатура.Экспорт = ЕстьЭкспорт; Сигнатура.Начало = Начало; Сигнатура.Конец = Парсер_ДанныеПредыдущегоТокена; @@ -2444,6 +2691,7 @@ Сигнатура.Директивы = Парсер_СписокДиректив; Сигнатура.Аннотации = Парсер_СписокАннотаций; Сигнатура.Параметры = Параметры; + Сигнатура.Асинхронный = Асинхронный; Сигнатура.Экспорт = ЕстьЭкспорт; Сигнатура.Начало = Начало; Сигнатура.Конец = Парсер_ДанныеПредыдущегоТокена; @@ -2511,8 +2759,12 @@ КонецФункции // РазобратьПараметры() Функция РазобратьОбъявлениеПараметра() - Перем Имя, ОбъявлениеПараметра, ПоЗначению, Начало; + Перем Имя, ОбъявлениеПараметра, ПоЗначению, Начало, АннотацииПараметра; Начало = Парсер_ДанныеТекущегоТокена; + АннотацииПараметра = Новый Массив; + Пока Парсер_Токен = Токены.Аннотация Цикл + АннотацииПараметра.Добавить(РазобратьОбъявлениеАннотации()); + КонецЦикла; Если Парсер_Токен = Токены.Знач Тогда ПоЗначению = Истина; СледующийТокен(); @@ -2526,6 +2778,7 @@ ОбъявлениеПараметра = Парсер_Узлы.ОбъявлениеПараметра.Добавить(); ОбъявлениеПараметра.Тип = Типы.ОбъявлениеПараметра; ОбъявлениеПараметра.Имя = Имя; + ОбъявлениеПараметра.Аннотации = АннотацииПараметра; ОбъявлениеПараметра.ПоЗначению = ПоЗначению; ОбъявлениеПараметра.Значение = РазобратьВыражениеУнарное(); ОбъявлениеПараметра.Начало = Начало; @@ -2534,6 +2787,7 @@ ОбъявлениеПараметра = Парсер_Узлы.ОбъявлениеПараметра.Добавить(); ОбъявлениеПараметра.Тип = Типы.ОбъявлениеПараметра; ОбъявлениеПараметра.Имя = Имя; + ОбъявлениеПараметра.Аннотации = АннотацииПараметра; ОбъявлениеПараметра.ПоЗначению = ПоЗначению; ОбъявлениеПараметра.Значение = Неопределено; ОбъявлениеПараметра.Начало = Начало; @@ -2601,6 +2855,8 @@ Оператор = РазобратьОператорВызватьИсключение(); ИначеЕсли Парсер_Токен = Токены.Выполнить Тогда Оператор = РазобратьОператорВыполнить(); + ИначеЕсли Парсер_Токен = Токены.Ждать Тогда + Оператор = РазобратьОператорЖдать(); ИначеЕсли Парсер_Токен = Токены.Перейти Тогда Оператор = РазобратьОператорПерейти(); ИначеЕсли Парсер_Токен = Токены.Метка Тогда @@ -2661,6 +2917,18 @@ Возврат Узел; КонецФункции // РазобратьОператорВыполнить() +Функция РазобратьОператорЖдать() + Перем Начало; + Начало = Парсер_ДанныеТекущегоТокена; + СледующийТокен(); + Узел = Парсер_Узлы.ОператорЖдать.Добавить(); + Узел.Тип = Типы.ОператорЖдать; + Узел.Выражение = РазобратьВыражение(); + Узел.Начало = Начало; + Узел.Конец = Парсер_ДанныеПредыдущегоТокена; + Возврат Узел; +КонецФункции // РазобратьОператорЖдать() + Функция РазобратьОператорПрисваиванияИлиВызоваПроцедуры() Перем ЛевыйОперанд, ЭтоВызов, ПравыйОперанд, Оператор, НоваяПеременная, Начало; Начало = Парсер_ДанныеТекущегоТокена; @@ -3150,6 +3418,19 @@ Возврат Узел; КонецФункции // РазобратьИнструкциюПрепроцессораОбласть() +Функция РазобратьИнструкциюПрепроцессораРежимВыполнения() + Перем Начало, Режим; + Начало = Парсер_ДанныеТекущегоТокена; + Режим = ?(Парсер_Токен = Токены._Native, "Native", "Stack"); + Парсер_Токен = Токены.ТочкаСЗапятой; // уловка + Узел = Парсер_Узлы.ИнструкцияПрепроцессораРежимВыполнения.Добавить(); + Узел.Тип = Типы.ИнструкцияПрепроцессораРежимВыполнения; + Узел.Режим = Режим; + Узел.Начало = Начало; + Узел.Конец = Парсер_ДанныеТекущегоТокена; + Возврат Узел; +КонецФункции // РазобратьИнструкциюПрепроцессораРежимВыполнения() + Функция РазобратьИнструкциюПрепроцессораКонецОбласти() Перем Начало; Начало = Парсер_ДанныеТекущегоТокена; @@ -3208,22 +3489,21 @@ Функция РазобратьИнструкциюПрепроцессораИспользовать() Перем Путь, Начало; Начало = Парсер_ДанныеТекущегоТокена; - СледующийТокен(); - Если Парсер_НомерТекущейСтроки <> Начало.НомерСтроки Тогда - Ошибка(20, Неопределено, Истина, Парсер_ДанныеТекущегоТокена); - КонецЕсли; - Если Парсер_Токен = Токены.Число Тогда - Путь = Парсер_Литерал; - Если КартаБуквЦифр[Парсер_Символ] = Буква Тогда - СледующийТокен(); - Путь = Путь + Парсер_Литерал; - КонецЕсли; - ИначеЕсли Парсер_Токен = Токены.Идентификатор - Или Парсер_Токен = Токены.Строка Тогда - Путь = Парсер_Литерал; + Если Парсер_ИмяБиблиотеки <> Неопределено Тогда + // имя библиотеки уже прочитано лексером целиком, вместе с дефисами и слэшами + Путь = Парсер_ИмяБиблиотеки; + Парсер_ИмяБиблиотеки = Неопределено; Иначе - Ошибка(20, Неопределено, Истина, Парсер_ДанныеТекущегоТокена); - КонецЕсли; + СледующийТокен(); + Если Парсер_НомерТекущейСтроки <> Начало.НомерСтроки Тогда + Ошибка(20, Неопределено, Истина, Парсер_ДанныеТекущегоТокена); + КонецЕсли; + Если Парсер_Токен = Токены.Строка Тогда + Путь = Парсер_Литерал; + Иначе + Ошибка(20, Неопределено, Истина, Парсер_ДанныеТекущегоТокена); + КонецЕсли; + КонецЕсли; Парсер_Токен = Токены.ТочкаСЗапятой; // уловка Узел = Парсер_Узлы.ИнструкцияПрепроцессораИспользовать.Добавить(); Узел.Тип = Типы.ИнструкцияПрепроцессораИспользовать; @@ -3375,12 +3655,14 @@ "ПосетитьВыражениеСкобочное, ПокинутьВыражениеСкобочное," "ПосетитьВыражениеНе, ПокинутьВыражениеНе," "ПосетитьВыражениеСтроковое, ПокинутьВыражениеСтроковое," + "ПосетитьВыражениеЖдать, ПокинутьВыражениеЖдать," "ПосетитьОператорПрисваивания, ПокинутьОператорПрисваивания," "ПосетитьОператорВозврат, ПокинутьОператорВозврат," "ПосетитьОператорПрервать, ПокинутьОператорПрервать," "ПосетитьОператорПродолжить, ПокинутьОператорПродолжить," "ПосетитьОператорВызватьИсключение, ПокинутьОператорВызватьИсключение," "ПосетитьОператорВыполнить, ПокинутьОператорВыполнить," + "ПосетитьОператорЖдать, ПокинутьОператорЖдать," "ПосетитьОператорВызоваПроцедуры, ПокинутьОператорВызоваПроцедуры," "ПосетитьОператорЕсли, ПокинутьОператорЕсли," "ПосетитьОператорИначеЕсли, ПокинутьОператорИначеЕсли," @@ -3485,7 +3767,8 @@ Или Тип = Типы.ИнструкцияПрепроцессораИначеЕсли Или Тип = Типы.ИнструкцияПрепроцессораИначе Или Тип = Типы.ИнструкцияПрепроцессораКонецЕсли - Или Тип = Типы.ИнструкцияПрепроцессораИспользовать Тогда + Или Тип = Типы.ИнструкцияПрепроцессораИспользовать + Или Тип = Типы.ИнструкцияПрепроцессораРежимВыполнения Тогда ПосетитьИнструкциюПрепроцессора(Объявление); КонецЕсли; КонецПроцедуры // ПосетитьОбъявлениеПоТипу() @@ -3618,6 +3901,8 @@ ПосетитьВыражениеНе(Выражение); ИначеЕсли Тип = Типы.ВыражениеСтроковое Тогда ПосетитьВыражениеСтроковое(Выражение); + ИначеЕсли Тип = Типы.ВыражениеЖдать Тогда + ПосетитьВыражениеЖдать(Выражение); КонецЕсли; КонецПроцедуры // ПосетитьВыражениеПоТипу() @@ -3761,12 +4046,45 @@ КонецЦикла; ДобавитьНаСтек(ВыражениеСкобочное); ПосетитьВыражениеПоТипу(ВыражениеСкобочное.Выражение); + ПосетитьХвост(ВыражениеСкобочное.Хвост); УдалитьСоСтека(); Для Каждого Подписка Из Посетитель_Подписки.ПокинутьВыражениеСкобочное Цикл Подписка.ПокинутьВыражениеСкобочное(ВыражениеСкобочное); КонецЦикла; КонецПроцедуры // ПосетитьВыражениеСкобочное() +Процедура ПосетитьХвост(Хвост) + Перем Элемент, Выражение; + Для Каждого Элемент Из Хвост Цикл + Если Элемент.Тип = Типы.ВыражениеПоле Тогда + Если Элемент.Аргументы <> Неопределено Тогда + Для Каждого Выражение Из Элемент.Аргументы Цикл + Если Выражение <> Неопределено Тогда + ПосетитьВыражениеПоТипу(Выражение); + КонецЕсли; + КонецЦикла; + КонецЕсли; + ИначеЕсли Элемент.Тип = Типы.ВыражениеИндекс Тогда + ПосетитьВыражениеПоТипу(Элемент.Выражение); + Иначе + ВызватьИсключение "нарушение протокола"; + КонецЕсли; + КонецЦикла; +КонецПроцедуры // ПосетитьХвост() + +Процедура ПосетитьВыражениеЖдать(ВыражениеЖдать) + Перем Подписка; + Для Каждого Подписка Из Посетитель_Подписки.ПосетитьВыражениеЖдать Цикл + Подписка.ПосетитьВыражениеЖдать(ВыражениеЖдать); + КонецЦикла; + ДобавитьНаСтек(ВыражениеЖдать); + ПосетитьВыражениеПоТипу(ВыражениеЖдать.Выражение); + УдалитьСоСтека(); + Для Каждого Подписка Из Посетитель_Подписки.ПокинутьВыражениеЖдать Цикл + Подписка.ПокинутьВыражениеЖдать(ВыражениеЖдать); + КонецЦикла; +КонецПроцедуры // ПосетитьВыражениеЖдать() + Процедура ПосетитьВыражениеНе(ВыражениеНе) Перем Подписка; Для Каждого Подписка Из Посетитель_Подписки.ПосетитьВыражениеНе Цикл @@ -3814,6 +4132,8 @@ ПосетитьОператорВызватьИсключение(Оператор); ИначеЕсли Тип = Типы.ОператорВыполнить Тогда ПосетитьОператорВыполнить(Оператор); + ИначеЕсли Тип = Типы.ОператорЖдать Тогда + ПосетитьОператорЖдать(Оператор); ИначеЕсли Тип = Типы.ОператорВызоваПроцедуры Тогда ПосетитьОператорВызоваПроцедуры(Оператор); ИначеЕсли Тип = Типы.ОператорЕсли Тогда @@ -3912,6 +4232,19 @@ КонецЦикла; КонецПроцедуры // ПосетитьОператорВызватьИсключение() +Процедура ПосетитьОператорЖдать(ОператорЖдать) + Перем Подписка; + Для Каждого Подписка Из Посетитель_Подписки.ПосетитьОператорЖдать Цикл + Подписка.ПосетитьОператорЖдать(ОператорЖдать); + КонецЦикла; + ДобавитьНаСтек(ОператорЖдать); + ПосетитьВыражениеПоТипу(ОператорЖдать.Выражение); + УдалитьСоСтека(); + Для Каждого Подписка Из Посетитель_Подписки.ПокинутьОператорЖдать Цикл + Подписка.ПокинутьОператорЖдать(ОператорЖдать); + КонецЦикла; +КонецПроцедуры // ПосетитьОператорЖдать() + Процедура ПосетитьОператорВыполнить(ОператорВыполнить) Перем Подписка; Для Каждого Подписка Из Посетитель_Подписки.ПосетитьОператорВыполнить Цикл diff --git "a/tests/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\320\270.os" "b/tests/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\320\270.os" new file mode 100644 index 0000000..eff219f --- /dev/null +++ "b/tests/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\320\270.os" @@ -0,0 +1,268 @@ +#Использовать asserts +#Использовать ".." + +// Аннотации OneScript: произвольные имена, параметры, вложенность, аннотации параметров метода. + +Функция Разобрать(Исходник) + + Парсер = Новый ПарсерВстроенногоЯзыка(); + Модуль = Парсер.Разобрать(Исходник); + + Ожидаем.Что(Парсер.ТаблицаОшибок().Количество(), "Ошибки разбора") + .Равно(0); + + Возврат Модуль; + +КонецФункции + +Функция ПерваяАннотацияМетода(Модуль) + + Возврат Модуль.Объявления[0].Сигнатура.Аннотации[0]; + +КонецФункции + +&Тест +Процедура АннотацияБезПараметров() Экспорт + + // Когда + + Модуль = Разобрать(" + |&Тест + |Процедура ТестЧегоТо() Экспорт + |КонецПроцедуры"); + + // Тогда + + Аннотация = ПерваяАннотацияМетода(Модуль); + + Ожидаем.Что(Аннотация.Имя, "Имя аннотации") + .Равно("Тест"); + + Ожидаем.Что(Аннотация.Параметры.Количество(), "Количество параметров") + .Равно(0); + +КонецПроцедуры + +&Тест +Процедура АннотацияСПозиционнымПараметром() Экспорт + + // Когда + + Модуль = Разобрать(" + |&ОтображаемоеИмя(""Проверка чего-то"") + |Процедура ТестЧегоТо() Экспорт + |КонецПроцедуры"); + + // Тогда + + Аннотация = ПерваяАннотацияМетода(Модуль); + + Ожидаем.Что(Аннотация.Имя, "Имя аннотации") + .Равно("ОтображаемоеИмя"); + + Ожидаем.Что(Аннотация.Параметры.Количество(), "Количество параметров") + .Равно(1); + + Параметр = Аннотация.Параметры[0]; + + Ожидаем.Что(Параметр.Имя, "Имя параметра") + .Равно(""); + + Ожидаем.Что(Параметр.Литерал, "Значение параметра") + .Равно("Проверка чего-то"); + +КонецПроцедуры + +&Тест +Процедура АннотацияСИменованнымПараметром() Экспорт + + // Когда + + Модуль = Разобрать(" + |&Деталька(""OneUnit.Таймаут"", ЗначениеПоУмолчанию = 500) + |Процедура ТестЧегоТо() Экспорт + |КонецПроцедуры"); + + // Тогда + + Аннотация = ПерваяАннотацияМетода(Модуль); + + Ожидаем.Что(Аннотация.Параметры.Количество(), "Количество параметров") + .Равно(2); + + Ожидаем.Что(Аннотация.Параметры[0].Имя, "Имя первого параметра") + .Равно(""); + + Ожидаем.Что(Аннотация.Параметры[1].Имя, "Имя второго параметра") + .Равно("ЗначениеПоУмолчанию"); + + Ожидаем.Что(Аннотация.Параметры[1].Литерал, "Значение второго параметра") + .Равно(500); + +КонецПроцедуры + +&Тест +Процедура АннотацияСВложеннойАннотацией() Экспорт + + // Когда + + Модуль = Разобрать(" + |&Напильник(ПрименяетсяТолькоНа = &Прозвище(""Желудь"")) + |Процедура ПриСозданииОбъекта() + |КонецПроцедуры"); + + // Тогда + + Аннотация = ПерваяАннотацияМетода(Модуль); + + Ожидаем.Что(Аннотация.Имя, "Имя внешней аннотации") + .Равно("Напильник"); + + Параметр = Аннотация.Параметры[0]; + + Ожидаем.Что(Параметр.Имя, "Имя параметра") + .Равно("ПрименяетсяТолькоНа"); + + Ожидаем.Что(Параметр.Значение.Тип, "Тип значения параметра") + .Равно(Новый ПарсерВстроенногоЯзыка().Типы().ОбъявлениеАннотации); + + Ожидаем.Что(Параметр.Значение.Имя, "Имя вложенной аннотации") + .Равно("Прозвище"); + +КонецПроцедуры + +&Тест +Процедура НесколькоАннотацийПодряд() Экспорт + + // Когда + + Модуль = Разобрать(" + |&Тест + |&Тег(""быстрый"") + |&Таймаут(1000) + |Процедура ТестЧегоТо() Экспорт + |КонецПроцедуры"); + + // Тогда + + Аннотации = Модуль.Объявления[0].Сигнатура.Аннотации; + + Ожидаем.Что(Аннотации.Количество(), "Количество аннотаций") + .Равно(3); + + Ожидаем.Что(Аннотации[2].Имя, "Имя третьей аннотации") + .Равно("Таймаут"); + +КонецПроцедуры + +&Тест +Процедура АннотацияПараметраМетода() Экспорт + + // Когда + + Модуль = Разобрать(" + |&Желудь + |Процедура ПриСозданииОбъекта(&Пластилин Сервис, Знач Обычный = 1) + |КонецПроцедуры"); + + // Тогда + + Параметры = Модуль.Объявления[0].Сигнатура.Параметры; + + Ожидаем.Что(Параметры.Количество(), "Количество параметров") + .Равно(2); + + Ожидаем.Что(Параметры[0].Аннотации.Количество(), "Аннотаций у первого параметра") + .Равно(1); + + Ожидаем.Что(Параметры[0].Аннотации[0].Имя, "Имя аннотации параметра") + .Равно("Пластилин"); + + Ожидаем.Что(Параметры[1].Аннотации.Количество(), "Аннотаций у второго параметра") + .Равно(0); + +КонецПроцедуры + +&Тест +Процедура АннотацияПараметраСПараметрами() Экспорт + + // Когда + + Модуль = Разобрать(" + |&Желудь + |Процедура ПриСозданииОбъекта(&Лог(""oscript.lib.mutatos"") Лог) + |КонецПроцедуры"); + + // Тогда + + Параметр = Модуль.Объявления[0].Сигнатура.Параметры[0]; + + Ожидаем.Что(Параметр.Аннотации[0].Имя, "Имя аннотации параметра") + .Равно("Лог"); + + Ожидаем.Что(Параметр.Аннотации[0].Параметры[0].Литерал, "Значение параметра аннотации") + .Равно("oscript.lib.mutatos"); + +КонецПроцедуры + +&Тест +Процедура АннотацияПеременнойМодуля() Экспорт + + // Когда + + Модуль = Разобрать(" + |&Пластилин + |Перем Сервис;"); + + // Тогда + + Объявление = Модуль.Объявления[0]; + + Ожидаем.Что(Объявление.Аннотации.Количество(), "Количество аннотаций") + .Равно(1); + + Ожидаем.Что(Объявление.Аннотации[0].Имя, "Имя аннотации") + .Равно("Пластилин"); + +КонецПроцедуры + +&Тест +Процедура ДирективыКомпиляцииНеСломаны() Экспорт + + // Когда + + Модуль = Разобрать(" + |&НаКлиенте + |Процедура НаКлиенте() Экспорт + |КонецПроцедуры"); + + // Тогда + + Ожидаем.Что(Модуль.Объявления[0].Сигнатура.Директивы.Количество(), "Количество директив") + .Равно(1); + +КонецПроцедуры + +&Тест +Процедура АннотацияПередКакРаньше() Экспорт + + // Аннотации 1С разбираются как обычные аннотации, но ИмяМетода остаётся доступным + + // Когда + + Модуль = Разобрать(" + |&Перед(""ИмяМетода"") + |Процедура Обработчик() Экспорт + |КонецПроцедуры"); + + // Тогда + + Аннотация = ПерваяАннотацияМетода(Модуль); + + Ожидаем.Что(Аннотация.Имя, "Имя аннотации") + .Равно("Перед"); + + Ожидаем.Что(Аннотация.ИмяМетода, "ИмяМетода для совместимости") + .Равно("ИмяМетода"); + +КонецПроцедуры diff --git "a/tests/\320\241\320\270\320\275\321\202\320\260\320\272\321\201\320\270\321\201OneScript.os" "b/tests/\320\241\320\270\320\275\321\202\320\260\320\272\321\201\320\270\321\201OneScript.os" new file mode 100644 index 0000000..6d78e20 --- /dev/null +++ "b/tests/\320\241\320\270\320\275\321\202\320\260\320\272\321\201\320\270\321\201OneScript.os" @@ -0,0 +1,348 @@ +#Использовать asserts +#Использовать ".." + +// Конструкции OneScript, которых нет во встроенном языке 1С:Предприятие, +// и общие конструкции, разбор которых не должен сломаться при доработках. + +Функция Разобрать(Исходник) + + Парсер = Новый ПарсерВстроенногоЯзыка(); + Модуль = Парсер.Разобрать(Исходник); + + Ожидаем.Что(Парсер.ТаблицаОшибок().Количество(), "Ошибки разбора") + .Равно(0); + + Возврат Модуль; + +КонецФункции + +#Область ИнструкцияИспользовать + +&Тест +Процедура ИспользоватьПростоеИмя() Экспорт + + Модуль = Разобрать(" + |#Использовать asserts + |А = 1;"); + + Ожидаем.Что(Модуль.Объявления[0].Путь, "Имя библиотеки") + .Равно("asserts"); + +КонецПроцедуры + +&Тест +Процедура ИспользоватьИмяСДефисом() Экспорт + + Модуль = Разобрать(" + |#Использовать autumn-collections + |А = 1;"); + + Ожидаем.Что(Модуль.Объявления[0].Путь, "Имя библиотеки") + .Равно("autumn-collections"); + +КонецПроцедуры + +&Тест +Процедура ИспользоватьИмяСоСлэшем() Экспорт + + Модуль = Разобрать(" + |#Использовать oint/api/grpc + |А = 1;"); + + Ожидаем.Что(Модуль.Объявления[0].Путь, "Имя библиотеки") + .Равно("oint/api/grpc"); + +КонецПроцедуры + +&Тест +Процедура ИспользоватьИмяНачинающеесяСЦифры() Экспорт + + Модуль = Разобрать(" + |#Использовать 1commands + |А = 1;"); + + Ожидаем.Что(Модуль.Объявления[0].Путь, "Имя библиотеки") + .Равно("1commands"); + +КонецПроцедуры + +&Тест +Процедура ИспользоватьИмяСТочкой() Экспорт + + Модуль = Разобрать(" + |#Использовать v8.runner + |А = 1;"); + + Ожидаем.Что(Модуль.Объявления[0].Путь, "Имя библиотеки") + .Равно("v8.runner"); + +КонецПроцедуры + +&Тест +Процедура ИспользоватьПутьВКавычках() Экспорт + + Модуль = Разобрать(" + |#Использовать ""./внутренние"" + |А = 1;"); + + // путь сохраняется вместе с кавычками, как он записан в исходнике + Ожидаем.Что(Модуль.Объявления[0].Путь, "Путь") + .Равно("""./внутренние"""); + +КонецПроцедуры + +#КонецОбласти // ИнструкцияИспользовать + +#Область ДирективыМодуля + +&Тест +Процедура ДирективаNative() Экспорт + + Модуль = Разобрать(" + |#Native + |А = 1;"); + + Ожидаем.Что(Модуль.Объявления[0].Режим, "Режим выполнения") + .Равно("Native"); + +КонецПроцедуры + +&Тест +Процедура ДирективаStack() Экспорт + + Модуль = Разобрать(" + |#Stack + |А = 1;"); + + Ожидаем.Что(Модуль.Объявления[0].Режим, "Режим выполнения") + .Равно("Stack"); + +КонецПроцедуры + +&Тест +Процедура ДирективаРежимаВместеСИспользовать() Экспорт + + Модуль = Разобрать(" + |#Native + |#Использовать asserts + |А = 1;"); + + Ожидаем.Что(Модуль.Объявления.Количество(), "Количество объявлений") + .Равно(2); + +КонецПроцедуры + +&Тест +Процедура СтрокаЗапускаСкрипта() Экспорт + + Разобрать(" + |#!/usr/bin/env oscript + |#Использовать asserts + |А = 1;"); + +КонецПроцедуры + +#КонецОбласти // ДирективыМодуля + +#Область ПостфиксныеМодификаторы + +&Тест +Процедура СвойствоСкобочногоВыражения() Экспорт + + Разобрать("ПолноеИмя = (Новый Файл(Путь)).ПолноеИмя;"); + +КонецПроцедуры + +&Тест +Процедура ВызовМетодаСкобочногоВыражения() Экспорт + + Разобрать(" + |Если Не (Новый Файл(Путь)).Существует() Тогда + | А = 1; + |КонецЕсли;"); + +КонецПроцедуры + +&Тест +Процедура ИндексСкобочногоВыражения() Экспорт + + Разобрать("Элемент = (А + Б)[1];"); + +КонецПроцедуры + +&Тест +Процедура ВызовМетодаНовогоОбъекта() Экспорт + + Разобрать(" + |Если Новый Рефлектор.МетодСуществует(Объект, ""Имя"") Тогда + | А = 1; + |КонецЕсли;"); + +КонецПроцедуры + +&Тест +Процедура ЦепочкаВызововПослеНовый() Экспорт + + Разобрать(" + |Объект = Новый ПостроительДекоратора + | .Поле(Новый Поле(""Число"")) + | .Метод(Новый Метод(""Имя""));"); + +КонецПроцедуры + +&Тест +Процедура СвойствоНовогоОбъектаБезСкобок() Экспорт + + Разобрать("Значение = Новый Массив.Количество();"); + +КонецПроцедуры + +#КонецОбласти // ПостфиксныеМодификаторы + +#Область АсинхронныеМетоды + +&Тест +Процедура АсинхроннаяФункция() Экспорт + + Модуль = Разобрать(" + |Асинх Функция Прочитать() + | Возврат 1; + |КонецФункции"); + + Ожидаем.Что(Модуль.Объявления[0].Сигнатура.Асинхронный, "Признак асинхронности") + .ЭтоИстина(); + +КонецПроцедуры + +&Тест +Процедура АсинхроннаяПроцедура() Экспорт + + Модуль = Разобрать(" + |Асинх Процедура Записать() + |КонецПроцедуры"); + + Ожидаем.Что(Модуль.Объявления[0].Сигнатура.Асинхронный, "Признак асинхронности") + .ЭтоИстина(); + +КонецПроцедуры + +&Тест +Процедура ОператорЖдать() Экспорт + + Разобрать(" + |Асинх Функция Прочитать() + | Результат = Ждать ПолучитьДанные(); + | Возврат Результат; + |КонецФункции"); + +КонецПроцедуры + +&Тест +Процедура ЖдатьБезПрисваивания() Экспорт + + Разобрать(" + |Асинх Процедура Обработать() + | Ждать Сохранить(); + |КонецПроцедуры"); + +КонецПроцедуры + +&Тест +Процедура ОбычнаяФункцияНеАсинхронная() Экспорт + + Модуль = Разобрать(" + |Функция Прочитать() + | Возврат 1; + |КонецФункции"); + + Ожидаем.Что(Модуль.Объявления[0].Сигнатура.Асинхронный, "Признак асинхронности") + .ЭтоЛожь(); + +КонецПроцедуры + +#КонецОбласти // АсинхронныеМетоды + +#Область РегрессияОбщихКонструкций + +&Тест +Процедура ТернарныйОператор() Экспорт + + Разобрать("А = ?(Б = 1, 2, 3);"); + +КонецПроцедуры + +&Тест +Процедура МноголинейнаяСтрока() Экспорт + + Разобрать("А = ""начало" + Символы.ПС + " |продолжение"";"); + +КонецПроцедуры + +&Тест +Процедура МеткаИПерейти() Экспорт + + Разобрать(" + |~Метка: + |А = 1; + |Перейти ~Метка;"); + +КонецПроцедуры + +&Тест +Процедура ОбработчикиСобытий() Экспорт + + Разобрать(" + |ДобавитьОбработчик Событие, Обработчик; + |УдалитьОбработчик Событие, Обработчик;"); + +КонецПроцедуры + +&Тест +Процедура ПрепроцессорныеИнструкции() Экспорт + + Разобрать(" + |#Если Сервер Тогда + | А = 1; + |#КонецЕсли"); + +КонецПроцедуры + +&Тест +Процедура ОбластиИЦиклы() Экспорт + + Разобрать(" + |#Область Публичные + |Процедура Обойти(Коллекция) Экспорт + | Для Каждого Элемент Из Коллекция Цикл + | Прервать; + | КонецЦикла; + | Для Сч = 1 По 10 Цикл + | Продолжить; + | КонецЦикла; + |КонецПроцедуры + |#КонецОбласти"); + +КонецПроцедуры + +&Тест +Процедура ПопыткаИсключение() Экспорт + + Разобрать(" + |Попытка + | А = 1; + |Исключение + | ВызватьИсключение; + |КонецПопытки;"); + +КонецПроцедуры + +&Тест +Процедура ДатаИЧисловыеЛитералы() Экспорт + + Разобрать(" + |Дата = '20240101'; + |Число = -1.5;"); + +КонецПроцедуры + +#КонецОбласти // РегрессияОбщихКонструкций From 0653343a01d99b3b32674c06507957e4b96b3d56 Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Thu, 27 Aug 2026 07:16:35 +0200 Subject: [PATCH 2/4] =?UTF-8?q?=D0=A1=D0=B1=D0=BE=D1=80=D0=BE=D1=87=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=BB=D0=B8=D0=BD=D0=B8=D0=B8=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B8=20=D0=BF=D1=83=D0=B1=D0=BB=D0=B8=D0=BA=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8=20=D1=80=D0=B5=D0=BB=D0=B8=D0=B7=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Используются переиспользуемые workflow из autumn-library/workflows: тесты OneUnit на актуальных версиях движка и публикация пакета в hub.oscript.io при выходе GitHub Release. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CP3TEtTKWGE2wxRjEDwVRV --- .github/workflows/release.yml | 15 +++++++++++++++ .github/workflows/test.yml | 20 ++++++++++++++++++++ tests/oscript.cfg | 1 + 3 files changed, 36 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test.yml create mode 100644 tests/oscript.cfg diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..19ee74a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,15 @@ +name: Публикация релиза + +on: + release: + types: + - published + workflow_dispatch: + +jobs: + release: + uses: autumn-library/workflows/.github/workflows/release.yml@v1 + with: + package_mask: "osparser-*.ospx" + secrets: + PUSH_TOKEN: ${{ secrets.PUSH_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..acde52a --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,20 @@ +name: Тестирование + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + test: + strategy: + fail-fast: false + matrix: + # версия среды из packagedef (1.0.21) оставлена для совместимости самой библиотеки, + # но тесты используют OneUnit, которому нужен движок 2.0 и новее + oscript_version: ['stable', 'dev'] + uses: autumn-library/workflows/.github/workflows/test.yml@v1 + with: + oscript_version: ${{ matrix.oscript_version }} + test_engine: oneunit + test_dir_paths: tests diff --git a/tests/oscript.cfg b/tests/oscript.cfg new file mode 100644 index 0000000..4101683 --- /dev/null +++ b/tests/oscript.cfg @@ -0,0 +1 @@ +lib.additional=../oscript_modules From f02f1893f7ce61cae40a53f5bda72dab0446e6c4 Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Thu, 27 Aug 2026 07:19:56 +0200 Subject: [PATCH 3/4] =?UTF-8?q?=D0=AF=D0=B2=D0=BD=D0=B0=D1=8F=20=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D1=81=D0=B8=D1=8F=20=D0=B4=D0=B2=D0=B8=D0=B6=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B2=20=D1=80=D0=B5=D0=BB=D0=B8=D0=B7=D0=BD=D0=BE?= =?UTF-8?q?=D0=B9=20=D1=81=D0=B1=D0=BE=D1=80=D0=BE=D1=87=D0=BD=D0=BE=D0=B9?= =?UTF-8?q?=20=D0=BB=D0=B8=D0=BD=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit По умолчанию версия вычисляется из ВерсияСреды в packagedef (1.0.21), которая оставлена для совместимости библиотеки. Сборка и публикация пакета выполняются на актуальном движке. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CP3TEtTKWGE2wxRjEDwVRV --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 19ee74a..8cccecd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,6 +10,7 @@ jobs: release: uses: autumn-library/workflows/.github/workflows/release.yml@v1 with: + oscript_version: stable package_mask: "osparser-*.ospx" secrets: PUSH_TOKEN: ${{ secrets.PUSH_TOKEN }} From 0ed1c678eb612cda37ee134471d7885eb83655ac Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Thu, 27 Aug 2026 07:23:47 +0200 Subject: [PATCH 4/4] =?UTF-8?q?=D0=90=D0=B4=D1=80=D0=B5=D1=81=20=D1=80?= =?UTF-8?q?=D0=B5=D0=BF=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B2=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CP3TEtTKWGE2wxRjEDwVRV --- packagedef | 1 + 1 file changed, 1 insertion(+) diff --git a/packagedef b/packagedef index 2560d8d..4ad8751 100644 --- a/packagedef +++ b/packagedef @@ -5,6 +5,7 @@ Описание.Имя("osparser") .Версия("0.1.0") .ВерсияСреды("1.0.21") + .АдресРепозитория("https://github.com/oscript-library/osparser") .ВключитьФайл("src") .ВключитьФайл("examples") .ВключитьФайл("docs")