Skip to content

Repository files navigation

osparser (oscript parser)

Парсер встроенного языка платформы 1С:Предприятие 8 и OneScript

Документация: Книга Джедая

Установка: opm install osparser

Самый короткий пример без плагинов:

#Использовать osparser

Парсер = Новый ПарсерВстроенногоЯзыка;
АСД = Парсер.Разобрать("x = x + 1;");
Сообщить(АСД.Операторы.Количество());

Содержание

  1. Введение
  2. Синтаксис OneScript
  3. Структура репозитория
  4. Принцип работы
  5. Разработка
  6. Благодарности

Введение

Перед тем как разбираться с этим проектом, убедитесь что вы хорошо понимаете что такое AST и Visitor и что можно с их помощью делать. Это важно, так как данная разработка предоставляет именно эти возможности. Не больше не меньше. Вы можете писать проверки кода, компиляторы, интерпретаторы и любые другие вещи, которые можно реализовать путем обработки AST. Сколько информации содержит AST можно увидеть тут: https://oscript-library.github.io/osparser

Общее представление можно получить в этой статье: Зачем нужен AST

Данная разработка устроена похожим образом. С поправкой на то, что это реализация без ООП на языке 1С. После ознакомления со статьей можно сразу посмотреть Принцип работы внизу этой страницы.

По сути это фронтенд компилятора, а вы можете к нему писать бакенды (плагины).

Пример плагина проверяющего наличие возврата в конце функций: ДетекторФункцийБезВозвратаВКонце

Конкретно весь код проверки выглядит так (остальное там просто интерфейс плагина):

Процедура ПосетитьОбъявлениеМетода(ОбъявлениеМетода) Экспорт
    Перем КоличествоОператоров;
    Если ОбъявлениеМетода.Сигнатура.Тип <> Типы.ОбъявлениеСигнатурыФункции Тогда
        Возврат;
    КонецЕсли;
    КоличествоОператоров = ОбъявлениеМетода.Операторы.Количество();
    Если КоличествоОператоров = 0 Или ОбъявлениеМетода.Операторы[КоличествоОператоров - 1].Тип <> Типы.ОператорВозврат Тогда
        Текст = СтрШаблон("Последней инструкцией функции `%1()` должен быть `Возврат`""", ОбъявлениеМетода.Сигнатура.Имя);
        Ошибка(Текст, ОбъявлениеМетода.Конец);
    КонецЕсли;
КонецПроцедуры

Эта процедура вызывается визитером (Visitor) во время обхода AST для каждой встреченной процедуры или функции. Суть реализации проверки: Сначала проверяется что это функция. Затем берется количество операторов в теле функции. Если 0 или последний оператор не Возврат, то регистрируется ошибка.

Пример плагина средней сложности: ДетекторНеиспользуемыхПеременных (этот код находит неиспользуемые переменные и параметры)

Пример сложного бакенда: Компилятор (это генератор байткода, который работает идентично платформенному)

Пример на OneScript, демонстрирующий прогон проверок исходного кода: test.os

Пример на OneScript, демонстрирующий автоматическое исправление исходного кода: test8.os

Пример выгрузки ошибок в SonarQube: test7.os

Синтаксис OneScript

Помимо встроенного языка 1С:Предприятие парсер разбирает конструкции, которые есть только в OneScript.

Аннотации с произвольным именем. Имя аннотации не ограничено списком аннотаций 1С:Предприятие, поддерживаются позиционные и именованные параметры, вложенные аннотации и аннотации параметров метода:

&Деталька("OneUnit.Таймаут", ЗначениеПоУмолчанию = 500)
&Напильник(ПрименяетсяТолькоНа = &Прозвище("Желудь"))
Процедура ПриСозданииОбъекта(&Пластилин Сервис, Знач Обычный = 1)

Аннотация хранится в узле ОбъявлениеАннотации: Имя - имя аннотации, Параметры - массив узлов ПараметрАннотации, у каждого есть Имя (пустое у позиционного), Значение (узел-выражение) и Литерал - готовое значение, если параметр задан константой. Для аннотаций 1С:Предприятие по-прежнему заполняются поля Аннотация и ИмяМетода.

Асинхронные методы. Признак асинхронности метода доступен в поле Асинхронный его сигнатуры, ожидание результата разбирается в узлы ВыражениеЖдать и ОператорЖдать:

Асинх Функция Прочитать()
    Возврат Ждать ПолучитьДанные();
КонецФункции

Имена библиотек с дефисами и слэшами в инструкции #Использовать:

#Использовать autumn-collections
#Использовать oint/api/grpc

Директивы режима выполнения #Native и #Stack разбираются в узел ИнструкцияПрепроцессораРежимВыполнения с полем Режим, а строка запуска скрипта (#!/usr/bin/env oscript) пропускается как не относящаяся к коду модуля.

Обращение к членам результата выражения - скобочного и созданного объекта:

ПолноеИмя = (Новый Файл(Путь)).ПолноеИмя;
Если Новый Рефлектор.МетодСуществует(Объект, "Имя") Тогда

Структура репозитория

  • /docs - файлы веб-страницы проекта https://oscript-library.github.io/osparser
  • /examples - примеры
  • /src - исходники парсера
  • /docgen.os - скрипт, генерирующий документацию в папке /docs

Принцип работы

Парсер разбирает переданный ему исходный код и возвращает модель этого кода в виде абстрактного синтаксического дерева. Узлы этого дерева соответствуют синтаксическим конструкциям и операторам языка. Например, конструкция Пока <условие> Цикл <тело> КонецЦикла представлена в дереве узлами типа ОператорПока, в которых условие представлено в подчиненном узле-выражении Выражение, а тело хранится в массиве узлов-операторов Операторы. Данных в дереве достаточно для полного восстановления по нему исходного кода вместе с комментариями, за исключением некоторых деталей форматирования. Порядок и подчиненность узлов в дереве в точности соответствует исходному коду. Описание узлов и элементов дерева вы можете найти на веб-странице проекта: https://oscript-library.github.io/osparser

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

Состояние плагина (в переменных модуля) сохраняется между вызовами до самого конца обхода дерева, а подписки на каждый узел возможны две: перед обходом узла и после обхода. Это существенно упрощает реализацию многих алгоритмов анализа. Плюс к этому, некоторую информацию предоставляет сам механизм обхода. Например, плагинам доступна статистика по родительским узлам (количество каждого вида).

Разработка

Установка окружения и запуск тестов:

opm install -l oneunit
./oscript_modules/bin/oneunit e -d tests

Благодарности

Спасибо всем кто так или иначе повлиял на этот проект.

About

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

Resources

Contributing

Stars

25 stars

Watchers

5 watching

Forks

Releases

Packages

Contributors

Languages