Skip to content

Пётр Советов — В Python есть готовый фронтенд для вашего компилятора

Доклад Петра Советова о готовом фронтенде для компилятора на Python с примерами и использованием модуля AST и сопоставления с образцом.

Ask about this video. Answers come from its transcript only — with the timestamp, so you can check them.

Generated from the transcript and can be wrong — check the timestamp.

Key Takeaways

  • Компиляторные технологии применимы не только в создании языков программирования, но и в различных инструментах.
  • Python предоставляет удобные средства для работы с AST и сопоставлением с образцом, упрощающие разработку компиляторов и DSL.
  • Примеры доклада показывают, что создание компилятора или анализатора может занимать менее 100 строк кода.
  • Использование модуля AST и новых конструкций Python позволяет писать выразительный и компактный код для трансляции и анализа.
  • Понимание архитектуры компилятора (frontend и backend) помогает лучше проектировать инструменты трансляции и конвертации.

What the video covers

  • Пётр Советов рассказывает, что написание компиляторов — не узкоспециализированная задача и компиляторные технологии применяются широко.
  • Приводится пример инструмента Pandoc, который по архитектуре похож на компилятор и даже на LLVM.
  • Объясняется роль frontend и backend в компиляторах на примере трансляции форматов и оптимизаций.
  • Доклад посвящён использованию модуля AST из стандартной библиотеки Python и конструкции сопоставления с образцом из Python 3.10.
  • Показаны примеры создания DSL, компиляторов, визуализаторов и статического анализатора на Python с минимальным количеством кода.
  • Обсуждается сравнение с классическим паттерном Visitor и преимущества нового подхода.
  • Демонстрируются примеры кода с использованием датаклассов и типизированных именованных кортежей для построения AST.
  • Поясняется, как можно получить и обрабатывать AST с помощью стандартных средств Python.
  • Рассматривается предметно-ориентированный язык для описания графов и его трансляция в язык Dot.
  • Приводится пример статического анализа для поиска неиспользуемых переменных.

Answers

Questions about this video

Что такое frontend и backend в контексте компилятора?

Frontend — это стадия трансляции внешнего входного языка во внутреннее представление (AST), а backend — этап трансляции из промежуточного представления в выходной язык или формат.

Как Python помогает в создании компиляторов и DSL?

Python предоставляет модуль AST для работы с абстрактным синтаксическим деревом и конструкцию сопоставления с образцом (с версии 3.10), что упрощает написание компиляторов и анализаторов.

Можно ли создавать компиляторы на Python с небольшим количеством кода?

Да, в докладе показано, что примеры компиляторов, визуализаторов и анализаторов занимают менее 100 строк кода, что делает процесс доступным и компактным.

Full Transcript — Download SRT & Markdown

00:00
Speaker A
[музыка] Итак, всем привет на новом докладе. Привет всем, кто нас смотрит в онлайне, а всех, кто у нас в оффлайне, настоятельно прошу зайти в первый зал. Если вы хотели послушать доклад Петра, будет интересно, будет очень насыщенно. Мы начнём прямо вот сразу, поэтому, пожалуйста, не задерживайтесь, проходите в зал соответственно. Разрешите представить Петра Советова, это наш преподаватель РТО мира, человек, который интересуется компиляторами, не только ими интересуется, пишет их, но и может заинтересовать других. Собственно, сегодня будет как раз доклад о том, что на самом деле написание компиляторов — это не какая-то специфическая задача, которую решают только люди, которые пишут свой Python или свой C++.
00:27
Speaker A
вот сразу поэтому пожалуйста не задерживай проходите В зал соответственно Разрешите представить Пётр Советов это нас преподаватель РТО мира человек который интересуется компилятора не только ими интересуется пишет их но и может заинтересовать других собственно сегодня будет Как раз доклад о том что на самом деле написание
00:47
Speaker A
Что я такое наме? Поэтому давайте приходите, входите в зал, и я, собственно, ухожу, передаю слово Петру. Но перед этим напоминаю, что у нас есть QR-код на доклад, всегда обязательно оставляйте, пожалуйста, фидбэк нам, это очень важно. Мы готовимся, спикеры готовятся, и очень хотелось бы услышать вашу обратную связь: что понравилось, не понравилось, что было непонятно, скажем так. Напоминаю, что после доклада у нас будет дискуссионная зона, я ещё раз об этом скажу, но если что, спикер не выходит через главный вход, а выходит через специальный путь. Поэтому просто приходите сразу в дискуссионную зону налево из зала. Всё, теперь слово передаю Петру. Большое спасибо и давайте немножечко аплодисментов, пожалуйста.
01:05
Speaker A
есть QR код на доклад всегда Обязательно оставляйте пожалуйста фидбэк нам это очень важно мы готовимся спикеры готовятся и очень хотелось бы услышать вашу обратную связь что понравилось не понравилось что было непонятно скажем так Напоминаю что после доклада у нас
01:23
Speaker A
Спасибо, спасибо, Юля. Добрый день всем. Ну что ж, без лишних предисловий я начинаю. И на самом деле Юлия уже начала доклад в принципе и без меня, то есть действительно первый вопрос, которым я хотел бы задаться, — это: компиляторы пишут только какие-то особенные, немногие? Наверно, всё-таки это не так. Компиляторы пишут многие, и даже более того, компиляторные технологии используют многие, и даже иногда сами того не зная, не ожидая.
01:37
Speaker A
немножечко аплодисментов Пожалуйста Спасибо Спасибо Юля Добрый день всем Ну что ж без лишних предисловий Я начинаю И на самом деле Юлия уже начала доклад в принципе и без меня то есть действительно первый вопрос который котором я хотел бы задаться и то
01:56
Speaker A
Ну вот конкретнее: предметно-ориентированные языки их гораздо больше, чем языков общего назначения. Их нужно создавать, кто-то этим занимается. По-английски это DSL, Domain-Specific Languages, различные инструменты, анализаторы всех мастей — всё это нужно разрабатывать. И на самом деле компиляторные технологии можно встретить далеко не только в компиляторах и около компиляторных инструментах.
02:17
Speaker A
чем языков общего назначения их нужно создавать кто-то этим занимается по-английски это DSL D комп ноже различные инструмен виу ко анализаторы всех мастей всё это нужно разрабатывать и на самом деле компилятор нае технологии можно встретить далеко не только в компилятора и около компилятор
02:40
Speaker A
Вот такой пример: инструмент Pandoc. Он вообще никак не связан с компиляторами, это утилита для конвертации текстовых форматов из одного в другой. Но если посмотреть на его архитектуру, вообще-то это очень похоже на компилятор. Я даже больше скажу, это похоже не просто на компилятор, это похоже на популярнейший компиляторный фреймворк, который называется LLVM.
02:58
Speaker A
похоже не просто на компилятор это похоже на популярнейший компилятор фреймворк который называется lvm то есть здесь у нас есть многоязычия вились ещё задолго до веб-разработке так вот frontend - это стадия трансляции какого-то внешнего входного языка в язык внутренний
03:25
Speaker A
То есть здесь у нас есть многоязычие, оно было ещё задолго до веб-разработки. Так вот, frontend — это стадия трансляции какого-то внешнего входного языка во внутреннее представление. То есть у нас есть на входе, положим, какие-то текстовые форматы, и мы переводим этот текст в соответствующем формате в какое-то внутреннее представление. В случае Pandoc — это AST, то есть дерево абстрактного синтаксиса, мы абстрагируемся, то есть убрали все несущественные для нас детали конкретного формата.
03:45
Speaker A
несущественные для нас детали конкретного формата далее происходит ряд преобразований компилятор Обычно говорят что это ряд оптимизируют backend А backend в случае компилятора - это этап трансляции из промежуточного представления в какой-то из выходных языков выходных форматов то есть вот пожалуйста пандок Казалось бы
04:06
Speaker A
Далее происходит ряд преобразований. Обычно говорят, что это ряд оптимизаций backend. А backend в случае компилятора — это этап трансляции из промежуточного представления в какой-то из выходных языков, выходных форматов. То есть вот, пожалуйста, Pandoc. Казалось бы, по сути, не компилятор, но с точки зрения своего устройства вполне себе похож на компилятор.
04:26
Speaker A
сопоставление с образцом это недавно появившаяся конструкция а насколько я помню Она появилась в питоне 310 и на мой взгляд она очень-очень удобна и часто просто люди не знают как её применить хорошо а рассмотрим мы этот подход на примерах исключительно на
04:43
Speaker A
Ну и о чём сегодня пойдёт речь? Я хочу рассказать вам о подходе, который основан на использовании модуля AST из стандартной библиотеки Python, а также использовании конструкции, то есть сопоставления с образцом. Это недавно появившаяся конструкция, насколько я помню, она появилась в Python 3.10, и на мой взгляд, она очень-очень удобна и часто просто люди не знают, как её применить хорошо.
04:58
Speaker A
ссылку в конце на репозиторий Вы сами можете в этом убедиться Ну и вс-таки перечислю некоторые плюсы этого подхода Ну Как перечислю Я просто хочу отметить что если мы рассматриваем этот подход в сравнении с например построением внешнего DSL то есть для которого мы
05:14
Speaker A
А рассмотрим мы этот подход на примерах, исключительно на примерах, то есть сухой теории я вам давать не буду. А примеры — это какие? DSL, компиляторы, визуализаторы и даже один статический анализатор. И важно, что каждый из этих примеров в реальности занимает не более 100 строк кода, и я дам ссылку в конце на репозиторий. Вы сами можете в этом убедиться.
05:32
Speaker A
выразительный синтаксис и так далее и тому подобное Но вам совершенно не нужно верить на слово Давайте ВС это рассмотрим на примерах и первый пример такой совсем-совсем вводный чтобы показать Зачем в принципе может понадобиться конструкция мы сравним её с классическим
05:50
Speaker A
Ну и всё-таки перечислю некоторые плюсы этого подхода. Ну как перечислю? Я просто хочу отметить, что если мы рассматриваем этот подход в сравнении, например, с построением внешнего DSL, то есть для которого мы пишем свой компилятор и так далее, есть определённые плюсы, например, бесплатный синтаксический разбор.
06:13
Speaker A
использую дата классы как сейчас это принято а справа всего лишь небольшая небольшое количество именованных кортежей собственно что здесь есть здесь есть базовый класс есть у нас числа дамен есть сложение и умножение больше ничего нет из этих вот классов мы можем строить объекты и
06:37
Speaker A
Если мы рассматриваем этот подход в сравнении с внутренними лямбдами, которые обычно реализуются внутри, например, Python, то есть, например, вы используете перегрузку __t__, тоже есть свои плюсы, например, выразительный синтаксис и так далее и тому подобное. Но вам совершенно не нужно верить на слово, давайте всё это рассмотрим на примерах.
06:54
Speaker A
обект какого-то из вариантов нашего выражения мы сделаем следующее мы получим строковой тип этого выражения то есть его класс соединим его с префиксом визит подчёркивания таким образом получим название метода который обрабатывает этот самый АСТ вариант это не то что я сейчас
07:18
Speaker A
И первый пример такой совсем-совсем вводный, чтобы показать, зачем в принципе может понадобиться конструкция. Мы сравним её с классическим шаблоном проектирования под названием визитор или Посетитель. Вот, положим, есть задача абстрактного синтаксиса простого арифметического выражения.
07:32
Speaker A
принято А теперь конкретное задачи Давайте попробуем что-нибудь сделать с этим а положим У нас есть задача форматирования кода например по какому-то стилю ну здесь совсем Всё просто то есть Я создаю дерево вот я использую конструкторы соответствующих классов Да ал тут у меня получается x x
07:51
Speaker A
Что у нас есть? Вот то, что слева — это классический ООП-вариант реализации. То есть у нас тут классы, наследование, и, конечно же, я использую датаклассы, как сейчас это принято. А справа — всего лишь небольшое количество именованных кортежей.
08:09
Speaker A
сопоставление с образцом что видно слева да в принципе всё достаточно просто вот мы рекурсивно обходим аргументы а потом форматируем соответствующие строчки что видно справа во-первых у нас появились вот эти вот самые случаи в них шаблоны различные например первый кейс Да это нам вал да то есть
08:31
Speaker A
Собственно, что здесь есть? Здесь есть базовый класс, есть у нас числа, домен, есть сложение и умножение, больше ничего нет. Из этих вот классов мы можем строить объекты и компоновать их, получать какие-то сложные выражения. А, ну конечно же, если мы работаем с посетителями, нам нужна ещё одна интересная конструкция.
08:48
Speaker A
реализовывать альтернативы здесь я два случая объединил в один То есть числа и переменные у меня обрабатывается единообразно Ну возможно вас такой пример не до конца убедил давайте рассмотрим другую задачу более сложную упрощение кода то что в принципе нужно и
09:04
Speaker A
Вот я тут задал класс базовый Посетитель и метод visit. Зачем он нужен? Когда мы на вход будем принимать объект какого-то из вариантов нашего выражения, мы сделаем следующее: мы получим строковой тип этого выражения, то есть его класс, соединим его с префиксом visit_ — таким образом получим название метода, который обрабатывает этот самый AST вариант.
09:17
Speaker A
у нас должны присутствовать И вот я добавил simplify Visit который упрощает выражение насколько это сложно реализовать Вот давайте посмотрим опять же слева о варин стало конечно заметно больше Ну вот он из instance конечно необходимая конструкция В таких случаях
09:36
Speaker A
Это не то, что я сейчас придумал, да, это абсолютно классическая вещь, и более того, в Python это считается идиоматическим подходом. Хотя в других языках, где тоже используются посетители, кто-то может сказать, что это немного странно, что тут какие-то строки складываем, но опять же, в Python так принято.
09:54
Speaker A
Обратите внимание насколько то есть первые два случая Это всего лишь вычисление констант А вот предпоследний случай здесь я буквально говорю что если у нас есть сложение 0 П x либо x П 0 Я возвращаю X тоже самое с умножением в
10:12
Speaker A
А теперь конкретная задача. Давайте попробуем что-нибудь сделать с этим. Положим, у нас есть задача форматирования кода, например, по какому-то стилю. Ну здесь совсем всё просто, то есть я создаю дерево, вот я использую конструкторы соответствующих классов. Да, ал тут у меня получается x, x2, p, y, у4, и я вызываю format_visit, который мне форматирует, расставляет скобки, даже, наверное, избыточно расставляет, но тем не менее.
10:30
Speaker A
сделать я мог бы использовать не просто именованный кортеж а типизированный его вариант вот я его использовал определил соответствующие классы и Обратите внимание последняя строчка я её выделил это то самое определение типа суммы То есть экп - это либо число либо
10:48
Speaker A
Вот, пожалуйста, результат в текстовом формате. Насколько сложно это реализовать? Вот давайте сравним реализации: слева, как всегда, ООП, справа — сопоставление с образцом. Что видно слева? Да, в принципе, всё достаточно просто, вот мы рекурсивно обходим аргументы, а потом форматируем соответствующие строчки.
11:12
Speaker A
добавил типы и в общем-то случаи различные тут достаточно простые То есть я сначала обрабатываю аргументы рекурсивно помещают и далее Вставляю какую-то операцию за ними уже без аргументов это классический вот этот вот постфиксный Да вариант обратная польская запись и тут есть ещё интересный момент в самом
11:36
Speaker A
Что видно справа? Во-первых, у нас появились вот эти вот самые случаи, в них шаблоны различные, например, первый кейс — да, это нам вал, то есть нам даже не пришлось заходить в поле, какое там есть. Вот в этом объекте класса у нас вал — переменная, которая сразу же сопоставляется с соответствующим полем нашего объекта.
11:55
Speaker A
забыл упомянуть какой-то из вариантов моего типа экспорт допустим забыл обработать Вар так вот э статический анализатор Может этот момент отловить ещё на этапе компиляции Вот это хорошо это очень хорошо но мы это использовать сегодня не будем Я сегодня обойдусь
12:11
Speaker A
Плюс ещё можно отметить, что у нас появилась вертикальная палочка, которая позволяет реализовывать альтернативы. Здесь я два случая объединил в один, то есть числа и переменные у меня обрабатываются единообразно.
12:28
Speaker A
знают Вот посмотрите тут целый список библиотек согласитесь достаточно известны библиотеки и каждый из этих библиотек использует в том или ином виде да тем или иным образом эту самую АСТ этот самый модуль АСТ А что он собой представляет если посмотреть на код
12:48
Speaker A
Ну, возможно, вас такой пример не до конца убедил. Давайте рассмотрим другую задачу, более сложную — упрощение кода, то, что в принципе нужно и в компиляторах, и в разных других областях. Не знаю, может быть, мы сделаем свой аналог в альгебраической математике или что-нибудь подобное.
13:09
Speaker A
ссылке указанной на слайде Ну тогда возникает вопрос а что что же тогда есть в этом модуле а а есть там функции для преобразования например исходного текста в АСТ и для обратного преобразования а Но ещё там конечно же есть вот эти вот
13:24
Speaker A
Так вот, упрощение y + 0 — да, это явно должно быть y, или 0 + x — это должно быть x, то есть такие правила у нас должны присутствовать. И вот я добавил simplify_visit, который упрощает выражение. Насколько это сложно реализовать? Вот давайте посмотрим, опять же, слева вариант стал, конечно, заметно больше. Ну вот он из inst...
13:42
Speaker A
пользовать использовать Нет мы это использовать Категорически не будем Потому что у нас есть сопоставление с образцом но Давайте по порядку самое первое что видимо потребуется Как получить вообще а представление какой-то функции Ну во-первых можно обратиться к модулю ик и вызвать функцию Get Source и
14:01
Speaker A
мы получили текст функции исходной А дальше мы можем вызвать функцию пас у модуля ST и получить наконец самост Кстати тут написано ST тока модуль это то что выдало наше дерево любая программа которая собственно говоря является результатом пас Да в формате
14:19
Speaker A
АСТ уже в виде А в самом на самом верхнем уровне является модули Ну вот с этим приходится считаться А как идти куда-то вглубь по дереву добраться до нужных каких-то данных или до нужного кода а для этого ну в принципе можно
14:36
Speaker A
посмотреть грамматику и оказывается что у каждого класса АСТ есть свой набор полей они по-разному называются и часто это очень неудобно Почему неудобно потому что у нас может быть функция которая хочет обойти всё дерево а Для этого нам нужно знать точно Какие где
14:53
Speaker A
поля Мы просто хотим найти какой-то конкретный объект Но вот приходится знать всё на самом деле не обязательно потому что есть специальное поле подчёркивания Fields которое выдаёт нам те в свою очередь поля которые реально присутствует в нашем объекте то есть вот
15:09
Speaker A
здесь вот мне выдал тто Fields Body плюс ещё что-то про типы Если я пойду по телу Да я попадаю в список который состоит из одного элемента это определение функции далее я могу идти глубже Я уже захожу в тело функции и нахожу там список из
15:27
Speaker A
одного оператора вот таким образом тоже можно ходить по АСТ более того в принципе этой информации вполне достаточна для того чтобы разработать визуализатор АСТ для питона вот то что показано слева это есть весь код визуализатора то есть Что здесь может нас заинтересовать функция
15:47
Speaker A
Вок вот мы ходим пост и э функция рекурсивная и мы как всегда используем сопоставление с образцом и один случай первый случай - это мы рассматриваем базовый класс а то есть если это какой-то класс унаследованный от то мы что делаем мы добавляем родительский
16:06
Speaker A
узел вернее связываем родительский узел с нашим узлом и идём по вот этим полям подчёркивания FS идём дальше вглубь если это список это второй случай Cas list в скобках то мы просто Идём по каждому элементу опять же рекурсивно вот и вся
16:20
Speaker A
функция А давайте посмотрим теперь на результат справа вот такой вот он это конечно же формат известного инструмента визуализации графа и в принципе выглядит достаточно симпатично На мой взгляд но здесь если присмотреться совсем недостаточно информации То есть у нас
16:37
Speaker A
указана Константа но какая Константа Мы не видим Допустим или имя А какое имя мы знаем что это X но это не видно на изображени Ну на самом деле это легко добавить и вот окончательный вариант визуализатора которым я ещё буду
16:52
Speaker A
пользоваться в течение доклада тут вот видно насколько детальна информация о каждом узле собственно говоря вст помещена часть из этой информации нам нужна часть можно игнорировать Ну а теперь следующий пример наконец-то Мы дошли до первого DSL компилятора то есть
17:09
Speaker A
компилятора нашего предметно ориентированного языка Ну вот Единственное что сам предметно ориентированный язык достаточно прост это язык описания графов Видимо для их визуализации скорее всего Итак Посмотрите на код слева это вот собственно говоря код на языке описания графов какой-то Граф и он представлен
17:30
Speaker A
справа это уже результат визуализации Ну что здесь можно обнаружить Я думаю что даже если я вам не буду подсказывать по поводу синтаксиса вы догадаетесь что больше меньше - это соответствующие стрелки Да к сожалению я не могу использовать минус например больше да
17:44
Speaker A
более красивую такую изящную стрелку поскольку такой такого символа токена В питоне К сожалению нет что я ещё сделал Я ещё позволил себе вольность и использовал аннотации типов не по назначению А как описание собственно говоря метки каждого узла и вот он
18:03
Speaker A
собственно говоря результат Можно ли бы было добиться всего этого с помощью перегрузки операций Ну я бы мог сейчас много об этом говорить но Обратите внимание на главное а у нас переменные Каким образом определяются а просто по факту их
18:17
Speaker A
появления То есть я сразу пишу а Боб Конечно же это не корректный код на питоне но мы-то Разбираем его дерево Поэтому нам в принципе это всё равно то есть вот это вот точно нельзя сделать просто силами внутреннего DSL насколько
18:31
Speaker A
вообще сложно такой вот язык реализовать нам нужно рассмотреть случаи вариантов синтаксиса то есть у нас есть например аннотация Да которая описывает метку какого-то узла графа и это с точки зрения а питона - это объект класса an то есть аннотированный вот снизу слева у
18:53
Speaker A
меня показан шаблон по которому я сразу могу использовать этот код в конструкции сопоставления образцом Обратите внимание что там указан далее То есть это дальше должно фигурировать имя а дальше Константа причём STR Это означает что мне нужна не просто
19:12
Speaker A
какая-то Константа а именно строковая Константа это Обратите внимание насколько лаконично с помощью сопоставления с образцом можно как раз нужные нам конкретные случаи описывать шаблонами и второй вариант синтаксиса это не присе в питоне Оказывается он формирует объект класса э А внутрь уже
19:34
Speaker A
помещает Ту самую операцию которую здесь фигурирует это сравнение как сравнение устроено вспомним что в питоне У нас есть цепочные сравнения Поэтому вот этот вот посмотрите на шаблон внизу да и - это на самом деле списки То есть - это
19:50
Speaker A
список операций больше меньше и так далее А это соответствующие Аргументы и собственно говоря опять же На этом этапе мы уже можем сделать DSL компилятор грави функция вторая это собственно говоря то что нам и делает всю основную работу здесь есть два случая первый
20:10
Speaker A
случай А exp compare - это как раз тот вариант синтаксиса где мы указываем грубо говоря стрелками Как связаны между собой узлы или с точки зрения питона это больше меньше и так далее цепов и здесь дополнительные проверки используются Но
20:27
Speaker A
самое главное что в конце концов вызывается функция добавления э рёбер которая э адекватным образом ставит стрелочки уже на языке Dot для инструмента gravis и второй случай an assign то есть аннотированный присваивание где я просто добавляю соответствующую метку здесь пожалуй
20:45
Speaker A
ничего интересного Однако есть один момент вот посмотрите тут есть ещё третий случай третий случай - это как раз то как мы в принципе должны работать с As когда мы делаем например DSL компиляторы и мы хотим обрабатывать ошибки То есть если ни один
21:01
Speaker A
из так сказать корректных случаев не подошёл Мы всегда пишем последний случай например кейс подчеркивания и здесь мы вызываем исключение Син Error но возникает вопрос а Как указать детали этой самой ошибки то есть нормальные компиляторы тот же самый питон Ведь они указывают место да где
21:20
Speaker A
эта ошибка была совершена как-то подсвечивают его и так далее А что же нам теперь самим это всё реализовывать Нет мы просто делает а получает информацию о конкретном объекте АСТ а та информация которая содержится в поле attributes атрибуты - это вот э номер строки и так
22:10
Speaker A
далее и так далее Короче говоря где в коде В исходном фигурирует данный АСТ объект и таким образом можно обрабатывать ошибки Ну и ещё один пример визуализации графа тут Я зачем-то построил бинарное дерево просто ещё раз показываю что это
22:24
Speaker A
всё работает А теперь давайте перейдём к следующему DSL компилятор если кому-то показалось что предыдущий DSL компилятор был очень упрощенным даже примитивным вот вам пожалуйста кое-что посложнее и поинтереснее многие ли знают про язык datalog наверное немногие язык достаточно старый Но сегодня он вновь
22:45
Speaker A
получает определённую популярность различные компании в духе Google там Amazon ещё кто-то начинает его использовать в своих проектах А что он собой представляет во-первых это язык логического программирования во-вторых и Наверное это это самое страшное для многих это вариант языка пролог
23:02
Speaker A
очень-очень маленький вариант Но если кто-то из вас изучал в университете язык пролог то у него скорее всего остались у этого человека негативные впечатления о языке как а совершенно бессмысленным и так далее и тому подобное Ну я во все
23:18
Speaker A
эти вопросы вдаваться не буду просто скажу что даталоггер точки зрения это язык запросов базам данных причём на нём очень выразительно можно описать запросы рекурсивного толка то есть рекурсивные запросы и основные применения даталоггер вю очередь статический анализ программ есть различные варианты реализации
23:57
Speaker A
даталогическая Хотя он действительно очень прост с точки зрения синтаксиса значит что здесь есть Вот пример А тут есть CT несколько строчек Да ordered и product давайте считать что City Order это product - Это просто таблицы и вот таким образом Я заполняю строки этих
24:13
Speaker A
таблиц э в даталогическая информация о чём-то ещё есть правила Вот например правило здесь которое показано Ship то есть куда мы поставляем какой-то продукт с именем да В какой город можно считать что это с точки зрения сиквела это виртуальная таблица если так можно
24:34
Speaker A
выразиться да то есть здесь мы связываем после если несколько таблиц C Order и prod друг с другом с помощью переменных переменные в даталоггер но сначала один момент это вообще говоря не совсем реальный синтаксис Да вот он реальный синтаксис
25:05
Speaker A
на самом деле место если в даталоггер по поводу запросов вот как выглядят запросы я пишу шип какую-то переменную Да и указываю конкретное значение то есть какие продукты поставляются в Москву и далок выдаёт Две позиции или какие продукты поставляются в какие
25:27
Speaker A
города да И тут выдается выдаётся просто вся возможная информация Вот как это работает Ну пока ничего вроде бы особенного Нет Есть ещё в доталогия запрос с отрицанием Вот ещё один совсем маленький пример какие у нас есть факты факт в том что персона - Это Вася и
25:44
Speaker A
также персона У нас есть Маша и дополнительный факт что Вася оказывается любит Машу и есть у нас правило правило это касается неразделённой любви то есть если некоторый и страдает неден любовью да то это означает что этот X любит
26:01
Speaker A
какой-то Y Да но при этом Y Как вы видите не любит X и мы можем сразу же задать запрос дало и он вот нам безжалостно ответит что вот кто у нас такой это Вася у нас от этого всего
26:14
Speaker A
страдает То есть можно ещё использовать отрицание на самом деле есть множество различных расширений да тало Но самое главное что всегда есть во всех диалектах Дага это рекурсивные запросы вот наконец-то мы до них добрались з пример это часть Московского
26:31
Speaker A
Метрополитена москвичи заметят что лишь небольшая часть здесь Ян фактами указал прямые связи между соседними станциями о ид это вот первый аргумент ун это номера линий и я хочу совершать запросы в духе от какой станции можно добраться до какой другой
26:51
Speaker A
станции я гово что это означает есть прямая связ уза только в одном направлении Но мы же можем поехать и от Y X поэтому есть второе правило что X от Y - это y x да то есть в обратном направлении как
27:08
Speaker A
это показано в графе справа ну и наконец вот он рекурсивный запрос то есть мы можем добраться из X до Y если мы используем какую-то промежуточную станцию Z и таким образом мы рекурсивно можем добраться откуда угодно докуда угодно если есть связи Вот я задал зада
27:26
Speaker A
можно добра изн можно добраться гораздо до большего количества станций Но вот здесь показано только вот этот вот фрагмент Вот это рекурсивные запросы А теперь о том как как всё это реализовать в питоне Да самое это интересное вот типичная ситуация у нас есть какой-то
27:42
Speaker A
мощный инструмент библиотека в данном случае Z3 и нам приходится использовать её программный интерфейс и этот программный интерфейс не всегда удобен Ну вот посмотрите на то что здесь у нас творится Да много-много кода такого низкоуровневого более того если вы приглядитесь там вот зелёным
28:01
Speaker A
отмечено у нас даже название станции это всё тот же пример про метро у нас даже названия станции исчезли потому что движок до талого Z3 не понимает объектов питона он даже со строками работать не может всё с чем он может работать - это
28:15
Speaker A
битовые векторы то есть числа фиксированной длины и поэтому когда мы смотрим вот в правой нижней части результат запроса нам пишут что-то такое в духе or ра ра 3 я даже вообще не могу сказать а о чём это то есть какой-то
28:29
Speaker A
запрос сработал Но это ещё нужно декодировать Ну какой здесь вывод нужен конечно же DSL как его реализовать вот Прошу обратить внимание Я немножко даже горжусь таким вот вариантом DL представления здесь в отличие от предыдущего ДС который у нас описывал
28:48
Speaker A
графы я использую декоратор То есть у меня есть функция в которой прямо вот в этом вот новского коде описан код на дало то есть с точки зрения питона - это корректный синтаксис но его смысл да этого кода семантика абсолютно отлична
29:05
Speaker A
от питона Ну и этот декоратор как мы уже знаем да может просто получить Исходный код функции и потом сделать pars далее вот как выглядит запрос с помощью вот этого DSL внутри питона для дало это просто текст Да quy и теперь о
29:25
Speaker A
том как получить Как разобрать синтаксис такого вот DSL во-первых у нас с точки зрения дало есть атомы атомы - это факты с которыми мы уже сталкивались это под цели которые через запятую справа от правила перечисляются или запросы это с
29:40
Speaker A
точки зрения питона Это всего лишь какие-то функции соответственно у нас и будет шаблон Call потом какое-то имя и аргументы следующий вариант отрицание Я выбрал тильду для отрицания То есть у меня тут инвертирование соответствующий шаблон UN О да унарная операция и инверт и
30:01
Speaker A
наверное кто-то скажет Слушайте а ведь в питоне есть над почему мы не можем использовать над А вот почему оказывается парсер питона не работает в такой связке Когда у нас есть то что мы используем в качестве стрелочки то есть
30:13
Speaker A
меньше либо равно а потом над вот не знаю многие ли пенистый вообще как бы слышали но вот такой синтаксис считается некорректным поэтому я к сожалению не могу использовать э вот именно над я буду использовать тильду ну и наконец
30:28
Speaker A
синтаксис правила когда я Пиу пишу эту стрелочку конечно с точки зрения питона это не стрелочка это не если это меньше либо равно Поэтому я использую здесь ну и наконец длинное правило когда у меня ещ есть запятые вот где-то я слышал
30:48
Speaker A
обсуждение того какие в языках нужно использовать операции для перез иту смы пере приме где полезно перегружать запятую Но конечно мы её не перегружая на уровне АСТ как здесь показано Вот теперь у нас есть все случаи и теперь осталось только
31:07
Speaker A
транслировать код в API то есть программный интерфейс Z3 ещё один маленький момент по поводу даталоггер случай это как ментом е первый символ в верхнем регистре а второй случай - это просто какое-то значение просто имя либо какая-то Константа какого-то типа я
31:35
Speaker A
использую Get value А теперь по поводу битовых векторов вернёмся к ним ведь в Z 3то мы не можем просто так использовать те же самые строки поэтому мне пришлось немножко так сказать и схитрил Кэш таблицу то есть словарь и
31:50
Speaker A
каждому значение Я составляю номер соответственно Если значение уже было в таблице Я возвращаю известный номер вот таким образом я поддержал и объекты произвольной природы питона внутри дало на Z3 и дало я на самом деле Ещё вернусь А пока наверное самая сложная из как бы
32:10
Speaker A
часть нашего сегодняшнего обсуждения DSL это Граф потока управления Граф потока управления вот этот вот cfg cfg Control Flow Граф это вещь действительно важная Например если мы говорим про компиляторы уровне лвм это промежуточное представление на котором они работают более того Граф потока управления - это
32:33
Speaker A
то с чем работает большинство серьёзных умных статических анализаторов Вот именно с потоком управления они могут какие-то факты вывести по поводу Вашей программы что он собой представляет это Граф в котором узлы - это операторы одиночные Да программы нашей а рёбра - это переходы между
32:53
Speaker A
операторами всего лишь кстати в cpython есть Граф потока управления но там он строится именно для нужд компилятора Python и мы прикладные программисты не имеем к нему доступа к сожалению Вот пример графа потока управления слева какой-то простой Код да
33:09
Speaker A
а справа Вот вот эти вот стрелочки Как раз показывают возможное выполнение Кода да от одного оператора к другому видно что поскольку у нас здесь есть то у нас получился цикл то есть от операторами ра дамы возвращаемся опять на сравнение на те едини и таким образом
33:29
Speaker A
крутимся пока не пошли по другой ветви Да Y Как построить такой граф потока управления Ну в принципе кажется что это достаточно просто нам нужно идти по естественно дереву абстрактного синтаксиса то что у нас сейчас есть и просто соединять операторы по цепочке Но
33:47
Speaker A
на самом деле это немного сложнее чем кажется потому что в случае составных операторов таких как и Да у нас есть две ветки и в конце концов надо соединить If со следующим оператором с точки зрения вот этих двух веток то есть обе ветки
34:00
Speaker A
надо соединить со следующим оператором поэтому я сделал следующим образом у меня каждый оператор имеет один входной какой-то а узел И множество выходов Вот как это работает с точки зрения If вот у нас есть какой-то If If If If и else Да
34:17
Speaker A
я разбираю сначала что-то внутри Y = 1 это просто единичная оператор и Обратите внимание у него in - это просто тройка да тройкой я назвал наш Y = 1 А вот выходы - это множество список Да пока что из него же самого из этого вот
34:34
Speaker A
оператора с номером три Но если я разбираю уже часть L If els у меня получается outs уже из двух элементов и так далее тут уже три элемента И это всё надо как-то соединять как это надо делать Вот посмотрите на часть кода
34:49
Speaker A
справа вот собственно говоря это фрагмент реализации главная здесь функция cg то есть обход графа потока управления и посмотрите на функцию Add Note в процессе обхода As и построения cfg мы вызываем функцию Add Note которая добавляет почему-то вызывает какой-то метод класса Граф мы об этом
35:13
Speaker A
ещё поговорим Но самое главное что она возвращает как раз in и outs Вот видите здесь not в квадратных скобках это Одиночный узел поэтому Я возвращаю просто его а вот в случае Connect вот Connect здесь Ключевая функция смотрите я соединяю множество выходов с одним
35:28
Speaker A
следующим оператором вот таким образом я и строю Граф потока управления А теперь о том что же такое Граф Note играф Edge это методы которые предоставляет сам пользователь То есть если посмотреть э слева внизу вот как мы вызываем нашу
35:42
Speaker A
функцию Vol cfg мы создаём какой-нибудь свой класс в котором обязательно определены Note и H а затем вызываем функцию Vol cfg с этим вот объектом этого класса то есть главное чтобы наш пользователь предоставил Note и Edge Ну а теперь
35:57
Speaker A
по поводу того как ещё построить цикл Wi буквально Я просто хочу показать насколько это компактно можно сделать Я создаю новый узел Да это тест от while X бо единицы потом я добавляю тело цикла потом я соединяю мой тест входом в тело цикла Да
36:15
Speaker A
и выход из тело цикла соединяю снова с тестом вот у меня получился уже реальный цикл уже на уровне графа Да и дальше я могу всю эту конструкцию Соединить с Y = 1 добавить Y таким образом всю функцию обойти с точки зрения получения
36:32
Speaker A
графа потока управления вот он весь визуализатор если у нас есть функция Vol cfg то мы можем создавать вот такие вот классы Я здесь опять же использую язык дот замечательный утилиты грави и я даже не знаю о чём здесь говорить здесь Всё
36:47
Speaker A
достаточно Просто я добавляю рёбра Я добавляю метки А ну Наверное стоит сказать про Вот эту вот выделенную функцию вредине Что она делает полезная функция которая на вход вы е можете передать какой-нибудь узел а она выдаст строковое его представление и я это
37:07
Speaker A
использую когда получаю визуализацию То есть у меня здесь всё в красивом виде прямо на питоне справо в этом графе представлено Ну а теперь зачем я так долго рассказывал пролог и про Граф потока управления с тем чтобы вот эния
37:23
Speaker A
наконец использовать сду зада взгляд задача должна вас заинтересовать это задача по поиску неиспользуемых переменных наверняка многие из вас используют среду иде да то есть какую-то среду разработки в которой есть статический анализ и может быть даже у вас вот эта
37:42
Speaker A
вот задача по поиску неиспользуемых переменных этим анализатором решается вот посмотрим на функцию есть тут неиспользуемые переменные Ну вообще есть Например можно посмотреть на последний аргумент это C Да он нигде не фигурирует в теле функции и так далее и тому
37:57
Speaker A
подобное тут на самом деле далеко не одна переменная не используемая сколько их вот было бы здорово если бы существовал такой у нас статический анализатор который бы выдавал нам вот информацию приведённую на слайде можно его написать можно это сделать буквально
38:13
Speaker A
сейчас рассказать как это делается буквально в двух словах можно это не так сложно оказывается но для этого что требуется А у нас почти всё готово для этого во-первых нам нужно сформулировать на языке дало нужные правила а во-вторых просто обойдём Граф потока управления и
38:28
Speaker A
соберём факты о переменных в виде базы данных для даталоггер А здесь вот указаны правила для живых переменных живые переменные - это переменные которые в какой-то точке живые то есть значит что в этой точке ещё их значение имеет какой-то смысл то
38:49
Speaker A
есть далее может быть кто-то этим значением воспользуется вот тут есть целых три правила и я думаю что сейчас у нас просто нет времени наверняка это будет излишне подробно останавливаться на том как они реализованы то есть мы тут рассматриваем два варианта переменная
39:06
Speaker A
жива на входе в оператор и переменная жива на выходе из оператора Ну вот самый первый пункт Он наверное самый простой то есть переменная жива на входе в оператор P если она используется в операторе п Это значит что где-то раньше
39:18
Speaker A
она по крайней мере была определена То есть она явно здесь живая Ну положим что мы поверили наслово Да что это эти три правила работают а как же не используемые это переменные А вот посмотрите вот здесь наверное можно даже
39:31
Speaker A
и понять Как это работает прямо вот сходу на слайде то есть что значит что переменная мертва это значит То есть она мертва в какой-то точке P и это переменная в это значит что она определена в этой точки но и не является живой на выходе из
39:45
Speaker A
оператора и всё это как бы решение для неиспользуемых переменных Ну конечно вся как бы сложность в том чтобы правильно написать правила для живых переменных и вот программа на доталогия которая ищет Мёртвые переменные собственно когда говорят о декларативных языках вот вам
40:03
Speaker A
пример декларативного языка настоящего и вот как реализуется сам статический анализ это вот весь статический анализатор здесь добавляются факты о конкретном операторе то есть какие переменные в этом операторе были определены какие были использованы и добавляется также факт о рёбрах между
40:26
Speaker A
двумя нали р ну и в конце концов делается запрос тут Наверное интересен следующий момент что за функция такая Get Вот она как раз получает информацию о и US то есть определениях переменных и их использования как это найти Ну можно
40:46
Speaker A
сделать очень сложную функцию которая просто проверяет все возможные конструкции а но к счастью в питоне за нас уже сдела сдела Очень полезная ве каждое имя оказывается имеет второй аргумент контекст либо либо Store Что такое Store Ну можно догадаться что - это как раз
41:04
Speaker A
use то есть использование переменной А - это запись переменно соответственно нам остаётся всего лишь рассмотреть опять же с помощью сопоставление с образцом случай фигурировать Что это у нас использование переменно здесь ну а соответственно второй случай это значит что мы
41:26
Speaker A
записываем в переменную новое значение то есть мы её определяем или переопределять Ну ээ собственно говоря Это всё что касается статического анализатора И теперь я думаю кульминация ещё более как мне кажется интересный а компилятор DSL компилятор в представлении Web assembly то есть VM Ну
41:47
Speaker A
сначала пару слов о том Зачем всё это нужно А есть очень интересная область интерактивных визуализаций То есть это веб-странице просто статичным текстом и какими-то статичными картинками Допустим мы хотим рассказать о каком-то важном предмете о какой-то концепции и было бы
42:04
Speaker A
здорово предоставить читателю не просто статичну информацию а некую интерактивную модель у которой есть параметры Представьте что вот эти графики интерактивные то есть я могу двигать курсором и сразу меняются все параметры меняются числа или например меняю числа и меняются графики то есть
42:19
Speaker A
во всех во все стороны это всё интерактивным образом работает здесь очевидно нужен какой-то скрипт ну на жава скрипте Да можно естественно написать а можно и на питоне и вот собственно говоря идея проект компилятор скриптов интерактивных графиков вам то
42:34
Speaker A
есть что нам бы хотелось чтобы компилировать под множество питонов вам причём настолько выразительно чтобы мы могли сначала прототипирования сразу компилировать в вас модуле причём Мы хотим это делать со скоростью значительно более высокой чем это делает OT lip и Python Мы хотим чтобы это
42:58
Speaker A
работало со скоростью жава скрипта и ещ Мы хотим чтобы результат компиляции занимал сотни байт а не сотни ме или хотя бы десятки мегабайт то есть мы не хотим компилировать весь cyon Ну и в конце концов Мы хотим чтобы реализация
43:11
Speaker A
компилятора занимала меньше 100 строк кода Да вот такие вот требования и вот некоторые особенности этого самого компилятора то есть в реальности поддерживаю только лот значения Ну коне я срезаю углы как же без этого обю их отде я поддерживаю функции но не
43:30
Speaker A
поддерживаю поскольку мне не хватило места строк кода и в конце концов в принципе с точки зрения реализации это та же самая генерация стекового кода с которой мы уже встречались в самом начале А вот по поводу списков Ну маленький момент если кто-то не знает
43:47
Speaker A
вас у нас достаточно серьёзные проблемы со сборкой мусора то есть по идее там вообще нет хотя вот сечас появилось предложение Наго туда можно добавить как же работать со списками вот собственно здесь представлено коротко как это выглядит то есть мы используем вызовы
44:04
Speaker A
импортированные функций из жава скрипта и таким образом их применяем Ну а теперь о том как это может выглядеть вот собственно говоря некоторый прототип визуализации фрактала Давайте попробую Если получится показать это вам в динамике А так да вот он этот
44:23
Speaker A
фрактал это уже скомпилированный ва модуль и я могу в реальном времени обратить внимание Можно ли это сделать на питоне Да хватит ли быстродействия на питоне чтобы так крутить А у меня к сожалению с мышкой тут проблема но в
44:38
Speaker A
принципе оно вот оно да крутится То есть это фрактал который в реальном времени А масштабируется вот вам ещё один пример вот пожалуйста это множество жулья так называемая Я тоже у меня тут с мышкой а не всегда Да вот
44:57
Speaker A
оно ага вот оно вот то есть вот пожалуйста как это может выглядеть Ну и у нас совсем мало времени осталось поэтому я просто как как бы сказать у меня же есть определённая традиция Я в самом конце доклада компилятор
45:15
Speaker A
обязательно предлагаю что-нибудь почитать по теме И вот сегодня я хотел бы предложить книгу Essentials of comp чем эта книга интересна эта книга интересна тем что во-первых она в духе о котором я сегодня говорил начинается сразу же с АСТ то есть синтаксического
45:30
Speaker A
разбора там нет во-вторых это книга с примерами на языке питон и в-третьих там используется сопоставление с образцом о котором я всё это время рассказывал да то есть то самое сопоставление с образцом маке Ну и Пожалуй это всё спасибо большое за внимание и как и
45:47
Speaker A
обещал ссылка на репозиторий со всеми примерами пожалуйста изучайте
Topics:PythonкомпиляторыASTсопоставление с образцомDSLстатический анализтрансляцияPandocLLVMвизуализация графов

Get More with the SozAI App

Transcribe recordings, audio files, and YouTube videos — with AI summaries, speaker detection, and unlimited transcriptions.

Or transcribe another YouTube video here →