Возникла такая мысль. Что скажите? Пока пишу KEEP,...
# russian
a
Возникла такая мысль. Что скажите? Пока пишу KEEP, но может зря... Рассмотрим как пример библиотеку kotlinx.serializaion 1. Разницы между
@Serializable
и
data class
в целом никакой нет. Но первое это библиотека + плагин, второе- часть языка. 2. После подключения
@Serializable
очень сложно понять, что за код там получился- надо отрезать исходники и смотреть декомпилированный файл (или можно проще? Скажите, интересно). 3. Глядя в реализацию плагина я вижу 3 части - jvm/js/native хотя в целом там должно быть всё одинаково. 4. Плагин надо брать версии kotlin а саму библиотеку- другой версии. И можно (в теории, мне не попадалось) выбрать несовместимые варианты. Мне давно уж казалось, что в подходе “аннотация+плагин” есть принципиальный изъян. И язык forth не давал покоя 🙂 Наконец в голове сложился пазл “как должно быть“: 1. Аннотация типа
@Serializable
должна быть специального типа - не
public annotation class Serializable
а
public plugin class Serializable
(имя неважно) и располагаться в compile-only-time библиотеке. 2. Класс аннотации должен выполнять работу над кодом, но не IR и т.п. а над PSI или FIR - см. новый frontend compiler, например

https://youtu.be/S2--aYB2GiE?t=1442

3. После выполнения плагина надо FIR превратить обратно в исходный код и сложить в какую-то папку, типа автогенерированных классов. 4. Понятно, что в рантайме не должно быть завязки на плагин-аннотацию, но хвостик должен остаться. Что получится? 1. Легко можно увидеть (поддержать в IDEA легко) результат применения аннотаций-плагинов, со всеми комментариями. И в дебаге можно видеть реальный код. 2. Разработка аннотаций-плагинов на порядок проще, чем обычных плагинов на основе аннотаций. 3. Т.к. IDEA всё равно должна строить FIR а аннотации-плагины не должны долго работать- IDEA будет “знать” результаты работы аннотации-плагина. 4. Если в скомпилированном коде будет “хвост” аннотации-плагина, то это позволит выполнять работу над классами-потомками - например для корректной реализации контрактов (в настоящий момент это нельзя сделать никак). 5. Можно изменять в том числе комментарий - и, соответственно, документацию.
👍 3
i
.replace("AST", "PSI")
✔️ 2
это во-первых. во-вторых, тогда уж хочется иметь всякие идеевские элементы работы с PSI типа нормализации кода
типа, я плагином склепал код:
val x:kotlin.String=(("kuku"as kotlin.String)+(12))
и хочу получить
val x = "kuku${12}"
еще есть более интересная, но сильно менее реальная идея
иметь возможность декомпилировать fir в код
тогда можно и над типами подумать, и структуру легко собирать
тот же PSI, например, можно собирать абсолютно хаотичным образом, не имеющим ничего общего с правильной структурой синтаксиса, а потом получать поехавшие баги
а FIR в этом плане гораздо жестче
a
Ок. AST общий термин, про psi почитаю
Нормализация PSI мне не нравится - все же чем меньше магии - тем лучше. Все же главный это исходный код.
i
ну вот идея так делает. там код генерят лишь-бы-работало, а потом допиливают так, чтобы он выглядел человеконаписанным, через отдельные пассы.
psi - это сильно более гибкая штука, это cst языка без жесткой структуры по сути
но котлин во фронте и старом беке юзает именно ее.
a
Это в груви было, называлось AST-трансыормации. Посмотрите туда
a
Спасибо! Читаю. Правда сайт http://codehaus.org/ почему-то не отвечает. Странно.
Да, похожая штука. По пунктам: 1, 3 и 4 нет 2 да 5 не имеет смысла без 1 и 3.
Ну и ещё - предложенный мной вариант позволяет все (!) аннотации реализовать таким способом- т.е. в компиляторе нет ничего, только код. Соответственно нальзя использовать аннотации для описания аннотаций 😉
иметь возможность декомпилировать fir в код
А это ж есть. Можно открыть native библиотеку
это во-первых. во-вторых, тогда уж хочется иметь всякие идеевские элементы работы с PSI типа нормализации кода
А, теперь понял (вчера с телефона читал, упустил). Надо глянуть, что там в PSI
i
@aleksey.tomin правда? я могу так написать и получить исходник?..
Copy code
val cls = buildRegularClass {
    name = Name.identifier("Kuku")
}
a
Не понял, о чем это
i
@aleksey.tomin декомпиляция FIR в сурсы
a
Ну так FIR в отличии от IR это дерево исходников, как PSI
d
Вклинюсь в дискуссию, как один из людей, которые работают над фиром в целом и компиляторном API в нём в частности.
Аннотация типа @Serializable должна быть специального типа - не public annotation class Serializable а public plugin class Serializable  (имя неважно) и располагаться в compile-only-time библиотеке.
О компиляторных плагинах и сейчас можно думать как оcompile-only зависимости, которая включает в себя две части: 1. библиотека с аннотациями с source retention'ом (хотя зависит и от аннотаций, т.к. кто-то может хотеть их и на рантайме тоже: тулинг/фреймворки/...) 2. jar с компиляторным плагином
Класс аннотации должен выполнять работу над кодом, но не IR и т.п. а над PSI или FIR - см. новый frontend compiler, например 

https://youtu.be/S2--aYB2GiE?t=1442

В такой концепции это уже получается не аннотация, а декоратор. И у них возможностей гораздо меньше чем у связки "аннотации + компиляторный плагин", т.к. декоратор имеет доступ только непосредственно к той декларации, на которую его повесили. Плагин же может получать от компилятора информацию про весь компилируемый мир (с некоторыми оговорками): все декларации, проаннотированные аннотацией из плагина/аннотациями, проаннотированными мета-аннотациями из плагина, информацию про любой доступный в compile-time класс (супертипы, мемберы и т.д) и много чего ещё. Более того, то, что плагин хочет генерить может зависеть именно на эту информацию. Также соединение аннотаций и плагина в один
plugin class
не решает проблему сочетаний версий плагина и компилятора, т.к. такому плагину всё-равно придётся зависеть на компилятор определённой версии, иначе никаких компиляторных плюшек ему получить не удастся
После выполнения плагина надо FIR превратить обратно в исходный код и сложить в какую-то папку, типа автогенерированных классов.
В текущей концепции на фронтенде плагинам предполагается создавать только декларации. Как именно будет создаваться контент тел ещё не ясно. Есть как минимум три различных способа: 1. создавать голый PSI/source string и прогонять весь пайплайн компилятора по этому телу 2. создавать порезолвленный FIR (со всеми проставленными типами, ссылками на функции в местах вызовов и прочим) 3. создавать уже IR на стадии бекенда (потому что фронтеду тело совершенно не нужно) В целом иметь возможность посмотреть на декомпилированный исходный код того, что нагенерили плагины -- это идея хорошая, но пока неясно, как это будет реализовано. Тут, к слову, может помочь декомпилятор IR'а, для которого у нас есть прототип (правда он сейчас заморожен, т.к. он не сильно в приоритете и нет свободных ресурсов, чтобы его завершить)
👌 2
Ну так FIR в отличии от IR это дерево исходников, как PSI
Это очень грубое и неправильное суждение PSI -- это синтаксическое дерево FIR, как и IR -- это семантическое дерево, из которого выкинута всякая ненужная информация про синтаксис (пробелы, скобки, комментарии) и сахар (так все if'ы представлены как when'ы), но добавлено много различной семантической информации, которую компилятор насобирал в процессе анализа Вся разница между FIR и IR в том, что в них есть несколько разная информация, которая нужна только фронтнеду или бекенду соответственно
И ещё, возвращаясь к плюсам от исходного предложения
Легко можно увидеть (поддержать в IDEA легко) результат применения аннотаций-плагинов, со всеми комментариями. И в дебаге можно видеть реальный код.
Т.к. IDEA всё равно должна строить FIR а аннотации-плагины не должны долго работать- IDEA будет “знать” результаты работы аннотации-плагина.
Видеть в дебаггере реальный код -- это наименьшая из проблем поддержки плагинов в IDE. Основнгая проблема заключается в том, как корректно отслеживать, что сгенерённые декларации меняются, если пользователь меняет какой-то свой код. Т.е. как правильно сделать такой инкрементальный и ленивый анализ, чтобы не провоцировать переанлиз всего проекта при изменении в каком-нибудь файле (API для фира мы дизайним с учётом этой проблемы, но до прототипирования IDE части пока не добрались)
Разработка аннотаций-плагинов на порядок проще, чем обычных плагинов на основе аннотаций.
Почему?
Если в скомпилированном коде будет “хвост” аннотации-плагина, то это позволит выполнять работу над классами-потомками - например для корректной реализации контрактов (в настоящий момент это нельзя сделать никак).
Можно изменять в том числе комментарий - и, соответственно, документацию.
Эти два пункта я не очень понял
a
Вклинюсь в дискуссию, как один из людей, которые работают над фиром в целом и компиляторном API в нём в частности.
Отлично, спасибо 🙂
О компиляторных плагинах и сейчас можно думать как оcompile-only зависимости, которая включает в себя две части
Собственно вот “две части” и составляет большую проблему. У нас есть совершенно неочевидная зависимость между этими частями.
Плагин же может получать от компилятора информацию про весь компилируемый мир (с некоторыми оговорками)
Не считая того, что нелокальность действия- антипатерн, но это ещё сильно осложняет работу IDE(A) - она не может показать то, что натворит плагин.
Также соединение аннотаций и плагина в один 
plugin class
 не решает проблему сочетаний версий плагина и компилятора, т.к. такому плагину всё-равно придётся зависеть на компилятор определённой версии, иначе никаких компиляторных плюшек ему получить не удастся
Это верно, если плагин входит в котлин (как kotlinx.serialization). Но для стороннего плагина это неверно- нужно правильно сочетать версию зависимости, плагина и компилятора. И не всегда это будет просто.
Тут, к слову, может помочь декомпилятор IR’а, для которого у нас есть прототип (правда он сейчас заморожен, т.к. он не сильно в приоритете и нет свободных ресурсов, чтобы его завершить)
А разве просмотр нативных библиотек в IDEA сделана не через декомпиляцию IR?
PSI -- это синтаксическое дерево
FIR, как и IR -- это семантическое дерево, из которого выкинута всякая ненужная информация про синтаксис
Странно. Я так понимаю, сейчас в новом компиляторе идёт преобразование
Source -> PSI -> raw FIR -> FIR -> IR
. И ошибки компиляции возможны на этапе
raw FIR -> FIR
. При этом компилятору нужно знать, где показать ошибку. Кроме того, я думал, что PSI вообще будет удалено в будущем- как-то привык к полуторопроходным цельным компиляторам и видеть четырёхпроходный фронтенд как-то необычно - думал, это временно.
Основная проблема заключается в том, как корректно отслеживать, что сгенерённые декларации меняются, если пользователь меняет какой-то свой код. Т.е. как правильно сделать такой инкрементальный и ленивый анализ, чтобы не провоцировать переанлиз всего проекта при изменении в каком-нибудь файле
Да, нелокальность плагина приводит и к этой проблеме. У меня есть некоторые мысли на эту тему, но надо будет внимательно посмотреть примеры использования нелокальных плагинов.
> Разработка аннотаций-плагинов на порядок проще, чем обычных плагинов на основе аннотаций.
Почему?
Во-первых работать с деревом исходного кода проще, чем с IR (хотя я работал только с java-плагином, который сразу байткод правит). Я пробовал генерировать как source-код, так и байткод- и боли во втором случае намного больше. Если будет возможность всегда посмотреть исходный код, порождённый декоратором - то отладка такой аннотации будет очень простой. Читать IR/bytecode это совершенно другой уровень.
Эти два пункта я не очень понял
> Если в скомпилированном коде будет “хвост” аннотации-плагина, то это позволит выполнять работу над классами-потомками - например для корректной реализации контрактов (в настоящий момент это нельзя сделать никак).
Я всё думаю на тему реализации контрактов, как в языке eiffel. Там описание контракта метода накладывает ограничение на всех наследников метода. Если аннотация-декоратор всё же оставляет след в виде обычной аннотации, то при работе аннотации-декораторе на наследнике метода можно получить значение из предка и гарантировать корректность кода. Второй пункт “Можно изменять в том числе комментарий - и, соответственно, документацию.” - при просмотре сторонней библиотеки я могу не видеть исходный код, а видеть только спецификацию метода и javadoc (или kotlindoc? Не знаю, как корректно назвать). Например та же
@Serializable
может добавлять в комментарий к классу- какие поля сериализуются, или ещё что-то там.
d
Собственно вот “две части” и составляет большую проблему. У нас есть совершенно неочевидная зависимость между этими частями.
Это чинится синхронным версионированием плагина и библиотек или же gradle пагином, который сразу подключит нужные версии (например, в нём зашито соответствие версии плагина к версии библиотеки в случае, если последняя обновляется реже)
Это верно, если плагин входит в котлин (как kotlinx.serialization). Но для стороннего плагина это неверно- нужно правильно сочетать версию зависимости, плагина и компилятора. И не всегда это будет просто
Я так понимаю, тут вы говорите ещё и про плагин для IDE. В идеальном мире, к которому мы стремимся, плагин для IDE является необязательной частью. Если же он есть, то он должен автоматически ставиться в идею, если в зависимостях проекта используется компиляторный плагин. Правда есть ещё проблема, что ставить в идею, если в разных модулях проекта используются разные версии компиляторного плагина (и для пока непонятно, что с таким делать)
И ошибки компиляции возможны на этапе raw FIR -> FIR . При этом компилятору нужно знать, где показать ошибку.
Внутри FIR мы храним ссылки на исходный код, чтобы можно было на нём репортить диагностики. При этом у нас есть два варианта представления исходников (PSI и light tree, который является сильно облегчённой версией PSI). В целом, для репортинга достаточно иметь где-нибудь строку с исходным кодом и start и end offset'ы для каждого элемента
Кроме того, я думал, что PSI вообще будет удалено в будущем
Не будет, т.к. IDE часть сильно зависит на PSI
видеть четырёхпроходный фронтенд как-то необычно - думал, это временно.
Опять же, это навсегда. Работать со своими внутренними представлениями (FIR, IR) гораздо проще, чем с исходником/бинарным представлением. Плюс IR структура необходима для нормальной одновременной реализации трёх (а в будущем, возможно, и большего числа) бекендов
Я всё думаю на тему реализации контрактов, как в языке eiffel. Там описание контракта метода накладывает ограничение на всех наследников метода.
Наследование контрактов -- это ещё нерешённый дизайновый вопрос (поэтому контракты на
open
функциях сейчас запрещены), и об этом говорить пока рано. Но вообще контракты записываются в kotlin metadata, неважно для исходных и сгенерённых деклараций, так что вряд ли с их поднятием возникнут какие-то проблемы
Второй пункт “Можно изменять в том числе комментарий - и, соответственно, документацию.” - при просмотре сторонней библиотеки я могу не видеть исходный код, а видеть только спецификацию метода и javadoc (или kotlindoc? Не знаю, как корректно назвать).
Например та же @Serializable может добавлять в комментарий к классу- какие поля сериализуются, или ещё что-то там.
Хороший юзкейс, мы о таком не думали. Спасибо
а какие хорошие примеры именно нелокальной работы плагина?
Во время исследования мы рассматривали следующий юзкейс (на основе, кажется, dagger'а) - есть некий пустой класс, объявленный пользователем (например, какая-нибудь
Factory
) - есть множество других классов, которые помечены специальной аннотацией - плагин генерит фабричные методы в этой
Factory
для всех помеченных классов
a
Это чинится синхронным версионированием плагина и библиотек или же gradle пагином, который сразу подключит нужные версии
gradle-плагин это лишняя сущность - нужен ещё maven-плагин, IDEA-плагин, потом bazel-плагин- это некрасиво. Зависимость чего угодно на версию компилятора - это нормально. А плагины- это лишнее. Моё решение вообще не требует плагинов вообще.
Наследование контрактов -- это ещё нерешённый дизайновый вопрос
Ну вот собственно я предлагаю решение 🙂 Хочется довести kotlin до идеала- и не хватает идей и forth и eiffel. Вот предлагаю 🙂 Хочется и делать- но как хобби это нереально- это только пока семьи нет можно написать forth-машину или кросс-компилятор долгими зимними вечерами…
Не будет, т.к. IDE часть сильно зависит на PSI
Да, понятно - PSI для IDEA, IR для backend-компилятора, FIR для фронтенд. Я так понимаю, IDEA, как самый старый продукт, сложнее всего изменить и заменить PSI. на raw-FIR слишком дорого стоит.
Во время исследования мы рассматривали следующий юзкейс (на основе, кажется, dagger’а)
Да, об этом я думал. Т.к. “декоратор” это объект класса, выполняемый внутри jvm компилятора, то там может быть либо некоторое хранилище (предоставляемое компилятором), либо просто
object
(хотя это путь в адъ утечек памяти). Соответственно аннотация на классе будет добавлять ссылку на класс в это хранилище, а
@Factory
- вытаскивать всё и создавать нужное. Появляются два вопроса: • как сделать так, чтобы фактори выполнилась строго после всех остальных классов. • что тут может показать IDEA. Ответ на первый вопрос - можно на (имя условное)
@Service
добавить
@Factory
в список зависимых.
d
Моё решение вообще не требует плагинов вообще.
Но при этом оно тащит весь компилятор на compile class path. Либо же порождает новый тип зависимости для билд систем, что, опять же, порождает плагины для них
Ну вот собственно я предлагаю решение
Мне приятен ваш энтузиазм, но проблема с контрактами лежит в несколько другой плоскости: наследование контрактов и возможность декларировать свои контракты в плагинах -- это две совершенно разные вещи, которые друг на друга никак не зависят (для второго у нас даже есть парочка рабочих прототипов)
как сделать так, чтобы фактори выполнилась строго после всех остальных классов.
Есть ещё важный момент, что работу плагинов необходимо уложить в текущую архитектуру FIR'а, которая в свою очередь состоит из n-го количества проходов (фаз) по всему миру. И при этом соблюдается контракт, что к моменту фазы
n
все декларации уже порезолвлены до фазы
n-1
Собственно, сами фазы: 1. Raw FIR (его построение) 2. резолв импортов во всех файлах 3. резолв супертипов всех классов 4. резолв явно указаных типов на нелокальных декларациях (функции, проперти, конструкторы) 5. резолв статусов всех деклараций (visibility, modality, модификаторы) 6. резолв контрактов 7. резолв тел функций/пропертей без явно указанного return типа 8. резолв всех остальных тел И вот в эту модель плагины надо впихивать очень аккуратно, т.к. если плагин генерит какой-то новый класс, то он должен это делать в три захода - сначала сгенерить саму декларацию класса перед фазой 2 - потом догенерить методы перед фазой 5 (т.к. от этого класса может наследоваться пользовательский код, что повлияет на резолв overrid'ов) - после чего сгенерить тела методов после фазы 8 или уже в IR'е
Предвосхищая вопрос, "зачем так сложно?", могу сказать, что такая схема -- это залог успеха для: - будущей поддержки и расширения компилятора - увеличения перформанса в сравнении с текущим фронтендом - возможности компилировать один модуль в несколько потоков (на некоторых фазах) - гораздо более гладкой интеграции IDE и компилятора, нежели это есть сейчас
a
Вот все это обсуждение по хорошему должно быть либо в задаче ютрека либо в keep ибо тут много аргументов в обе стороны накидали, как бы в слаке это все не забылось в итоге :)
d
Я сохранил ссылку на этот тред в основном внутреннем документе про плагины в FIR
a
Я пишу keep и все полезное туда занесу
Но при этом оно тащит весь компилятор на compile class path.
Только
org.jetbrains.kotlin.psi
по сути своей. На вход методу отдаётся текущее дерево класса- он там что-то ковыряет и отдаёт дальше. Под “psi” я понимаю его вместе с map’ой (ссылаясь на то же видео).
наследование контрактов и возможность декларировать свои контракты в плагинах…
А, кстати, я пропустил появление https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.contracts/ - надо почитать внимательнее...
Есть ещё важный момент, что работу плагинов необходимо уложить в текущую архитектуру FIR’а, которая в свою очередь состоит из n-го количества проходов (фаз) по всему миру.
Я собственно хочу вклинится сразу после генерации PSI - максимально близко к исходному коду. Кстати, а есть ли описание этих 8 шагов FIR’а в доступной извне документации?
d
Только org.jetbrains.kotlin.psi по сути своей.
На вход методу отдаётся текущее дерево класса- он там что-то ковыряет и отдаёт дальше.
Под “psi” я понимаю его вместе с map’ой (ссылаясь на то же видео).
BindingContext
(мапа) притащит за собой всё остальное https://github.com/JetBrains/kotlin/blob/master/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java Плюс на FIR это никак не ляжет, а делать compiler plugin API для текущего фронтенда мы не планируем
Я собственно хочу вклинится сразу после генерации PSI - максимально близко к исходному коду.
На данном этапе никакой информации от компилятора не будет. Похожую идею реализовали в #arrow-meta
Кстати, а есть ли описание этих 8 шагов FIR’а в доступной извне документации?
У нас по компилятору в целом никакой документации нету, ни внутренней, ни общей
Если хотите, могу показать entry point'ы в коде, по которым можно начать изучать компиляторный пайплайн
a
BindingContext
 (мапа) притащит за собой всё остальное
Понятно, спасибо! Я так понимаю, плагин с IR меньше всего тащит?
Плюс на FIR это никак не ляжет, а делать compiler plugin API для текущего фронтенда мы не планируем
Понятно, что старый компилятор +- заморожен. Но в новом же тоже будет PSI?
У нас по компилятору в целом никакой документации нету, ни внутренней, ни общей (edited)
Т.е. то интервью это максимум? Может ещё где-то были интересные беседы?
Если хотите, могу показать entry point’ы в коде, по которым можно начать изучать компиляторный пайплайн
Да, спасибо, пойду читать...
Похожую идею реализовали в #arrow-meta
О как. Минимум надо изучить эту штуку, спасибо!
d
Понятно, спасибо!
Я так понимаю, плагин с IR меньше всего тащит?
Всё также немало. Но при разделении плагина на, собственно, плагин и библиотеку с аннотациями пользователю на classpath попадает только последняя, которая ни на что не завсит
Но в новом же тоже будет PSI?
Не обязательно. У нас есть режим компиляции с парсером, который производит не PSI, а его упрощённое представление (это ускоряет парсинг примерно в два раза, если я правильно помню)
Т.е. то интервью это максимум? Может ещё где-то были интересные беседы?
На недавнем джокере Семён выступал с более подробным докладом на эту тему, но я не уверен, что его запись есть где-то в открытом доступе
Вот этот класс является основной точкой входа в FIR, на вход ему дают PSI: https://github.com/JetBrains/kotlin/blob/master/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/analysis/FirAnalyzerFacade.kt В целом все части, которые как-то связаны с FIR'ом лежат в вот этом модуле: https://github.com/JetBrains/kotlin/tree/master/compiler/fir/ Тесты, которые можно позапускать для дебага здесь: https://github.com/JetBrains/kotlin/blob/master/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java
👍 1
a
Отпустили меня рабочие задачи, полез читать :) Да, интересно. Скромные интерфейсы
FirElement
и
KtFile
внезапно тащат за собой библиотеки IDEA. Причём попытка получить исходник библиотеки приводит к ошибке
Could not find kotlin.build:intellij-core:202.7660.26
(изучаю мастер обновлённый на этой неделе).
d
Исходники уже скачаны при импорте проекта, их нужно просто вручную подключить Лежат они в
~/.gradle/kotlin-build-dependencies/repo/kotlin.build/sources/intellij-core:202.7660.26-sources.jar
a
Спасибо. Да, печаль. Читал код, читал - и понял, без большого рефакторинга нельзя тянуть PSI в compile-time. И даже на java много кода 😄 Про FIR послушал на Джокере доклад Семёна - его нельзя считать исходником - хотя бы
if -> when
решает. Не знаю даже, можно ли первоначальную задумку реализовать, пока не пройтись по PSI “огнём и мечом“. Может за праздники что-то и придёт в голову.
@dmitriy.novozhilov Доброе утро и с прошедшими праздниками 🙂 На выходные родились мысли: 1. Да, тащить classpath компилятора в библиотеку нельзя. Изначальная идея не реализуема, минимум сейчас. 2. Плагин компилятора неизбежная штука. Но при этом хочется иметь возможность создавать не только полноценный плагин, обрабатывающий всё дерево, но и декоратор, имеющий возможность менять строго один класс- этого достаточно для
data class
,
serializer
и многих других вещей. При этом такой “локальный” плагин должен работать быстрее и, самое главное, отлично ладит с инкрементальной компиляцией. 3. Сейчас плагин
serializer
работает над байткодом (и аналогами для native/js) - лучше, если (все/большинство) плагины будут работать над платформенно-независимой частью дерева. Есть ли какое-то описанное представление по новой схеме компиляторных плагинов? Сейчас видится предложение как “создание локальных плагинов/декораторов, основанных на аннотациях и работающих на PSI/FIR с созданием файлов исходного кода в
generated
по соответствующей настройке“, но вдруг это уже есть в планах? PS: а почему парсинг исходников и генерация PSI не рассматривается как часть фронтэнда?
d
При этом такой “локальный” плагин должен работать быстрее и, самое главное, отлично ладит с инкрементальной компиляцией.
Мы дизайним новый API плагинов так, чтобы любой плагин дружил с IDE и IC из коробки
лучше, если (все/большинство) плагины будут работать над платформенно-независимой частью дерева
Сейчас уже есть extension point'ы, которые позволяют работать с backend IR вместо байткода на бекенде, и этой концепции мы и планируем придерживаться
Есть ли какое-то описанное представление по новой схеме компиляторных плагинов? Сейчас видится предложение как “создание локальных плагинов/декораторов, основанных на аннотациях и работающих на PSI/FIR с созданием файлов исходного кода в generated по соответствующей настройке“, но вдруг это уже есть в планах?
Пока что мы работаем над низкоуровневым API, которое позволит генерировать новые декларации/ограниченно модифицировать существующие/добавлять новые проверки/модифицировать то, что в итоге будет генериться, и при этом чтобы это всё было совместимо с IC и IDE, как я писал выше (правда это несколько заблокировано тем, что IDE плагин на FIR сейчас в очень ранней стадии, а к IC мы только приступили). Уже поверх этого API можно будет выстраивать дополнительные уровни API, которые позволят легко обрабатывать описанные вами сценарии
PS: а почему парсинг исходников и генерация PSI не рассматривается как часть фронтэнда?
Т.к. компилятор изначально писался так, чтобы его можно было использовать в IDE, то фронтенд на вход принимал уже готовый PSI, который был заранее построен идеей. Плюс сейчас парсер выносится в совсем отдельную компоненту, и для одного и того же фронтенда (FIR) можно использовать разные парсеры, которые порождают разное промежуточное представление (сейчас мы используем парсеры в PSI и LightTree, но в будущем никто не помешает энтузиастам добавить что-нибудь своё)
a
Итого - мои пожелания либо уже в планах, либо нереальные. Значит не зря начал обсуждение. Спасибо!
👍 1
Кстати. Недавно узнал, что то, что я описал - это макросы Scala (которые удалили в 3й версии).