├── .gitignore ├── .vscode └── launch.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── book.md ├── docgen.os ├── docs ├── ast.css └── index.html ├── examples ├── backends │ └── Классы │ │ ├── ГенераторДокументацииДляПарсера.os │ │ └── Компилятор.os ├── multiprocessing.ps1 ├── param.json ├── plugins │ └── Классы │ │ ├── Визажист.os │ │ ├── ДетекторВложенныхТернарныхОператоров.os │ │ ├── ДетекторКонструкторовСтруктур.os │ │ ├── ДетекторНеиспользуемыхПеременных.os │ │ ├── ДетекторОшибочныхЗамыкающихКомментариев.os │ │ ├── ДетекторПропущенныхТочекСЗапятой.os │ │ ├── ДетекторФункцийБезВозвратаВКонце.os │ │ ├── ЗаменаНеканоничныхКлючевыхСлов.os │ │ ├── ПереименованиеПеременных.os │ │ ├── ПлагинСПараметром.os │ │ ├── ПодсчетКогнитивнойСложностиМетодов.os │ │ ├── ПроверкаКаноничностиКлючевыхСлов.os │ │ ├── РасстановкаПропущенныхТочекСЗапятой.os │ │ └── РекурсивныйПодсчетСерверныхВызововВМодуляхФорм.os ├── test.os ├── test2.os ├── test3.os ├── test4.os ├── test5.os ├── test6.os ├── test7.os ├── test8.os └── test9.os ├── packagedef └── src └── Классы └── ПарсерВстроенногоЯзыка.os /.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | sandbox -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Отладка 1Script", 9 | "type": "oscript", 10 | "request": "launch", 11 | "program": "${file}", 12 | "args": [], 13 | "cwd": "${workspaceRoot}", 14 | "runtimeExecutable": null, 15 | "debugPort": 2801, 16 | "protocol": "internal" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Вы можете оказать следующую помощь проекту: 2 | * Сообщить об ошибке [тут](https://github.com/oscript-library/osparser/issues) 3 | * Предложить исправление ошибки любым удобным для вас способом 4 | * Поделиться идеями по улучшению конкретного кода или архитектуры в целом 5 | * Дополнить или улучшить документацию 6 | 7 | Формальностей на данный момент никаких нет. Просьба только сначала создавать [issue](https://github.com/oscript-library/osparser/issues), а pull request уже после обсуждения. 8 | 9 | Чтобы создать пулл реквест (запрос на вливание изменений из вашего форка в исходный репозиторий), нужно выполнить следующую последовательность шагов: 10 | * Установить [git](https://git-scm.com/) 11 | * Создать форк (копию) этого репозитория на [github](https://github.com/oscript-library/osparser) (кнопка справа вверху) 12 | * Клонировать этот форк себе на диск: `git clone https://github.com/<ваш_аккаунт>/osparser` 13 | * Внести правки 14 | * Зафиксировать изменения: `git add .` и `git commit -am "суть правки (#<номер_issue>)"` 15 | * Отправить изменения на github: `git push` 16 | * Открыть форк на github, перейти на вкладку "Pull requests" и создать новый 17 | * Подтвердить 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Tsukanov Alexander 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # osparser (oscript parser) 2 | 3 | ## Парсер встроенного языка платформы 1С:Предприятие 8 4 | 5 | Документация: [Книга Джедая](book.md) 6 | 7 | Установка: `opm install osparser` 8 | 9 | Самый короткий пример без плагинов: 10 | 11 | ```bsl 12 | #Использовать osparser 13 | 14 | Парсер = Новый ПарсерВстроенногоЯзыка; 15 | АСД = Парсер.Разобрать("x = x + 1;"); 16 | Сообщить(АСД.Операторы.Количество()); 17 | ``` 18 | 19 | ## Содержание 20 | 21 | 1. [Введение](#введение) 22 | 2. [Структура репозитория](#структура-репозитория) 23 | 3. [Принцип работы](#принцип-работы) 24 | 4. [Благодарности](#благодарности) 25 | 26 | ## Введение 27 | 28 | Перед тем как разбираться с этим проектом, убедитесь что вы хорошо понимаете что такое AST и Visitor и что можно с их помощью делать. 29 | Это важно, так как данная разработка предоставляет именно эти возможности. Не больше не меньше. 30 | Вы можете писать проверки кода, компиляторы, интерпретаторы и любые другие вещи, которые можно реализовать путем обработки AST. 31 | Сколько информации содержит AST можно увидеть тут: https://oscript-library.github.io/osparser 32 | 33 | Общее представление можно получить в этой статье: [Зачем нужен AST](https://ps-group.github.io/compilers/ast) 34 | 35 | Данная разработка устроена похожим образом. С поправкой на то, что это реализация без ООП на языке 1С. 36 | После ознакомления со статьей можно сразу посмотреть [Принцип работы](#принцип-работы) внизу этой страницы. 37 | 38 | По сути это фронтенд компилятора, а вы можете к нему писать бакенды (плагины). 39 | 40 | Пример плагина проверяющего наличие возврата в конце функций: [ДетекторФункцийБезВозвратаВКонце](./examples/plugins/Классы/ДетекторФункцийБезВозвратаВКонце.os) 41 | 42 | Конкретно весь код проверки выглядит так (остальное там просто интерфейс плагина): 43 | 44 | ```bsl 45 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 46 | Перем КоличествоОператоров; 47 | Если ОбъявлениеМетода.Сигнатура.Тип <> Типы.ОбъявлениеСигнатурыФункции Тогда 48 | Возврат; 49 | КонецЕсли; 50 | КоличествоОператоров = ОбъявлениеМетода.Операторы.Количество(); 51 | Если КоличествоОператоров = 0 Или ОбъявлениеМетода.Операторы[КоличествоОператоров - 1].Тип <> Типы.ОператорВозврат Тогда 52 | Текст = СтрШаблон("Последней инструкцией функции `%1()` должен быть `Возврат`""", ОбъявлениеМетода.Сигнатура.Имя); 53 | Ошибка(Текст, ОбъявлениеМетода.Конец); 54 | КонецЕсли; 55 | КонецПроцедуры 56 | ``` 57 | 58 | Эта процедура вызывается визитером (Visitor) во время обхода AST для каждой встреченной процедуры или функции. 59 | Суть реализации проверки: Сначала проверяется что это функция. Затем берется количество операторов в теле функции. 60 | Если 0 или последний оператор не `Возврат`, то регистрируется ошибка. 61 | 62 | Пример плагина средней сложности: [ДетекторНеиспользуемыхПеременных](./examples/plugins/Классы/ДетекторНеиспользуемыхПеременных.os) 63 | (этот код находит неиспользуемые переменные и параметры) 64 | 65 | Пример сложного бакенда: [Компилятор](./examples/backends/Классы/Компилятор.os) 66 | (это генератор байткода, который работает идентично платформенному) 67 | 68 | Пример на OneScript, демонстрирующий прогон проверок исходного кода: [test.os](./examples/test.os) 69 | 70 | Пример на OneScript, демонстрирующий автоматическое исправление исходного кода: [test8.os](./examples/test8.os) 71 | 72 | Пример выгрузки ошибок в [SonarQube](https://www.sonarqube.org/): [test7.os](./examples/test7.os) 73 | 74 | ## Структура репозитория 75 | 76 | * /docs - файлы веб-страницы проекта 77 | * /examples - примеры 78 | * /src - исходники парсера 79 | * /docgen.os - скрипт, генерирующий документацию в папке /docs 80 | 81 | ## Принцип работы 82 | 83 | Парсер разбирает переданный ему исходный код и возвращает модель этого кода в виде [абстрактного синтаксического дерева](https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%BE%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE). Узлы этого дерева соответствуют синтаксическим конструкциям и операторам языка. Например, конструкция `Пока <условие> Цикл <тело> КонецЦикла` представлена в дереве узлами типа `ОператорПока`, в которых условие представлено в подчиненном узле-выражении `Выражение`, а тело хранится в массиве узлов-операторов `Операторы`. Данных в дереве достаточно для полного восстановления по нему исходного кода вместе с комментариями, за исключением некоторых деталей форматирования. Порядок и подчиненность узлов в дереве в точности соответствует исходному коду. Описание узлов и элементов дерева вы можете найти на веб-странице проекта: [https://oscript-library.github.io/osparser](https://oscript-library.github.io/osparser) 84 | 85 | После формирования дерева запускается общий механизм обхода (шаблон проектирования Visitor), который при посещении узла вызывает обработчики подписанных на этот узел плагинов. Полезная (прикладная) работа выполняется именно плагином. Это может быть сбор статистики, поиск ошибок, анализ цикломатической сложности, построение документации по коду и т.д. и т.п. Кроме того, плагин может выполнить модификацию исходного кода путем регистрации замен фрагментов текста в исходнике (например, в целях исправления ошибок или форматирования). 86 | 87 | Состояние плагина (в переменных модуля) сохраняется между вызовами до самого конца обхода дерева, а подписки на каждый узел возможны две: перед обходом узла и после обхода. Это существенно упрощает реализацию многих алгоритмов анализа. Плюс к этому, некоторую информацию предоставляет сам механизм обхода. Например, плагинам доступна статистика по родительским узлам (количество каждого вида). 88 | 89 | ## Благодарности 90 | 91 | Спасибо всем кто так или иначе повлиял на этот проект. 92 | -------------------------------------------------------------------------------- /book.md: -------------------------------------------------------------------------------- 1 | # Книга Джедая 2 | 3 | May the Force be with you. 4 | 5 | ## Содержание 6 | 7 | - [Парсер](#парсер) 8 | - [Общие сведения](#общие-сведения) 9 | - [Программный интерфейс парсера](#программный-интерфейс-парсера) 10 | - [Основные методы](#основные-методы) 11 | - [`Пуск`](#пускисходник-плагины-параметры-окружение-массив) 12 | - [`Разобрать`](#разобратьисходник-окружение-структура) 13 | - [`Подключить`](#подключитьплагины) 14 | - [`Посетить`](#посетитьмодуль-параметры) 15 | - [`Токенизировать`](#токенизироватьисходник-таблицазначений) 16 | - [`ВыполнитьЗамены`](#выполнитьзамены-строка) 17 | - [`Очистить`](#очистить) 18 | - [Дополнительные методы](#дополнительные-методы) 19 | - [`Узлы`](#узлы-структура) 20 | - [`КлючевыеСлова`](#ключевыеслова-структура) 21 | - [`Токены`](#токены-структура) 22 | - [`Типы`](#типы-структура) 23 | - [`Директивы`](#директивы-структура) 24 | - [`Аннотации`](#аннотации-структура) 25 | - [`СимволыПрепроцессора`](#символыпрепроцессора-структура) 26 | - [`Стек`](#стек-массив) 27 | - [`Счетчики`](#счетчики-соответствие) 28 | - [`Исходник`](#исходник-строка) 29 | - [`ТаблицаТокенов`](#таблицатокенов-таблицазначений) 30 | - [`ТаблицаОшибок`](#таблицаошибок-таблицазначений) 31 | - [`ТаблицаЗамен`](#таблицазамен-таблицазначений) 32 | - [Продвинутые методы](#продвинутые-методы) 33 | - [`Окружение`](#окружениевнешнееокружение-структура) 34 | - [`ЭлементОкружения`](#элементокруженияимя-объявление-структура) 35 | - [`ОбъявлениеГлобальногоОбъекта`](#объявлениеглобальногообъектаимя-доступность-структура) 36 | - [`ОбъявлениеГлобальногоМетода`](#объявлениеглобальногометодаимя-возвращаетзначение-параметры-доступность-структура) 37 | - [`Доступность`](#доступностьклиент-внешнеесоединение-мобильноеприложение-мобильныйклиент-мобильныйсервер-сервер-толстыйклиент-тонкийклиент-вебклиент-интеграция-структура) 38 | - [Служебные методы](#служебные-методы) 39 | - [`УстановитьИсходник`](#установитьисходникисходник) 40 | - [`УстановитьТаблицуТокенов`](#установитьтаблицутокеновтаблицатокенов) 41 | - [`УстановитьТаблицуОшибок`](#установитьтаблицуошибоктаблицаошибок) 42 | - [Параметры](#параметры) 43 | - [`СтрогийРежим`](#строгийрежим-булево) 44 | - [Плагины](#плагины) 45 | - [Программный интерфейс плагина](#программный-интерфейс-плагина) 46 | - [`Открыть`](#открытьпарсер-параметры) 47 | - [`Закрыть`](#закрыть-произвольный) 48 | - [`Подписки`](#подписки-массив) 49 | - [Минимальный шаблон плагина](#минимальный-шаблон-плагина) 50 | - [Полный шаблон плагина](#полный-шаблон-плагина) 51 | - [Бакенды](#бакенды) 52 | - [Программный интерфейс бакенда](#программный-интерфейс-бакенда) 53 | - [`Посетить`](#посетитьпарсер-асд-произвольный) 54 | 55 | ## Парсер 56 | 57 | ### Общие сведения 58 | 59 | Парсер полностью реализован в виде одного класса `ПарсерВстроенногоЯзыка`, который предоставляет три механизма: 60 | 61 | - Разбор исходного кода на встроенном языке платформы 1С:Предприятие 8.3 с результатом в виде AST. 62 | - Встроенный механизм обхода AST для плагинов. 63 | - Встроенный механизм замен участков текста в исходнике. 64 | 65 | Создать экземпляр парсера можно следующим образом: 66 | 67 | ```bsl 68 | #Использовать osparser 69 | 70 | Парсер = Новый ПарсерВстроенногоЯзыка; 71 | ``` 72 | 73 | Типичный сценарий работы с плагинами, которые регистрируют ошибки: 74 | 75 | ```bsl 76 | Плагины = Новый Массив; 77 | Плагины.Добавить(Новый ДетекторНеиспользуемыхПеременных); 78 | Плагины.Добавить(Новый ДетекторПропущенныхТочекСЗапятой); 79 | Парсер.Пуск(Исходник, Плагины); 80 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 81 | Сообщить(СтрШаблон("%1 [стр: %2; кол: %3]", Ошибка.Текст, Ошибка.НомерСтрокиНачала, Ошибка.НомерКолонкиНачала)) 82 | КонецЦикла; 83 | ``` 84 | 85 | Типичный сценарий работы с плагинами, которые генерируют текст: 86 | 87 | ```bsl 88 | Результаты = ПарсерВстроенногоЯзыка.Пуск(Исходник, Плагин); 89 | Сообщить(СтрСоединить(Результаты)); 90 | ``` 91 | 92 | Типичный сценарий работы с плагинами, которые регистрируют замены: 93 | 94 | ```bsl 95 | Плагины = Новый Массив; 96 | Плагины.Добавить(Новый РасстановкаПропущенныхТочекСЗапятой); 97 | Плагины.Добавить(Новый ЗаменаНеканоничныхКлючевыхСлов); 98 | Парсер.Пуск(Исходник, Плагины); 99 | ИсправленныйИсходник = Парсер.ВыполнитьЗамены(); 100 | Сообщить(ИсправленныйИсходник); 101 | ``` 102 | 103 | Типичный сценарий работы с бакендом: 104 | 105 | ```bsl 106 | АСД = Парсер.Разобрать(Исходник); 107 | Текст = Бакенд.Посетить(Парсер, АСД); 108 | Сообщить(Текст); 109 | ``` 110 | 111 | ### Программный интерфейс парсера 112 | 113 | #### Основные методы 114 | 115 | Данные методы составляют основной программный интерфейс для внешней по отношению к парсеру системы. Позволяют выполнить разбор исходного кода, обход AST с плагинами и выполнить модификацию исходного кода по сгенерированным плагинами заменам. 116 | 117 | Чаще всего используется метод `Пуск()`, который заключает в себе типовую последовательность вызовов `Разобрать()`, `Подключить()`, `Посетить()` и `Очистить()`. 118 | Рабочие примеры использования данных методов смотрите в скриптах в папке [/examples](/examples) 119 | 120 | ##### `Пуск(Исходник, Плагины, Параметры, Окружение): Массив` 121 | 122 | *Выполняет разбор исходника в указанном окружении, обход AST с указанными плагинами и их параметрами и возвращает результаты (обычно текстовые) работы плагинов.* 123 | 124 | Параметры: 125 | 126 | - `Исходник: Строка` -- исходный код для анализа. 127 | - `Плагины: Массив или Объект` -- плагины, с которыми будет выполняться обход AST. 128 | - `Параметры: Соответствие (необязательный)` -- параметры плагинов. 129 | - `Окружение: Структура (необязательный)` -- окружение (контекст), в котором будет выполняться разбор исходника. 130 | 131 | Пример с одним плагином: 132 | 133 | ```bsl 134 | Исходник = ЧтениеТекста.Прочитать(); 135 | 136 | Парсер = Новый ПарсерВстроенногоЯзыка; 137 | 138 | Плагин = Новый Плагин; 139 | 140 | Парсер.Пуск(Исходник, Плагин); // тут выполняется синтаксический анализ и обход АСД с плагинами 141 | 142 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 143 | Сообщить(Ошибка.Текст); // вывод найденных парсером и плагином ошибок 144 | КонецЦикла; 145 | ``` 146 | 147 | Пример с набором плагинов: 148 | 149 | ```bsl 150 | Исходник = ЧтениеТекста.Прочитать(); 151 | 152 | Парсер = Новый ПарсерВстроенногоЯзыка; 153 | 154 | Плагины = Новый Массив; 155 | Плагины.Добавить(Новый Плагин1); 156 | Плагины.Добавить(Новый Плагин2); 157 | 158 | Парсер.Пуск(Исходник, Плагины); // тут выполняется синтаксический анализ и обход АСД с плагинами 159 | 160 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 161 | Сообщить(Ошибка.Текст); // вывод найденных парсером и плагинами ошибок 162 | КонецЦикла; 163 | ``` 164 | 165 | Пример с параметрами плагинов: 166 | 167 | ```bsl 168 | Исходник = ЧтениеТекста.Прочитать(); 169 | 170 | Парсер = Новый ПарсерВстроенногоЯзыка; 171 | Плагин1 = Новый Плагин1; 172 | Плагин2 = Новый Плагин2; 173 | 174 | Плагины = Новый Массив; 175 | Плагины.Добавить(Плагин1); 176 | Плагины.Добавить(Плагин2); 177 | 178 | Параметры = Новый Соответствие; // у каждого плагина своя структура параметров 179 | Параметры[Плагин1] = Новый Структура("Параметр1, Параметр2", 1, 2); 180 | Параметры[Плагин2] = Новый Структура("Параметр1, Параметр2", 3, 4) 181 | 182 | Парсер.Пуск(Исходник, Плагины, Параметры); // тут выполняется синтаксический анализ и обход АСД с плагинами 183 | 184 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 185 | Сообщить(Ошибка.Текст); // вывод найденных парсером и плагинами ошибок 186 | КонецЦикла; 187 | ``` 188 | 189 | Пример с окружением: 190 | 191 | ```bsl 192 | Исходник = ЧтениеТекста.Прочитать(); 193 | 194 | Парсер = Новый ПарсерВстроенногоЯзыка; 195 | Узлы = Парсер.Узлы(); 196 | 197 | Плагин = Новый Плагин); 198 | 199 | Окружение = Парсер.Окружение(); 200 | 201 | // например, контекст формы: 202 | Элемент = Узлы.ЭлементОкружения.Добавить(); 203 | Элемент.Имя = "ЭтаФорма"; 204 | ПроизвольноеОкружение.Переменные.Вставить("ЭтаФорма", Элемент); 205 | // ... 206 | Элемент = Узлы.ЭлементОкружения.Добавить(); 207 | Элемент.Имя = "РеквизитФормыВЗначение"; 208 | ПроизвольноеОкружение.Методы.Вставить("РеквизитФормыВЗначение", Элемент); 209 | // ... 210 | 211 | Парсер.Пуск(Исходник, Плагины,, Окружение); 212 | 213 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 214 | Сообщить(Ошибка.Текст); // вывод найденных парсером и плагином ошибок 215 | КонецЦикла; 216 | ``` 217 | 218 | ##### `Разобрать(Исходник, Окружение): Структура` 219 | 220 | *Выполняет разбор исходника в указанном окружении и возвращает AST.* 221 | 222 | Параметры: 223 | 224 | - `Исходник: Строка` -- исходный код для анализа. 225 | - `Окружение: Структура (необязательный)` -- окружение (контекст), в котором будет выполняться разбор исходника. 226 | 227 | Пример: 228 | 229 | ```bsl 230 | Исходник = ЧтениеТекста.Прочитать(); 231 | 232 | Парсер = Новый ПарсерВстроенногоЯзыка; 233 | Узлы = Парсер.Узлы(); 234 | 235 | Окружение = Парсер.Окружение(); 236 | 237 | // например, контекст формы: 238 | Элемент = Узлы.ЭлементОкружения.Добавить(); 239 | Элемент.Имя = "ЭтаФорма"; 240 | ПроизвольноеОкружение.Переменные.Вставить("ЭтаФорма", Элемент); 241 | // ... 242 | Элемент = Узлы.ЭлементОкружения.Добавить(); 243 | Элемент.Имя = "РеквизитФормыВЗначение"; 244 | ПроизвольноеОкружение.Методы.Вставить("РеквизитФормыВЗначение", Элемент); 245 | // ... 246 | 247 | АСД = Парсер.Разобрать(Исходник, Окружение); 248 | 249 | Сообщить(АСД.Объявления.Количество()); 250 | ``` 251 | 252 | ##### `Подключить(Плагины)` 253 | 254 | *Подключает плагины к парсеру.* 255 | 256 | Параметры: 257 | 258 | - `Плагины: Массив или Объект` -- плагины для подключения к парсеру. 259 | 260 | Пример: 261 | 262 | ```bsl 263 | Парсер = Новый ПарсерВстроенногоЯзыка; 264 | Плагин = Новый Плагин; 265 | 266 | АСД = Парсер.Разобрать(Исходник); // тут выполняется синтаксический анализ 267 | Парсер.Подключить(Плагин); // тут плагин подключается к парсеру 268 | Парсер.Посетить(АСД); // тут выполняется обход АСД с вызовом подписок плагина 269 | 270 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 271 | Сообщить(Ошибка.Текст); // вывод найденных парсером и плагином ошибок 272 | КонецЦикла; 273 | ``` 274 | 275 | ##### `Посетить(Модуль, Параметры)` 276 | 277 | *Выполняет обход AST с подключенными плагинами и указанными параметрами плагинов.* 278 | 279 | Параметры: 280 | 281 | - `Модуль: Структура` -- АСД для обхода. 282 | - `Параметры: Соответствие (необязательный)` -- параметры плагинов, с которыми нужно выполнить обход. 283 | 284 | Пример: 285 | 286 | ```bsl 287 | Исходник = ЧтениеТекста.Прочитать(); 288 | 289 | Парсер = Новый ПарсерВстроенногоЯзыка; 290 | Плагин = Новый Плагин; 291 | 292 | АСД = Парсер.Разобрать(Исходник); // тут выполняется синтаксический анализ 293 | Парсер.Подключить(Плагин); // тут плагин подключается к парсеру 294 | Парсер.Посетить(АСД); // тут выполняется обход АСД с вызовом подписок плагина 295 | 296 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 297 | Сообщить(Ошибка.Текст); // вывод найденных парсером и плагином ошибок 298 | КонецЦикла; 299 | ``` 300 | 301 | ##### `Токенизировать(Исходник): ТаблицаЗначений` 302 | 303 | *Выполняет лексический анализ и возвращает таблицу токенов.* 304 | 305 | Параметры: 306 | 307 | - `Исходник: Строка` -- исходный код для анализа. 308 | 309 | Пример: 310 | 311 | ```bsl 312 | Исходник = ЧтениеТекста.Прочитать(); 313 | 314 | Парсер = Новый ПарсерВстроенногоЯзыка; 315 | 316 | ТаблицаТокенов = Парсер.Токенизировать(Исходник); // тут выполняется лексический анализ 317 | 318 | Для Каждого ДанныеТокена Из ТаблицаТокенов Цикл 319 | Сообщить(ДанныеТокена.Токен); // вывод всех токенов 320 | КонецЦикла; 321 | ``` 322 | 323 | ##### `ВыполнитьЗамены(): Строка` 324 | 325 | *Возвращает исходник после выполнения на нем замен участков текста.* 326 | 327 | Пример: 328 | 329 | ```bsl 330 | Исходник = ЧтениеТекста.Прочитать(); 331 | 332 | Парсер = Новый ПарсерВстроенногоЯзыка; 333 | Плагин = Новый Плагин; 334 | 335 | Парсер.Пуск(Исходник, Плагин); // тут плагин наполняет таблицу замен 336 | 337 | ИсправленныйИсходник = Парсер.ВыполнитьЗамены(); // тут по таблице замен последовательно заменяются участки текста в исходнике. 338 | 339 | Сообщить(ИсправленныйИсходник) 340 | ``` 341 | 342 | ##### `Очистить()` 343 | 344 | *Очищает в парсере таблицы токенов и узлов. Так освобождается память и парсер подготавливается к следующему разбору. Перед разбором таблицы улов не очищаются, т.к. могут быть наполнены извне при формировании внешнего окружения. Метод `Пуск()` уже включает этот вызов.* 345 | 346 | Пример: 347 | 348 | ```bsl 349 | ПарсерВстроенногоЯзыка = Новый ПарсерВстроенногоЯзыка; 350 | АСД = ПарсерВстроенногоЯзыка.Разобрать(Исходник); 351 | Сайт = ГенераторДокументации.Посетить(ПарсерВстроенногоЯзыка, АСД); 352 | ПарсерВстроенногоЯзыка.Очистить(); 353 | ``` 354 | 355 | #### Дополнительные методы 356 | 357 | Данные методы в основном используются в плагинах и вызываются один раз в процедуре Открыть(). Методы предоставляют различную вспомогательную информацию и таблицы, в которых плагины могут регистрировать ошибки и замены. 358 | 359 | Примеры использования данных методов смотрите в плагинах в папке /plugins 360 | 361 | ##### `Узлы(): Структура` 362 | 363 | *Возвращает структуру таблиц, хранящих узлы. На каждый тип узла отдельная таблица в одноименном свойстве структуры.* 364 | 365 | Пример (фрагмент кода плагина): 366 | 367 | ```bsl 368 | Перем Узлы; 369 | 370 | Процедура Открыть(Парсер, Параметры) Экспорт 371 | Узлы = Парсер.Узлы(); 372 | КонецПроцедуры 373 | 374 | Функция Закрыть() Экспорт 375 | Для Каждого Объявление Из Узлы.ОбъявлениеМетода Цикл 376 | Сообщить(Объявление.Сигнатура.Имя); 377 | КонецЦикла; 378 | Возврат Неопределено; 379 | КонецФункции 380 | ``` 381 | 382 | ##### `КлючевыеСлова(): Структура` 383 | 384 | *Возвращает перечисление допустимых ключевых слов.* 385 | 386 | Пример (фрагмент кода плагина): 387 | 388 | ```bsl 389 | Перем ТаблицаТокенов, КлючевыеСлова; 390 | 391 | Процедура Открыть(Парсер, Параметры) Экспорт 392 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 393 | КлючевыеСлова = Парсер.КлючевыеСлова(); 394 | КонецПроцедуры 395 | 396 | Функция Закрыть() Экспорт 397 | Для Каждого ДанныеТокена Из ТаблицаТокенов Цикл 398 | Если ДанныеТокена.Токен = КлючевыеСлова.ИначеЕсли Тогда 399 | // ... 400 | КонецЕсли; 401 | КонецЦикла; 402 | Возврат Неопределено; 403 | КонецФункции 404 | ``` 405 | 406 | ##### `Токены(): Структура` 407 | 408 | *Возвращает перечисление допустимых токенов.* 409 | 410 | Пример (фрагмент кода плагина): 411 | 412 | ```bsl 413 | Перем ТаблицаТокенов, Токены; 414 | 415 | Процедура Открыть(Парсер, Параметры) Экспорт 416 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 417 | Токены = Парсер.Токены(); 418 | КонецПроцедуры 419 | 420 | Функция Закрыть() Экспорт 421 | Для Каждого ДанныеТокена Из ТаблицаТокенов Цикл 422 | Если ДанныеТокена.Токен = Токены.ЗнакСложения Тогда 423 | // ... 424 | КонецЕсли; 425 | КонецЦикла; 426 | Возврат Неопределено; 427 | КонецФункции 428 | ``` 429 | 430 | ##### `Типы(): Структура` 431 | 432 | *Возвращает перечисление допустимых типов узлов AST.* 433 | 434 | Пример (фрагмент кода плагина): 435 | 436 | ```bsl 437 | Перем Типы; 438 | 439 | Процедура Открыть(Парсер, Параметры) Экспорт 440 | Типы = Парсер.Типы(); 441 | КонецПроцедуры 442 | 443 | Процедура ПосетитьОператоры(Операторы) Экспорт 444 | Для Каждого Оператор Из Операторы Цикл 445 | Если Оператор.Тип = Типы.ОператорПрисваивания Тогда 446 | // ... 447 | КонецЕсли; 448 | КонецЦикла; 449 | КонецПроцедуры 450 | ``` 451 | 452 | ##### `Директивы(): Структура` 453 | 454 | *Возвращает перечисление допустимых директив.* 455 | 456 | Пример (фрагмент кода плагина): 457 | 458 | ```bsl 459 | Перем Директивы; 460 | 461 | Процедура Открыть(Парсер, Параметры) Экспорт 462 | Директивы = Парсер.Директивы(); 463 | КонецПроцедуры 464 | 465 | Процедура ПосетитьОбъявлениеПеременнойМодуля(Объявление) Экспорт 466 | Если Объявление.Директивы.Количество() = 1 467 | И Объявление.Директивы[0].Директива = Директивы.НаКлиенте Тогда 468 | // ... 469 | КонецЕсли; 470 | КонецПроцедуры 471 | ``` 472 | 473 | ##### `Аннотации(): Структура` 474 | 475 | *Возвращает перечисление допустимых аннотаций.* 476 | 477 | Пример (фрагмент кода плагина): 478 | 479 | ```bsl 480 | Перем Аннотации; 481 | 482 | Процедура Открыть(Парсер, Параметры) Экспорт 483 | Аннотации = Парсер.Аннотации(); 484 | КонецПроцедуры 485 | 486 | Процедура ПосетитьОбъявлениеМетода(Объявление) Экспорт 487 | Аннотации = Объявление.Сигнатура.Аннотации; 488 | Если Аннотации.Количество() = 1 489 | И Аннотации[0].Аннотация = Аннотации.Вместо Тогда 490 | // ... 491 | КонецЕсли; 492 | КонецПроцедуры 493 | ``` 494 | 495 | ##### `СимволыПрепроцессора(): Структура` 496 | 497 | *Возвращает перечисление допустимых символов препроцессора.* 498 | 499 | Пример (фрагмент кода плагина): 500 | 501 | ```bsl 502 | Перем СимволыПрепроцессора; 503 | 504 | Процедура Открыть(Парсер, Параметры) Экспорт 505 | СимволыПрепроцессора = Парсер.СимволыПрепроцессора(); 506 | КонецПроцедуры 507 | 508 | Процедура ПосетитьВыражениеПрепроцессораСимвол(Выражение) Экспорт 509 | Если Выражение.Символ = СимволыПрепроцессора.ТолстыйКлиентОбычноеПриложение Тогда 510 | // ... 511 | КонецЕсли; 512 | КонецПроцедуры 513 | ``` 514 | 515 | ##### `Стек(): Массив` 516 | 517 | *Возвращает стек узлов, который меняется во время обхода AST и позволяет получить текущие родительские узлы в подписках плагинов.* 518 | 519 | Пример (фрагмент кода плагина): 520 | 521 | ```bsl 522 | Перем Стек; 523 | 524 | Процедура Открыть(Парсер, Параметры) Экспорт 525 | Стек = Парсер.Стек(); 526 | КонецПроцедуры 527 | 528 | Процедура ПосетитьВыражениеТернарное(Выражение) Экспорт 529 | Для Каждого Родитель Из Стек Цикл 530 | Если Родитель.Тип = Типы.ВыражениеТернарное Тогда 531 | Сообщить("Вложенный тернарный оператор"); 532 | Прервать; 533 | КонецЕсли; 534 | КонецЦикла; 535 | КонецПроцедуры 536 | ``` 537 | 538 | ##### `Счетчики(): Соответствие` 539 | 540 | *Возвращает счетчики родительских узлов, которые меняются во время обхода AST и позволяет получить количество текущих родительских узлов по типам в подписках плагинов.* 541 | 542 | Пример (фрагмент кода плагина): 543 | 544 | ```bsl 545 | Перем Счетчики; 546 | 547 | Процедура Открыть(Парсер, Параметры) Экспорт 548 | Счетчики = Парсер.Счетчики(); 549 | КонецПроцедуры 550 | 551 | Процедура ПосетитьВыражениеТернарное(Выражение) Экспорт 552 | Если Счетчики.ВыражениеТернарное > 0 Тогда 553 | Сообщить("Вложенный тернарный оператор"); 554 | КонецЕсли; 555 | КонецПроцедуры 556 | ``` 557 | 558 | ##### `Исходник(): Строка` 559 | 560 | *Возвращает текущий исходник.* 561 | 562 | Пример (фрагмент кода плагина): 563 | 564 | ```bsl 565 | Перем Исходник, Токены, ТаблицаТокенов; 566 | 567 | Процедура Открыть(Парсер, Параметры) Экспорт 568 | Исходник = Парсер.Исходник(); 569 | Токены = Парсер.Токены(); 570 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 571 | КонецПроцедуры 572 | 573 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 574 | ДанныеСледующегоТокена = ТаблицаТокенов[ОбъявлениеМетода.Конец.Индекс + 1]; 575 | Если ДанныеСледующегоТокена.Токен = Токены.Комментарий Тогда 576 | Сообщить(Сред(Исходник, ДанныеСледующегоТокена.Позиция, ДанныеСледующегоТокена.Длина)); 577 | КонецЕсли; 578 | КонецПроцедуры 579 | ``` 580 | 581 | ##### `ТаблицаТокенов(): ТаблицаЗначений` 582 | 583 | *Возвращает текущую таблицу токенов, которая содержит подробную информацию о положении каждого токена в исходном коде. Каждый узел AST имеет поля `Начало` и `Конец`, которые хранят строки данной таблицы и представляют первый и последний токен узла. Например, получить номер первой строки узла можно так: `НомерСтроки = Узел.Начало.НомерСтроки`. Получить следующий за узлом токен можно так: `ДанныеСледующегоТокена = ТаблицаТокенов[Узел.Конец.Индекс + 1]`.* 584 | 585 | Колонки: 586 | 587 | - `Индекс: Число` -- индекс строки для удобства. 588 | - `Токен: Строка` -- токен из перечисления Токены. 589 | - `НомерСтроки: Число` -- номер строки, в которой находится токен. 590 | - `НомерКолонки: Число` -- номер колонки, в которой начинается токен. 591 | - `Позиция: Число` -- позиция в тексте, в которой начинается токен. 592 | - `Длина: Число` -- длина участка текста, который представляет токен. 593 | 594 | Пример (фрагмент кода плагина): 595 | 596 | ```bsl 597 | Перем Исходник, Токены, ТаблицаТокенов; 598 | 599 | Процедура Открыть(Парсер, Параметры) Экспорт 600 | Исходник = Парсер.Исходник(); 601 | Токены = Парсер.Токены(); 602 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 603 | КонецПроцедуры 604 | 605 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 606 | ДанныеСледующегоТокена = ТаблицаТокенов[ОбъявлениеМетода.Конец.Индекс + 1]; 607 | Если ДанныеСледующегоТокена.Токен = Токены.Комментарий Тогда 608 | Сообщить(Сред(Исходник, ДанныеСледующегоТокена.Позиция, ДанныеСледующегоТокена.Длина)); 609 | КонецЕсли; 610 | КонецПроцедуры 611 | ``` 612 | 613 | ##### `ТаблицаОшибок(): ТаблицаЗначений` 614 | 615 | *Возвращает текущую таблицу ошибок, в которой плагины могут регистрировать ошибки.* 616 | 617 | Колонки: 618 | 619 | - `Источник: Строка` -- имя плагина, который зарегистрировал ошибку. 620 | - `Текст: Строка` -- текст ошибки 621 | - `ПозицияНачала: Число` -- позиция в тексте, с которой начинается ошибочный участок. 622 | - `ПозицияКонца: Число` -- позиция в тексте, на которой заканчивается ошибочный участок. 623 | - `ЕстьЗамена: Булево` -- признак, что для ошибки есть замена (исправление) в таблице замен. 624 | - `Код: Число` -- код ошибки (для плагинов всегда 0). 625 | - `НомерСтрокиНачала: Число` -- номер строки, на которой начинается ошибочный участок. 626 | - `НомерКолонкиНачала: Число` -- номер колонки, с которой начинается ошибочный участок. 627 | - `НомерСтрокиКонца: Число` -- номер строки, на которой заканчивается ошибочный участок. 628 | - `НомерКолонкиКонца: Число` -- номер колонки, на которой заканчивается ошибочный участок. 629 | - `МинутНаИсправление: Число` -- примерная оценка затрат на исправление ошибки в минутах. 630 | - `Серьезность: Строка` -- произвольный текст на усмотрение разработчика. 631 | - `Приоритет: Число` -- произвольное число на усмотрение разработчика. 632 | - `Правило: Строка` -- произвольный текст на усмотрение разработчика. 633 | - `Тип: Строка` -- произвольный текст на усмотрение разработчика. 634 | 635 | Пример (фрагмент кода плагина): 636 | 637 | ```bsl 638 | Перем Исходник, Токены, ТаблицаТокенов; 639 | 640 | Процедура Открыть(Парсер, Параметры) Экспорт 641 | Исходник = Парсер.Исходник(); 642 | Токены = Парсер.Токены(); 643 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 644 | КонецПроцедуры 645 | 646 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 647 | 648 | СледующийТокен = ТаблицаТокенов[ОбъявлениеМетода.Конец.Индекс + 1]; 649 | 650 | Если СледующийТокен.Токен = Токены.Комментарий 651 | И СледующийТокен.НомерСтроки = ОбъявлениеМетода.Конец.НомерСтроки Тогда 652 | 653 | Комментарий = СокрП(Сред(Исходник, СледующийТокен.Позиция, СледующийТокен.Длина)); 654 | ПравильныйКомментарий = СтрШаблон(" %1%2", ОбъявлениеМетода.Сигнатура.Имя, "()"); 655 | 656 | Если Комментарий <> ПравильныйКомментарий Тогда 657 | Ошибка("Замыкающий комментарий неактуален", СледующийТокен); 658 | КонецЕсли; 659 | 660 | КонецЕсли; 661 | 662 | КонецПроцедуры 663 | 664 | Процедура Ошибка(Текст, ДанныеТокена) 665 | Ошибка = ТаблицаОшибок.Добавить(); 666 | Ошибка.Источник = "ИмяЭтогоПлагина"; 667 | Ошибка.Текст = Текст; 668 | Ошибка.ПозицияНачала = ДанныеТокена.Позиция; 669 | Ошибка.НомерСтрокиНачала = ДанныеТокена.НомерСтроки; 670 | Ошибка.НомерКолонкиНачала = ДанныеТокена.НомерКолонки; 671 | Ошибка.ПозицияКонца = ДанныеТокена.Позиция + ДанныеТокена.Длина; 672 | Ошибка.НомерСтрокиКонца = ДанныеТокена.НомерСтроки; 673 | Ошибка.НомерКолонкиКонца = ДанныеТокена.НомерКолонки + ДанныеТокена.Длина; 674 | КонецПроцедуры 675 | ``` 676 | 677 | ##### `ТаблицаЗамен(): ТаблицаЗначений` 678 | 679 | *Возвращает текущую таблицу замен, в которой плагины могут регистрировать замены.* 680 | 681 | Колонки: 682 | 683 | - `Источник: Число` -- имя плагина, который зарегистрировал замену. 684 | - `Текст: Строка` -- фрагмент текста, на который нужно заменить указанный участок. 685 | - `Позиция: Число` -- позиция участка текста для замены. 686 | - `Длина: Число` -- длина участка текста для замены. 687 | 688 | Пример (фрагмент кода плагина): 689 | 690 | ```bsl 691 | Перем Исходник, Токены, ТаблицаТокенов, ТаблицаЗамен; 692 | 693 | Процедура Открыть(Парсер, Параметры) Экспорт 694 | Исходник = Парсер.Исходник(); 695 | Токены = Парсер.Токены(); 696 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 697 | ТаблицаЗамен = Парсер.ТаблицаЗамен(); 698 | КонецПроцедуры 699 | 700 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 701 | 702 | СледующийТокен = ТаблицаТокенов[ОбъявлениеМетода.Конец.Индекс + 1]; 703 | 704 | Если СледующийТокен.Токен = Токены.Комментарий 705 | И СледующийТокен.НомерСтроки = ОбъявлениеМетода.Конец.НомерСтроки Тогда 706 | 707 | Комментарий = СокрП(Сред(Исходник, СледующийТокен.Позиция, СледующийТокен.Длина)); 708 | ПравильныйКомментарий = СтрШаблон(" %1%2", ОбъявлениеМетода.Сигнатура.Имя, "()"); 709 | 710 | Если Комментарий <> ПравильныйКомментарий Тогда 711 | Замена(ПравильныйКомментарий, СледующийТокен); 712 | КонецЕсли; 713 | 714 | КонецЕсли; 715 | 716 | КонецПроцедуры 717 | 718 | Процедура Замена(Текст, ДанныеТокена) 719 | НоваяЗамена = ТаблицаЗамен.Добавить(); 720 | НоваяЗамена.Источник = "ИмяЭтогоПлагина"; 721 | НоваяЗамена.Текст = Текст; 722 | НоваяЗамена.Позиция = ДанныеТокена.Позиция; 723 | НоваяЗамена.Длина = ДанныеТокена.Длина; 724 | КонецПроцедуры 725 | ``` 726 | 727 | #### Продвинутые методы 728 | 729 | Данные методы позволяют сформировать окружение, в контексте которого будет выполняться разбор исходного кода. 730 | 731 | Пример формирования окружения смотрите в скрипте: [/examples/test5.os](/examples/test5.os) 732 | 733 | ##### `Окружение(ВнешнееОкружение): Структура` 734 | 735 | *Конструктор. Возвращает новое окружение.* 736 | 737 | Параметры: 738 | 739 | - `ВнешнееОкружение: Структура` -- внешнее окружение по отношению к создаваемому. 740 | 741 | ##### `Доступность(Клиент, ВнешнееСоединение, МобильноеПриложение, МобильныйКлиент, МобильныйСервер, Сервер, ТолстыйКлиент, ТонкийКлиент, ВебКлиент, Интеграция): Структура` 742 | 743 | *Конструктор. Возвращает новую структуру доступности.* 744 | 745 | Параметры: 746 | 747 | - `Клиент: Булево` -- признак доступности в одноименном контексте. 748 | - `ВнешнееСоединение: Булево` -- признак доступности в одноименном контексте. 749 | - `МобильноеПриложение: Булево` -- признак доступности в одноименном контексте. 750 | - `МобильныйКлиент: Булево` -- признак доступности в одноименном контексте. 751 | - `МобильныйСервер: Булево` -- признак доступности в одноименном контексте. 752 | - `Сервер: Булево` -- признак доступности в одноименном контексте. 753 | - `ТолстыйКлиент: Булево` -- признак доступности в одноименном контексте. 754 | - `ТонкийКлиент: Булево` -- признак доступности в одноименном контексте. 755 | - `ВебКлиент: Булево` -- признак доступности в одноименном контексте. 756 | - `Интеграция: Булево` -- признак доступности в одноименном контексте. 757 | 758 | #### Служебные методы 759 | 760 | Эти методы позволяют частично установить состояние парсера без выполнения разбора. 761 | Это необходимо при выполнении обхода кэшированных AST, чтобы плагинам была доступна соответствующая информация при инициализации. 762 | 763 | ##### `УстановитьИсходник(Исходник)` 764 | 765 | *Устанавливает исходник напрямую без выполнения анализа.* 766 | 767 | Параметры: 768 | 769 | - `Исходник: Строка` -- исходный код, который нужно установить в парсер. 770 | 771 | ##### `УстановитьТаблицуТокенов(ТаблицаТокенов)` 772 | 773 | *Устанавливает таблицу токенов напрямую без выполнения анализа.* 774 | 775 | Параметры: 776 | 777 | - `ТаблицаТокенов: ТаблицаЗначений` -- таблица токенов, которую нужно установить в парсер. 778 | 779 | ##### `УстановитьТаблицуОшибок(ТаблицаОшибок)` 780 | 781 | *Устанавливает таблицу ошибок напрямую без выполнения анализа.* 782 | 783 | Параметры: 784 | 785 | - `ТаблицаОшибок: ТаблицаЗначений` -- таблица ошибок, которую нужно установить в парсер. 786 | 787 | #### Параметры 788 | 789 | ##### `СтрогийРежим: Булево` 790 | 791 | *Определяет поведение парсера при возникновении ошибочных ситуаций.* 792 | 793 | ## Плагины 794 | 795 | С помощью плагинов можно решать много различных задач. В частности: 796 | 797 | - Поиск ошибок в исходном коде. 798 | - Проверка исходного кода на соответствие стандартам как внешним так и внутренним. 799 | - Проверка исходного кода на соответствие требованиям безопасности. 800 | - Проверка оформления исходного кода. 801 | - Модификация исходного кода путем замен/вставки/удаления фрагментов. 802 | - Форматирование исходного кода. 803 | - Генерация документации по исходному коду. 804 | - Подготовка исходного кода к публикации (генерация html). 805 | - Сбор статистики по исходному коду. 806 | - Выполнение автоматизированных переименований и переводов. 807 | - Перевод исходного кода на другие языки программирования. 808 | - Обфускация исходного кода. 809 | - Интерпретация и компиляция. 810 | - Продвинутый автоматизированный поиск по исходному коду. 811 | 812 | Плагин реализуется в виде одного класса. 813 | 814 | Для создания плагина нужно выполнить следующую последовательность шагов: 815 | 816 | 1. Создать новый класс. 817 | 2. В модуль класса скопировать шаблон с сайта: [osparser](https://oscript-library.github.io/osparser) 818 | 3. Заглянуть в метод **`Подписки()` в классе парсера** и выбрать те, которые нужны для решения задачи. 819 | Например, если нужно проверить все присваивания, то можно выбрать подписку "ПосетитьОператорПрисваивания". 820 | 4. Добавить подписку в массив в методе `Подписки()` будущего плагина. Это указание парсеру что плагин реализует такую процедуру. 821 | 5. Создать одноименную экспортную процедуру и написать в ней код, решающий задачу. 822 | 6. Удалить лишние переменные, которые были скопированы из шаблона, но в итоге не пригодились. 823 | 824 | ### Программный интерфейс плагина 825 | 826 | Интерфейс плагина состоит из трех постоянных методов и набора методов-подписок. 827 | 828 | Например, плагин может подписаться на посещение узла оператора присваивания. В этом случае он должен реализовать экспортный метод `ПосетитьОператорПрисваивания(ОператорПрисваивания)` и вернуть имя этого метода `ПосетитьОператорПрисваивания` в методе `Подписки()` 829 | 830 | #### `Открыть(Парсер, Параметры)` 831 | 832 | *Вызывается один раз перед обходом AST; позволяет выполнить необходимую инициализацию плагина.* 833 | 834 | Параметры: 835 | 836 | - `Парсер: Объект` -- экземпляр парсера, к кторому подключен плагин. 837 | - `Параметры: Структура` -- параметры плагина, переданные парсеру в методе `Пуск()` или `Посетить()`. 838 | 839 | #### `Закрыть(): Произвольный` 840 | 841 | *Вызывается один раз после обхода AST, позволяет плагину "подвести итоги" и вернуть результат своей работы. Некоторые плагины всю работу выполняют в данном методе.* 842 | 843 | #### `Подписки(): Массив` 844 | 845 | *Вызывается один раз при подключении плагинов. Возвращает список имен процедур-подписок, которые реализует данный плагин.* 846 | 847 | ### Минимальный шаблон плагина 848 | 849 | ```bsl 850 | Перем Результат; 851 | 852 | // Будет вызвана один раз перед обходом AST. 853 | // Тут можно получить необходимые перечисления и таблицы из парсера, 854 | // и выполнить инициализацию плагина с учетом полученных параметров. 855 | Процедура Открыть(Парсер, Параметры) Экспорт 856 | Результат = Новый Массив; 857 | КонецПроцедуры 858 | 859 | // Будет вызвана после полного обхода AST. 860 | // Возвращает текстовый результат работы плагина, если он есть. 861 | // Плагины, которые регистрируют ошибки и/или замены, могут вернуть Неопределено. 862 | Функция Закрыть() Экспорт 863 | Возврат СтрСоединить(Результат); 864 | КонецФункции 865 | 866 | // Возвращает список процедур-подписок, которые будут вызываться визитером. 867 | // Состав возможных подписок можно посмотреть в исходнике парсера в функции Подписки(). 868 | // Имена большинства подписок образуются добавлением префикса Посетить/Покинуть к имени типа узла. 869 | // Справка по типам узлов находится по этому адресу: https://oscript-library.github.io/osparser/ 870 | Функция Подписки() Экспорт 871 | Перем Подписки; 872 | Подписки = Новый Массив; 873 | Подписки.Добавить("ПосетитьОператорПрисваивания"); 874 | Подписки.Добавить("ПокинутьОператорПрисваивания"); 875 | Возврат Подписки; 876 | КонецФункции 877 | 878 | #Область РеализацияПодписок 879 | 880 | // Описание структуры узла `ОператорПрисваивания`: https://oscript-library.github.io/osparser/#ОператорПрисваивания 881 | 882 | // Данная процедура будет вызвана при посещении узла AST перед посещением подчиненных ему узлов. 883 | // Вызов подписок с префиксом `Посетить` отражает рекурсивный спуск визитера по AST. 884 | // Сначала вызывается подписка на родительский узел, потом на этот, потом на подчиненный и так далее. 885 | Процедура ПосетитьОператорПрисваивания(ОператорПрисваивания) Экспорт 886 | // ... 887 | КонецПроцедуры 888 | 889 | // Данная процедура будет вызвана при посещении узла AST после посещения подчиненных ему узлов. 890 | // Вызов подписок с префиксом `Покинуть` отражает рекурсивный подъем визитера по AST. 891 | // Сначала вызывается подписка на подчиненный узел, потом на этот, потом на родительский и так далее. 892 | Процедура ПокинутьОператорПрисваивания(ОператорПрисваивания) Экспорт 893 | // ... 894 | КонецПроцедуры 895 | 896 | #КонецОбласти 897 | ``` 898 | 899 | ### Полный шаблон плагина 900 | 901 | ```bsl 902 | Перем Типы; 903 | Перем Токены; 904 | Перем Исходник; 905 | Перем ТаблицаТокенов; 906 | Перем ТаблицаОшибок; 907 | Перем ТаблицаЗамен; 908 | Перем Стек; 909 | Перем Счетчики; 910 | Перем Директивы; 911 | Перем Аннотации; 912 | Перем СимволыПрепроцессора; 913 | 914 | Перем Результат; 915 | 916 | Процедура Открыть(Парсер, Параметры) Экспорт 917 | 918 | Типы = Парсер.Типы(); 919 | Токены = Парсер.Токены(); 920 | Исходник = Парсер.Исходник(); 921 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 922 | ТаблицаОшибок = Парсер.ТаблицаОшибок(); 923 | ТаблицаЗамен = Парсер.ТаблицаЗамен(); 924 | Стек = Парсер.Стек(); 925 | Счетчики = Парсер.Счетчики(); 926 | Директивы = Парсер.Директивы(); 927 | Аннотации = Парсер.Аннотации(); 928 | СимволыПрепроцессора = Парсер.СимволыПрепроцессора(); 929 | 930 | Результат = Новый Массив; 931 | 932 | КонецПроцедуры 933 | 934 | Функция Закрыть() Экспорт 935 | // ... 936 | Возврат СтрСоединить(Результат); 937 | КонецФункции 938 | 939 | Функция Подписки() Экспорт 940 | Перем Подписки; 941 | Подписки = Новый Массив; 942 | Подписки.Добавить("ПосетитьОператорПрисваивания"); 943 | //Подписки.Добавить("ПокинутьОператорПрисваивания"); 944 | Возврат Подписки; 945 | КонецФункции 946 | 947 | #Область РеализацияПодписок 948 | 949 | Процедура ПосетитьОператорПрисваивания(ОператорПрисваивания) Экспорт 950 | Ошибка("Ошибка в операторе присваивания", ОператорПрисваивания.Начало, ОператорПрисваивания.Конец); 951 | КонецПроцедуры // ПосетитьОператорПрисваивания() 952 | 953 | //Процедура ПокинутьОператорПрисваивания(ОператорПрисваивания) Экспорт 954 | // 955 | //КонецПроцедуры // ПокинутьОператорПрисваивания() 956 | 957 | #КонецОбласти 958 | 959 | Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) 960 | Ошибка = ТаблицаОшибок.Добавить(); 961 | Ошибка.Источник = "ИмяЭтогоПлагина"; 962 | Ошибка.Текст = Текст; 963 | Ошибка.ПозицияНачала = Начало.Позиция; 964 | Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; 965 | Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; 966 | Если Конец = Неопределено Или Конец = Начало Тогда 967 | Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; 968 | Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; 969 | Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; 970 | Иначе 971 | Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; 972 | Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; 973 | Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; 974 | КонецЕсли; 975 | Ошибка.ЕстьЗамена = ЕстьЗамена; 976 | КонецПроцедуры 977 | 978 | Процедура Замена(Текст, Начало, Конец = Неопределено) 979 | НоваяЗамена = ТаблицаЗамен.Добавить(); 980 | НоваяЗамена.Источник = "ИмяЭтогоПлагина"; 981 | НоваяЗамена.Текст = Текст; 982 | НоваяЗамена.Позиция = Начало.Позиция; 983 | Если Конец = Неопределено Тогда 984 | НоваяЗамена.Длина = Начало.Длина; 985 | Иначе 986 | НоваяЗамена.Длина = Конец.Позиция + Конец.Длина - Начало.Позиция; 987 | КонецЕсли; 988 | КонецПроцедуры 989 | 990 | Процедура Вставка(Текст, Позиция) 991 | НоваяЗамена = ТаблицаЗамен.Добавить(); 992 | НоваяЗамена.Источник = "ИмяЭтогоПлагина"; 993 | НоваяЗамена.Текст = Текст; 994 | НоваяЗамена.Позиция = Позиция; 995 | НоваяЗамена.Длина = 0; 996 | КонецПроцедуры 997 | ``` 998 | 999 | ## Бакенды 1000 | 1001 | Бакенд реализуется в виде одного класса. 1002 | 1003 | Бакенды отличаются от плагинов тем, что не используют общий механизм обхода, а выполняют всю работу сами. 1004 | 1005 | ### Программный интерфейс бакенда 1006 | 1007 | Бакенд должен реализовать один метод: 1008 | 1009 | #### `Посетить(Парсер, АСД): Произвольный` 1010 | 1011 | *Выполняет произвольную работу и возвращает произвольный результат.* 1012 | 1013 | - `Парсер: Объект` -- экземпляр парсера. 1014 | - `АСД: Структура` -- абстрактное синтаксическое дерево. 1015 | -------------------------------------------------------------------------------- /docgen.os: -------------------------------------------------------------------------------- 1 | 2 | #Использовать "./src" 3 | #Использовать "./examples/backends" 4 | 5 | ЧтениеТекста = Новый ЧтениеТекста(".\src\Классы\ПарсерВстроенногоЯзыка.os"); 6 | Исходник = ЧтениеТекста.Прочитать(); 7 | 8 | ГенераторДокументации = Новый ГенераторДокументацииДляПарсера; 9 | 10 | ПарсерВстроенногоЯзыка = Новый ПарсерВстроенногоЯзыка; 11 | АСД = ПарсерВстроенногоЯзыка.Разобрать(Исходник); 12 | Сайт = ГенераторДокументации.Посетить(ПарсерВстроенногоЯзыка, АСД); 13 | ПарсерВстроенногоЯзыка.Очистить(); 14 | 15 | ЗаписьТекста = Новый ЗаписьТекста(".\docs\index.html"); 16 | ЗаписьТекста.Записать(Сайт); -------------------------------------------------------------------------------- /docs/ast.css: -------------------------------------------------------------------------------- 1 | html { 2 | scroll-behavior: smooth; 3 | margin-bottom: 25%; 4 | max-width: 950px; 5 | /* margin: auto; */ 6 | margin-left: 50px; 7 | } 8 | 9 | body { 10 | font-family: Menlo, monospace; 11 | font-size: 14px; 12 | } 13 | 14 | .permalink { 15 | display: none; 16 | } 17 | 18 | :hover > .permalink { 19 | display: inline; 20 | color: black; 21 | } 22 | 23 | h2 { 24 | color:#963200; 25 | } 26 | 27 | pre { 28 | background: #dce5e9; 29 | width: 100%; 30 | padding: 15px; 31 | overflow: auto; 32 | min-width: 80ch 33 | } 34 | 35 | :target { 36 | background-color: #F0F0F0 ; 37 | margin: -4px ; 38 | padding: 4px ; 39 | border-radius: 4px ; 40 | outline: none ; 41 | } 42 | 43 | a:link, a:visited { 44 | text-decoration: none; 45 | color: blue; 46 | } 47 | 48 | a:hover, a:active { 49 | text-decoration: underline; 50 | color: blue; 51 | } -------------------------------------------------------------------------------- /examples/backends/Классы/ГенераторДокументацииДляПарсера.os: -------------------------------------------------------------------------------- 1 |  2 | // Генератор технической документации по парсеру 3 | 4 | Перем Узлы; 5 | Перем Токены; 6 | Перем Типы; 7 | Перем Директивы; 8 | Перем Аннотации; 9 | Перем СимволыПрепроцессора; 10 | Перем ТаблицаТокенов; 11 | Перем Исходник; 12 | 13 | Перем Результат; 14 | 15 | Функция Посетить(Парсер, Параметры) Экспорт 16 | 17 | Узлы = Парсер.Узлы(); 18 | Токены = Парсер.Токены(); 19 | Типы = Парсер.Типы(); 20 | Директивы = Парсер.Директивы(); 21 | Аннотации = Парсер.Аннотации(); 22 | СимволыПрепроцессора = Парсер.СимволыПрепроцессора(); 23 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 24 | Исходник = Парсер.Исходник(); 25 | 26 | Результат = Новый Массив; 27 | 28 | Результат.Добавить( 29 | " 30 | | 31 | | 32 | | 33 | |Парсер встроенного языка 34 | | 35 | | 36 | | 37 | |
38 | |

Парсер встроенного языка

39 | |
40 | |На данной странице находится быстрая справка.
41 | |Руководство по парсеру находится в Книге Джедая.
42 | |
43 | |Настоящим Джедаям рекомендуется смотреть исходный код.
44 | |Только так можно достичь просветления. 45 | |

Содержание

46 | | 74 | |

Примеры использования парсера


75 | |
 76 | 		|
 77 | 		|#Использовать osparser
 78 | 		|#Использовать ""./plugins""
 79 | 		|
 80 | 		|ЧтениеТекста = Новый ЧтениеТекста(""Модуль.bsl"");
 81 | 		|Исходник = ЧтениеТекста.Прочитать();
 82 | 		|
 83 | 		|Парсер = Новый ПарсерВстроенногоЯзыка;
 84 | 		|Плагин = Новый ДетекторНеиспользуемыхПеременных;
 85 | 		|Парсер.Пуск(Исходник, Плагин);
 86 | 		|
 87 | 		|Отчет = Новый Массив;
 88 | 		|Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл
 89 | 		|	Отчет.Добавить(Ошибка.Текст);
 90 | 		|	Отчет.Добавить(СтрШаблон("" [стр: %1; кол: %2]"", Ошибка.НомерСтрокиНачала, Ошибка.НомерКолонкиНачала));
 91 | 		|	Отчет.Добавить(Символы.ПС);
 92 | 		|КонецЦикла;
 93 | 		|Сообщить(СтрСоединить(Отчет));
 94 | 		|
 95 | 		|
96 | |

Минимальный шаблон плагина

97 | |
 98 | 		|
 99 | 		|Перем Результат;
100 | 		|
101 | 		|// Будет вызвана один раз перед обходом AST.
102 | 		|// Тут можно получить необходимые перечисления и таблицы из парсера,
103 | 		|// и выполнить инициализацию плагина с учетом полученных параметров.
104 | 		|Процедура Открыть(Парсер, Параметры) Экспорт
105 | 		|	Результат = Новый Массив;
106 | 		|КонецПроцедуры
107 | 		|
108 | 		|// Будет вызвана после полного обхода AST.
109 | 		|// Возвращает текстовый результат работы плагина, если он есть.
110 | 		|// Плагины, которые регистрируют ошибки и/или замены, могут вернуть Неопределено.
111 | 		|Функция Закрыть() Экспорт
112 | 		|	Возврат СтрСоединить(Результат);
113 | 		|КонецФункции
114 | 		|
115 | 		|// Возвращает список процедур-подписок, которые будут вызываться визитером.
116 | 		|// Состав возможных подписок можно посмотреть в исходнике парсера в функции Подписки().
117 | 		|// Имена большинства подписок образуются добавлением префикса Посетить/Покинуть к имени типа узла.
118 | 		|// Справка по типам узлов находится по этому адресу: https://oscript-library.github.io/osparser/
119 | 		|Функция Подписки() Экспорт
120 | 		|	Перем Подписки;
121 | 		|	Подписки = Новый Массив;
122 | 		|	Подписки.Добавить(""ПосетитьОператорПрисваивания"");
123 | 		|	Подписки.Добавить(""ПокинутьОператорПрисваивания"");
124 | 		|	Возврат Подписки;
125 | 		|КонецФункции
126 | 		|
127 | 		|#Область РеализацияПодписок
128 | 		|
129 | 		|// Описание структуры узла `ОператорПрисваивания`: https://oscript-library.github.io/osparser/#ОператорПрисваивания
130 | 		|
131 | 		|// Данная процедура будет вызвана при посещении узла AST перед посещением подчиненных ему узлов.
132 | 		|// Вызов подписок с префиксом `Посетить` отражает рекурсивный спуск визитера по AST.
133 | 		|// Сначала вызывается подписка на родительский узел, потом на этот, потом на подчиненный и так далее.
134 | 		|Процедура ПосетитьОператорПрисваивания(ОператорПрисваивания) Экспорт
135 | 		|	// ...
136 | 		|КонецПроцедуры
137 | 		|
138 | 		|// Данная процедура будет вызвана при посещении узла AST после посещения подчиненных ему узлов.
139 | 		|// Вызов подписок с префиксом `Покинуть` отражает рекурсивный подъем визитера по AST.
140 | 		|// Сначала вызывается подписка на подчиненный узел, потом на этот, потом на родительский и так далее.
141 | 		|Процедура ПокинутьОператорПрисваивания(ОператорПрисваивания) Экспорт
142 | 		|	// ...
143 | 		|КонецПроцедуры
144 | 		|
145 | 		|#КонецОбласти
146 | 		|
147 | 		|
148 | | 149 | | 150 | |

Полный шаблон плагина

151 | |
152 | 		|Перем Типы;
153 | 		|Перем Токены;
154 | 		|Перем Исходник;
155 | 		|Перем ТаблицаТокенов;
156 | 		|Перем ТаблицаОшибок;
157 | 		|Перем ТаблицаЗамен;
158 | 		|Перем Стек;
159 | 		|Перем Счетчики;
160 | 		|Перем Директивы;
161 | 		|Перем Аннотации;
162 | 		|Перем СимволыПрепроцессора;
163 | 		|
164 | 		|Перем Результат;
165 | 		|
166 | 		|Процедура Открыть(Парсер, Параметры) Экспорт
167 | 		|	
168 | 		|	Типы = Парсер.Типы();
169 | 		|	Токены = Парсер.Токены();
170 | 		|	Исходник = Парсер.Исходник();
171 | 		|	ТаблицаТокенов = Парсер.ТаблицаТокенов();
172 | 		|	ТаблицаОшибок = Парсер.ТаблицаОшибок();
173 | 		|	ТаблицаЗамен = Парсер.ТаблицаЗамен();
174 | 		|	Стек = Парсер.Стек();
175 | 		|	Счетчики = Парсер.Счетчики();
176 | 		|	Директивы = Парсер.Директивы();
177 | 		|	Аннотации = Парсер.Аннотации();
178 | 		|	СимволыПрепроцессора = Парсер.СимволыПрепроцессора();
179 | 		|	
180 | 		|	Результат = Новый Массив;
181 | 		|	
182 | 		|КонецПроцедуры
183 | 		|
184 | 		|Функция Закрыть() Экспорт
185 | 		|	// ...
186 | 		|	Возврат СтрСоединить(Результат);
187 | 		|КонецФункции
188 | 		|
189 | 		|Функция Подписки() Экспорт
190 | 		|	Перем Подписки;
191 | 		|	Подписки = Новый Массив;
192 | 		|	Подписки.Добавить(""ПосетитьОператорПрисваивания"");
193 | 		|	//Подписки.Добавить(""ПокинутьОператорПрисваивания"");
194 | 		|	Возврат Подписки;
195 | 		|КонецФункции
196 | 		|
197 | 		|#Область РеализацияПодписок
198 | 		|
199 | 		|Процедура ПосетитьОператорПрисваивания(ОператорПрисваивания) Экспорт
200 | 		|	Ошибка(""Ошибка в операторе присваивания"", ОператорПрисваивания.Начало, ОператорПрисваивания.Конец);
201 | 		|КонецПроцедуры // ПосетитьОператорПрисваивания()
202 | 		|
203 | 		|//Процедура ПокинутьОператорПрисваивания(ОператорПрисваивания) Экспорт
204 | 		|//
205 | 		|//КонецПроцедуры // ПокинутьОператорПрисваивания()
206 | 		|
207 | 		|#КонецОбласти
208 | 		|
209 | 		|Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь)
210 | 		|	Ошибка = ТаблицаОшибок.Добавить();
211 | 		|	Ошибка.Источник = ""ИмяЭтогоПлагина"";
212 | 		|	Ошибка.Текст = Текст;
213 | 		|	Ошибка.ПозицияНачала = Начало.Позиция;
214 | 		|	Ошибка.НомерСтрокиНачала = Начало.НомерСтроки;
215 | 		|	Ошибка.НомерКолонкиНачала = Начало.НомерКолонки;
216 | 		|	Если Конец = Неопределено Или Конец = Начало Тогда
217 | 		|		Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина;
218 | 		|		Ошибка.НомерСтрокиКонца = Начало.НомерСтроки;
219 | 		|		Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина;
220 | 		|	Иначе
221 | 		|		Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина;
222 | 		|		Ошибка.НомерСтрокиКонца = Конец.НомерСтроки;
223 | 		|		Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина;
224 | 		|	КонецЕсли;
225 | 		|	Ошибка.ЕстьЗамена = ЕстьЗамена;
226 | 		|КонецПроцедуры
227 | 		|
228 | 		|Процедура Замена(Текст, Начало, Конец = Неопределено)
229 | 		|	НоваяЗамена = ТаблицаЗамен.Добавить();
230 | 		|	НоваяЗамена.Источник = ""ИмяЭтогоПлагина"";
231 | 		|	НоваяЗамена.Текст = Текст;
232 | 		|	НоваяЗамена.Позиция = Начало.Позиция;
233 | 		|	Если Конец = Неопределено Тогда
234 | 		|		НоваяЗамена.Длина = Начало.Длина;
235 | 		|	Иначе
236 | 		|		НоваяЗамена.Длина = Конец.Позиция + Конец.Длина - Начало.Позиция;
237 | 		|	КонецЕсли;
238 | 		|КонецПроцедуры
239 | 		|
240 | 		|Процедура Вставка(Текст, Позиция)
241 | 		|	НоваяЗамена = ТаблицаЗамен.Добавить();
242 | 		|	НоваяЗамена.Источник = ""ИмяЭтогоПлагина"";
243 | 		|	НоваяЗамена.Текст = Текст;
244 | 		|	НоваяЗамена.Позиция = Позиция;
245 | 		|	НоваяЗамена.Длина = 0;
246 | 		|КонецПроцедуры
247 | 		|
248 | 		|
249 | |

Таблицы

250 | |

ТаблицаТокенов

251 | | 266 | | 267 | |

ТаблицаОшибок

268 | | 292 | | 293 | |

ТаблицаЗамен

294 | | " 308 | "" 309 | ); 310 | 311 | Имена = Новый Структура; 312 | Имена.Вставить("ИнициализироватьУзлы", Ложь); 313 | Имена.Вставить("ИнициализироватьОбъявления", Истина); 314 | Имена.Вставить("ИнициализироватьВыражения", Истина); 315 | Имена.Вставить("ИнициализироватьОператоры", Истина); 316 | Имена.Вставить("ИнициализироватьИнструкцииПрепроцессора", Истина); 317 | Имена.Вставить("ИнициализироватьВыраженияПрепроцессора", Истина); 318 | 319 | Результат.Добавить("

Абстрактное синтаксическое дерево

" ""); 320 | 321 | Для Каждого Объявление Из Узлы.ОбъявлениеМетода Цикл 322 | 323 | ДобавлятьЗаголовок = Ложь; 324 | 325 | Если Имена.Свойство(Объявление.Сигнатура.Имя, ДобавлятьЗаголовок) Тогда 326 | 327 | Если ДобавлятьЗаголовок Тогда 328 | Результат.Добавить(СтрШаблон("

%1

" "", Сред(Объявление.Сигнатура.Имя, 17))); 329 | КонецЕсли; 330 | 331 | Для Каждого Оператор Из Объявление.Операторы Цикл 332 | 333 | Если Оператор.Тип = Типы.ОператорВызоваПроцедуры Тогда 334 | 335 | Если Оператор.Идентификатор.Голова.Имя = "Парсер_Узлы" Тогда 336 | 337 | УзелИмя = Оператор.Идентификатор.Хвост[0].Аргументы[0].Элементы[0].Значение; 338 | 339 | СписокОписаний = Новый СписокЗначений; 340 | 341 | ДанныеСледующегоТокена = ТаблицаТокенов[Оператор.Конец.Индекс + 2]; 342 | Пока ДанныеСледующегоТокена.Токен = Токены.Комментарий Цикл 343 | СписокОписаний.Добавить(Сред(Исходник, ДанныеСледующегоТокена.Позиция, ДанныеСледующегоТокена.Длина)); 344 | ДанныеСледующегоТокена = ТаблицаТокенов[ДанныеСледующегоТокена.Индекс + 1]; 345 | КонецЦикла; 346 | 347 | Результат.Добавить(СтрШаблон( 348 | "

%1

349 | | " ""); 397 | КонецЕсли; 398 | 399 | КонецЕсли; 400 | 401 | КонецЕсли; 402 | 403 | КонецЦикла; 404 | 405 | КонецЕсли; 406 | 407 | КонецЦикла; 408 | 409 | Результат.Добавить( 410 | "

Прочее

411 | |

Доступность

412 | | 424 | | 425 | |" 426 | ); 427 | 428 | Результат.Добавить("

Перечисления

"); 429 | Результат.Добавить(СгенерироватьПеречисление("Типы", Типы, Истина)); 430 | Результат.Добавить(СгенерироватьПеречисление("Директивы", Директивы)); 431 | Результат.Добавить(СгенерироватьПеречисление("Аннотации", Аннотации)); 432 | Результат.Добавить(СгенерироватьПеречисление("СимволыПрепроцессора", СимволыПрепроцессора)); 433 | Результат.Добавить(СгенерироватьПеречисление("Токены", Токены)); 434 | 435 | Возврат СтрСоединить(Результат); 436 | 437 | КонецФункции 438 | 439 | Функция СгенерироватьПеречисление(Имя, Перечисление, Ссылка = Ложь) 440 | Перем Буфер; 441 | Буфер = Новый Массив; 442 | Буфер.Добавить(СтрШаблон( 443 | "

%1

444 | |" ""); 459 | Возврат СтрСоединить(Буфер); 460 | КонецФункции // СгенерироватьПеречисление() 461 | 462 | Функция СгенерироватьСписокТипов(СписокТипов) 463 | Перем Буфер; 464 | Буфер = Новый Массив; 465 | Для Каждого Элемент Из СписокТипов Цикл 466 | Если Элемент.Ребенок = Неопределено Тогда 467 | Если Lower(Элемент.Идентификатор) = Элемент.Идентификатор Тогда 468 | Буфер.Добавить(Элемент.Идентификатор); 469 | Иначе 470 | Идентификатор = Элемент.Идентификатор; 471 | Если СтрНачинаетсяС(Идентификатор, "#") Тогда 472 | Идентификатор = Сред(Идентификатор, 2); 473 | КонецЕсли; 474 | Буфер.Добавить(СтрШаблон( 475 | "%1", 476 | Идентификатор 477 | )); 478 | КонецЕсли; 479 | ИначеЕсли ТипЗнч(Элемент.Ребенок) = Тип("Строка") Тогда 480 | Ребенок = Элемент.Ребенок; 481 | Если СтрНачинаетсяС(Ребенок, "#") Тогда 482 | Ребенок = Сред(Ребенок, 2); 483 | КонецЕсли; 484 | Буфер.Добавить(СтрШаблон( 485 | "%1 %2", 486 | Элемент.Идентификатор, 487 | Ребенок 488 | )); 489 | Иначе 490 | Буфер.Добавить(СтрШаблон( 491 | "%1 (%2)", 492 | Элемент.Идентификатор, 493 | СгенерироватьСписокТипов(Элемент.Ребенок) 494 | )); 495 | КонецЕсли; 496 | КонецЦикла; 497 | Возврат СтрСоединить(Буфер, ", "); 498 | КонецФункции 499 | 500 | #Область ПарсерТипов 501 | 502 | Функция РазобратьТипы(ТипыСтрокой) 503 | Перем Позиция, Идентификатор, Список; 504 | Позиция = 1; Список = Новый Массив; 505 | Пока Истина Цикл 506 | Ребенок = Неопределено; 507 | ПропуститьНевидимыеСимволы(ТипыСтрокой, Позиция); 508 | Идентификатор = СканироватьИдентификатор(ТипыСтрокой, Позиция); 509 | ПропуститьНевидимыеСимволы(ТипыСтрокой, Позиция); 510 | Если Идентификатор = "один" Тогда 511 | Если Сред(ТипыСтрокой, Позиция, 2) <> "из" Тогда 512 | ВызватьИсключение "ошибка"; 513 | КонецЕсли; 514 | Позиция = Позиция + 2; 515 | Идентификатор = "один из"; 516 | ПропуститьНевидимыеСимволы(ТипыСтрокой, Позиция); 517 | Ребенок = СканироватьИдентификатор(ТипыСтрокой, Позиция); 518 | ИначеЕсли Сред(ТипыСтрокой, Позиция, 1) = "(" Тогда 519 | Позиция = Позиция + 1; 520 | Начало = Позиция; 521 | ПропуститьДо(ТипыСтрокой, Позиция, ")"); 522 | Ребенок = РазобратьТипы(Сред(ТипыСтрокой, Начало, Позиция - Начало)); 523 | Позиция = Позиция + 1; 524 | КонецЕсли; 525 | Список.Добавить(Новый Структура("Идентификатор, Ребенок", Идентификатор, Ребенок)); 526 | Если Сред(ТипыСтрокой, Позиция, 1) <> "," Тогда 527 | Прервать; 528 | КонецЕсли; 529 | Позиция = Позиция + 1; 530 | КонецЦикла; 531 | Возврат Список; 532 | КонецФункции 533 | 534 | Процедура ПропуститьНевидимыеСимволы(Строка, Позиция) 535 | Для Позиция = Позиция По СтрДлина(Строка) Цикл 536 | Если Не ПустаяСтрока(Сред(Строка, Позиция, 1)) Тогда 537 | Прервать; 538 | КонецЕсли; 539 | КонецЦикла; 540 | КонецПроцедуры 541 | 542 | Процедура ПропуститьДо(Строка, Позиция, Символ) 543 | Для Позиция = Позиция По СтрДлина(Строка) Цикл 544 | Если Сред(Строка, Позиция, 1) = Символ Тогда 545 | Прервать; 546 | КонецЕсли; 547 | КонецЦикла; 548 | КонецПроцедуры 549 | 550 | Функция СканироватьИдентификатор(Строка, Позиция) 551 | Перем Начало, Символ; 552 | Начало = Позиция; 553 | Для Позиция = Позиция По СтрДлина(Строка) Цикл 554 | Символ = Сред(Строка, Позиция, 1); 555 | Если ПустаяСтрока(Символ) Или Символ = "," Тогда 556 | Прервать; 557 | КонецЕсли; 558 | КонецЦикла; 559 | Возврат Сред(Строка, Начало, Позиция - Начало); 560 | КонецФункции 561 | 562 | #КонецОбласти // ПарсерТипов -------------------------------------------------------------------------------- /examples/backends/Классы/Компилятор.os: -------------------------------------------------------------------------------- 1 |  2 | // MIT License 3 | 4 | // Copyright (c) 2020 Tsukanov Alexander 5 | 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | // Lasciate ogni speranza, voi ch'entrate. 25 | // Внимание! Это просто proof of concept и попытка мимикрировать под компилятор платформы. 26 | // Если что-то кажется странным, то это не кажется. Странное сознательно делалось ради мимикрии. 27 | // Попытка повторить компилятор платформы оказалась для автора единственным развлечением в этом унылом занятии. 28 | // Генератор ничего интересного сам по себе не представляет. Сложность на уровне курсовой работы в универе. 29 | // Использовать можно разве что в учебных целях. 30 | 31 | // Разработка велась с использованием материалов https://github.com/EvilBeaver/v8asm 32 | 33 | Перем Типы; 34 | Перем Токены; 35 | Перем Исходник; 36 | Перем ТаблицаТокенов; 37 | 38 | Перем РазделКоманд; 39 | Перем РазделКонстант; 40 | Перем РазделПеременных; 41 | Перем РазделМетодов; 42 | Перем РазделПеременныхМетода; 43 | 44 | Перем ПеременныеМетодов; // структура 45 | Перем ЗначенияПараметровМетодовПоУмолчанию; // структура 46 | 47 | Перем КомандыЗагрузкиПеременных; 48 | Перем КомандыБинарныхОпераций; 49 | 50 | Перем Команды; 51 | Перем ВстроенныеФункции; 52 | 53 | Перем КэшКонстант; // соответствие 54 | Перем КэшПеременных; // соответствие 55 | Перем КэшМетодов; // соответствие 56 | Перем КэшВременныхПеременных; // соответствие 57 | Перем Возвраты; // массив 58 | Перем Метки; // соответствие 59 | Перем ПереходыНаМетки; // соответствие 60 | Перем ПереходыНаКонецМодуля; // массив 61 | 62 | Перем ФиктивныеОбъявления; // соответствие 63 | 64 | Перем СтекПереходовВЦиклах; 65 | 66 | Перем ЭтоТелоМодуля; 67 | 68 | Перем ФлагиПеременных; 69 | Перем ФлагиМетодов; 70 | 71 | Перем ТочкаВходаМодуля; 72 | Перем ТочкиВходаМетодов; 73 | 74 | Процедура Открыть(Парсер) 75 | 76 | Типы = Парсер.Типы(); 77 | Токены = Парсер.Токены(); 78 | Исходник = Парсер.Исходник(); 79 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 80 | 81 | РазделКоманд.Очистить(); 82 | РазделКонстант.Очистить(); 83 | РазделПеременных.Очистить(); 84 | РазделМетодов.Очистить(); 85 | РазделПеременныхМетода.Очистить(); 86 | 87 | ПеременныеМетодов.Очистить(); 88 | ЗначенияПараметровМетодовПоУмолчанию.Очистить(); 89 | 90 | КомандыЗагрузкиПеременных.Очистить(); 91 | 92 | КэшКонстант.Очистить(); 93 | КэшПеременных.Очистить(); 94 | КэшМетодов.Очистить(); 95 | КэшВременныхПеременных.Очистить(); 96 | Возвраты.Очистить(); 97 | Метки.Очистить(); 98 | ПереходыНаМетки.Очистить(); 99 | ПереходыНаКонецМодуля.Очистить(); 100 | 101 | ФиктивныеОбъявления.Очистить(); 102 | 103 | СтекПереходовВЦиклах.Очистить(); 104 | 105 | ЭтоТелоМодуля = Ложь; 106 | 107 | КомандыБинарныхОпераций[Токены.И] = Команды.And; 108 | КомандыБинарныхОпераций[Токены.Или] = Команды.Or; 109 | КомандыБинарныхОпераций[Токены.ЗнакСложения] = Команды.Add; 110 | КомандыБинарныхОпераций[Токены.ЗнакВычитания] = Команды.Sub; 111 | КомандыБинарныхОпераций[Токены.ЗнакУмножения] = Команды.Mul; 112 | КомандыБинарныхОпераций[Токены.ЗнакДеления] = Команды.Div; 113 | КомандыБинарныхОпераций[Токены.ЗнакОстатка] = Команды.Mod; 114 | КомандыБинарныхОпераций[Токены.ЗнакРавно] = Команды.Cmp; 115 | КомандыБинарныхОпераций[Токены.ЗнакНеРавно] = Команды.Ne; 116 | КомандыБинарныхОпераций[Токены.ЗнакМеньше] = Команды.Lt; 117 | КомандыБинарныхОпераций[Токены.ЗнакБольше] = Команды.Gt; 118 | КомандыБинарныхОпераций[Токены.ЗнакМеньшеИлиРавно] = Команды.Lte; 119 | КомандыБинарныхОпераций[Токены.ЗнакБольшеИлиРавно] = Команды.Gte; 120 | 121 | КонецПроцедуры 122 | 123 | Функция Закрыть() 124 | 125 | // осторожно, тут лютый фарш 126 | // мне лень делать это красиво, да и смысла пока не вижу 127 | // цель была только мимикрировать под платформу с минимальными усилиями 128 | 129 | Результат = Новый Массив; 130 | 131 | // Команды 132 | 133 | Результат.Добавить(СтрШаблон("{""Cmd"",%1,%2," "", Сериализовать(РазделКоманд.Количество()), Сериализовать(ТочкаВходаМодуля))); 134 | 135 | СписокКоманд = Новый Массив; 136 | Для Каждого Элемент Из РазделКоманд Цикл 137 | СписокКоманд.Добавить(СериализоватьСписок(Элемент)); 138 | КонецЦикла; 139 | Результат.Добавить(СтрСоединить(СписокКоманд, "," + Символы.ПС)); 140 | 141 | Результат.Добавить("" "}"); 142 | 143 | // Константы 144 | 145 | Если РазделКонстант.Количество() > 0 Тогда 146 | 147 | Результат.Добавить(СтрШаблон("," "{""Const"",%1," "", Сериализовать(РазделКонстант.Количество()))); 148 | СписокКонстант = Новый Массив; 149 | Для Каждого Элемент Из РазделКонстант Цикл 150 | Константа = Новый Массив; 151 | Если ТипЗнч(Элемент) = Тип("Строка") Тогда 152 | Константа.Добавить("S"); 153 | ИначеЕсли ТипЗнч(Элемент) = Тип("Число") Тогда 154 | Константа.Добавить("N"); 155 | ИначеЕсли ТипЗнч(Элемент) = Тип("Дата") Тогда 156 | Константа.Добавить("D"); 157 | ИначеЕсли ТипЗнч(Элемент) = Тип("Неопределено") Тогда 158 | Константа.Добавить("U"); 159 | ИначеЕсли ТипЗнч(Элемент) = Тип("Булево") Тогда 160 | Константа.Добавить("B"); 161 | Иначе 162 | Константа.Добавить(""); 163 | КонецЕсли; 164 | Константа.Добавить(Элемент); 165 | СписокКонстант.Добавить(СериализоватьСписок(Константа)); 166 | КонецЦикла; 167 | Результат.Добавить(СтрСоединить(СписокКонстант, "," + Символы.ПС)); 168 | 169 | Результат.Добавить("" "}"); 170 | 171 | КонецЕсли; 172 | 173 | // Переменные 174 | 175 | Если РазделПеременных.Количество() > 0 Тогда 176 | 177 | Результат.Добавить(СтрШаблон("," "{""Var"",%1," "", Сериализовать(РазделПеременных.Количество()))); 178 | 179 | СписокПеременных = Новый Массив; 180 | Для Каждого Элемент Из РазделПеременных Цикл 181 | СписокПеременных.Добавить(СериализоватьСписок(Элемент)); 182 | КонецЦикла; 183 | Результат.Добавить(СтрСоединить(СписокПеременных, "," + Символы.ПС)); 184 | 185 | Результат.Добавить("" "}"); 186 | 187 | КонецЕсли; 188 | 189 | // Методы 190 | 191 | Если РазделМетодов.Количество() > 0 Тогда 192 | 193 | Результат.Добавить(СтрШаблон("," "{""Proc"",%1," "", Сериализовать(РазделМетодов.Количество()))); 194 | 195 | СписокМетодов = Новый Массив; 196 | Для Каждого ОписаниеМетода Из РазделМетодов Цикл 197 | 198 | ТочкаВходаМетода = Неопределено; 199 | Если ТочкиВходаМетодов.Свойство(ОписаниеМетода[0], ТочкаВходаМетода) Тогда 200 | ОписаниеМетода[3] = ТочкаВходаМетода; 201 | КонецЕсли; 202 | 203 | Метод = Новый Массив; 204 | 205 | ДобавлятьПеренос = Ложь; 206 | 207 | Метод.Добавить("{"); 208 | 209 | Для Каждого Элемент Из ОписаниеМетода Цикл 210 | Метод.Добавить(Сериализовать(Элемент)); 211 | Метод.Добавить(","); 212 | КонецЦикла; 213 | Метод.Удалить(Метод.ВГраница()); 214 | 215 | // Переменные метода 216 | 217 | РазделПеременныхМетода = Неопределено; 218 | 219 | Если ПеременныеМетодов.Свойство(ОписаниеМетода[0], РазделПеременныхМетода) 220 | И РазделПеременныхМетода.Количество() > 0 Тогда 221 | 222 | Метод.Добавить(СтрШаблон("," "{""Var"",%1," "", Сериализовать(РазделПеременныхМетода.Количество()))); 223 | 224 | СписокПеременных = Новый Массив; 225 | Для Каждого Элемент Из РазделПеременныхМетода Цикл 226 | СписокПеременных.Добавить(СериализоватьСписок(Элемент)); 227 | КонецЦикла; 228 | Метод.Добавить(СтрСоединить(СписокПеременных, "," + Символы.ПС)); 229 | 230 | Метод.Добавить("" "}"); 231 | 232 | ДобавлятьПеренос = Истина; 233 | 234 | КонецЕсли; 235 | 236 | // Значения параметров по умолчанию 237 | 238 | ЗначенияПараметровПоУмолчанию = Неопределено; 239 | 240 | Если ЗначенияПараметровМетодовПоУмолчанию.Свойство(ОписаниеМетода[0], ЗначенияПараметровПоУмолчанию) 241 | И ЗначенияПараметровПоУмолчанию.Количество() > 0 Тогда 242 | 243 | Метод.Добавить(СтрШаблон("," "{""DefPrm"",%1," "", Сериализовать(ЗначенияПараметровПоУмолчанию.Количество()))); 244 | 245 | СписокЗначенийПараметров = Новый Массив; 246 | Для Каждого Элемент Из ЗначенияПараметровПоУмолчанию Цикл 247 | ЗначениеПараметра = Новый Массив; 248 | Если ТипЗнч(Элемент) = Тип("СтрокаТаблицыЗначений") 249 | И Элемент.Тип = Типы.ВыражениеЛитерал Тогда 250 | Если ТипЗнч(Элемент.Значение) = Тип("Строка") Тогда 251 | ЗначениеПараметра.Добавить("S"); 252 | ИначеЕсли ТипЗнч(Элемент.Значение) = Тип("Число") Тогда 253 | ЗначениеПараметра.Добавить("N"); 254 | ИначеЕсли ТипЗнч(Элемент.Значение) = Тип("Дата") Тогда 255 | ЗначениеПараметра.Добавить("D"); 256 | ИначеЕсли ТипЗнч(Элемент.Значение) = Тип("Неопределено") Тогда 257 | ЗначениеПараметра.Добавить("U"); 258 | ИначеЕсли ТипЗнч(Элемент.Значение) = Тип("Булево") Тогда 259 | ЗначениеПараметра.Добавить("B"); 260 | Иначе 261 | ЗначениеПараметра.Добавить(""); 262 | КонецЕсли; 263 | ИначеЕсли ТипЗнч(Элемент) = Тип("СтрокаТаблицыЗначений") 264 | И Элемент.Тип = Типы.ВыражениеСтроковое Тогда 265 | СписокЧастей = Новый Массив; 266 | Для Каждого Часть Из Элемент.Элементы Цикл 267 | СписокЧастей.Добавить(Часть.Значение); 268 | КонецЦикла; 269 | ЗначениеПараметра.Добавить("S"); 270 | ЗначениеПараметра.Добавить(СтрСоединить(СписокЧастей, Символы.ПС)); 271 | Иначе 272 | ЗначениеПараметра.Добавить(""); 273 | КонецЕсли; 274 | Если Элемент <> Неопределено 275 | И Элемент.Тип <> Типы.ВыражениеСтроковое 276 | И Элемент.Значение <> Неопределено Тогда 277 | ЗначениеПараметра.Добавить(Элемент.Значение); 278 | КонецЕсли; 279 | СписокЗначенийПараметров.Добавить(СериализоватьСписок(ЗначениеПараметра)); 280 | КонецЦикла; 281 | 282 | Метод.Добавить(СтрСоединить(СписокЗначенийПараметров, "," + Символы.ПС)); 283 | 284 | Метод.Добавить("" "}"); 285 | 286 | ДобавлятьПеренос = Истина; 287 | 288 | КонецЕсли; 289 | 290 | Если ДобавлятьПеренос Тогда 291 | Метод.Добавить(Символы.ПС); 292 | КонецЕсли; 293 | Метод.Добавить("}"); 294 | 295 | СписокМетодов.Добавить(СтрСоединить(Метод)); 296 | 297 | КонецЦикла; 298 | Результат.Добавить(СтрСоединить(СписокМетодов, "," + Символы.ПС)); 299 | 300 | Результат.Добавить("" "}"); 301 | 302 | КонецЕсли; 303 | 304 | Возврат СтрШаблон("{1," "%1" "}", СтрСоединить(Результат)); 305 | 306 | КонецФункции 307 | 308 | Функция СериализоватьСписок(Список) 309 | 310 | Результат = Новый Массив; 311 | 312 | Для Каждого Элемент Из Список Цикл 313 | Результат.Добавить(Сериализовать(Элемент)); 314 | КонецЦикла; 315 | 316 | Возврат СтрШаблон("{%1}", СтрСоединить(Результат, ",")); 317 | 318 | КонецФункции 319 | 320 | Функция Сериализовать(Элемент) 321 | 322 | Если ТипЗнч(Элемент) = Тип("Строка") Тогда 323 | Возврат """" + СтрЗаменить(Элемент, """", """""") + """"; 324 | КонецЕсли; 325 | 326 | Возврат Формат(Элемент, "ЧРД=.; ЧН=0; ЧГ=; ЧО=1; ДФ=yyyyMMddhhmmss; ДП=00010101000000; БЛ=0; БИ=1"); 327 | 328 | КонецФункции 329 | 330 | Функция Посетить(Парсер, Модуль) Экспорт 331 | 332 | Открыть(Парсер); 333 | 334 | ПосетитьОбъявления(Модуль.Объявления); 335 | ЭтоТелоМодуля = Истина; 336 | ТочкаВходаМодуля = ИндексСледующейКоманды(); 337 | ПосетитьОператоры(Модуль.Операторы); 338 | ЭтоТелоМодуля = Ложь; 339 | ВыдатьКоманду(Команды.End); 340 | Если Модуль.Операторы.Количество() = 0 Тогда 341 | ВыдатьКоманду(Команды.End); // без понятия что за ересь, но так делает платформа 342 | КонецЕсли; 343 | Для Каждого ИндексПерехода Из ПереходыНаКонецМодуля Цикл 344 | ВставитьКоманду(ИндексПерехода, Команды.Jmp, ИндексТекущейКоманды()); 345 | КонецЦикла; 346 | ВставитьПереходыНаМетки(); 347 | 348 | Возврат Закрыть(); 349 | 350 | КонецФункции // Посетить() 351 | 352 | Процедура ПосетитьОбъявления(Объявления) 353 | Для Каждого Объявление Из Объявления Цикл 354 | ПосетитьОбъявление(Объявление); 355 | КонецЦикла; 356 | КонецПроцедуры // ПосетитьОбъявления() 357 | 358 | Процедура ПосетитьОператоры(Операторы) 359 | Для Каждого Оператор Из Операторы Цикл 360 | Если Оператор.Тип <> Типы.ОператорПопытка 361 | И Оператор.Тип <> Типы.ОператорМетка Тогда 362 | ВыдатьКоманду(Команды.LineNum, Оператор.Начало.НомерСтроки); 363 | КонецЕсли; 364 | ПосетитьОператор(Оператор); 365 | Если Оператор.Тип <> Типы.ОператорПопытка 366 | И Оператор.Тип <> Типы.ОператорПрервать 367 | И Оператор.Тип <> Типы.ОператорПродолжить 368 | И Оператор.Тип <> Типы.ОператорПрисваивания 369 | И Оператор.Тип <> Типы.ОператорМетка 370 | И Оператор.Тип <> Типы.ОператорПерейти 371 | И Оператор.Тип <> Типы.ОператорВозврат 372 | И Оператор.Тип <> Типы.ОператорПока 373 | И Оператор.Тип <> Типы.ОператорДля 374 | И Оператор.Тип <> Типы.ОператорДляКаждого 375 | И Оператор.Тип <> Типы.ОператорВызватьИсключение Тогда 376 | Если Оператор.Тип = Типы.ОператорВызоваПроцедуры Тогда 377 | ВыдатьКоманду(Команды.LineNum, Оператор.Начало.НомерСтроки); 378 | Иначе 379 | ВыдатьКоманду(Команды.LineNum, Оператор.Конец.НомерСтроки); 380 | КонецЕсли; 381 | КонецЕсли; 382 | КонецЦикла; 383 | КонецПроцедуры // ПосетитьОператоры() 384 | 385 | #Область ПосещениеОбъявлений 386 | 387 | Процедура ПосетитьОбъявление(Объявление) 388 | Тип = Объявление.Тип; 389 | Если Тип = Типы.ОбъявлениеСпискаПеременныхМодуля Тогда 390 | Для Каждого ОбъявлениеПеременнойМодуля Из Объявление.Объявления Цикл 391 | ВыдатьПеременную(ОбъявлениеПеременнойМодуля.Имя, ОбъявлениеПеременнойМодуля); 392 | КонецЦикла; 393 | ИначеЕсли Тип = Типы.ОбъявлениеМетода Тогда 394 | ПосетитьОбъявлениеМетода(Объявление); 395 | ИначеЕсли Тип = Типы.ИнструкцияПрепроцессораОбласть 396 | Или Тип = Типы.ИнструкцияПрепроцессораКонецОбласти 397 | Или Тип = Типы.ИнструкцияПрепроцессораЕсли 398 | Или Тип = Типы.ИнструкцияПрепроцессораИначеЕсли 399 | Или Тип = Типы.ИнструкцияПрепроцессораИначе 400 | Или Тип = Типы.ИнструкцияПрепроцессораКонецЕсли Тогда 401 | ПосетитьИнструкциюПрепроцессора(Объявление); 402 | КонецЕсли; 403 | КонецПроцедуры // ПосетитьОбъявление() 404 | 405 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) 406 | ВыдатьМетод(ОбъявлениеМетода.Сигнатура.Имя, ОбъявлениеМетода.Сигнатура); // просто чтобы занять индекс 407 | ТочкиВходаМетодов.Вставить(ОбъявлениеМетода.Сигнатура.Имя, ИндексСледующейКоманды()); 408 | Возвраты.Очистить(); 409 | РазделПеременныхМетода = Новый Массив; 410 | ПеременныеМетодов.Вставить(ОбъявлениеМетода.Сигнатура.Имя, РазделПеременныхМетода); 411 | ЗначенияПараметровПоУмолчанию = Новый Массив; 412 | ЗначенияПараметровМетодовПоУмолчанию.Вставить(ОбъявлениеМетода.Сигнатура.Имя, ЗначенияПараметровПоУмолчанию); 413 | Для Каждого ОбъявлениеПараметра Из ОбъявлениеМетода.Сигнатура.Параметры Цикл 414 | ВыдатьПеременную(ОбъявлениеПараметра.Имя, ОбъявлениеПараметра); 415 | ЗначенияПараметровПоУмолчанию.Добавить(ОбъявлениеПараметра.Значение); 416 | КонецЦикла; 417 | Для Каждого ОбъявлениеЛокальнойПеременной Из ОбъявлениеМетода.Переменные Цикл 418 | ВыдатьПеременную(ОбъявлениеЛокальнойПеременной.Имя, ОбъявлениеЛокальнойПеременной); 419 | КонецЦикла; 420 | ПосетитьОператоры(ОбъявлениеМетода.Операторы); 421 | ИндексКонца = ВыдатьКоманду(Команды.LineNum, ОбъявлениеМетода.Конец.НомерСтроки); 422 | ВыдатьКоманду(Команды.End); 423 | Для Каждого Индекс Из Возвраты Цикл 424 | ВставитьКоманду(Индекс, Команды.Jmp, ИндексКонца); 425 | КонецЦикла; 426 | ВставитьПереходыНаМетки(); 427 | КонецПроцедуры // ПосетитьОбъявлениеМетода() 428 | 429 | #КонецОбласти // ПосещениеОбъявлений 430 | 431 | #Область ПосещениеВыражений 432 | 433 | Процедура ПосетитьВыражение(Выражение) 434 | Тип = Выражение.Тип; 435 | Если Тип = Типы.ВыражениеЛитерал Тогда 436 | ПосетитьВыражениеЛитерал(Выражение); 437 | ИначеЕсли Тип = Типы.ВыражениеИдентификатор Тогда 438 | ПосетитьВыражениеИдентификатор(Выражение); 439 | ИначеЕсли Тип = Типы.ВыражениеУнарное Тогда 440 | ПосетитьВыражениеУнарное(Выражение); 441 | ИначеЕсли Тип = Типы.ВыражениеБинарное Тогда 442 | ПосетитьВыражениеБинарное(Выражение); 443 | ИначеЕсли Тип = Типы.ВыражениеНовый Тогда 444 | ПосетитьВыражениеНовый(Выражение); 445 | ИначеЕсли Тип = Типы.ВыражениеТернарное Тогда 446 | ПосетитьВыражениеТернарное(Выражение); 447 | ИначеЕсли Тип = Типы.ВыражениеСкобочное Тогда 448 | ПосетитьВыражениеСкобочное(Выражение); 449 | ИначеЕсли Тип = Типы.ВыражениеНе Тогда 450 | ПосетитьВыражениеНе(Выражение); 451 | ИначеЕсли Тип = Типы.ВыражениеСтроковое Тогда 452 | ПосетитьВыражениеСтроковое(Выражение); 453 | КонецЕсли; 454 | КонецПроцедуры // ПосетитьВыражение() 455 | 456 | Процедура ПосетитьВыражениеЛитерал(ВыражениеЛитерал) 457 | ВидЛитерала = ВыражениеЛитерал.Вид; 458 | Если ВидЛитерала = Токены.Неопределено Тогда 459 | ВыдатьКоманду(Команды.LdUndef); 460 | ИначеЕсли ВидЛитерала = Токены.Истина Тогда 461 | ВыдатьКоманду(Команды.LdTrue); 462 | ИначеЕсли ВидЛитерала = Токены.Ложь Тогда 463 | ВыдатьКоманду(Команды.LdFalse); 464 | ИначеЕсли ВидЛитерала = Токены.Null Тогда 465 | ВыдатьКоманду(Команды.LdNull); 466 | Иначе 467 | ВыдатьКоманду(Команды.LdConst, ВыдатьКонстанту(ВыражениеЛитерал.Значение)); 468 | КонецЕсли; 469 | КонецПроцедуры // ПосетитьВыражениеЛитерал() 470 | 471 | Процедура ПосетитьВыражениеИдентификатор(ВыражениеИдентификатор, ВызовПроцедуры = Ложь) 472 | Если ВыражениеИдентификатор.Аргументы = Неопределено Тогда 473 | ВыдатьКомандуЗагрузкиПеременной(ВыражениеИдентификатор.Голова); 474 | Иначе 475 | РазделКомандНастоящий = РазделКоманд; // финт ушами чтобы индексы методов совпадали с платформой 476 | РазделКоманд = Новый Массив; 477 | КодФункции = Неопределено; 478 | Если Не ВызовПроцедуры Тогда 479 | ИмяНРег = НРег(ВыражениеИдентификатор.Голова.Имя); 480 | Если ИмяНРег = "min" 481 | Или ИмяНРег = "мин" 482 | Или ИмяНРег = "max" 483 | Или ИмяНРег = "макс" Тогда 484 | ВыдатьКоманду(Команды.ArgNum, ВыражениеИдентификатор.Аргументы.Количество()); 485 | КодФункции = НайтиВстроеннуюФункцию(ВыражениеИдентификатор.Голова.Имя, Неопределено); 486 | Иначе 487 | КодФункции = НайтиВстроеннуюФункцию(ВыражениеИдентификатор.Голова.Имя, ВыражениеИдентификатор.Аргументы.Количество()); 488 | КонецЕсли; 489 | КонецЕсли; 490 | Если КодФункции <> Неопределено Тогда 491 | ВыдатьКоманду(КодФункции); 492 | Иначе 493 | ВыдатьКоманду(Команды.ArgNum, ВыражениеИдентификатор.Аргументы.Количество()); 494 | ВыдатьКоманду(Команды.CallLoc, ВыдатьМетод(ВыражениеИдентификатор.Голова.Имя, ВыражениеИдентификатор.Голова.Объявление, ВызовПроцедуры)); 495 | Если Не ВызовПроцедуры Или ВыражениеИдентификатор.Хвост.Количество() > 0 Тогда 496 | ВыдатьКоманду(Команды.LdRet); 497 | ВыдатьКоманду(Команды.LineNum, ВыражениеИдентификатор.Начало.НомерСтроки); 498 | КонецЕсли; 499 | КонецЕсли; 500 | РазделКомандФиктивный = РазделКоманд; 501 | РазделКоманд = РазделКомандНастоящий; 502 | Для Каждого Выражение Из ВыражениеИдентификатор.Аргументы Цикл 503 | Если Выражение = Неопределено Тогда 504 | ВыдатьКоманду(Команды.LdNone); 505 | Иначе 506 | ПосетитьВыражение(Выражение); 507 | КонецЕсли; 508 | КонецЦикла; 509 | Для Каждого Команда Из РазделКомандФиктивный Цикл 510 | РазделКоманд.Добавить(Команда); 511 | КонецЦикла; 512 | КонецЕсли; 513 | ПосетитьХвост(ВыражениеИдентификатор.Хвост, ВызовПроцедуры); 514 | КонецПроцедуры // ПосетитьВыражениеИдентификатор() 515 | 516 | Процедура ПосетитьХвост(Хвост, ВызовПроцедуры = Ложь) 517 | 518 | Для Каждого Элемент Из Хвост Цикл 519 | Если Элемент.Тип = Типы.ВыражениеПоле Тогда 520 | Если Элемент.Аргументы = Неопределено Тогда 521 | ВыдатьКоманду(Команды.LdProp, ВыдатьКонстанту(Элемент.Имя)); 522 | Иначе 523 | ИндексИмениМетода = ВыдатьКонстанту(Элемент.Имя); // до выражения чтобы индекс с платформой совпадал 524 | Для Каждого Выражение Из Элемент.Аргументы Цикл 525 | Если Выражение = Неопределено Тогда 526 | ВыдатьКоманду(Команды.LdNone); 527 | Иначе 528 | ПосетитьВыражение(Выражение); 529 | КонецЕсли; 530 | КонецЦикла; 531 | ВыдатьКоманду(Команды.ArgNum, Элемент.Аргументы.Количество()); 532 | Если ВызовПроцедуры Тогда 533 | ВыдатьКоманду(Команды.CallProc, ИндексИмениМетода); 534 | Иначе 535 | ВыдатьКоманду(Команды.CallFunc, ИндексИмениМетода); 536 | ВыдатьКоманду(Команды.LdRet); 537 | ВыдатьКоманду(Команды.LineNum, Элемент.Начало.НомерСтроки); 538 | КонецЕсли; 539 | КонецЕсли; 540 | ИначеЕсли Элемент.Тип = Типы.ВыражениеИндекс Тогда 541 | ПосетитьВыражение(Элемент.Выражение); 542 | ВыдатьКоманду(Команды.LdIndex); 543 | Иначе 544 | ВызватьИсключение "нарушение протокола"; 545 | КонецЕсли; 546 | КонецЦикла; 547 | 548 | КонецПроцедуры 549 | 550 | Процедура ПосетитьВыражениеУнарное(ВыражениеУнарное) 551 | ПосетитьВыражение(ВыражениеУнарное.Операнд); 552 | Если ВыражениеУнарное.Операция.Токен = Токены.ЗнакВычитания Тогда 553 | ВыдатьКоманду(Команды.Minus); 554 | КонецЕсли; 555 | КонецПроцедуры // ПосетитьВыражениеУнарное() 556 | 557 | Процедура ПосетитьВыражениеБинарное(ВыражениеБинарное) 558 | ЭтоЛогическаяОперация = ( 559 | ВыражениеБинарное.Операция.Токен = Токены.И 560 | Или ВыражениеБинарное.Операция.Токен = Токены.Или 561 | ); 562 | ПосетитьВыражение(ВыражениеБинарное.ЛевыйОперанд); 563 | Если ЭтоЛогическаяОперация Тогда 564 | ИндексПерехода = ВыдатьЗаглушку(); 565 | КонецЕсли; 566 | ПосетитьВыражение(ВыражениеБинарное.ПравыйОперанд); 567 | Если ЭтоЛогическаяОперация Тогда 568 | ВыдатьКоманду(Команды.Boolean); 569 | ВставитьКоманду(ИндексПерехода, КомандыБинарныхОпераций[ВыражениеБинарное.Операция.Токен], ИндексСледующейКоманды()); 570 | Иначе 571 | ВыдатьКоманду(КомандыБинарныхОпераций[ВыражениеБинарное.Операция.Токен]); 572 | КонецЕсли; 573 | КонецПроцедуры // ПосетитьВыражениеБинарное() 574 | 575 | Процедура ПосетитьВыражениеНовый(ВыражениеНовый) 576 | Для Каждого Выражение Из ВыражениеНовый.Аргументы Цикл 577 | Если Выражение <> Неопределено Тогда 578 | ПосетитьВыражение(Выражение); 579 | КонецЕсли; 580 | КонецЦикла; 581 | Если ВыражениеНовый.Имя <> Неопределено Тогда 582 | ВыдатьКоманду(Команды.ArgNum, ВыражениеНовый.Аргументы.Количество()); 583 | ВыдатьКоманду(Команды.New, ВыдатьКонстанту(ВыражениеНовый.Имя)); 584 | Иначе 585 | КодФункции = НайтиВстроеннуюФункцию("New", ВыражениеНовый.Аргументы.Количество()); 586 | Если КодФункции <> Неопределено Тогда 587 | ВыдатьКоманду(КодФункции); 588 | Иначе 589 | ВызватьИсключение "ошибка компиляции"; 590 | КонецЕсли; 591 | КонецЕсли; 592 | КонецПроцедуры // ПосетитьВыражениеНовый() 593 | 594 | Процедура ПосетитьВыражениеТернарное(ВыражениеТернарное) 595 | ПосетитьВыражение(ВыражениеТернарное.Выражение); 596 | ИндексУсловия = ВыдатьЗаглушку(); 597 | ПосетитьВыражение(ВыражениеТернарное.Тогда); 598 | ИндексПереходаНаКонец = ВыдатьЗаглушку(); 599 | ВставитьКоманду(ИндексУсловия, Команды.JmpFalse, ИндексСледующейКоманды()); 600 | ПосетитьВыражение(ВыражениеТернарное.Иначе); 601 | ВставитьКоманду(ИндексПереходаНаКонец, Команды.Jmp, ИндексСледующейКоманды()); 602 | ПосетитьХвост(ВыражениеТернарное.Хвост); 603 | КонецПроцедуры // ПосетитьВыражениеТернарное() 604 | 605 | Процедура ПосетитьВыражениеСкобочное(ВыражениеСкобочное) 606 | ПосетитьВыражение(ВыражениеСкобочное.Выражение); 607 | КонецПроцедуры // ПосетитьВыражениеСкобочное() 608 | 609 | Процедура ПосетитьВыражениеНе(ВыражениеНе) 610 | ПосетитьВыражение(ВыражениеНе.Выражение); 611 | ВыдатьКоманду(Команды.Not); 612 | КонецПроцедуры // ПосетитьВыражениеНе() 613 | 614 | Процедура ПосетитьВыражениеСтроковое(ВыражениеСтроковое) 615 | СписокЧастей = Новый Массив; 616 | Для Каждого Выражение Из ВыражениеСтроковое.Элементы Цикл 617 | СписокЧастей.Добавить(Выражение.Значение); 618 | КонецЦикла; 619 | ВыдатьКоманду(Команды.LdConst, ВыдатьКонстанту(СтрСоединить(СписокЧастей, Символы.ПС))); 620 | КонецПроцедуры // ПосетитьВыражениеСтроковое() 621 | 622 | #КонецОбласти // ПосещениеВыражений 623 | 624 | #Область ПосещениеОператоров 625 | 626 | Процедура ПосетитьОператор(Оператор) 627 | Тип = Оператор.Тип; 628 | Если Тип = Типы.ОператорПрисваивания Тогда 629 | ПосетитьОператорПрисваивания(Оператор); 630 | ИначеЕсли Тип = Типы.ОператорВозврат Тогда 631 | ПосетитьОператорВозврат(Оператор); 632 | ИначеЕсли Тип = Типы.ОператорПрервать Тогда 633 | ПосетитьОператорПрервать(Оператор); 634 | ИначеЕсли Тип = Типы.ОператорПродолжить Тогда 635 | ПосетитьОператорПродолжить(Оператор); 636 | ИначеЕсли Тип = Типы.ОператорВызватьИсключение Тогда 637 | ПосетитьОператорВызватьИсключение(Оператор); 638 | ИначеЕсли Тип = Типы.ОператорВыполнить Тогда 639 | ПосетитьОператорВыполнить(Оператор); 640 | ИначеЕсли Тип = Типы.ОператорВызоваПроцедуры Тогда 641 | ПосетитьОператорВызоваПроцедуры(Оператор); 642 | ИначеЕсли Тип = Типы.ОператорЕсли Тогда 643 | ПосетитьОператорЕсли(Оператор); 644 | ИначеЕсли Тип = Типы.ОператорПока Тогда 645 | ПосетитьОператорПока(Оператор); 646 | ИначеЕсли Тип = Типы.ОператорДля Тогда 647 | ПосетитьОператорДля(Оператор); 648 | ИначеЕсли Тип = Типы.ОператорДляКаждого Тогда 649 | ПосетитьОператорДляКаждого(Оператор); 650 | ИначеЕсли Тип = Типы.ОператорПопытка Тогда 651 | ПосетитьОператорПопытка(Оператор); 652 | ИначеЕсли Тип = Типы.ОператорПерейти Тогда 653 | ПосетитьОператорПерейти(Оператор); 654 | ИначеЕсли Тип = Типы.ОператорМетка Тогда 655 | ПосетитьОператорМетка(Оператор); 656 | ИначеЕсли Тип = Типы.ИнструкцияПрепроцессораОбласть 657 | Или Тип = Типы.ИнструкцияПрепроцессораКонецОбласти 658 | Или Тип = Типы.ИнструкцияПрепроцессораЕсли 659 | Или Тип = Типы.ИнструкцияПрепроцессораИначеЕсли 660 | Или Тип = Типы.ИнструкцияПрепроцессораИначе 661 | Или Тип = Типы.ИнструкцияПрепроцессораКонецЕсли Тогда 662 | ПосетитьИнструкциюПрепроцессора(Оператор); 663 | КонецЕсли; 664 | КонецПроцедуры // ПосетитьОператор() 665 | 666 | Процедура ПосетитьОператорПрисваивания(ОператорПрисваивания) 667 | ПосетитьВыражениеИдентификатор(ОператорПрисваивания.ЛевыйОперанд); 668 | ПосетитьВыражение(ОператорПрисваивания.ПравыйОперанд); 669 | ВыдатьКоманду(Команды.Assign); 670 | КонецПроцедуры // ПосетитьОператорПрисваивания() 671 | 672 | Процедура ПосетитьОператорВозврат(ОператорВозврат) 673 | Если ОператорВозврат.Выражение <> Неопределено Тогда 674 | ПосетитьВыражение(ОператорВозврат.Выражение); 675 | ВыдатьКоманду(Команды.Ret); 676 | КонецЕсли; 677 | ВыдатьКоманду(Команды.BlckEnd); 678 | Возвраты.Добавить(ВыдатьЗаглушку()); 679 | КонецПроцедуры // ПосетитьОператорВозврат() 680 | 681 | Процедура ПосетитьОператорПрервать(ОператорПрервать) 682 | ВзятьПоследнееЗначение(СтекПереходовВЦиклах).Прервать.Добавить(ВыдатьЗаглушку()); 683 | КонецПроцедуры // ПосетитьОператорПрервать() 684 | 685 | Процедура ПосетитьОператорПродолжить(ОператорПродолжить) 686 | ВзятьПоследнееЗначение(СтекПереходовВЦиклах).Продолжить.Добавить(ВыдатьЗаглушку()); 687 | КонецПроцедуры // ПосетитьОператорПродолжить() 688 | 689 | Процедура ПосетитьОператорВызватьИсключение(ОператорВызватьИсключение) 690 | Если ОператорВызватьИсключение.Выражение <> Неопределено Тогда 691 | ПосетитьВыражение(ОператорВызватьИсключение.Выражение); 692 | ВыдатьКоманду(Команды.Raise, 1); 693 | Иначе 694 | ВыдатьКоманду(Команды.Raise, 0); 695 | КонецЕсли; 696 | КонецПроцедуры // ПосетитьОператорВызватьИсключение() 697 | 698 | Процедура ПосетитьОператорВыполнить(ОператорВыполнить) 699 | ПосетитьВыражение(ОператорВыполнить.Выражение); 700 | ВыдатьКоманду(Команды.Exec); 701 | КонецПроцедуры // ПосетитьОператорВыполнить() 702 | 703 | Процедура ПосетитьОператорВызоваПроцедуры(ОператорВызоваПроцедуры) 704 | ПосетитьВыражениеИдентификатор(ОператорВызоваПроцедуры.Идентификатор, Истина); 705 | КонецПроцедуры // ПосетитьОператорВызоваПроцедуры() 706 | 707 | Процедура ПосетитьОператорЕсли(ОператорЕсли) 708 | ПосетитьВыражение(ОператорЕсли.Выражение); 709 | ИндексПоследнегоУсловия = ВыдатьЗаглушку(); 710 | ИндексыПереходовНаИначеИлиКонец = Новый Массив; 711 | ПосетитьОператоры(ОператорЕсли.Тогда); 712 | Если ОператорЕсли.ИначеЕсли <> Неопределено Тогда 713 | Для Каждого ОператорИначеЕсли Из ОператорЕсли.ИначеЕсли Цикл 714 | ИндексыПереходовНаИначеИлиКонец.Добавить(ВыдатьЗаглушку()); 715 | ВыдатьКоманду(Команды.LineNum, ОператорИначеЕсли.Начало.НомерСтроки); 716 | ВставитьКоманду(ИндексПоследнегоУсловия, Команды.JmpFalse, ИндексТекущейКоманды()); 717 | ПосетитьВыражение(ОператорИначеЕсли.Выражение); 718 | ИндексПоследнегоУсловия = ВыдатьЗаглушку(); 719 | ПосетитьОператоры(ОператорИначеЕсли.Тогда); 720 | КонецЦикла; 721 | КонецЕсли; 722 | Если ОператорЕсли.Иначе <> Неопределено Тогда 723 | ИндексыПереходовНаИначеИлиКонец.Добавить(ВыдатьЗаглушку()); 724 | ВставитьКоманду(ИндексПоследнегоУсловия, Команды.JmpFalse, ИндексСледующейКоманды()); 725 | ПосетитьОператоры(ОператорЕсли.Иначе.Операторы); 726 | Иначе 727 | ИндексыПереходовНаИначеИлиКонец.Добавить(ВыдатьЗаглушку()); 728 | ВставитьКоманду(ИндексПоследнегоУсловия, Команды.JmpFalse, ИндексСледующейКоманды()); 729 | КонецЕсли; 730 | ИндексСледующейКоманды = ИндексСледующейКоманды(); 731 | Для Каждого Индекс Из ИндексыПереходовНаИначеИлиКонец Цикл 732 | ВставитьКоманду(Индекс, Команды.Jmp, ИндексСледующейКоманды); 733 | КонецЦикла; 734 | КонецПроцедуры // ПосетитьОператорЕсли() 735 | 736 | Процедура ПосетитьОператорПока(ОператорПока) 737 | ПередПосещениемЦикла(); 738 | ИндексНачала = РазделКоманд.ВГраница(); 739 | ПосетитьВыражение(ОператорПока.Выражение); 740 | ВыдатьКоманду(Команды.LineNum, ОператорПока.Начало.НомерСтроки); 741 | ИндексУсловия = ВыдатьЗаглушку(); 742 | ПосетитьОператоры(ОператорПока.Операторы); 743 | ВыдатьКоманду(Команды.LineNum, ОператорПока.Конец.НомерСтроки); 744 | ВыдатьКоманду(Команды.Jmp, ИндексНачала); 745 | ИндексКонца = ИндексСледующейКоманды(); 746 | ВставитьКоманду(ИндексУсловия, Команды.JmpFalse, ИндексКонца); 747 | ПослеПосещенияЦикла(ИндексНачала, ИндексКонца); 748 | КонецПроцедуры // ПосетитьОператорПока() 749 | 750 | Процедура ПосетитьОператорДля(ОператорДля) 751 | ПередПосещениемЦикла(); 752 | ПосетитьВыражениеИдентификатор(ОператорДля.Идентификатор); 753 | ПосетитьВыражение(ОператорДля.Старт); 754 | ВыдатьКоманду(Команды.Assign); 755 | ВыдатьКоманду(Команды.PutTmp); 756 | ВыдатьКоманду(Команды.LdTmp); 757 | ПосетитьВыражение(ОператорДля.Финиш); 758 | ВыдатьКоманду(Команды.Assign); 759 | ИндексНачала = ВыдатьКоманду(Команды.LineNum, ОператорДля.Начало.НомерСтроки); 760 | ВыдатьКоманду(Команды.LdTmp); 761 | ПосетитьВыражениеИдентификатор(ОператорДля.Идентификатор); 762 | ВыдатьКоманду(Команды.Gte); 763 | ИндексУсловия = ВыдатьЗаглушку(); 764 | ПосетитьОператоры(ОператорДля.Операторы); 765 | ВыдатьКоманду(Команды.LineNum, ОператорДля.Конец.НомерСтроки); 766 | ИндексПродолжения = ИндексСледующейКоманды(); 767 | ПосетитьВыражениеИдентификатор(ОператорДля.Идентификатор); 768 | ВыдатьКоманду(Команды.Inc); 769 | ВыдатьКоманду(Команды.Jmp, ИндексНачала); 770 | ИндексКонца = ВыдатьКоманду(Команды.PopTmp, 1); 771 | ВставитьКоманду(ИндексУсловия, Команды.JmpFalse, ИндексКонца); 772 | ПослеПосещенияЦикла(ИндексПродолжения, ИндексКонца); 773 | КонецПроцедуры // ПосетитьОператорДля() 774 | 775 | Процедура ПосетитьОператорДляКаждого(ОператорДляКаждого) 776 | ПередПосещениемЦикла(); 777 | ВыдатьПеременную(ОператорДляКаждого.Идентификатор.Голова.Имя, ОператорДляКаждого.Идентификатор.Голова.Объявление); // просто чтоб индекс занять 778 | ВременнаяПеременная = ВременнаяПеременная(ОператорДляКаждого.Идентификатор.Голова); 779 | ВыдатьПеременную(ВременнаяПеременная.Имя, ВременнаяПеременная.Объявление); // просто чтоб индекс занять 780 | ВыдатьКоманду(Команды.PutTmp); 781 | ВыдатьКоманду(Команды.LdTmp); 782 | ПосетитьВыражение(ОператорДляКаждого.Коллекция); 783 | ВыдатьКоманду(Команды.Iter); 784 | ВыдатьКоманду(Команды.Assign); 785 | ВыдатьКоманду(Команды.LineNum, ОператорДляКаждого.Начало.НомерСтроки); 786 | ИндексНачала = ИндексТекущейКоманды(); 787 | ВыдатьКомандуЗагрузкиПеременной(ВременнаяПеременная); 788 | ВыдатьКоманду(Команды.LdTmp); 789 | ВыдатьКоманду(Команды.Assign); 790 | ВыдатьКомандуЗагрузкиПеременной(ВременнаяПеременная); 791 | ВыдатьКоманду(Команды.Next); 792 | ИндексУсловия = ВыдатьЗаглушку(); 793 | ПосетитьВыражениеИдентификатор(ОператорДляКаждого.Идентификатор); 794 | ВыдатьКомандуЗагрузкиПеременной(ВременнаяПеременная); 795 | ВыдатьКоманду(Команды.Assign); 796 | ВыдатьКомандуЗагрузкиПеременной(ВременнаяПеременная); 797 | ВыдатьКоманду(Команды.LdUndef); 798 | ВыдатьКоманду(Команды.Assign); 799 | ПосетитьОператоры(ОператорДляКаждого.Операторы); 800 | ВыдатьКоманду(Команды.LineNum, ОператорДляКаждого.Конец.НомерСтроки); 801 | ИндексПродолжения = ВыдатьКоманду(Команды.Jmp, ИндексНачала); 802 | ИндексКонца = ВыдатьКоманду(Команды.PopTmp, 1); 803 | ВставитьКоманду(ИндексУсловия, Команды.JmpFalse, ИндексКонца); 804 | ВыдатьКомандуЗагрузкиПеременной(ВременнаяПеременная); 805 | ВыдатьКоманду(Команды.LdUndef); 806 | ВыдатьКоманду(Команды.Assign); 807 | // хз зачем второй раз, но так делает платформа 808 | ВыдатьКомандуЗагрузкиПеременной(ВременнаяПеременная); 809 | ВыдатьКоманду(Команды.LdUndef); 810 | ВыдатьКоманду(Команды.Assign); 811 | ПослеПосещенияЦикла(ИндексПродолжения, ИндексКонца); 812 | КонецПроцедуры // ПосетитьОператорДляКаждого() 813 | 814 | Процедура ПосетитьОператорПопытка(ОператорПопытка) 815 | ИндексНачала = ВыдатьЗаглушку(); 816 | ПосетитьОператоры(ОператорПопытка.Попытка); 817 | ВыдатьКоманду(Команды.LineNum, ОператорПопытка.Конец.НомерСтроки); 818 | ВыдатьКоманду(Команды.BlckEnd, 1); 819 | ИндексПерехода = ВыдатьЗаглушку(); 820 | ВставитьКоманду(ИндексНачала, Команды.BeginTry, ИндексСледующейКоманды()); 821 | ПосетитьОператоры(ОператорПопытка.Исключение.Операторы); 822 | ВыдатьКоманду(Команды.LineNum, ОператорПопытка.Конец.НомерСтроки); 823 | ВыдатьКоманду(Команды.EndTry); 824 | ВставитьКоманду(ИндексПерехода, Команды.Jmp, ИндексСледующейКоманды()); 825 | КонецПроцедуры // ПосетитьОператорПопытка() 826 | 827 | Процедура ПосетитьОператорПерейти(ОператорПерейти) 828 | СписокПереходовНаМетку = СписокПереходовНаМетку(ОператорПерейти.Метка); 829 | СписокПереходовНаМетку.Добавить(ВыдатьЗаглушку()); 830 | КонецПроцедуры // ПосетитьОператорПерейти() 831 | 832 | Процедура ПосетитьОператорМетка(ОператорМетка) 833 | Метки[НРег(ОператорМетка.Метка)] = Новый Структура("ИндексМетки, ИндексКоманды", Метки.Количество(), ИндексСледующейКоманды()); 834 | КонецПроцедуры // ПосетитьОператорМетка() 835 | 836 | #КонецОбласти // ПосещениеОператоров 837 | 838 | #Область ПосещениеВыраженийПрепроцессора 839 | 840 | // полный игнор 841 | 842 | Процедура ПосетитьВыражениеПрепроцессора(ВыражениеПрепроцессора) 843 | Тип = ВыражениеПрепроцессора.Тип; 844 | Если Тип = Типы.ВыражениеПрепроцессораСимвол Тогда 845 | ПосетитьВыражениеПрепроцессораСимвол(ВыражениеПрепроцессора); 846 | ИначеЕсли Тип = Типы.ВыражениеПрепроцессораБинарное Тогда 847 | ПосетитьВыражениеПрепроцессораБинарное(ВыражениеПрепроцессора); 848 | ИначеЕсли Тип = Типы.ВыражениеПрепроцессораНе Тогда 849 | ПосетитьВыражениеПрепроцессораНе(ВыражениеПрепроцессора); 850 | ИначеЕсли Тип = Типы.ВыражениеПрепроцессораСкобочное Тогда 851 | ПосетитьВыражениеПрепроцессораСкобочное(ВыражениеПрепроцессора); 852 | КонецЕсли; 853 | КонецПроцедуры // ПосетитьВыражениеПрепроцессора() 854 | 855 | Процедура ПосетитьВыражениеПрепроцессораСимвол(ВыражениеПрепроцессораСимвол) 856 | 857 | КонецПроцедуры // ПосетитьВыражениеПрепроцессораСимвол() 858 | 859 | Процедура ПосетитьВыражениеПрепроцессораБинарное(ВыражениеПрепроцессораБинарное) 860 | ПосетитьВыражениеПрепроцессора(ВыражениеПрепроцессораБинарное.ЛевыйОперанд); 861 | ПосетитьВыражениеПрепроцессора(ВыражениеПрепроцессораБинарное.ПравыйОперанд); 862 | КонецПроцедуры // ПосетитьВыражениеПрепроцессораБинарное() 863 | 864 | Процедура ПосетитьВыражениеПрепроцессораНе(ВыражениеПрепроцессораНе) 865 | ПосетитьВыражениеПрепроцессора(ВыражениеПрепроцессораНе.Выражение); 866 | КонецПроцедуры // ПосетитьВыражениеПрепроцессораНе() 867 | 868 | Процедура ПосетитьВыражениеПрепроцессораСкобочное(ВыражениеПрепроцессораСкобочное) 869 | ПосетитьВыражениеПрепроцессора(ВыражениеПрепроцессораСкобочное.Выражение); 870 | КонецПроцедуры // ПосетитьВыражениеПрепроцессораСкобочное() 871 | 872 | Процедура ПосетитьИнструкциюПрепроцессора(ИнструкцияПрепроцессора) 873 | Если ИнструкцияПрепроцессора.Владелец().Колонки.Найти("Выражение") <> Неопределено Тогда 874 | ПосетитьВыражениеПрепроцессора(ИнструкцияПрепроцессора.Выражение); 875 | КонецЕсли; 876 | КонецПроцедуры // ПосетитьИнструкциюПрепроцессора() 877 | 878 | #КонецОбласти // ПосещениеВыраженийПрепроцессора 879 | 880 | #Область СлужебныеМетоды 881 | 882 | Функция ВыдатьКоманду(Команда, Параметр = 0) 883 | 884 | ОписаниеКоманды = Новый Массив; 885 | ОписаниеКоманды.Добавить(Команда); 886 | ОписаниеКоманды.Добавить(Параметр); 887 | РазделКоманд.Добавить(ОписаниеКоманды); 888 | 889 | Возврат РазделКоманд.ВГраница(); 890 | 891 | КонецФункции 892 | 893 | Функция ВыдатьЗаглушку() 894 | 895 | РазделКоманд.Добавить(Неопределено); 896 | 897 | Возврат РазделКоманд.ВГраница(); 898 | 899 | КонецФункции 900 | 901 | Процедура ВставитьКоманду(Индекс, Команда, Параметр = 0) 902 | 903 | ОписаниеКоманды = Новый Массив; 904 | ОписаниеКоманды.Добавить(Команда); 905 | ОписаниеКоманды.Добавить(Параметр); 906 | РазделКоманд[Индекс] = ОписаниеКоманды; 907 | 908 | КонецПроцедуры 909 | 910 | Функция ИндексТекущейКоманды() 911 | Возврат РазделКоманд.ВГраница(); 912 | КонецФункции 913 | 914 | Функция ИндексСледующейКоманды() 915 | Возврат РазделКоманд.Количество(); 916 | КонецФункции 917 | 918 | Функция ВыдатьКонстанту(Значение) 919 | 920 | Индекс = КэшКонстант[Значение]; 921 | 922 | Если Индекс = Неопределено Тогда 923 | 924 | РазделКонстант.Добавить(Значение); 925 | Индекс = РазделКонстант.ВГраница(); 926 | 927 | КэшКонстант[Значение] = Индекс; 928 | 929 | КонецЕсли; 930 | 931 | Возврат Индекс; 932 | 933 | КонецФункции 934 | 935 | Функция ВыдатьПеременную(Имя, Знач Объявление) 936 | 937 | Если Объявление = Неопределено Тогда 938 | Объявление = ФиктивныеОбъявления[НРег(Имя)]; 939 | КонецЕсли; 940 | 941 | Индекс = КэшПеременных[Объявление]; 942 | 943 | Если Индекс = Неопределено Тогда 944 | 945 | Если Объявление = Неопределено Тогда 946 | Объявление = Новый Структура("Тип", "ФиктивноеОбъявление"); 947 | ФиктивныеОбъявления[НРег(Имя)] = Объявление; 948 | КонецЕсли; 949 | 950 | Если ЭтоТелоМодуля 951 | Или Объявление.Тип = Типы.ОбъявлениеПеременнойМодуля 952 | Или Объявление.Тип = Типы.ОбъявлениеГлобальногоОбъекта 953 | Или Объявление.Тип = "ФиктивноеОбъявление" Тогда 954 | Раздел = РазделПеременных; 955 | КомандыЗагрузкиПеременных[Объявление] = Команды.LdVar; 956 | Иначе 957 | Раздел = РазделПеременныхМетода; 958 | КомандыЗагрузкиПеременных[Объявление] = Команды.LdLoc; 959 | КонецЕсли; 960 | 961 | Флаги = 0; 962 | 963 | Если Объявление.Тип = Типы.ОбъявлениеГлобальногоОбъекта 964 | Или Объявление.Тип = "ФиктивноеОбъявление" Тогда 965 | Флаги = Флаги + ФлагиПеременных.Глобальная; 966 | Иначе 967 | Если Объявление.Тип = Типы.ОбъявлениеПеременнойМодуля Тогда 968 | Если Объявление.Экспорт Тогда 969 | Флаги = Флаги + ФлагиПеременных.Экспорт; 970 | КонецЕсли; 971 | Иначе 972 | Флаги = Флаги + ФлагиПеременных.Локальная; 973 | КонецЕсли; 974 | КонецЕсли; 975 | 976 | Если Объявление.Тип = Типы.ОбъявлениеПараметра Тогда 977 | Флаги = Флаги + ФлагиПеременных.Параметр; 978 | Если Объявление.ПоЗначению Тогда 979 | Флаги = Флаги + ФлагиПеременных.Знач; 980 | КонецЕсли; 981 | КонецЕсли; 982 | 983 | ОписаниеПеременной = Новый Массив; 984 | ОписаниеПеременной.Добавить(Имя); 985 | ОписаниеПеременной.Добавить(Флаги); 986 | ОписаниеПеременной.Добавить(-1); 987 | 988 | Раздел.Добавить(ОписаниеПеременной); 989 | Индекс = Раздел.ВГраница(); 990 | 991 | КэшПеременных[Объявление] = Индекс; 992 | 993 | КонецЕсли; 994 | 995 | Возврат Индекс; 996 | 997 | КонецФункции 998 | 999 | Функция ВыдатьМетод(Имя, Сигнатура, ВызовПроцедуры = Истина) 1000 | 1001 | Индекс = КэшМетодов[НРег(Имя)]; 1002 | 1003 | Если Индекс = Неопределено Тогда 1004 | 1005 | Флаги = 0; 1006 | 1007 | Если Сигнатура = Неопределено Или Сигнатура.Тип = Типы.ОбъявлениеГлобальногоМетода Тогда 1008 | Флаги = Флаги + ФлагиМетодов.Глобальный; 1009 | Если Не ВызовПроцедуры Тогда 1010 | Флаги = Флаги + ФлагиМетодов.Функция; 1011 | КонецЕсли; 1012 | Иначе 1013 | Если Сигнатура.Тип = Типы.ОбъявлениеСигнатурыФункции Тогда 1014 | Флаги = Флаги + ФлагиМетодов.Функция; 1015 | КонецЕсли; 1016 | Если Сигнатура.Экспорт Тогда 1017 | Флаги = Флаги + ФлагиМетодов.Экспорт; 1018 | КонецЕсли; 1019 | КонецЕсли; 1020 | 1021 | ОписаниеМетода = Новый Массив; 1022 | ОписаниеМетода.Добавить(Имя); 1023 | ОписаниеМетода.Добавить(Флаги); 1024 | Если Сигнатура = Неопределено Тогда 1025 | ОписаниеМетода.Добавить(0); // число параметров неизвестно 1026 | Иначе 1027 | ОписаниеМетода.Добавить(Сигнатура.Параметры.Количество()); 1028 | КонецЕсли; 1029 | ОписаниеМетода.Добавить(0); // точка входа (см. ТочкиВходаМетодов) 1030 | 1031 | РазделМетодов.Добавить(ОписаниеМетода); 1032 | Индекс = РазделМетодов.ВГраница(); 1033 | 1034 | КэшМетодов[НРег(Имя)] = Индекс; 1035 | 1036 | КонецЕсли; 1037 | 1038 | Возврат Индекс; 1039 | 1040 | КонецФункции 1041 | 1042 | Функция СписокПереходовНаМетку(Имя) 1043 | 1044 | Список = ПереходыНаМетки[НРег(Имя)]; 1045 | 1046 | Если Список = Неопределено Тогда 1047 | Список = Новый Массив; 1048 | ПереходыНаМетки[НРег(Имя)] = Список; 1049 | КонецЕсли; 1050 | 1051 | Возврат Список; 1052 | 1053 | КонецФункции 1054 | 1055 | Функция ВременнаяПеременная(ЭлементОкружения) 1056 | ВременнаяПеременная = КэшВременныхПеременных[ЭлементОкружения]; 1057 | ФиктивноеОбъявление = ЭлементОкружения.Объявление.Владелец().Добавить(); 1058 | ЗаполнитьЗначенияСвойств(ФиктивноеОбъявление, ЭлементОкружения.Объявление); 1059 | Если ВременнаяПеременная = Неопределено Тогда 1060 | ВременнаяПеременная = Новый Структура( 1061 | "Тип," // строка (один из Типы) 1062 | "Имя," // строка 1063 | "Объявление", // неопределено, структура (один из #Объявления) 1064 | Типы.ЭлементОкружения, "0" + ЭлементОкружения.Имя, ФиктивноеОбъявление); 1065 | КэшВременныхПеременных[ЭлементОкружения] = ВременнаяПеременная; 1066 | КонецЕсли; 1067 | Возврат ВременнаяПеременная; 1068 | КонецФункции 1069 | 1070 | Процедура ВыдатьКомандуЗагрузкиПеременной(ЭлементОкружения) 1071 | ИндексПеременной = ВыдатьПеременную(ЭлементОкружения.Имя, ЭлементОкружения.Объявление); 1072 | Объявление = ЭлементОкружения.Объявление; 1073 | Если Объявление = Неопределено Тогда 1074 | Объявление = ФиктивныеОбъявления[НРег(ЭлементОкружения.Имя)]; 1075 | КонецЕсли; 1076 | КомандаЗагрузки = КомандыЗагрузкиПеременных[Объявление]; 1077 | ВыдатьКоманду(КомандаЗагрузки, ИндексПеременной); 1078 | КонецПроцедуры 1079 | 1080 | Функция НайтиВстроеннуюФункцию(Имя, КоличествоПараметров) 1081 | 1082 | Фильтр = Новый Структура; 1083 | Фильтр.Вставить("Имя", НРег(Имя)); 1084 | Фильтр.Вставить("КоличествоПараметров", КоличествоПараметров); 1085 | ИскомыеСтроки = ВстроенныеФункции.НайтиСтроки(Фильтр); 1086 | Если ИскомыеСтроки.Количество() > 0 Тогда 1087 | Возврат ИскомыеСтроки[0].Код; 1088 | КонецЕсли; 1089 | 1090 | Возврат Неопределено; 1091 | 1092 | КонецФункции 1093 | 1094 | Процедура ПередПосещениемЦикла() 1095 | 1096 | СтекПереходовВЦиклах.Добавить(Новый Структура("Прервать, Продолжить", Новый Массив, Новый Массив)); 1097 | 1098 | КонецПроцедуры 1099 | 1100 | Процедура ПослеПосещенияЦикла(ИндексНачала, ИндексКонца) 1101 | 1102 | Переходы = СнятьПоследнееЗначение(СтекПереходовВЦиклах); 1103 | 1104 | Для Каждого ИндексПерехода Из Переходы.Продолжить Цикл 1105 | ВставитьКоманду(ИндексПерехода, Команды.Jmp, ИндексНачала); 1106 | КонецЦикла; 1107 | 1108 | Для Каждого ИндексПерехода Из Переходы.Прервать Цикл 1109 | ВставитьКоманду(ИндексПерехода, Команды.Jmp, ИндексКонца); 1110 | КонецЦикла; 1111 | 1112 | КонецПроцедуры 1113 | 1114 | Функция СнятьПоследнееЗначение(Стек) 1115 | 1116 | ИндексВершиныСтека = Стек.ВГраница(); 1117 | Значение = Стек[ИндексВершиныСтека]; 1118 | Стек.Удалить(ИндексВершиныСтека); 1119 | 1120 | Возврат Значение; 1121 | 1122 | КонецФункции 1123 | 1124 | Функция ВзятьПоследнееЗначение(Стек) 1125 | 1126 | Возврат Стек[Стек.ВГраница()]; 1127 | 1128 | КонецФункции 1129 | 1130 | Процедура ВставитьПереходыНаМетки() 1131 | Для Каждого ПереходыНаМетку Из ПереходыНаМетки Цикл 1132 | ИндексМетки = Метки[ПереходыНаМетку.Ключ].ИндексМетки; 1133 | Для Каждого ИндексПерехода Из ПереходыНаМетку.Значение Цикл 1134 | ВставитьКоманду(ИндексПерехода, Команды.Goto, ИндексМетки); 1135 | КонецЦикла; 1136 | КонецЦикла; 1137 | ПереходыНаМетки.Очистить(); 1138 | Метки.Очистить(); 1139 | КонецПроцедуры 1140 | 1141 | Процедура ДобавитьВстроеннуюФункцию(ИмяНаРусском, ИмяНаАнглийском, КоличествоПараметров, Код) 1142 | 1143 | НоваяСтрока = ВстроенныеФункции.Добавить(); 1144 | НоваяСтрока.Имя = Нрег(ИмяНаРусском); 1145 | НоваяСтрока.КоличествоПараметров = КоличествоПараметров; 1146 | НоваяСтрока.Код = Код; 1147 | 1148 | НоваяСтрока = ВстроенныеФункции.Добавить(); 1149 | НоваяСтрока.Имя = Нрег(ИмяНаАнглийском); 1150 | НоваяСтрока.КоличествоПараметров = КоличествоПараметров; 1151 | НоваяСтрока.Код = Код; 1152 | 1153 | КонецПроцедуры 1154 | 1155 | #КонецОбласти // СлужебныеМетоды 1156 | 1157 | РазделКоманд = Новый Массив; 1158 | РазделКонстант = Новый Массив; 1159 | РазделПеременных = Новый Массив; 1160 | РазделМетодов = Новый Массив; 1161 | РазделПеременныхМетода = Новый Массив; 1162 | 1163 | ПеременныеМетодов = Новый Структура; 1164 | ЗначенияПараметровМетодовПоУмолчанию = Новый Структура; 1165 | 1166 | КомандыЗагрузкиПеременных = Новый Соответствие; 1167 | КомандыБинарныхОпераций = Новый Соответствие; 1168 | 1169 | КэшКонстант = Новый Соответствие; 1170 | КэшПеременных = Новый Соответствие; 1171 | КэшМетодов = Новый Соответствие; 1172 | КэшВременныхПеременных = Новый Соответствие; 1173 | Возвраты = Новый Массив; 1174 | Метки = Новый Соответствие; 1175 | ПереходыНаМетки = Новый Соответствие; 1176 | ПереходыНаКонецМодуля = Новый Массив; 1177 | 1178 | ФиктивныеОбъявления = Новый Соответствие; 1179 | 1180 | СтекПереходовВЦиклах = Новый Массив; 1181 | 1182 | ЭтоТелоМодуля = Ложь; 1183 | 1184 | ФлагиПеременных = Новый Структура; 1185 | ФлагиПеременных.Вставить("Локальная", 1); 1186 | ФлагиПеременных.Вставить("Глобальная", 2); 1187 | ФлагиПеременных.Вставить("Параметр", 4); 1188 | ФлагиПеременных.Вставить("Знач", 8); 1189 | ФлагиПеременных.Вставить("Экспорт", 16); 1190 | 1191 | ФлагиМетодов = Новый Структура; 1192 | ФлагиМетодов.Вставить("Функция", 1); 1193 | ФлагиМетодов.Вставить("Экспорт", 16); 1194 | ФлагиМетодов.Вставить("Глобальный", 32); 1195 | 1196 | ТочкаВходаМодуля = 0; 1197 | ТочкиВходаМетодов = Новый Структура; 1198 | 1199 | Команды = Новый Структура; 1200 | Команды.Вставить("Nop", 0); 1201 | Команды.Вставить("LineNum", 1); 1202 | Команды.Вставить("LdVar", 2); 1203 | Команды.Вставить("LdLoc", 3); 1204 | Команды.Вставить("LdConst", 4); 1205 | Команды.Вставить("LdRet", 5); 1206 | Команды.Вставить("LdFalse", 6); 1207 | Команды.Вставить("LdTrue", 7); 1208 | Команды.Вставить("LdUndef", 8); 1209 | Команды.Вставить("LdNull", 9); 1210 | Команды.Вставить("LdNone", 10); 1211 | Команды.Вставить("Unknown", 11); 1212 | Команды.Вставить("LdProp", 12); 1213 | Команды.Вставить("LdIndex", 13); 1214 | Команды.Вставить("Iter", 14); 1215 | Команды.Вставить("Next", 15); 1216 | Команды.Вставить("Assign", 16); 1217 | Команды.Вставить("Ret", 17); 1218 | Команды.Вставить("ArgNum", 18); 1219 | Команды.Вставить("CallLoc", 19); 1220 | Команды.Вставить("CallProc", 20); 1221 | Команды.Вставить("CallFunc", 21); 1222 | Команды.Вставить("End", 22); 1223 | Команды.Вставить("Minus", 23); 1224 | Команды.Вставить("Add", 24); 1225 | Команды.Вставить("Sub", 25); 1226 | Команды.Вставить("Mul", 26); 1227 | Команды.Вставить("Div", 27); 1228 | Команды.Вставить("Mod", 28); 1229 | Команды.Вставить("Not", 29); 1230 | Команды.Вставить("And", 30); 1231 | Команды.Вставить("Or", 31); 1232 | Команды.Вставить("Unused", 32); 1233 | Команды.Вставить("Cmp", 33); 1234 | Команды.Вставить("Ne", 34); 1235 | Команды.Вставить("Gt", 35); 1236 | Команды.Вставить("Lt", 36); 1237 | Команды.Вставить("Gte", 37); 1238 | Команды.Вставить("Lte", 38); 1239 | Команды.Вставить("Jmp", 39); 1240 | Команды.Вставить("JmpFalse", 40); 1241 | Команды.Вставить("JmpTrue", 41); 1242 | Команды.Вставить("Goto", 42); 1243 | Команды.Вставить("Inc", 43); 1244 | Команды.Вставить("BeginTry", 44); 1245 | Команды.Вставить("BlckEnd", 45); 1246 | Команды.Вставить("EndTry", 46); 1247 | Команды.Вставить("Raise", 47); 1248 | Команды.Вставить("PutTmp", 48); 1249 | Команды.Вставить("LdTmp", 49); 1250 | Команды.Вставить("PopTmp", 50); 1251 | Команды.Вставить("New", 51); 1252 | Команды.Вставить("Exec", 52); 1253 | Команды.Вставить("Boolean", 69); // так же есть во встроенных функциях 1254 | Команды.Вставить("ДобавитьОбработчикЛокальный", 123); 1255 | Команды.Вставить("ДобавитьОбработчик", 124); 1256 | Команды.Вставить("УдалитьОбработчикЛокальный", 125); 1257 | Команды.Вставить("УдалитьОбработчик", 126); 1258 | 1259 | ВстроенныеФункции = Новый ТаблицаЗначений; 1260 | ВстроенныеФункции.Колонки.Добавить("Имя"); 1261 | ВстроенныеФункции.Колонки.Добавить("КоличествоПараметров"); 1262 | ВстроенныеФункции.Колонки.Добавить("Код"); 1263 | ВстроенныеФункции.Индексы.Добавить("Имя, КоличествоПараметров"); 1264 | 1265 | ДобавитьВстроеннуюФункцию("СтрДлина", "StrLen", 1, 53); 1266 | ДобавитьВстроеннуюФункцию("СокрЛ", "TrimL", 1, 54); 1267 | ДобавитьВстроеннуюФункцию("СокрП", "TrimR", 1, 55); 1268 | ДобавитьВстроеннуюФункцию("СокрЛП", "TrimAll", 1, 56); 1269 | ДобавитьВстроеннуюФункцию("Лев", "Left", 2, 57); 1270 | ДобавитьВстроеннуюФункцию("Прав", "Right", 2, 58); 1271 | ДобавитьВстроеннуюФункцию("Сред", "Mid", 3, 59); 1272 | ДобавитьВстроеннуюФункцию("Найти", "Find", 2, 60); 1273 | ДобавитьВстроеннуюФункцию("Врег", "Upper", 1, 61); 1274 | ДобавитьВстроеннуюФункцию("Нрег", "Lower", 1, 62); 1275 | ДобавитьВстроеннуюФункцию("Символ", "Char", 1, 63); 1276 | ДобавитьВстроеннуюФункцию("КодСимвола", "CharCode", 2, 64); 1277 | ДобавитьВстроеннуюФункцию("ПустаяСтрока", "IsBlankString", 1, 65); 1278 | ДобавитьВстроеннуюФункцию("Цел", "Int", 1, 66); 1279 | ДобавитьВстроеннуюФункцию("Окр", "Round", 2, 67); 1280 | ДобавитьВстроеннуюФункцию("Окр", "Round", 3, 68); 1281 | ДобавитьВстроеннуюФункцию("Булево", "Boolean", 1, 69); 1282 | ДобавитьВстроеннуюФункцию("Число", "Number", 1, 70); 1283 | ДобавитьВстроеннуюФункцию("Строка", "String", 1, 71); 1284 | ДобавитьВстроеннуюФункцию("Дата", "Date", 1, 72); 1285 | ДобавитьВстроеннуюФункцию("Дата", "Date", 3, 73); 1286 | ДобавитьВстроеннуюФункцию("Дата", "Date", 6, 74); 1287 | ДобавитьВстроеннуюФункцию("ДобавитьМесяц", "AddMonth", 2, 75); 1288 | ДобавитьВстроеннуюФункцию("НачалоМесяца", "BegOfMonth", 1, 76); 1289 | ДобавитьВстроеннуюФункцию("КонецМесяца", "EndOfMonth", 1, 77); 1290 | ДобавитьВстроеннуюФункцию("НачалоКвартала", "BegOfQuarter", 1, 78); 1291 | ДобавитьВстроеннуюФункцию("КонецКвартала", "EndOfQuarter", 1, 79); 1292 | ДобавитьВстроеннуюФункцию("НачалоГода", "BegOfYear", 1, 80); 1293 | ДобавитьВстроеннуюФункцию("КонецГода", "EndOfYear", 1, 81); 1294 | ДобавитьВстроеннуюФункцию("Год", "Year", 1, 82); 1295 | ДобавитьВстроеннуюФункцию("Месяц", "Month", 1, 83); 1296 | ДобавитьВстроеннуюФункцию("День", "Day", 1, 84); 1297 | ДобавитьВстроеннуюФункцию("Час", "Hour", 1, 85); 1298 | ДобавитьВстроеннуюФункцию("Минута", "Minute", 1, 86); 1299 | ДобавитьВстроеннуюФункцию("Секунда", "Second", 1, 87); 1300 | ДобавитьВстроеннуюФункцию("ДеньГода", "DayOfYear", 1, 88); 1301 | ДобавитьВстроеннуюФункцию("НеделяГода", "WeekOfYear", 1, 89); 1302 | ДобавитьВстроеннуюФункцию("ДеньНедели", "WeekDay", 1, 90); 1303 | ДобавитьВстроеннуюФункцию("НачалоНедели", "BegOfWeek", 1, 91); 1304 | ДобавитьВстроеннуюФункцию("КонецНедели", "EndOfWeek", 1, 92); 1305 | ДобавитьВстроеннуюФункцию("НачалоДня", "BegOfDay", 1, 93); 1306 | ДобавитьВстроеннуюФункцию("КонецДня", "EndOfDay", 1, 94); 1307 | ДобавитьВстроеннуюФункцию("НачалоЧаса", "BegOfHour", 1, 95); 1308 | ДобавитьВстроеннуюФункцию("КонецЧаса", "EndOfHour", 1, 96); 1309 | ДобавитьВстроеннуюФункцию("НачалоМинуты", "BegOfMinute", 1, 97); 1310 | ДобавитьВстроеннуюФункцию("КонецМинуты", "EndOfMinute", 1, 98); 1311 | ДобавитьВстроеннуюФункцию("ТекущаяДата", "CurrentDate", 0, 99); 1312 | ДобавитьВстроеннуюФункцию("СтрЗаменить", "StrReplace", 3, 100); 1313 | ДобавитьВстроеннуюФункцию("СтрЧислоСтрок", "StrLineCount", 1, 101); 1314 | ДобавитьВстроеннуюФункцию("СтрПолучитьСтроку", "StrGetLine", 2, 102); 1315 | ДобавитьВстроеннуюФункцию("Мин", "Min", Неопределено, 103); // см. ПосетитьВыражениеИдентификатор() 1316 | ДобавитьВстроеннуюФункцию("Макс", "Max", Неопределено, 104); // см. ПосетитьВыражениеИдентификатор() 1317 | ДобавитьВстроеннуюФункцию("СтрЧислоВхождений", "StrOccurrenceCount", 2, 105); 1318 | ДобавитьВстроеннуюФункцию("ОписаниеОшибки", "ErrorDescription", 0, 106); 1319 | ДобавитьВстроеннуюФункцию("ТипЗнч", "TypeOf", 1, 107); 1320 | ДобавитьВстроеннуюФункцию("Тип", "Type", 1, 108); 1321 | ДобавитьВстроеннуюФункцию("Вычислить", "Eval", 1, 109); 1322 | ДобавитьВстроеннуюФункцию("Формат", "Format", 2, 110); 1323 | ДобавитьВстроеннуюФункцию("Новый", "New", 2, 111); 1324 | ДобавитьВстроеннуюФункцию("ACos", "ACos", 1, 112); 1325 | ДобавитьВстроеннуюФункцию("ASin", "ASin", 1, 113); 1326 | ДобавитьВстроеннуюФункцию("ATan", "ATan", 1, 114); 1327 | ДобавитьВстроеннуюФункцию("Cos", "Cos", 1, 115); 1328 | ДобавитьВстроеннуюФункцию("Exp", "Exp", 1, 116); 1329 | ДобавитьВстроеннуюФункцию("Log", "Log", 1, 117); 1330 | ДобавитьВстроеннуюФункцию("Log10", "Log10", 1, 118); 1331 | ДобавитьВстроеннуюФункцию("Pow", "Pow", 2, 119); 1332 | ДобавитьВстроеннуюФункцию("Sin", "Sin", 1, 120); 1333 | ДобавитьВстроеннуюФункцию("Sqrt", "Sqrt", 1, 121); 1334 | ДобавитьВстроеннуюФункцию("Tan", "Tan", 1, 122); 1335 | ДобавитьВстроеннуюФункцию("ТРег", "ТРег", 1, 127); 1336 | ДобавитьВстроеннуюФункцию("ИнформацияОбОшибке", "ErrorInfo", 0, 128); 1337 | -------------------------------------------------------------------------------- /examples/multiprocessing.ps1: -------------------------------------------------------------------------------- 1 | # пример многопоточного анализа для onescript 2 | # каждый поток пишет результат работы плагинов в файлы report_<номер потока>.txt 3 | 4 | # папка с выгрузкой конфигурации в файлы 5 | $path = "C:\temp\SSL" 6 | 7 | $files = Get-ChildItem -Path $path -File -Recurse -ErrorAction SilentlyContinue -Filter *.bsl | Select-Object -ExpandProperty FullName 8 | $chunk_size = 100 9 | $chunks = for($i = 0; $i -lt $files.length; $i += $chunk_size){, $files[$i..($i+$chunk_size-1)]} 10 | $threads = 6 11 | 12 | for ($i = 0; $i -lt $threads; $i++) { 13 | New-Item "report_$i.txt" -Force | Out-Null 14 | } 15 | 16 | $jobs = @($null) * $threads 17 | $chunk_i = 0 18 | 19 | while ($chunk_i -lt $chunks.Length) { 20 | 21 | for ($job_i = 0; $job_i -lt $threads; $job_i++) { 22 | $job = $jobs[$job_i] 23 | if ($null -eq $job -or $job.JobStateInfo.State -ne "Running") { 24 | if ($null -ne $job) { 25 | $result = Receive-Job -Job $job -AutoRemoveJob -Wait 26 | # Write-Host $job_i, $result 27 | } 28 | Write-Progress -Activity "Анализ в $threads потоков" -Status "Прогресс:" -PercentComplete ($chunk_i / $chunks.Length * 100) 29 | $job = Start-Job -ScriptBlock { 30 | Param([string]$workdir, [string]$script, [string]$file, [string]$report) 31 | Set-Location $workdir 32 | oscript.exe $script $file $report 33 | } -ArgumentList (Get-Location), ".\test4.os", ($chunks[$chunk_i++] -join ";"), "report_$job_i.txt" 34 | $jobs[$job_i] = $job 35 | } 36 | } 37 | 38 | Start-Sleep -Milliseconds 100 39 | 40 | } -------------------------------------------------------------------------------- /examples/param.json: -------------------------------------------------------------------------------- 1 | { 2 | "МойПараметр": "Это параметр плагина" 3 | } -------------------------------------------------------------------------------- /examples/plugins/Классы/Визажист.os: -------------------------------------------------------------------------------- 1 |  2 | Перем Токены; 3 | Перем Исходник; 4 | Перем ТаблицаТокенов; 5 | Перем КлючевыеСлова; 6 | 7 | Перем Результат; 8 | 9 | Процедура Открыть(Парсер, Параметры) Экспорт 10 | Токены = Парсер.Токены(); 11 | Исходник = Парсер.Исходник(); 12 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 13 | КлючевыеСлова = Парсер.КлючевыеСлова(); 14 | Результат.Очистить(); 15 | КонецПроцедуры // Открыть() 16 | 17 | Функция Закрыть() Экспорт 18 | 19 | Результат.Добавить( 20 | " 21 | | 22 | | 23 | | 24 | | Исходник 25 | | 79 | | 80 | | 81 | |
82 | | " 83 | ); 84 | 85 | КоличествоТокенов = ТаблицаТокенов.Количество(); 86 | 87 | КоличествоСтрок = ТаблицаТокенов[ТаблицаТокенов.Количество()-2].НомерСтроки; 88 | 89 | Индекс = 1; 90 | 91 | Позиция = 1; 92 | 93 | Для НомерСтроки = 1 По КоличествоСтрок Цикл 94 | 95 | Результат.Добавить(СтрШаблон("" 96 | " 97 | | 98 | | " 151 | " " 152 | ); 153 | 154 | КонецЦикла; 155 | 156 | Результат.Добавить("" 157 | "
%1", 99 | Формат(НомерСтроки, "ЧГ=") 100 | )); 101 | 102 | Пока Индекс < КоличествоТокенов 103 | И ТаблицаТокенов[Индекс].НомерСтроки <= НомерСтроки Цикл 104 | 105 | Токен = ТаблицаТокенов[Индекс]; 106 | 107 | Промежуток = Токен.Позиция - Позиция; 108 | Если Промежуток > 0 Тогда 109 | Пробелы = Сред(Исходник, Позиция, Промежуток); 110 | ПозицияНачалаСтроки = СтрНайти(Пробелы, Символы.ПС, НаправлениеПоиска.СКонца); 111 | Если ПозицияНачалаСтроки > 0 Тогда 112 | Позиция = Позиция + ПозицияНачалаСтроки; 113 | Промежуток = Токен.Позиция - Позиция; 114 | КонецЕсли; 115 | Если Промежуток > 0 Тогда 116 | Если ПустаяСтрока(Пробелы) Тогда 117 | Добавить(Позиция, Промежуток); 118 | Иначе 119 | Добавить(Позиция, Промежуток, "comment"); 120 | КонецЕсли; 121 | КонецЕсли; 122 | КонецЕсли; 123 | Позиция = Токен.Позиция + Токен.Длина; 124 | 125 | Если КлючевыеСлова.Свойство(Токен.Токен) И ТаблицаТокенов[Индекс - 1].Токен <> Токены.Точка Тогда 126 | Добавить(Токен.Позиция, Токен.Длина, "keyword"); 127 | ИначеЕсли Токен.Токен = Токены.Комментарий Тогда 128 | Добавить(Токен.Позиция, Токен.Длина, "comment"); 129 | ИначеЕсли Токен.Токен = Токены.Строка 130 | Или Токен.Токен = Токены.НачалоСтроки 131 | Или Токен.Токен = Токены.ПродолжениеСтроки 132 | Или Токен.Токен = Токены.ОкончаниеСтроки Тогда 133 | Добавить(Токен.Позиция, Токен.Длина, "string"); 134 | ИначеЕсли Токен.Токен = Токены.Точка 135 | Или Токен.Токен = Токены.Запятая 136 | Или Токен.Токен = Токены.ТочкаСЗапятой 137 | Или Токен.Токен = Токены.ЛеваяКруглаяСкобка 138 | Или Токен.Токен = Токены.ПраваяКруглаяСкобка 139 | Или Токен.Токен = Токены.ЛеваяКвадратнаяСкобка 140 | Или Токен.Токен = Токены.ПраваяКвадратнаяСкобка Тогда 141 | Добавить(Токен.Позиция, Токен.Длина, "special"); 142 | Иначе 143 | Добавить(Токен.Позиция, Токен.Длина); 144 | КонецЕсли; 145 | 146 | Индекс = Индекс + 1; 147 | 148 | КонецЦикла; 149 | 150 | Результат.Добавить("
158 | |
159 | |" 160 | ); 161 | 162 | Возврат СтрСоединить(Результат); 163 | КонецФункции // Закрыть() 164 | 165 | Функция Добавить(Знач Начало, Знач Длина, Класс = Неопределено) 166 | Текст = БезопасныйHTML(Сред(Исходник, Начало, Длина)); 167 | Если Класс <> Неопределено Тогда 168 | Результат.Добавить(СтрШаблон("%2", Класс, Текст)); 169 | Иначе 170 | Результат.Добавить(Текст); 171 | КонецЕсли; 172 | КонецФункции 173 | 174 | Функция БезопасныйHTML(Текст) 175 | 176 | // нельзя так заменять 177 | // надо за один проход 178 | 179 | //Текст = СтрЗаменить(Текст, """, "&quot;"); 180 | //Текст = СтрЗаменить(Текст, "&", "&amp;"); 181 | //Текст = СтрЗаменить(Текст, "<", "&lt;"); 182 | //Текст = СтрЗаменить(Текст, ">", "&gt;"); 183 | Текст = СтрЗаменить(Текст, "<", "<"); 184 | Текст = СтрЗаменить(Текст, ">", ">"); 185 | Текст = СтрЗаменить(Текст, """", """); 186 | 187 | Возврат Текст; 188 | 189 | КонецФункции 190 | 191 | Функция Подписки() Экспорт 192 | Перем Подписки; 193 | Подписки = Новый Массив; 194 | Возврат Подписки; 195 | КонецФункции // Подписки() 196 | 197 | Результат = Новый Массив; -------------------------------------------------------------------------------- /examples/plugins/Классы/ДетекторВложенныхТернарныхОператоров.os: -------------------------------------------------------------------------------- 1 |  2 | // Пример использования стека 3 | 4 | Перем Типы; 5 | Перем ТаблицаОшибок; 6 | Перем Стек; 7 | 8 | Процедура Открыть(Парсер, Параметры) Экспорт 9 | Типы = Парсер.Типы(); 10 | Стек = Парсер.Стек(); 11 | ТаблицаОшибок = Парсер.ТаблицаОшибок(); 12 | КонецПроцедуры // Открыть() 13 | 14 | Функция Закрыть() Экспорт 15 | Возврат Неопределено; 16 | КонецФункции // Закрыть() 17 | 18 | Функция Подписки() Экспорт 19 | Перем Подписки; 20 | Подписки = Новый Массив; 21 | Подписки.Добавить("ПосетитьВыражениеТернарное"); 22 | Возврат Подписки; 23 | КонецФункции // Подписки() 24 | 25 | #Область РеализацияПодписок 26 | 27 | Процедура ПосетитьВыражениеТернарное(ВыражениеТернарное) Экспорт 28 | Для Каждого Родитель Из Стек Цикл 29 | Если Родитель.Тип = Типы.ВыражениеТернарное Тогда 30 | Ошибка("Вложенный тернарный оператор", ВыражениеТернарное.Начало, ВыражениеТернарное.Конец); 31 | Прервать; 32 | КонецЕсли; 33 | КонецЦикла; 34 | КонецПроцедуры // ПосетитьВыражениеТернарное() 35 | 36 | #КонецОбласти // РеализацияПодписок 37 | 38 | Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) 39 | Ошибка = ТаблицаОшибок.Добавить(); 40 | Ошибка.Источник = "ДетекторВложенныхТернарныхОператоров"; 41 | Ошибка.Текст = Текст; 42 | Ошибка.ПозицияНачала = Начало.Позиция; 43 | Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; 44 | Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; 45 | Если Конец = Неопределено Или Конец = Начало Тогда 46 | Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; 47 | Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; 48 | Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; 49 | Иначе 50 | Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; 51 | Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; 52 | Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; 53 | КонецЕсли; 54 | Ошибка.ЕстьЗамена = ЕстьЗамена; 55 | КонецПроцедуры 56 | -------------------------------------------------------------------------------- /examples/plugins/Классы/ДетекторКонструкторовСтруктур.os: -------------------------------------------------------------------------------- 1 |  2 | // Пример диагностики, которая не только находит ошибку, но и предлагает замену (автоматическое исправление). 3 | // Плагин обнаруживает использование конструкторов структур, регистрирует ошибку и замену в виде вставки ключей. 4 | // Пример: 5 | // Сотрудник = Новый Структура("Имя, Фамилия", "Иван"); 6 | // будет заменено на: 7 | // Сотрудник = Новый Структура; 8 | // Сотрудник.Вставить("Имя", "Иван"); 9 | // Сотрудник.Вставить("Фамилия", Неопределено); 10 | 11 | Перем Токены; 12 | Перем Типы; 13 | Перем ТаблицаТокенов; 14 | Перем Исходник; 15 | Перем ТаблицаОшибок; 16 | Перем ТаблицаЗамен; 17 | Перем Стек; 18 | 19 | Перем ФрагментыПоИменам; 20 | 21 | Процедура Открыть(Парсер, Параметры) Экспорт 22 | 23 | Токены = Парсер.Токены(); 24 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 25 | Исходник = Парсер.Исходник(); 26 | Типы = Парсер.Типы(); 27 | ТаблицаОшибок = Парсер.ТаблицаОшибок(); 28 | ТаблицаЗамен = Парсер.ТаблицаЗамен(); 29 | Стек = Парсер.Стек(); 30 | 31 | ФрагментыПоИменам = Новый Структура; 32 | 33 | ФрагментыНаРусском = Новый Структура; 34 | ФрагментыНаРусском.Вставить("Фрагмент1", "Новый Структура;"); 35 | ФрагментыНаРусском.Вставить("Фрагмент2", ".Вставить(""%1"", "); 36 | ФрагментыНаРусском.Вставить("Фрагмент3", "Неопределено"); 37 | 38 | ФрагментыПоИменам.Вставить("Структура", ФрагментыНаРусском); 39 | 40 | ФрагментыНаАнглийском = Новый Структура; 41 | ФрагментыНаАнглийском.Вставить("Фрагмент1", "New Structure;"); 42 | ФрагментыНаАнглийском.Вставить("Фрагмент2", ".Insert(""%1"", "); 43 | ФрагментыНаАнглийском.Вставить("Фрагмент3", "Undefined"); 44 | 45 | ФрагментыПоИменам.Вставить("Structure", ФрагментыНаАнглийском); 46 | 47 | КонецПроцедуры // Открыть() 48 | 49 | Функция Закрыть() Экспорт 50 | 51 | Возврат Неопределено; 52 | 53 | КонецФункции // Закрыть() 54 | 55 | Функция Подписки() Экспорт 56 | Перем Подписки; 57 | Подписки = Новый Массив; 58 | Подписки.Добавить("ПосетитьВыражениеНовый"); 59 | Возврат Подписки; 60 | КонецФункции // Подписки() 61 | 62 | #Область РеализацияПодписок 63 | 64 | Процедура ПосетитьВыражениеНовый(ВыражениеНовый) Экспорт 65 | 66 | Фрагменты = Неопределено; 67 | 68 | Если ВыражениеНовый.Аргументы = Неопределено 69 | Или ВыражениеНовый.Аргументы.Количество() = 0 70 | Или Не ФрагментыПоИменам.Свойство(ВыражениеНовый.Имя, Фрагменты) Тогда 71 | Возврат; // Либо аргументов конструктора нет, либо это не структура 72 | КонецЕсли; 73 | 74 | ТекстОшибки = "Не рекомендуется использовать конструктор структур."; 75 | 76 | ПервыйАргумент = ВыражениеНовый.Аргументы[0]; 77 | 78 | Если ПервыйАргумент.Тип <> Типы.ВыражениеСтроковое Тогда 79 | Ошибка(ТекстОшибки, ВыражениеНовый.Начало, ВыражениеНовый.Конец); 80 | Возврат; // Замены выполняются только для ключей заданных строкой 81 | КонецЕсли; 82 | 83 | Родитель = Стек[Стек.ВГраница()]; 84 | 85 | Если Родитель.Тип <> Типы.ОператорПрисваивания Тогда 86 | Ошибка(ТекстОшибки, ВыражениеНовый.Начало, ВыражениеНовый.Конец); 87 | Возврат; // Замены выполняются только для присваиваний 88 | КонецЕсли; 89 | 90 | Идентификатор = Родитель.ЛевыйОперанд; 91 | 92 | Если Идентификатор.Аргументы <> Неопределено 93 | Или Идентификатор.Хвост.Количество() <> 0 Тогда 94 | Ошибка(ТекстОшибки, ВыражениеНовый.Начало, ВыражениеНовый.Конец); 95 | Возврат; // Замены выполняются только для простых переменных 96 | КонецЕсли; 97 | 98 | ПервыйТокенИдентификатора = Идентификатор.Начало; 99 | ДлинаОтступа = ПервыйТокенИдентификатора.НомерКолонки - 1; 100 | Отступ = Сред(Исходник, ПервыйТокенИдентификатора.Позиция - ДлинаОтступа, ДлинаОтступа); 101 | 102 | Если Не ПустаяСтрока(Отступ) Тогда 103 | Ошибка(ТекстОшибки, ВыражениеНовый.Начало, ВыражениеНовый.Конец); 104 | Возврат; // Что-то есть перед переменной в строке. Замена невозможна 105 | КонецЕсли; 106 | 107 | СписокКлючей = Новый Массив; 108 | 109 | Для Каждого Элемент Из ПервыйАргумент.Элементы Цикл 110 | СписокКлючей.Добавить(Элемент.Значение); 111 | КонецЦикла; 112 | 113 | Попытка 114 | Ключи = СтрРазделить(СтрСоединить(СписокКлючей), ",", Ложь); 115 | Исключение 116 | Ошибка(ТекстОшибки, ВыражениеНовый.Начало, ВыражениеНовый.Конец); 117 | Возврат; // Что-то пошло не так. Замена невозможна 118 | КонецПопытки; 119 | 120 | Буфер = Новый Массив; 121 | 122 | КоличествоЗначений = ВыражениеНовый.Аргументы.Количество() - 1; 123 | 124 | Буфер.Добавить(Фрагменты.Фрагмент1); 125 | 126 | Для Индекс = 0 По Ключи.Количество() - 1 Цикл 127 | 128 | Ключ = СокрЛП(Ключи[Индекс]); 129 | 130 | Буфер.Добавить(Символы.ПС); 131 | Буфер.Добавить(Отступ); 132 | Буфер.Добавить(УчастокТекста(Исходник, Идентификатор.Начало, Идентификатор.Конец)); 133 | Буфер.Добавить(СтрШаблон(Фрагменты.Фрагмент2, Ключ)); 134 | 135 | Если Индекс < КоличествоЗначений И ВыражениеНовый.Аргументы[Индекс + 1] <> Неопределено Тогда 136 | Аргумент = ВыражениеНовый.Аргументы[Индекс + 1]; 137 | Буфер.Добавить(УчастокТекста(Исходник, Аргумент.Начало, Аргумент.Конец)); 138 | Иначе 139 | Буфер.Добавить(Фрагменты.Фрагмент3); 140 | КонецЕсли; 141 | 142 | Буфер.Добавить(");"); 143 | 144 | КонецЦикла; 145 | 146 | Текст = СтрСоединить(Буфер); 147 | 148 | ПервыйТокен = ВыражениеНовый.Начало; 149 | ПоследнийТокен = ВыражениеНовый.Конец; 150 | СледующийТокен = ТаблицаТокенов[ВыражениеНовый.Конец.Индекс + 1]; 151 | 152 | Если СледующийТокен.Токен = Токены.ТочкаСЗапятой Тогда 153 | ПоследнийТокен = СледующийТокен; 154 | КонецЕсли; 155 | 156 | Ошибка(ТекстОшибки, ПервыйТокен, ПоследнийТокен, Истина); 157 | Замена(Текст, ПервыйТокен, ПоследнийТокен); 158 | 159 | КонецПроцедуры 160 | 161 | #КонецОбласти 162 | 163 | #Область ВспомогательныеМетоды 164 | 165 | Функция УчастокТекста(Текст, Начало, Конец) 166 | Возврат Сред(Текст, Начало.Позиция, Конец.Позиция + Конец.Длина - Начало.Позиция); 167 | КонецФункции 168 | 169 | Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) 170 | Ошибка = ТаблицаОшибок.Добавить(); 171 | Ошибка.Источник = "ДетекторКонструкторовСтруктур"; 172 | Ошибка.Текст = Текст; 173 | Ошибка.ПозицияНачала = Начало.Позиция; 174 | Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; 175 | Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; 176 | Если Конец = Неопределено Или Конец = Начало Тогда 177 | Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; 178 | Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; 179 | Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; 180 | Иначе 181 | Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; 182 | Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; 183 | Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; 184 | КонецЕсли; 185 | Ошибка.ЕстьЗамена = ЕстьЗамена; 186 | КонецПроцедуры 187 | 188 | Процедура Замена(Текст, Начало, Конец = Неопределено) 189 | НоваяЗамена = ТаблицаЗамен.Добавить(); 190 | НоваяЗамена.Источник = "ДетекторКонструкторовСтруктур"; 191 | НоваяЗамена.Текст = Текст; 192 | НоваяЗамена.Позиция = Начало.Позиция; 193 | Если Конец = Неопределено Тогда 194 | НоваяЗамена.Длина = Начало.Длина; 195 | Иначе 196 | НоваяЗамена.Длина = Конец.Позиция + Конец.Длина - Начало.Позиция; 197 | КонецЕсли; 198 | КонецПроцедуры 199 | 200 | #КонецОбласти 201 | -------------------------------------------------------------------------------- /examples/plugins/Классы/ДетекторНеиспользуемыхПеременных.os: -------------------------------------------------------------------------------- 1 |  2 | // Плагин для проверки использования переменных и параметров. 3 | // Отслеживаются следующие ситуации: 4 | // - значение переменной не читается после присваивания (объявление тоже считается присваиванием) 5 | // - значение параметра-значения не читается после присваивания 6 | // - к параметру-ссылке нет обращений 7 | // 8 | // примечания: 9 | // Анализ в целом выполняется поверхностно и возможны ложные срабатывания. 10 | 11 | // todo: проверять два присваивания одной переменной подряд 12 | 13 | Перем Типы; 14 | Перем Счетчики; 15 | Перем ТаблицаОшибок; 16 | Перем ТаблицаТокенов; 17 | Перем Результат; 18 | 19 | Перем Переменные, Параметры, ЛевыйОперандПрисваивания, Места; 20 | 21 | Процедура Открыть(Парсер, Параметры) Экспорт 22 | Типы = Парсер.Типы(); 23 | Счетчики = Парсер.Счетчики(); 24 | ТаблицаОшибок = Парсер.ТаблицаОшибок(); 25 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 26 | Результат = Новый Массив; 27 | Переменные = Новый Соответствие; 28 | Параметры = Новый Соответствие; 29 | Места = Новый Соответствие; 30 | КонецПроцедуры // Открыть() 31 | 32 | Функция Закрыть() Экспорт 33 | Возврат СтрСоединить(Результат, Символы.ПС); 34 | КонецФункции // Закрыть() 35 | 36 | Функция Подписки() Экспорт 37 | Перем Подписки; 38 | Подписки = Новый Массив; 39 | Подписки.Добавить("ПосетитьОператорПрисваивания"); 40 | Подписки.Добавить("ПокинутьОператорПрисваивания"); 41 | Подписки.Добавить("ПосетитьВыражениеИдентификатор"); 42 | Подписки.Добавить("ПосетитьОбъявлениеМетода"); 43 | Подписки.Добавить("ПокинутьОбъявлениеМетода"); 44 | Возврат Подписки; 45 | КонецФункции // Подписки() 46 | 47 | Процедура ПосетитьОператорПрисваивания(ОператорПрисваивания) Экспорт 48 | ЛевыйОперандПрисваивания = ОператорПрисваивания.ЛевыйОперанд; 49 | КонецПроцедуры // ПосетитьОператорПрисваивания() 50 | 51 | Процедура ПокинутьОператорПрисваивания(ОператорПрисваивания) Экспорт 52 | Перем Объявление, Операция; 53 | Если ОператорПрисваивания.ЛевыйОперанд.Аргументы <> Неопределено Или ОператорПрисваивания.ЛевыйОперанд.Хвост.Count() > 0 Тогда 54 | Возврат ; 55 | КонецЕсли; 56 | Объявление = ОператорПрисваивания.ЛевыйОперанд.Голова.Объявление; 57 | Места[Объявление] = ОператорПрисваивания.Начало; 58 | ЛевыйОперандПрисваивания = Неопределено; 59 | Операция = Переменные[Объявление]; 60 | Если Операция <> Неопределено Тогда 61 | Если Операция <> "ЧтениеВЦикле" Или УровеньЦикла(Счетчики) = 0 Тогда 62 | Переменные[Объявление] = "Изменение"; 63 | КонецЕсли; 64 | Иначе 65 | Операция = Параметры[Объявление]; 66 | Если Операция <> Неопределено Тогда 67 | Если Операция <> "ЧтениеВЦикле" Или УровеньЦикла(Счетчики) = 0 Тогда 68 | Параметры[Объявление] = "Изменение"; 69 | КонецЕсли; 70 | КонецЕсли; 71 | КонецЕсли; 72 | КонецПроцедуры // ПокинутьОператорПрисваивания() 73 | 74 | Процедура ПосетитьВыражениеИдентификатор(ВыражениеИдентификатор) Экспорт 75 | Перем Объявление, Операция; 76 | Если ВыражениеИдентификатор.Хвост.Количество() = 0 77 | И ВыражениеИдентификатор = ЛевыйОперандПрисваивания Тогда 78 | Возврат ; 79 | КонецЕсли; 80 | Объявление = ВыражениеИдентификатор.Голова.Объявление; 81 | Если УровеньЦикла(Счетчики) > 0 Тогда 82 | Операция = "ЧтениеВЦикле"; 83 | Иначе 84 | Операция = "Чтение"; 85 | КонецЕсли; 86 | Если Переменные[Объявление] <> Неопределено Тогда 87 | Переменные[Объявление] = Операция; 88 | ИначеЕсли Параметры[Объявление] <> Неопределено Тогда 89 | Параметры[Объявление] = Операция; 90 | КонецЕсли; 91 | КонецПроцедуры // ПосетитьВыражениеИдентификатор() 92 | 93 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 94 | Переменные = Новый Соответствие; 95 | Параметры = Новый Соответствие; 96 | Для Каждого Параметр Из ОбъявлениеМетода.Сигнатура.Параметры Цикл 97 | Параметры[Параметр] = "Чтение"; 98 | //Параметры[Параметр] = "Неопределено"; <- чтобы чекать все параметры (в формах адъ) 99 | КонецЦикла; 100 | Для Каждого ОбъявлениеПеременной Из ОбъявлениеМетода.Переменные Цикл 101 | Переменные[ОбъявлениеПеременной] = "Изменение"; 102 | Места[ОбъявлениеПеременной] = ОбъявлениеПеременной.Начало; 103 | КонецЦикла; 104 | КонецПроцедуры // ПосетитьОбъявлениеМетода() 105 | 106 | Процедура ПокинутьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 107 | Перем Метод, Текст; 108 | Если ОбъявлениеМетода.Сигнатура.Тип = Типы.ОбъявлениеСигнатурыФункции Тогда 109 | Метод = "Функция"; 110 | Иначе 111 | Метод = "Процедура"; 112 | КонецЕсли; 113 | Для Каждого Элемент Из Переменные Цикл 114 | Если Не СтрНачинаетсяС(Элемент.Значение, "Чтение") Тогда 115 | Текст = СтрШаблон("%1 `%2()` содержит неиспользуемую переменную `%3`", Метод, ОбъявлениеМетода.Сигнатура.Имя, Элемент.Ключ.Имя); 116 | Ошибка(Текст, Места[Элемент.Ключ]); 117 | КонецЕсли; 118 | КонецЦикла; 119 | Для Каждого Элемент Из Параметры Цикл 120 | Если Элемент.Значение = "Неопределено" Или Элемент.Значение = "Изменение" И Элемент.Ключ.ПоЗначению Тогда 121 | Текст = СтрШаблон("%1 `%2()` содержит неиспользуемый параметр `%3`", Метод, ОбъявлениеМетода.Сигнатура.Имя, Элемент.Ключ.Имя); 122 | Ошибка(Текст, Места[Элемент.Ключ]); 123 | КонецЕсли; 124 | КонецЦикла; 125 | КонецПроцедуры 126 | 127 | Функция УровеньЦикла(Счетчики) 128 | Возврат Счетчики[Типы.ОператорПока] + Счетчики[Типы.ОператорДляКаждого] + Счетчики[Типы.ОператорДля]; 129 | КонецФункции 130 | 131 | Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) 132 | Ошибка = ТаблицаОшибок.Добавить(); 133 | Ошибка.Источник = "ДетекторНеиспользуемыхПеременных"; 134 | Ошибка.Текст = Текст; 135 | Ошибка.ПозицияНачала = Начало.Позиция; 136 | Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; 137 | Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; 138 | Если Конец = Неопределено Или Конец = Начало Тогда 139 | Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; 140 | Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; 141 | Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; 142 | Иначе 143 | Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; 144 | Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; 145 | Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; 146 | КонецЕсли; 147 | Ошибка.ЕстьЗамена = ЕстьЗамена; 148 | КонецПроцедуры 149 | 150 | -------------------------------------------------------------------------------- /examples/plugins/Классы/ДетекторОшибочныхЗамыкающихКомментариев.os: -------------------------------------------------------------------------------- 1 |  2 | // Проверка замыкающих комментариев в окончаниях методов и областей 3 | 4 | Перем Типы; 5 | Перем Токены; 6 | Перем Исходник; 7 | Перем ТаблицаТокенов; 8 | Перем ТаблицаОшибок; 9 | Перем ТаблицаЗамен; 10 | 11 | Перем УровеньОбласти; 12 | Перем СтекОбластей; 13 | 14 | Процедура Открыть(Парсер, Параметры) Экспорт 15 | 16 | Типы = Парсер.Типы(); 17 | Токены = Парсер.Токены(); 18 | Исходник = Парсер.Исходник(); 19 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 20 | ТаблицаОшибок = Парсер.ТаблицаОшибок(); 21 | ТаблицаЗамен = Парсер.ТаблицаЗамен(); 22 | 23 | УровеньОбласти = 0; 24 | СтекОбластей = Новый Соответствие; 25 | 26 | КонецПроцедуры 27 | 28 | Функция Закрыть() Экспорт 29 | Возврат Неопределено; 30 | КонецФункции 31 | 32 | Функция Подписки() Экспорт 33 | Перем Подписки; 34 | Подписки = Новый Массив; 35 | Подписки.Добавить("ПосетитьОбъявлениеМетода"); 36 | Подписки.Добавить("ПосетитьИнструкциюПрепроцессора"); 37 | Возврат Подписки; 38 | КонецФункции 39 | 40 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 41 | 42 | СледующийТокен = ТаблицаТокенов[ОбъявлениеМетода.Конец.Индекс + 1]; 43 | 44 | Если СледующийТокен.Токен = Токены.Комментарий 45 | И СледующийТокен.НомерСтроки = ОбъявлениеМетода.Конец.НомерСтроки Тогда 46 | 47 | Комментарий = СокрП(Сред(Исходник, СледующийТокен.Позиция, СледующийТокен.Длина)); 48 | ПравильныйКомментарий = СтрШаблон(" %1%2", ОбъявлениеМетода.Сигнатура.Имя, "()"); 49 | 50 | Если Комментарий <> ПравильныйКомментарий Тогда 51 | Ошибка("Замыкающий комментарий неактуален", СледующийТокен,, Истина); 52 | Замена(ПравильныйКомментарий, СледующийТокен); 53 | КонецЕсли; 54 | 55 | КонецЕсли; 56 | 57 | КонецПроцедуры 58 | 59 | Процедура ПосетитьИнструкциюПрепроцессора(ИнструкцияПрепроцессора) Экспорт 60 | 61 | Если ИнструкцияПрепроцессора.Тип = Типы.ИнструкцияПрепроцессораОбласть Тогда 62 | 63 | УровеньОбласти = УровеньОбласти + 1; 64 | СтекОбластей[УровеньОбласти] = ИнструкцияПрепроцессора.Имя; 65 | 66 | ИначеЕсли ИнструкцияПрепроцессора.Тип = Типы.ИнструкцияПрепроцессораКонецОбласти Тогда 67 | СледующийТокен = ТаблицаТокенов[ИнструкцияПрепроцессора.Конец.Индекс + 1]; 68 | 69 | Если СледующийТокен.Токен = Токены.Комментарий 70 | И СледующийТокен.НомерСтроки = ИнструкцияПрепроцессора.Конец.НомерСтроки Тогда 71 | 72 | Комментарий = СокрП(Сред(Исходник, СледующийТокен.Позиция, СледующийТокен.Длина)); 73 | ИмяОбласти = СтекОбластей[УровеньОбласти]; 74 | ПравильныйКомментарий = СтрШаблон(" %1", ИмяОбласти); 75 | 76 | Если Комментарий <> ПравильныйКомментарий Тогда 77 | Ошибка("Замыкающий комментарий неактуален", СледующийТокен,, Истина); 78 | Замена(ПравильныйКомментарий, СледующийТокен); 79 | КонецЕсли; 80 | 81 | КонецЕсли; 82 | 83 | УровеньОбласти = УровеньОбласти - 1; 84 | 85 | КонецЕсли; 86 | 87 | КонецПроцедуры 88 | 89 | Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) 90 | Ошибка = ТаблицаОшибок.Добавить(); 91 | Ошибка.Источник = "ДетекторОшибочныхЗамыкающихКомментариев"; 92 | Ошибка.Текст = Текст; 93 | Ошибка.ПозицияНачала = Начало.Позиция; 94 | Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; 95 | Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; 96 | Если Конец = Неопределено Или Конец = Начало Тогда 97 | Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; 98 | Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; 99 | Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; 100 | Иначе 101 | Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; 102 | Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; 103 | Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; 104 | КонецЕсли; 105 | Ошибка.ЕстьЗамена = ЕстьЗамена; 106 | КонецПроцедуры 107 | 108 | Процедура Замена(Текст, Начало, Конец = Неопределено) 109 | НоваяЗамена = ТаблицаЗамен.Добавить(); 110 | НоваяЗамена.Источник = "ДетекторОшибочныхЗамыкающихКомментариев"; 111 | НоваяЗамена.Текст = Текст; 112 | НоваяЗамена.Позиция = Начало.Позиция; 113 | Если Конец = Неопределено Тогда 114 | НоваяЗамена.Длина = Начало.Длина; 115 | Иначе 116 | НоваяЗамена.Длина = Конец.Позиция + Конец.Длина - Начало.Позиция; 117 | КонецЕсли; 118 | КонецПроцедуры -------------------------------------------------------------------------------- /examples/plugins/Классы/ДетекторПропущенныхТочекСЗапятой.os: -------------------------------------------------------------------------------- 1 |  2 | Перем Токены; 3 | Перем Типы; 4 | Перем ТаблицаТокенов; 5 | Перем ТаблицаОшибок; 6 | 7 | Процедура Открыть(Парсер, Параметры) Экспорт 8 | Токены = Парсер.Токены(); 9 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 10 | ТаблицаОшибок = Парсер.ТаблицаОшибок(); 11 | Типы = Парсер.Типы(); 12 | КонецПроцедуры // Открыть() 13 | 14 | Функция Закрыть() Экспорт 15 | Возврат Неопределено; 16 | КонецФункции // Закрыть() 17 | 18 | Функция Подписки() Экспорт 19 | Перем Подписки; 20 | Подписки = Новый Массив; 21 | Подписки.Добавить("ПосетитьОператоры"); 22 | Возврат Подписки; 23 | КонецФункции // Подписки() 24 | 25 | #Область РеализацияПодписок 26 | 27 | Процедура ПосетитьОператоры(Операторы) Экспорт 28 | 29 | Для Каждого Оператор Из Операторы Цикл 30 | 31 | СледующийТокен = ТаблицаТокенов[Оператор.Конец.Индекс + 1]; 32 | 33 | Если СледующийТокен.Токен <> Токены.ТочкаСЗапятой И Не СтрНачинаетсяС(Оператор.Тип, "ИнструкцияПрепроцессора") Тогда 34 | 35 | Ошибка("Пропущена точка с запятой", Оператор.Конец); 36 | 37 | КонецЕсли; 38 | 39 | КонецЦикла; 40 | 41 | КонецПроцедуры // ПосетитьОператоры() 42 | 43 | #КонецОбласти // РеализацияПодписок 44 | 45 | Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) 46 | Ошибка = ТаблицаОшибок.Добавить(); 47 | Ошибка.Источник = "ДетекторПропущенныхТочекСЗапятой"; 48 | Ошибка.Текст = Текст; 49 | Ошибка.ПозицияНачала = Начало.Позиция; 50 | Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; 51 | Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; 52 | Если Конец = Неопределено Или Конец = Начало Тогда 53 | Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; 54 | Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; 55 | Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; 56 | Иначе 57 | Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; 58 | Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; 59 | Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; 60 | КонецЕсли; 61 | Ошибка.ЕстьЗамена = ЕстьЗамена; 62 | КонецПроцедуры -------------------------------------------------------------------------------- /examples/plugins/Классы/ДетекторФункцийБезВозвратаВКонце.os: -------------------------------------------------------------------------------- 1 |  2 | // Простая и эффективная проверка на наличие возврата из функции. 3 | // Чаще всего возврат просто забывают написать. 4 | // Нет никакого смысла разбирать сложные случаи, 5 | // когда пропущен возврат в одной из логических ветвей, 6 | // так как такие ошибки встречаются редко. 7 | // Гораздо проще договориться с командой, что функция всегда 8 | // должна оканчиваться инструкцией Возврат и автоматически 9 | // проверять код подобным плагином. 10 | 11 | Перем Типы; 12 | Перем ТаблицаТокенов; 13 | Перем ТаблицаОшибок; 14 | 15 | Процедура Открыть(Парсер, Параметры) Экспорт 16 | Типы = Парсер.Типы(); 17 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 18 | ТаблицаОшибок = Парсер.ТаблицаОшибок(); 19 | КонецПроцедуры 20 | 21 | Функция Закрыть() Экспорт 22 | Возврат Неопределено; 23 | КонецФункции 24 | 25 | Функция Подписки() Экспорт 26 | Перем Подписки; 27 | Подписки = Новый Массив; 28 | Подписки.Добавить("ПосетитьОбъявлениеМетода"); 29 | Возврат Подписки; 30 | КонецФункции 31 | 32 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 33 | Перем КоличествоОператоров; 34 | Если ОбъявлениеМетода.Сигнатура.Тип <> Типы.ОбъявлениеСигнатурыФункции Тогда 35 | Возврат; 36 | КонецЕсли; 37 | КоличествоОператоров = ОбъявлениеМетода.Операторы.Количество(); 38 | Если КоличествоОператоров = 0 Или ОбъявлениеМетода.Операторы[КоличествоОператоров - 1].Тип <> Типы.ОператорВозврат Тогда 39 | Текст = СтрШаблон("Последней инструкцией функции `%1()` должен быть `Возврат`""", ОбъявлениеМетода.Сигнатура.Имя); 40 | Ошибка(Текст, ОбъявлениеМетода.Конец); 41 | КонецЕсли; 42 | КонецПроцедуры 43 | 44 | Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) 45 | Ошибка = ТаблицаОшибок.Добавить(); 46 | Ошибка.Источник = "ДетекторФункцийБезВозвратаВКонце"; 47 | Ошибка.Текст = Текст; 48 | Ошибка.ПозицияНачала = Начало.Позиция; 49 | Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; 50 | Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; 51 | Если Конец = Неопределено Или Конец = Начало Тогда 52 | Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; 53 | Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; 54 | Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; 55 | Иначе 56 | Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; 57 | Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; 58 | Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; 59 | КонецЕсли; 60 | Ошибка.ЕстьЗамена = ЕстьЗамена; 61 | КонецПроцедуры -------------------------------------------------------------------------------- /examples/plugins/Классы/ЗаменаНеканоничныхКлючевыхСлов.os: -------------------------------------------------------------------------------- 1 |  2 | Перем Токены; 3 | Перем Типы; 4 | Перем ТаблицаТокенов; 5 | Перем Исходник; 6 | Перем ТаблицаЗамен; 7 | 8 | Перем КлючевыеСлова; 9 | 10 | Процедура Открыть(Парсер, Параметры) Экспорт 11 | 12 | Токены = Парсер.Токены(); 13 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 14 | Исходник = Парсер.Исходник(); 15 | Типы = Парсер.Типы(); 16 | ТаблицаЗамен = Парсер.ТаблицаЗамен(); 17 | 18 | КлючевыеСлова = Новый Структура; 19 | КлючевыеСлова.Вставить("Если", "Если"); 20 | КлючевыеСлова.Вставить("If", "If"); 21 | КлючевыеСлова.Вставить("Тогда", "Тогда"); 22 | КлючевыеСлова.Вставить("Then", "Then"); 23 | КлючевыеСлова.Вставить("ИначеЕсли", "ИначеЕсли"); 24 | КлючевыеСлова.Вставить("ElsIf", "ElsIf"); 25 | КлючевыеСлова.Вставить("Иначе", "Иначе"); 26 | КлючевыеСлова.Вставить("Else", "Else"); 27 | КлючевыеСлова.Вставить("КонецЕсли", "КонецЕсли"); 28 | КлючевыеСлова.Вставить("EndIf", "EndIf"); 29 | КлючевыеСлова.Вставить("Для", "Для"); 30 | КлючевыеСлова.Вставить("For", "For"); 31 | КлючевыеСлова.Вставить("Каждого", "Каждого"); 32 | КлючевыеСлова.Вставить("Each", "Each"); 33 | КлючевыеСлова.Вставить("Из", "Из"); 34 | КлючевыеСлова.Вставить("In", "In"); 35 | КлючевыеСлова.Вставить("По", "По"); 36 | КлючевыеСлова.Вставить("To", "To"); 37 | КлючевыеСлова.Вставить("Пока", "Пока"); 38 | КлючевыеСлова.Вставить("While", "While"); 39 | КлючевыеСлова.Вставить("Цикл", "Цикл"); 40 | КлючевыеСлова.Вставить("Do", "Do"); 41 | КлючевыеСлова.Вставить("КонецЦикла", "КонецЦикла"); 42 | КлючевыеСлова.Вставить("EndDo", "EndDo"); 43 | КлючевыеСлова.Вставить("Процедура", "Процедура"); 44 | КлючевыеСлова.Вставить("Procedure", "Procedure"); 45 | КлючевыеСлова.Вставить("КонецПроцедуры", "КонецПроцедуры"); 46 | КлючевыеСлова.Вставить("EndProcedure", "EndProcedure"); 47 | КлючевыеСлова.Вставить("Функция", "Функция"); 48 | КлючевыеСлова.Вставить("Function", "Function"); 49 | КлючевыеСлова.Вставить("КонецФункции", "КонецФункции"); 50 | КлючевыеСлова.Вставить("EndFunction", "EndFunction"); 51 | КлючевыеСлова.Вставить("Перем", "Перем"); 52 | КлючевыеСлова.Вставить("Var", "Var"); 53 | КлючевыеСлова.Вставить("Знач", "Знач"); 54 | КлючевыеСлова.Вставить("Val", "Val"); 55 | КлючевыеСлова.Вставить("Возврат", "Возврат"); 56 | КлючевыеСлова.Вставить("Return", "Return"); 57 | КлючевыеСлова.Вставить("Продолжить", "Продолжить"); 58 | КлючевыеСлова.Вставить("Continue", "Continue"); 59 | КлючевыеСлова.Вставить("Прервать", "Прервать"); 60 | КлючевыеСлова.Вставить("Break", "Break"); 61 | КлючевыеСлова.Вставить("И", "И"); 62 | КлючевыеСлова.Вставить("And", "And"); 63 | КлючевыеСлова.Вставить("Или", "Или"); 64 | КлючевыеСлова.Вставить("Or", "Or"); 65 | КлючевыеСлова.Вставить("Не", "Не"); 66 | КлючевыеСлова.Вставить("Not", "Not"); 67 | КлючевыеСлова.Вставить("ДобавитьОбработчик", "ДобавитьОбработчик"); 68 | КлючевыеСлова.Вставить("AddHandler", "AddHandler"); 69 | КлючевыеСлова.Вставить("УдалитьОбработчик", "УдалитьОбработчик"); 70 | КлючевыеСлова.Вставить("RemoveHandler", "RemoveHandler"); 71 | КлючевыеСлова.Вставить("Попытка", "Попытка"); 72 | КлючевыеСлова.Вставить("Try", "Try"); 73 | КлючевыеСлова.Вставить("Исключение", "Исключение"); 74 | КлючевыеСлова.Вставить("Except", "Except"); 75 | КлючевыеСлова.Вставить("ВызватьИсключение", "ВызватьИсключение"); 76 | КлючевыеСлова.Вставить("Raise", "Raise"); 77 | КлючевыеСлова.Вставить("КонецПопытки", "КонецПопытки"); 78 | КлючевыеСлова.Вставить("EndTry", "EndTry"); 79 | КлючевыеСлова.Вставить("Новый", "Новый"); 80 | КлючевыеСлова.Вставить("New", "New"); 81 | КлючевыеСлова.Вставить("Выполнить", "Выполнить"); 82 | КлючевыеСлова.Вставить("Execute", "Execute"); 83 | КлючевыеСлова.Вставить("Экспорт", "Экспорт"); 84 | КлючевыеСлова.Вставить("Export", "Export"); 85 | КлючевыеСлова.Вставить("Перейти", "Перейти"); 86 | КлючевыеСлова.Вставить("Goto", "Goto"); 87 | КлючевыеСлова.Вставить("Истина", "Истина"); 88 | КлючевыеСлова.Вставить("True", "True"); 89 | КлючевыеСлова.Вставить("Ложь", "Ложь"); 90 | КлючевыеСлова.Вставить("False", "False"); 91 | КлючевыеСлова.Вставить("Неопределено", "Неопределено"); 92 | КлючевыеСлова.Вставить("Undefined", "Undefined"); 93 | КлючевыеСлова.Вставить("Null", "Null"); 94 | 95 | КонецПроцедуры // Открыть() 96 | 97 | Функция Закрыть() Экспорт 98 | 99 | Для ИндексТокена = 0 По ТаблицаТокенов.Количество() - 1 Цикл 100 | ДанныеТокена = ТаблицаТокенов[ИндексТокена]; 101 | Если КлючевыеСлова.Свойство(ДанныеТокена.Токен) Тогда 102 | Литерал = Сред(Исходник, ДанныеТокена.Позиция, ДанныеТокена.Длина); 103 | КлючевоеСлово = Неопределено; 104 | Если КлючевыеСлова.Свойство(Литерал, КлючевоеСлово) И Литерал <> КлючевоеСлово Тогда 105 | Замена(КлючевоеСлово, ДанныеТокена); 106 | КонецЕсли; 107 | КонецЕсли; 108 | КонецЦикла; 109 | 110 | Возврат Неопределено; 111 | КонецФункции // Закрыть() 112 | 113 | Функция Подписки() Экспорт 114 | Перем Подписки; 115 | Подписки = Новый Массив; 116 | Возврат Подписки; 117 | КонецФункции // Подписки() 118 | 119 | Процедура Замена(Текст, Начало, Конец = Неопределено) 120 | НоваяЗамена = ТаблицаЗамен.Добавить(); 121 | НоваяЗамена.Источник = "ЗаменаНеканоничныхКлючевыхСлов"; 122 | НоваяЗамена.Текст = Текст; 123 | НоваяЗамена.Позиция = Начало.Позиция; 124 | Если Конец = Неопределено Тогда 125 | НоваяЗамена.Длина = Начало.Длина; 126 | Иначе 127 | НоваяЗамена.Длина = Конец.Позиция + Конец.Длина - Начало.Позиция; 128 | КонецЕсли; 129 | КонецПроцедуры 130 | -------------------------------------------------------------------------------- /examples/plugins/Классы/ПереименованиеПеременных.os: -------------------------------------------------------------------------------- 1 |  2 | // Этот плагин выполняет переименование переменных если это возможно. 3 | // При возникновении конфликтов регистрирует ошибку, которая указывает на конфликтную переменную. 4 | 5 | // Пример ожидаемой структуры параметров (json): 6 | // {"СтароеИмя1": "НовоеИмя1", "СтароеИмя2": "НовоеИмя2"} 7 | 8 | Перем Типы; 9 | Перем ТаблицаОшибок; 10 | Перем ТаблицаЗамен; 11 | 12 | Перем ПеременныеДляПереименования; 13 | Перем КонфликтыПриПереименовании; 14 | Перем СтруктураЗамен; 15 | Перем ЦелевыеИмена; 16 | 17 | Процедура Открыть(Парсер, Параметры) Экспорт 18 | 19 | Если Параметры = Неопределено Тогда 20 | ВызватьИсключение "Не указаны параметры плагина 'ПереименованиеПеременных'"; 21 | КонецЕсли; 22 | 23 | Типы = Парсер.Типы(); 24 | ТаблицаОшибок = Парсер.ТаблицаОшибок(); 25 | ТаблицаЗамен = Парсер.ТаблицаЗамен(); 26 | 27 | СтруктураЗамен = Параметры; 28 | 29 | ЦелевыеИмена = Новый Структура; 30 | Для Каждого Элемент Из СтруктураЗамен Цикл 31 | ЦелевыеИмена.Вставить(Элемент.Значение, Элемент.Значение); 32 | КонецЦикла; 33 | 34 | ПеременныеДляПереименования = Новый Соответствие; 35 | КонфликтыПриПереименовании = Новый Соответствие; 36 | 37 | КонецПроцедуры // Открыть() 38 | 39 | Функция Закрыть() Экспорт 40 | Возврат Неопределено; 41 | КонецФункции // Закрыть() 42 | 43 | Функция Подписки() Экспорт 44 | Перем Подписки; 45 | Подписки = Новый Массив; 46 | Подписки.Добавить("ПосетитьВыражениеИдентификатор"); 47 | Подписки.Добавить("ПосетитьОбъявлениеМетода"); 48 | Подписки.Добавить("ПокинутьОбъявлениеМетода"); 49 | Возврат Подписки; 50 | КонецФункции // Подписки() 51 | 52 | #Область РеализацияПодписок 53 | 54 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 55 | 56 | ПеременныеДляПереименования = Новый Соответствие; 57 | КонфликтыПриПереименовании = Новый Соответствие; 58 | 59 | СобратьПеременныеДляПереименования(ОбъявлениеМетода.Сигнатура.Параметры); 60 | 61 | СобратьПеременныеДляПереименования(ОбъявлениеМетода.Переменные); 62 | 63 | СписокОчистки = Новый Массив; 64 | 65 | Для Каждого Элемент Из ПеременныеДляПереименования Цикл 66 | 67 | ТекстЗамены = Элемент.Значение; 68 | 69 | Объявление = Элемент.Ключ; 70 | 71 | Если Объявление.Тип = Типы.ОбъявлениеПараметра 72 | Или Объявление.Тип = Типы.ОбъявлениеЛокальнойПеременной Тогда 73 | 74 | КонфликтноеОбъявление = КонфликтыПриПереименовании[ТекстЗамены]; 75 | 76 | Если КонфликтноеОбъявление = Неопределено Тогда 77 | 78 | ДанныеТокена = Объявление.Начало; 79 | 80 | Замена(ТекстЗамены, ДанныеТокена); 81 | 82 | Иначе 83 | 84 | СписокОчистки.Добавить(Объявление); 85 | Ошибка(СтрШаблон("Конфликт при переименовании переменной '%1'", Объявление.Имя), КонфликтноеОбъявление.Начало); 86 | 87 | КонецЕсли; 88 | 89 | КонецЕсли; 90 | 91 | КонецЦикла; 92 | 93 | Для Каждого Объявление Из СписокОчистки Цикл 94 | ПеременныеДляПереименования[Объявление] = Неопределено; 95 | КонецЦикла; 96 | 97 | КонецПроцедуры 98 | 99 | Процедура СобратьПеременныеДляПереименования(Объявления) 100 | 101 | ТекстЗамены = Неопределено; 102 | 103 | Для Каждого Объявление Из Объявления Цикл 104 | Если СтруктураЗамен.Свойство(Объявление.Имя, ТекстЗамены) Тогда 105 | ПеременныеДляПереименования[Объявление] = ТекстЗамены; 106 | ИначеЕсли ЦелевыеИмена.Свойство(Объявление.Имя, ТекстЗамены) Тогда 107 | КонфликтыПриПереименовании[ТекстЗамены] = Объявление; 108 | КонецЕсли; 109 | КонецЦикла; 110 | 111 | КонецПроцедуры 112 | 113 | Процедура ПосетитьВыражениеИдентификатор(ВыражениеИдентификатор) Экспорт 114 | 115 | Объявление = ВыражениеИдентификатор.Голова.Объявление; 116 | 117 | ТекстЗамены = ПеременныеДляПереименования[Объявление]; 118 | 119 | Если ТекстЗамены <> Неопределено Тогда 120 | 121 | КонфликтноеОбъявление = КонфликтыПриПереименовании[ТекстЗамены]; 122 | 123 | Если КонфликтноеОбъявление = Неопределено Тогда 124 | 125 | ДанныеТокена = ВыражениеИдентификатор.Начало; 126 | 127 | Замена(ТекстЗамены, ДанныеТокена); 128 | 129 | Иначе 130 | 131 | ПеременныеДляПереименования[Объявление] = Неопределено; 132 | Ошибка(СтрШаблон("Конфликт при переименовании переменной '%1'", Объявление.Имя), КонфликтноеОбъявление.Начало); 133 | 134 | КонецЕсли; 135 | 136 | КонецЕсли; 137 | 138 | КонецПроцедуры 139 | 140 | Процедура ПокинутьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 141 | 142 | ПеременныеДляПереименования.Очистить(); 143 | КонфликтыПриПереименовании.Очистить(); 144 | 145 | КонецПроцедуры 146 | 147 | #КонецОбласти // РеализацияПодписок 148 | 149 | Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) 150 | Ошибка = ТаблицаОшибок.Добавить(); 151 | Ошибка.Источник = "ПереименованиеПеременных"; 152 | Ошибка.Текст = Текст; 153 | Ошибка.ПозицияНачала = Начало.Позиция; 154 | Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; 155 | Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; 156 | Если Конец = Неопределено Или Конец = Начало Тогда 157 | Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; 158 | Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; 159 | Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; 160 | Иначе 161 | Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; 162 | Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; 163 | Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; 164 | КонецЕсли; 165 | Ошибка.ЕстьЗамена = ЕстьЗамена; 166 | КонецПроцедуры 167 | 168 | Процедура Замена(Текст, Начало, Конец = Неопределено) 169 | НоваяЗамена = ТаблицаЗамен.Добавить(); 170 | НоваяЗамена.Источник = "ПереименованиеПеременных"; 171 | НоваяЗамена.Текст = Текст; 172 | НоваяЗамена.Позиция = Начало.Позиция; 173 | Если Конец = Неопределено Тогда 174 | НоваяЗамена.Длина = Начало.Длина; 175 | Иначе 176 | НоваяЗамена.Длина = Конец.Позиция + Конец.Длина - Начало.Позиция; 177 | КонецЕсли; 178 | КонецПроцедуры 179 | -------------------------------------------------------------------------------- /examples/plugins/Классы/ПлагинСПараметром.os: -------------------------------------------------------------------------------- 1 | 2 | Процедура Открыть(Парсер, Параметры) Экспорт 3 | Сообщить(Параметры.МойПараметр); 4 | КонецПроцедуры // Открыть() 5 | 6 | Функция Закрыть() Экспорт 7 | Возврат Неопределено; 8 | КонецФункции // Закрыть() 9 | 10 | Функция Подписки() Экспорт 11 | Перем Подписки; 12 | Подписки = Новый Массив; 13 | Возврат Подписки; 14 | КонецФункции // Подписки() -------------------------------------------------------------------------------- /examples/plugins/Классы/ПодсчетКогнитивнойСложностиМетодов.os: -------------------------------------------------------------------------------- 1 |  2 | // Подсчет когнитивной сложности методов (регистрируется как ошибка только сложность > 100). 3 | // Не учитываются косвенные рекурсивные вызовы. 4 | 5 | // Метод очень спорный. Никакого отношения к реальной когнитивной нагрузке скорее всего не имеет. 6 | 7 | 8 | Перем Типы; 9 | Перем Токены; 10 | Перем ТаблицаОшибок; 11 | Перем ТаблицаТокенов; 12 | Перем Результат; 13 | 14 | Перем Уровень; 15 | Перем КогнитивнаяСложность; 16 | Перем ТекущийМетод; 17 | Перем УровеньВыражения; 18 | 19 | Процедура Открыть(Парсер, Параметры) Экспорт 20 | Типы = Парсер.Типы(); 21 | Токены = Парсер.Токены(); 22 | ТаблицаОшибок = Парсер.ТаблицаОшибок(); 23 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 24 | Результат = Новый Массив; 25 | Уровень = 1; 26 | КогнитивнаяСложность = 0; 27 | УровеньВыражения = 0; 28 | КонецПроцедуры // Открыть() 29 | 30 | Функция Подписки() Экспорт 31 | Перем Подписки; 32 | Подписки = Новый Массив; 33 | Подписки.Добавить("ПосетитьОбъявлениеМетода"); 34 | Подписки.Добавить("ПокинутьОбъявлениеМетода"); 35 | Подписки.Добавить("ПосетитьВыражениеБинарное"); 36 | Подписки.Добавить("ПокинутьВыражениеБинарное"); 37 | Подписки.Добавить("ПосетитьВыражениеТернарное"); 38 | Подписки.Добавить("ПосетитьОператорЕсли"); 39 | Подписки.Добавить("ПокинутьОператорЕсли"); 40 | Подписки.Добавить("ПосетитьОператорИначеЕсли"); 41 | Подписки.Добавить("ПосетитьОператорИначе"); 42 | Подписки.Добавить("ПосетитьОператорПока"); 43 | Подписки.Добавить("ПокинутьОператорПока"); 44 | Подписки.Добавить("ПосетитьОператорДля"); 45 | Подписки.Добавить("ПокинутьОператорДля"); 46 | Подписки.Добавить("ПосетитьОператорДляКаждого"); 47 | Подписки.Добавить("ПокинутьОператорДляКаждого"); 48 | Подписки.Добавить("ПосетитьОператорИсключение"); 49 | Подписки.Добавить("ПосетитьОператорВызоваПроцедуры"); 50 | Подписки.Добавить("ПосетитьОператорПерейти"); 51 | Подписки.Добавить("ПосетитьОператорПрервать"); 52 | Подписки.Добавить("ПосетитьОператорПродолжить"); 53 | Возврат Подписки; 54 | КонецФункции // Подписки() 55 | 56 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 57 | ТекущийМетод = ОбъявлениеМетода.Сигнатура; 58 | КонецПроцедуры // ПосетитьОбъявлениеМетода() 59 | 60 | Процедура ПокинутьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 61 | Если КогнитивнаяСложность > 100 Тогда 62 | Текст = СтрШаблон("Когнитивная сложность %1", КогнитивнаяСложность); 63 | Ошибка(Текст, ОбъявлениеМетода.Начало, ОбъявлениеМетода.Конец); 64 | КонецЕсли; 65 | Уровень = 1; 66 | КогнитивнаяСложность = 0; 67 | КонецПроцедуры // ПокинутьОбъявлениеМетода() 68 | 69 | Процедура ПосетитьВыражениеБинарное(ВыражениеБинарное) Экспорт 70 | Если УровеньВыражения = 0 Тогда // только для корневого 71 | СписокОпераций = Новый Массив; 72 | ПостроитьСписокОпераций(СписокОпераций, ВыражениеБинарное); 73 | ТекущаяОперация = Неопределено; 74 | Для Каждого Операция Из СписокОпераций Цикл 75 | Если Операция <> ТекущаяОперация Тогда 76 | ТекущаяОперация = Операция; 77 | Если ТекущаяОперация = Токены.Или 78 | Или ТекущаяОперация = Токены.И Тогда 79 | КогнитивнаяСложность = КогнитивнаяСложность + 1; 80 | КонецЕсли; 81 | КонецЕсли; 82 | КонецЦикла; 83 | КонецЕсли; 84 | УровеньВыражения = УровеньВыражения + 1; 85 | КонецПроцедуры // ПосетитьВыражениеБинарное() 86 | 87 | Процедура ПокинутьВыражениеБинарное(ВыражениеБинарное) Экспорт 88 | УровеньВыражения = УровеньВыражения - 1; 89 | КонецПроцедуры // ПокинутьВыражениеБинарное() 90 | 91 | Процедура ПостроитьСписокОпераций(СписокОпераций, ВыражениеБинарное) 92 | Если ВыражениеБинарное.ЛевыйОперанд.Тип = Типы.ВыражениеБинарное Тогда 93 | ПостроитьСписокОпераций(СписокОпераций, ВыражениеБинарное.ЛевыйОперанд); 94 | КонецЕсли; 95 | СписокОпераций.Добавить(ВыражениеБинарное.Операция.Токен); 96 | Если ВыражениеБинарное.ПравыйОперанд.Тип = Типы.ВыражениеБинарное Тогда 97 | ПостроитьСписокОпераций(СписокОпераций, ВыражениеБинарное.ПравыйОперанд); 98 | КонецЕсли; 99 | КонецПроцедуры // ПостроитьСписокОпераций() 100 | 101 | Процедура ПосетитьВыражениеТернарное(ВыражениеТернарное) Экспорт 102 | КогнитивнаяСложность = КогнитивнаяСложность + Уровень; 103 | КонецПроцедуры // ПосетитьВыражениеТернарное() 104 | 105 | Процедура ПосетитьОператорВызоваПроцедуры(ОператорВызоваПроцедуры) Экспорт 106 | Если ОператорВызоваПроцедуры.Идентификатор.Голова.Объявление = ТекущийМетод Тогда 107 | КогнитивнаяСложность = КогнитивнаяСложность + 1; 108 | КонецЕсли; 109 | КонецПроцедуры // ПосетитьОператорВызоваПроцедуры() 110 | 111 | Процедура ПосетитьОператорЕсли(ОператорЕсли) Экспорт 112 | КогнитивнаяСложность = КогнитивнаяСложность + Уровень; 113 | Уровень = Уровень + 1; 114 | КонецПроцедуры // ПосетитьОператорЕсли() 115 | 116 | Процедура ПокинутьОператорЕсли(ОператорЕсли) Экспорт 117 | Уровень = Уровень - 1; 118 | КонецПроцедуры // ПокинутьОператорЕсли() 119 | 120 | Процедура ПосетитьОператорИначеЕсли(ОператорИначеЕсли) Экспорт 121 | КогнитивнаяСложность = КогнитивнаяСложность + 1; 122 | КонецПроцедуры // ПосетитьОператорИначеЕсли() 123 | 124 | Процедура ПосетитьОператорИначе(ОператорИначе) Экспорт 125 | КогнитивнаяСложность = КогнитивнаяСложность + 1; 126 | КонецПроцедуры // ПосетитьОператорИначе() 127 | 128 | Процедура ПосетитьОператорПока(ОператорПока) Экспорт 129 | КогнитивнаяСложность = КогнитивнаяСложность + Уровень; 130 | Уровень = Уровень + 1; 131 | КонецПроцедуры // ПосетитьОператорПока() 132 | 133 | Процедура ПокинутьОператорПока(ОператорПока) Экспорт 134 | Уровень = Уровень - 1; 135 | КонецПроцедуры // ПокинутьОператорПока() 136 | 137 | Процедура ПосетитьОператорДля(ОператорДля) Экспорт 138 | КогнитивнаяСложность = КогнитивнаяСложность + Уровень; 139 | Уровень = Уровень + 1; 140 | КонецПроцедуры // ПосетитьОператорДля() 141 | 142 | Процедура ПокинутьОператорДля(ОператорДля) Экспорт 143 | Уровень = Уровень - 1; 144 | КонецПроцедуры // ПокинутьОператорДля() 145 | 146 | Процедура ПосетитьОператорДляКаждого(ОператорДляКаждого) Экспорт 147 | КогнитивнаяСложность = КогнитивнаяСложность + Уровень; 148 | Уровень = Уровень + 1; 149 | КонецПроцедуры // ПосетитьОператорДляКаждого() 150 | 151 | Процедура ПокинутьОператорДляКаждого(ОператорДляКаждого) Экспорт 152 | Уровень = Уровень - 1; 153 | КонецПроцедуры // ПокинутьОператорДляКаждого() 154 | 155 | Процедура ПосетитьОператорИсключение(ОператорИсключение) Экспорт 156 | КогнитивнаяСложность = КогнитивнаяСложность + Уровень; 157 | Уровень = Уровень + 1; 158 | КонецПроцедуры // ПосетитьОператорИсключение() 159 | 160 | Процедура ПосетитьОператорПерейти(ОператорПерейти) Экспорт 161 | КогнитивнаяСложность = КогнитивнаяСложность + 1; 162 | КонецПроцедуры // ПосетитьОператорПерейти() 163 | 164 | Процедура ПосетитьОператорПрервать(ОператорПрервать) Экспорт 165 | КогнитивнаяСложность = КогнитивнаяСложность + 1; 166 | КонецПроцедуры // ПосетитьОператорПрервать() 167 | 168 | Процедура ПосетитьОператорПродолжить(ОператорПродолжить) Экспорт 169 | КогнитивнаяСложность = КогнитивнаяСложность + 1; 170 | КонецПроцедуры // ПосетитьОператорПродолжить() 171 | 172 | Функция Закрыть() Экспорт 173 | Возврат СтрСоединить(Результат, Символы.ПС); 174 | КонецФункции 175 | 176 | Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) 177 | Ошибка = ТаблицаОшибок.Добавить(); 178 | Ошибка.Источник = "ПодсчетКогнитивнойСложностиМетодов"; 179 | Ошибка.Текст = Текст; 180 | Ошибка.ПозицияНачала = Начало.Позиция; 181 | Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; 182 | Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; 183 | Если Конец = Неопределено Или Конец = Начало Тогда 184 | Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; 185 | Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; 186 | Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; 187 | Иначе 188 | Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; 189 | Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; 190 | Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; 191 | КонецЕсли; 192 | Ошибка.ЕстьЗамена = ЕстьЗамена; 193 | КонецПроцедуры -------------------------------------------------------------------------------- /examples/plugins/Классы/ПроверкаКаноничностиКлючевыхСлов.os: -------------------------------------------------------------------------------- 1 |  2 | Перем Токены; 3 | Перем Исходник; 4 | Перем ТаблицаТокенов; 5 | Перем ТаблицаОшибок; 6 | 7 | Перем КлючевыеСлова; 8 | 9 | Процедура Открыть(Парсер, Параметры) Экспорт 10 | 11 | Токены = Парсер.Токены(); 12 | Исходник = Парсер.Исходник(); 13 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 14 | ТаблицаОшибок = Парсер.ТаблицаОшибок(); 15 | 16 | КлючевыеСлова = Новый Структура; 17 | КлючевыеСлова.Вставить("Если", "Если"); 18 | КлючевыеСлова.Вставить("If", "If"); 19 | КлючевыеСлова.Вставить("Тогда", "Тогда"); 20 | КлючевыеСлова.Вставить("Then", "Then"); 21 | КлючевыеСлова.Вставить("ИначеЕсли", "ИначеЕсли"); 22 | КлючевыеСлова.Вставить("ElsIf", "ElsIf"); 23 | КлючевыеСлова.Вставить("Иначе", "Иначе"); 24 | КлючевыеСлова.Вставить("Else", "Else"); 25 | КлючевыеСлова.Вставить("КонецЕсли", "КонецЕсли"); 26 | КлючевыеСлова.Вставить("EndIf", "EndIf"); 27 | КлючевыеСлова.Вставить("Для", "Для"); 28 | КлючевыеСлова.Вставить("For", "For"); 29 | КлючевыеСлова.Вставить("Каждого", "Каждого"); 30 | КлючевыеСлова.Вставить("Each", "Each"); 31 | КлючевыеСлова.Вставить("Из", "Из"); 32 | КлючевыеСлова.Вставить("In", "In"); 33 | КлючевыеСлова.Вставить("По", "По"); 34 | КлючевыеСлова.Вставить("To", "To"); 35 | КлючевыеСлова.Вставить("Пока", "Пока"); 36 | КлючевыеСлова.Вставить("While", "While"); 37 | КлючевыеСлова.Вставить("Цикл", "Цикл"); 38 | КлючевыеСлова.Вставить("Do", "Do"); 39 | КлючевыеСлова.Вставить("КонецЦикла", "КонецЦикла"); 40 | КлючевыеСлова.Вставить("EndDo", "EndDo"); 41 | КлючевыеСлова.Вставить("Процедура", "Процедура"); 42 | КлючевыеСлова.Вставить("Procedure", "Procedure"); 43 | КлючевыеСлова.Вставить("КонецПроцедуры", "КонецПроцедуры"); 44 | КлючевыеСлова.Вставить("EndProcedure", "EndProcedure"); 45 | КлючевыеСлова.Вставить("Функция", "Функция"); 46 | КлючевыеСлова.Вставить("Function", "Function"); 47 | КлючевыеСлова.Вставить("КонецФункции", "КонецФункции"); 48 | КлючевыеСлова.Вставить("EndFunction", "EndFunction"); 49 | КлючевыеСлова.Вставить("Перем", "Перем"); 50 | КлючевыеСлова.Вставить("Var", "Var"); 51 | КлючевыеСлова.Вставить("Знач", "Знач"); 52 | КлючевыеСлова.Вставить("Val", "Val"); 53 | КлючевыеСлова.Вставить("Возврат", "Возврат"); 54 | КлючевыеСлова.Вставить("Return", "Return"); 55 | КлючевыеСлова.Вставить("Продолжить", "Продолжить"); 56 | КлючевыеСлова.Вставить("Continue", "Continue"); 57 | КлючевыеСлова.Вставить("Прервать", "Прервать"); 58 | КлючевыеСлова.Вставить("Break", "Break"); 59 | КлючевыеСлова.Вставить("И", "И"); 60 | КлючевыеСлова.Вставить("And", "And"); 61 | КлючевыеСлова.Вставить("Или", "Или"); 62 | КлючевыеСлова.Вставить("Or", "Or"); 63 | КлючевыеСлова.Вставить("Не", "Не"); 64 | КлючевыеСлова.Вставить("Not", "Not"); 65 | КлючевыеСлова.Вставить("ДобавитьОбработчик", "ДобавитьОбработчик"); 66 | КлючевыеСлова.Вставить("AddHandler", "AddHandler"); 67 | КлючевыеСлова.Вставить("УдалитьОбработчик", "УдалитьОбработчик"); 68 | КлючевыеСлова.Вставить("RemoveHandler", "RemoveHandler"); 69 | КлючевыеСлова.Вставить("Попытка", "Попытка"); 70 | КлючевыеСлова.Вставить("Try", "Try"); 71 | КлючевыеСлова.Вставить("Исключение", "Исключение"); 72 | КлючевыеСлова.Вставить("Except", "Except"); 73 | КлючевыеСлова.Вставить("ВызватьИсключение", "ВызватьИсключение"); 74 | КлючевыеСлова.Вставить("Raise", "Raise"); 75 | КлючевыеСлова.Вставить("КонецПопытки", "КонецПопытки"); 76 | КлючевыеСлова.Вставить("EndTry", "EndTry"); 77 | КлючевыеСлова.Вставить("Новый", "Новый"); 78 | КлючевыеСлова.Вставить("New", "New"); 79 | КлючевыеСлова.Вставить("Выполнить", "Выполнить"); 80 | КлючевыеСлова.Вставить("Execute", "Execute"); 81 | КлючевыеСлова.Вставить("Экспорт", "Экспорт"); 82 | КлючевыеСлова.Вставить("Export", "Export"); 83 | КлючевыеСлова.Вставить("Перейти", "Перейти"); 84 | КлючевыеСлова.Вставить("Goto", "Goto"); 85 | КлючевыеСлова.Вставить("Истина", "Истина"); 86 | КлючевыеСлова.Вставить("True", "True"); 87 | КлючевыеСлова.Вставить("Ложь", "Ложь"); 88 | КлючевыеСлова.Вставить("False", "False"); 89 | КлючевыеСлова.Вставить("Неопределено", "Неопределено"); 90 | КлючевыеСлова.Вставить("Undefined", "Undefined"); 91 | КлючевыеСлова.Вставить("Null", "Null"); 92 | 93 | КонецПроцедуры // Открыть() 94 | 95 | Функция Закрыть() Экспорт 96 | 97 | Для ИндексТокена = 0 По ТаблицаТокенов.Количество() - 1 Цикл 98 | ДанныеТокена = ТаблицаТокенов[ИндексТокена]; 99 | Если КлючевыеСлова.Свойство(ДанныеТокена.Токен) Тогда 100 | Литерал = Сред(Исходник, ДанныеТокена.Позиция, ДанныеТокена.Длина); 101 | КлючевоеСлово = Неопределено; 102 | Если КлючевыеСлова.Свойство(Литерал, КлючевоеСлово) И Литерал <> КлючевоеСлово Тогда 103 | Ошибка("Неканоничное написание ключевого слова", ДанныеТокена); 104 | КонецЕсли; 105 | КонецЕсли; 106 | КонецЦикла; 107 | 108 | Возврат Неопределено; 109 | КонецФункции // Закрыть() 110 | 111 | Функция Подписки() Экспорт 112 | Перем Подписки; 113 | Подписки = Новый Массив; 114 | Возврат Подписки; 115 | КонецФункции // Подписки() 116 | 117 | Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) 118 | Ошибка = ТаблицаОшибок.Добавить(); 119 | Ошибка.Источник = "ПроверкаКаноничностиКлючевыхСлов"; 120 | Ошибка.Текст = Текст; 121 | Ошибка.ПозицияНачала = Начало.Позиция; 122 | Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; 123 | Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; 124 | Если Конец = Неопределено Или Конец = Начало Тогда 125 | Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; 126 | Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; 127 | Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; 128 | Иначе 129 | Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; 130 | Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; 131 | Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; 132 | КонецЕсли; 133 | Ошибка.ЕстьЗамена = ЕстьЗамена; 134 | КонецПроцедуры -------------------------------------------------------------------------------- /examples/plugins/Классы/РасстановкаПропущенныхТочекСЗапятой.os: -------------------------------------------------------------------------------- 1 |  2 | Перем Токены; 3 | Перем Типы; 4 | Перем ТаблицаТокенов; 5 | Перем Исходник; 6 | Перем ТаблицаЗамен; 7 | 8 | Процедура Открыть(Парсер, Параметры) Экспорт 9 | Токены = Парсер.Токены(); 10 | ТаблицаТокенов = Парсер.ТаблицаТокенов(); 11 | Исходник = Парсер.Исходник(); 12 | Типы = Парсер.Типы(); 13 | ТаблицаЗамен = Парсер.ТаблицаЗамен(); 14 | КонецПроцедуры // Открыть() 15 | 16 | Функция Закрыть() Экспорт 17 | Возврат Неопределено; 18 | КонецФункции // Закрыть() 19 | 20 | Функция Подписки() Экспорт 21 | Перем Подписки; 22 | Подписки = Новый Массив; 23 | Подписки.Добавить("ПокинутьОператоры"); 24 | Возврат Подписки; 25 | КонецФункции // Подписки() 26 | 27 | #Область РеализацияПодписок 28 | 29 | Процедура ПокинутьОператоры(Операторы) Экспорт 30 | 31 | Для Каждого Оператор Из Операторы Цикл 32 | 33 | ПоследнийТокен = Оператор.Конец; 34 | СледующийТокен = ТаблицаТокенов[Оператор.Конец.Индекс + 1]; 35 | 36 | Если СледующийТокен.Токен <> Токены.ТочкаСЗапятой И Не СтрНачинаетсяС(Оператор.Тип, "ИнструкцияПрепроцессора") Тогда 37 | 38 | Вставка(";", ПоследнийТокен.Позиция + ПоследнийТокен.Длина); 39 | 40 | КонецЕсли; 41 | 42 | КонецЦикла; 43 | 44 | КонецПроцедуры // ПокинутьОператоры() 45 | 46 | #КонецОбласти // РеализацияПодписок 47 | 48 | Процедура Вставка(Текст, Позиция) 49 | НоваяЗамена = ТаблицаЗамен.Добавить(); 50 | НоваяЗамена.Источник = "РасстановкаПропущенныхТочекСЗапятой"; 51 | НоваяЗамена.Текст = Текст; 52 | НоваяЗамена.Позиция = Позиция; 53 | НоваяЗамена.Длина = 0; 54 | КонецПроцедуры -------------------------------------------------------------------------------- /examples/plugins/Классы/РекурсивныйПодсчетСерверныхВызововВМодуляхФорм.os: -------------------------------------------------------------------------------- 1 |  2 | // Рекурсивный подсчет серверных вызовов в модулях форм. 3 | // Выводятся только случаи с количеством серверных вызовов > 1. 4 | 5 | // Вызовы других модулей не учитываются. 6 | // Вызовы типа Таблица.НайтиСтроки() не учитываются. 7 | 8 | Перем Типы; 9 | Перем Директивы; 10 | Перем Результат; 11 | 12 | Перем Вызывающий, ВызывающийНаКлиенте; 13 | Перем ТаблицаВызовов; 14 | Перем Методы; 15 | Перем Стек; 16 | 17 | Процедура Открыть(Парсер, Параметры) Экспорт 18 | Типы = Парсер.Типы(); 19 | Директивы = Парсер.Директивы(); 20 | Результат = Новый Массив; 21 | ТаблицаВызовов = Новый ТаблицаЗначений; 22 | ТаблицаВызовов.Колонки.Добавить("Вызывающий"); 23 | ТаблицаВызовов.Колонки.Добавить("НаКлиенте", Новый ОписаниеТипов("Булево")); 24 | ТаблицаВызовов.Колонки.Добавить("Метод"); 25 | ТаблицаВызовов.Колонки.Добавить("ВызовСервера", Новый ОписаниеТипов("Число")); 26 | ТаблицаВызовов.Indexes.Добавить("Метод, НаКлиенте"); 27 | Стек = Новый Соответствие; 28 | Методы = Новый Соответствие; 29 | КонецПроцедуры // Открыть() 30 | 31 | Функция Подписки() Экспорт 32 | Перем Подписки; 33 | Подписки = Новый Массив; 34 | Подписки.Добавить("ПосетитьОбъявлениеМетода"); 35 | Подписки.Добавить("ПосетитьВыражениеИдентификатор"); 36 | Возврат Подписки; 37 | КонецФункции // Подписки() 38 | 39 | Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт 40 | Вызывающий = ОбъявлениеМетода.Сигнатура; 41 | ВызывающийНаКлиенте = (Вызывающий.Директивы.Количество() > 0 И Вызывающий.Директивы[0].Директива = Директивы.НаКлиенте); 42 | КонецПроцедуры // ПосетитьОбъявлениеМетода() 43 | 44 | Процедура ПосетитьВыражениеИдентификатор(ВыражениеИдентификатор) Экспорт 45 | Перем НоваяСтрока, Метод; 46 | Если ВыражениеИдентификатор.Аргументы <> Неопределено И ВыражениеИдентификатор.Хвост.Количество() = 0 Тогда // только простые вызовы методов данного модуля 47 | Метод = ВыражениеИдентификатор.Голова.Объявление; 48 | Если Метод <> Неопределено // только известные методы 49 | И Метод.Тип <> Типы.ОбъявлениеГлобальногоМетода Тогда 50 | НоваяСтрока = ТаблицаВызовов.Добавить(); 51 | НоваяСтрока.Вызывающий = Вызывающий; 52 | НоваяСтрока.НаКлиенте = ВызывающийНаКлиенте; 53 | НоваяСтрока.Метод = Метод; 54 | Методы[Метод] = Истина; 55 | КонецЕсли; 56 | КонецЕсли; 57 | КонецПроцедуры // ПосетитьВыражениеИдентификатор() 58 | 59 | Функция Закрыть() Экспорт 60 | Для Каждого Метод Из Методы Цикл 61 | Если Метод.Ключ.Директивы.Количество() = 0 Или Метод.Ключ.Директивы[0].Директива = Директивы.НаСервере Тогда 62 | ПодсчитатьВызовыСервера(Метод.Ключ); 63 | КонецЕсли; 64 | КонецЦикла; 65 | ТаблицаВызовов.GroupBy("Вызывающий", "ВызовСервера"); 66 | Для Каждого Строка Из ТаблицаВызовов Цикл 67 | Если Строка.ВызовСервера > 1 Тогда 68 | Результат.Добавить(СтрШаблон("Метод `%1()` содержит %2 серверных вызовов", Строка.Вызывающий.Имя, Строка.ВызовСервера)); 69 | КонецЕсли; 70 | КонецЦикла; 71 | Возврат СтрСоединить(Результат, Символы.ПС); 72 | КонецФункции // Закрыть() 73 | 74 | Процедура ПодсчитатьВызовыСервера(Метод) 75 | Перем ВызовыНаКлиенте; 76 | Если Стек[Метод.Имя] <> Неопределено Тогда 77 | Возврат; 78 | КонецЕсли; 79 | Стек[Метод.Имя] = Истина; 80 | ВызовыНаКлиенте = ТаблицаВызовов.НайтиСтроки(Новый Структура("Метод, НаКлиенте", Метод, Истина)); 81 | Для Каждого Строка Из ВызовыНаКлиенте Цикл 82 | Строка.ВызовСервера = Строка.ВызовСервера + 1; 83 | ПодсчитатьВызовыСервера(Строка.Вызывающий); 84 | КонецЦикла; 85 | Стек[Метод.Имя] = Неопределено; 86 | КонецПроцедуры // ПодсчитатьВызовыСервера() 87 | -------------------------------------------------------------------------------- /examples/test.os: -------------------------------------------------------------------------------- 1 | // Пример скрипта выполняющего проверку исходного кода 2 | 3 | #Использовать osparser 4 | #Использовать "./plugins" 5 | 6 | // читаем исходный код, который хотим проверить. 7 | ЧтениеТекста = Новый ЧтениеТекста("..\src\Классы\ПарсерВстроенногоЯзыка.os"); 8 | Исходник = ЧтениеТекста.Прочитать(); 9 | ЧтениеТекста.Закрыть(); 10 | 11 | // собираем нужные плагины в массив 12 | Плагины = Новый Массив; 13 | Плагины.Добавить(Новый ДетекторНеиспользуемыхПеременных); 14 | Плагины.Добавить(Новый ДетекторОшибочныхЗамыкающихКомментариев); 15 | Плагины.Добавить(Новый ДетекторФункцийБезВозвратаВКонце); 16 | 17 | // Запуск проверки на данном исходном коде (Исходник) с желаемым набором плагинов (Плагины). 18 | Парсер = Новый ПарсерВстроенногоЯзыка; 19 | Парсер.Пуск(Исходник, Плагины); 20 | 21 | // Выводим результаты работы плагинов. 22 | Отчет = Новый Массив; 23 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 24 | Отчет.Добавить(Ошибка.Текст); 25 | Отчет.Добавить(СтрШаблон(" [стр: %1; кол: %2]", Ошибка.НомерСтрокиНачала, Ошибка.НомерКолонкиНачала)); 26 | Отчет.Добавить(Символы.ПС); 27 | КонецЦикла; 28 | Сообщить(СтрСоединить(Отчет)); -------------------------------------------------------------------------------- /examples/test2.os: -------------------------------------------------------------------------------- 1 | 2 | #Использовать osparser 3 | #Использовать "./plugins" 4 | 5 | Если АргументыКоманднойСтроки.Количество() = 0 Тогда 6 | ВызватьИсключение "Укажите в качестве параметра путь к папке с модулями os"; 7 | КонецЕсли; 8 | 9 | ПутьКМодулям = АргументыКоманднойСтроки[0]; 10 | Файлы = НайтиФайлы(ПутьКМодулям, "*.os", Истина); 11 | 12 | Парсер = Новый ПарсерВстроенногоЯзыка; 13 | 14 | Плагины = Новый Массив; 15 | Плагины.Добавить(Новый ДетекторНеиспользуемыхПеременных); 16 | Плагины.Добавить(Новый ДетекторОшибочныхЗамыкающихКомментариев); 17 | Плагины.Добавить(Новый ДетекторФункцийБезВозвратаВКонце); 18 | 19 | ЧтениеТекста = Новый ЧтениеТекста; 20 | 21 | Отчет = Новый Массив; 22 | 23 | Для Каждого Файл Из Файлы Цикл 24 | Если Файл.ЭтоФайл() Тогда 25 | ЧтениеТекста.Открыть(Файл.ПолноеИмя, "UTF-8"); 26 | Исходник = ЧтениеТекста.Прочитать(); 27 | Попытка 28 | Парсер.Пуск(Исходник, Плагины); 29 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 30 | Отчет.Добавить(Символы.ПС); 31 | Отчет.Добавить(Файл.ПолноеИмя); 32 | Отчет.Добавить(Символы.ПС); 33 | Отчет.Добавить(Ошибка.Текст); 34 | Отчет.Добавить(СтрШаблон(" [стр: %1; кол: %2]", Ошибка.НомерСтрокиНачала, Ошибка.НомерКолонкиНачала)); 35 | Отчет.Добавить(Символы.ПС); 36 | КонецЦикла; 37 | Исключение 38 | Отчет.Добавить(Символы.ПС); 39 | Отчет.Добавить(Файл.ПолноеИмя); 40 | Отчет.Добавить(Символы.ПС); 41 | Отчет.Добавить("ОШИБКА:"); 42 | Отчет.Добавить(ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); 43 | Отчет.Добавить(Символы.ПС); 44 | КонецПопытки; 45 | ЧтениеТекста.Закрыть(); 46 | КонецЕсли; 47 | КонецЦикла; 48 | 49 | ЗаписьТекста = Новый ЗаписьТекста; 50 | ЗаписьТекста.Открыть("Отчет.txt", "UTF-8"); 51 | ЗаписьТекста.Записать(СтрСоединить(Отчет)); 52 | ЗаписьТекста.Закрыть(); 53 | 54 | Сообщить("Проверка закончена. Отчет о проверке находится в файле 'Отчет.txt'"); -------------------------------------------------------------------------------- /examples/test3.os: -------------------------------------------------------------------------------- 1 | 2 | #Использовать osparser 3 | #Использовать "./backends" 4 | 5 | ЧтениеТекста = Новый ЧтениеТекста("..\src\Классы\ПарсерВстроенногоЯзыка.os"); 6 | Исходник = ЧтениеТекста.Прочитать(); 7 | 8 | Парсер = Новый ПарсерВстроенногоЯзыка; 9 | АСД = Парсер.Разобрать(Исходник); 10 | 11 | Компилятор = Новый Компилятор; 12 | Байткод = Компилятор.Посетить(Парсер, АСД); 13 | 14 | Сообщить(Байткод); -------------------------------------------------------------------------------- /examples/test4.os: -------------------------------------------------------------------------------- 1 | 2 | #Использовать osparser 3 | #Использовать "./plugins" 4 | 5 | Если АргументыКоманднойСтроки.Количество() <> 2 Тогда 6 | ВызватьИсключение "Укажите в качестве параметров список модулей bsl через ';' и имя файла отчета"; 7 | КонецЕсли; 8 | 9 | Пути = СтрРазделить(АргументыКоманднойСтроки[0], ";"); 10 | Файлы = Новый Массив; 11 | Для Каждого Путь Из Пути Цикл 12 | Файлы.Добавить(Новый Файл(Путь)); 13 | КонецЦикла; 14 | 15 | Парсер = Новый ПарсерВстроенногоЯзыка; 16 | 17 | Плагины = Новый Массив; 18 | Плагины.Добавить(Новый ДетекторОшибочныхЗамыкающихКомментариев); 19 | Плагины.Добавить(Новый ДетекторПропущенныхТочекСЗапятой); 20 | 21 | ЧтениеТекста = Новый ЧтениеТекста; 22 | 23 | Отчет = Новый Массив; 24 | 25 | Для Каждого Файл Из Файлы Цикл 26 | Если Файл.ЭтоФайл() Тогда 27 | ЧтениеТекста.Открыть(Файл.ПолноеИмя, "UTF-8"); 28 | Исходник = ЧтениеТекста.Прочитать(); 29 | Попытка 30 | Парсер.Пуск(Исходник, Плагины); 31 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 32 | Отчет.Добавить(Символы.ПС); 33 | Отчет.Добавить(Файл.ПолноеИмя); 34 | Отчет.Добавить(Символы.ПС); 35 | Отчет.Добавить(Ошибка.Текст); 36 | Отчет.Добавить(СтрШаблон(" [стр: %1; кол: %2]", Ошибка.НомерСтрокиНачала, Ошибка.НомерКолонкиНачала)); 37 | Отчет.Добавить(Символы.ПС); 38 | КонецЦикла; 39 | Исключение 40 | Отчет.Добавить(Символы.ПС); 41 | Отчет.Добавить(Файл.ПолноеИмя); 42 | Отчет.Добавить(Символы.ПС); 43 | Отчет.Добавить("ОШИБКА:"); 44 | Отчет.Добавить(ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); 45 | Отчет.Добавить(Символы.ПС); 46 | КонецПопытки; 47 | ЧтениеТекста.Закрыть(); 48 | КонецЕсли; 49 | КонецЦикла; 50 | 51 | ЗаписьТекста = Новый ЗаписьТекста(АргументыКоманднойСтроки[1], "UTF-8",, Истина); 52 | ЗаписьТекста.Записать(СтрСоединить(Отчет)); 53 | ЗаписьТекста.Закрыть(); 54 | 55 | Сообщить(СтрШаблон("Проверка закончена. Отчет о проверке находится в файле '%1'", АргументыКоманднойСтроки[1])); 56 | -------------------------------------------------------------------------------- /examples/test5.os: -------------------------------------------------------------------------------- 1 | 2 | #Использовать osparser 3 | #Использовать "./plugins" 4 | 5 | ЧтениеТекста = Новый ЧтениеТекста("..\src\Классы\ПарсерВстроенногоЯзыка.os"); 6 | Исходник = ЧтениеТекста.Прочитать(); 7 | ЧтениеТекста.Закрыть(); 8 | 9 | Плагины = Новый Массив; 10 | Плагины.Добавить(Новый ДетекторНеиспользуемыхПеременных); 11 | 12 | ПараметрыПлагинов = Новый Соответствие; 13 | 14 | Парсер = Новый ПарсерВстроенногоЯзыка; 15 | Узлы = Парсер.Узлы(); 16 | 17 | ПроизвольноеОкружение = Парсер.Окружение(); 18 | 19 | // например, контекст формы: 20 | Элемент = Узлы.ЭлементОкружения.Добавить(); 21 | Элемент.Имя = "ЭтаФорма"; 22 | ПроизвольноеОкружение.Переменные.Вставить("ЭтаФорма", Элемент); 23 | // ... 24 | Элемент = Узлы.ЭлементОкружения.Добавить(); 25 | Элемент.Имя = "РеквизитФормыВЗначение"; 26 | ПроизвольноеОкружение.Методы.Вставить("РеквизитФормыВЗначение", Элемент); 27 | // ... 28 | 29 | Парсер.Пуск(Исходник, Плагины, ПараметрыПлагинов, ПроизвольноеОкружение); 30 | 31 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 32 | Сообщить(Ошибка.Текст) 33 | КонецЦикла; -------------------------------------------------------------------------------- /examples/test6.os: -------------------------------------------------------------------------------- 1 | // пример работы с параметрами плагинов 2 | 3 | #Использовать osparser 4 | #Использовать "./plugins" 5 | 6 | Исходник = "x = 1;"; 7 | 8 | ПлагинСПараметром = Новый ПлагинСПараметром; 9 | 10 | Плагины = Новый Массив; 11 | Плагины.Добавить(ПлагинСПараметром); 12 | 13 | ЧтениеJSON = Новый ЧтениеJSON; 14 | ЧтениеJSON.ОткрытьФайл(".\param.json", "UTF-8"); 15 | ПараметрыПлагина = ПрочитатьJSON(ЧтениеJSON); 16 | 17 | ПараметрыПлагинов = Новый Соответствие; 18 | ПараметрыПлагинов[ПлагинСПараметром] = ПараметрыПлагина; 19 | 20 | Парсер = Новый ПарсерВстроенногоЯзыка; 21 | 22 | Результаты = Парсер.Пуск(Исходник, Плагины, ПараметрыПлагинов); 23 | Сообщить(СтрСоединить(Результаты)); 24 | -------------------------------------------------------------------------------- /examples/test7.os: -------------------------------------------------------------------------------- 1 | // Пример формирования отчета в формате Generic Issue Data для sonarqube 2 | // https://docs.sonarqube.org/latest/analysis/generic-issue/ 3 | 4 | #Использовать osparser 5 | #Использовать "./plugins" 6 | 7 | ПутьИсходника = "C:\dev\sonarqube\myprj\src\CommonModules\CommonUse\Ext\Module.bsl"; 8 | ПутьОтчета = "C:\dev\sonarqube\myprj\bsl-generic-json.json"; 9 | 10 | ЧтениеТекста = Новый ЧтениеТекста(ПутьИсходника); 11 | Исходник = ЧтениеТекста.Прочитать(); 12 | ЧтениеТекста.Закрыть(); 13 | 14 | Плагины = Новый Массив; 15 | Плагины.Добавить(Новый ДетекторНеиспользуемыхПеременных); 16 | Плагины.Добавить(Новый ДетекторОшибочныхЗамыкающихКомментариев); 17 | Плагины.Добавить(Новый ДетекторФункцийБезВозвратаВКонце); 18 | Плагины.Добавить(Новый ДетекторПропущенныхТочекСЗапятой); 19 | Плагины.Добавить(Новый ПроверкаКаноничностиКлючевыхСлов); 20 | 21 | Парсер = Новый ПарсерВстроенногоЯзыка; 22 | Парсер.Пуск(Исходник, Плагины); 23 | 24 | Проблемы = Новый Массив; 25 | 26 | Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл 27 | 28 | Диапазон = Новый Структура; 29 | Диапазон.Вставить("startLine", Ошибка.НомерСтрокиНачала); 30 | Диапазон.Вставить("endLine", Ошибка.НомерСтрокиКонца); 31 | Диапазон.Вставить("startColumn", Ошибка.НомерКолонкиНачала - 1); 32 | Диапазон.Вставить("endColumn", Ошибка.НомерКолонкиКонца - 1); 33 | 34 | Место = Новый Структура; 35 | Место.Вставить("message", Ошибка.Текст); 36 | Место.Вставить("filePath", ПутьИсходника); 37 | Место.Вставить("textRange", Диапазон); 38 | 39 | Проблема = Новый Структура; 40 | Проблема.Вставить("engineId", "osparser"); 41 | Проблема.Вставить("ruleId", Ошибка.Источник); // Ошибка.Правило 42 | Проблема.Вставить("severity", "INFO"); // Ошибка.Серьезность 43 | Проблема.Вставить("type", "CODE_SMELL"); // Ошибка.Тип 44 | Проблема.Вставить("primaryLocation", Место); 45 | Проблема.Вставить("effortMinutes", 5); // Ошибка.МинутНаИсправление 46 | Проблемы.Добавить(Проблема); 47 | 48 | КонецЦикла; 49 | 50 | Отчет = Новый Структура("issues", Проблемы); 51 | 52 | ЗаписьJSON = Новый ЗаписьJSON; 53 | 54 | ЗаписьJSON.ОткрытьФайл(ПутьОтчета, "UTF-8",, Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Unix)); 55 | ЗаписатьJSON(ЗаписьJSON, Отчет); 56 | ЗаписьJSON.Закрыть() 57 | 58 | // ЗаписьJSON.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Unix)); 59 | // Сообщить(ЗаписьJSON.Закрыть()); -------------------------------------------------------------------------------- /examples/test8.os: -------------------------------------------------------------------------------- 1 | // Пример автоматического исправления ошибок. 2 | // Данный скрипт расставляет пропущенные точки с запятой в исходниках в указанной папке. 3 | // Плюс заменяет ключевые слова, написанные не по канону (титульный регистр). 4 | 5 | #Использовать osparser 6 | #Использовать "./plugins" 7 | 8 | Если АргументыКоманднойСтроки.Количество() = 0 Тогда 9 | ВызватьИсключение "Укажите в качестве параметра путь к папке с модулями bsl"; 10 | КонецЕсли; 11 | 12 | ПутьКМодулям = АргументыКоманднойСтроки[0]; 13 | Файлы = НайтиФайлы(ПутьКМодулям, "*.bsl", Истина); 14 | 15 | Парсер = Новый ПарсерВстроенногоЯзыка; 16 | 17 | Плагины = Новый Массив; 18 | Плагины.Добавить(Новый РасстановкаПропущенныхТочекСЗапятой); 19 | Плагины.Добавить(Новый ЗаменаНеканоничныхКлючевыхСлов); 20 | 21 | ЧтениеТекста = Новый ЧтениеТекста; 22 | 23 | Отчет = Новый Массив; 24 | 25 | Количество = 0; 26 | 27 | Для Каждого Файл Из Файлы Цикл 28 | Если Файл.ЭтоФайл() Тогда 29 | ЧтениеТекста.Открыть(Файл.ПолноеИмя, "UTF-8"); 30 | Исходник = ЧтениеТекста.Прочитать(); 31 | ЧтениеТекста.Закрыть(); 32 | Попытка 33 | Парсер.Пуск(Исходник, Плагины); 34 | ИсправленныйИсходник = Парсер.ВыполнитьЗамены(); 35 | Если ИсправленныйИсходник <> Неопределено Тогда 36 | ЗаписьТекста = Новый ЗаписьТекста; 37 | ЗаписьТекста.Открыть(Файл.ПолноеИмя, "UTF-8"); 38 | ЗаписьТекста.Записать(ИсправленныйИсходник); 39 | ЗаписьТекста.Закрыть(); 40 | Количество = Количество + 1; 41 | КонецЕсли; 42 | Исключение 43 | Сообщить(ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); 44 | КонецПопытки; 45 | КонецЕсли; 46 | КонецЦикла; 47 | 48 | Сообщить(СтрШаблон("Исправлено %1 исходников", Количество)); -------------------------------------------------------------------------------- /examples/test9.os: -------------------------------------------------------------------------------- 1 | // Нагрузочный тест. 2 | // Сравнение общего времени анализа на одном плагине и на сотне. 3 | // ожидаемый результат: 4 | // ДетекторНеиспользуемыхПеременных - 100 плагинов в 10 раз дольше чем один 5 | // ДетекторОшибочныхЗамыкающихКомментариев - 100 плагинов в 2 раза дольше чем один 6 | 7 | #Использовать osparser 8 | #Использовать "./plugins" 9 | 10 | ИмяПлагина = "ДетекторОшибочныхЗамыкающихКомментариев"; 11 | 12 | КоличествоПлагинов = 100; 13 | 14 | Если АргументыКоманднойСтроки.Количество() = 0 Тогда 15 | ВызватьИсключение "Укажите в качестве параметра путь к папке с общими модулями bsl"; 16 | КонецЕсли; 17 | 18 | Сообщить("Тест плагина: " + ИмяПлагина); 19 | 20 | ПутьКМодулям = АргументыКоманднойСтроки[0]; 21 | Файлы = НайтиФайлы(ПутьКМодулям, "*.bsl", Истина); 22 | 23 | // ------------------------------------------------------------------------------------------------ 24 | 25 | Старт = ТекущаяУниверсальнаяДатаВМиллисекундах(); 26 | 27 | Парсер = Новый ПарсерВстроенногоЯзыка; 28 | 29 | Плагин = Новый(ИмяПлагина); 30 | 31 | ЧтениеТекста = Новый ЧтениеТекста; 32 | Отчет = Новый Массив; 33 | Для Каждого Файл Из Файлы Цикл 34 | Если Файл.ЭтоФайл() Тогда 35 | ЧтениеТекста.Открыть(Файл.ПолноеИмя, "UTF-8"); 36 | Исходник = ЧтениеТекста.Прочитать(); 37 | Попытка 38 | Парсер.Пуск(Исходник, Плагин); 39 | Исключение 40 | КонецПопытки; 41 | ЧтениеТекста.Закрыть(); 42 | КонецЕсли; 43 | КонецЦикла; 44 | 45 | Финиш = ТекущаяУниверсальнаяДатаВМиллисекундах() - Старт; 46 | 47 | Сообщить(СтрШаблон("Время 1 плагина: %1 сек", Финиш / 1000)); 48 | 49 | // ------------------------------------------------------------------------------------------------ 50 | 51 | Старт = ТекущаяУниверсальнаяДатаВМиллисекундах(); 52 | 53 | Парсер = Новый ПарсерВстроенногоЯзыка; 54 | 55 | Плагины = Новый Массив; 56 | Для Индекс = 1 По КоличествоПлагинов Цикл 57 | Плагины.Добавить(Новый(ИмяПлагина)); 58 | КонецЦикла; 59 | 60 | ЧтениеТекста = Новый ЧтениеТекста; 61 | Отчет = Новый Массив; 62 | Для Каждого Файл Из Файлы Цикл 63 | Если Файл.ЭтоФайл() Тогда 64 | ЧтениеТекста.Открыть(Файл.ПолноеИмя, "UTF-8"); 65 | Исходник = ЧтениеТекста.Прочитать(); 66 | Попытка 67 | Парсер.Пуск(Исходник, Плагины); 68 | Исключение 69 | КонецПопытки; 70 | ЧтениеТекста.Закрыть(); 71 | КонецЕсли; 72 | КонецЦикла; 73 | 74 | Финиш = ТекущаяУниверсальнаяДатаВМиллисекундах() - Старт; 75 | 76 | Сообщить(СтрШаблон("Время %1 плагинов: %2 сек", КоличествоПлагинов, Финиш / 1000)); 77 | -------------------------------------------------------------------------------- /packagedef: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////// 2 | // Описание пакета для сборки и установки 3 | // Полную документацию см. на hub.oscript.io/packaging 4 | 5 | Описание.Имя("osparser") 6 | .Версия("0.0.3") 7 | .ВерсияСреды("1.0.21") 8 | .ВключитьФайл("src") 9 | .ВключитьФайл("examples") 10 | .ВключитьФайл("docs") 11 | .ОпределяетКласс("ПарсерВстроенногоЯзыка", "src/Классы/ПарсерВстроенногоЯзыка.os") 12 | .ВключитьФайл("README.md") 13 | .ВключитьФайл("LICENSE") --------------------------------------------------------------------------------