Программирование — это, в первую очередь, практика. На магистерской программе JetBrains и Университета ИТМО «Разработка программного обеспечения / Software Engineering» её у студентов много: еженедельные домашние задания, семестровые проекты и студенческие хакатоны DevDays, где участники находят интересные решения.
В этом посте магистранты программы Арсений Терехов, Евгений Слободкин, Сергей Сокольвяк и Николай Егоров расскажут про проект, который стал лучшим на весеннем DevDays — плагине для языка Lama для IntelliJ IDEA. И что такое Lama, тоже расскажут.
Пара слов о хакатоне
Каждые полгода в магистратуре проходит студенческий хакатон. Участие в нем обязательно для всех студентов. Хакатон позволяет реализовать самые сумасшедшие идеи, которые возникают у ребят в процессе (а иногда и до) обучения. За последние годы часть проектов превратилась в отдельные команды в рамках компаний (например, Grazie в JetBrains), а еще часть используется в образовательном процессе (тут и автоматическая разметка слайдов по видеозаписи лекции, и многочисленные боты для поддержки учебы).
Правила хакатона просты: собираются команды по 3-4 человека, которые в течение трех дней пилят проект. Состав команды определяется на этапе распределения, когда студенты выбирают себе понравившийся проект из пула прошедших этапов голосования. На последнем хакатоне участники предложили 37 проектов, семь из них реализовали.
Знакомьтесь, Lama
Lama — это язык программирования, который разрабатывают в лаборатории языковых инструментов JetBrains Research для образовательных целей. У нас в магистратуре есть курс по компиляторам, где Lama используют в качестве иллюстративного примера для ознакомления с областью языков программирования и их компиляции. Все домашние задания по этому курсу студенты также пишут на Lama.
Хоть Lama и учебный инструмент, все же это вполне полноценный язык программирования, вдохновленный такими функциональными языками, как Haskell и OCaml. В нем функции — это объекты первого класса: есть сборщик мусора, есть S-выражения, напоминающие алгебраические типы данных, есть сопоставления с образцом и много что еще.
То есть писать на Lama довольно легко и приятно. Единственное, без нормальной поддержки в IDE это делать муторно. Так у нас и возникла идея для хакатона — написать плагин для популярной среды разработки IntelliJ IDEA. Мотивацию еще «подогревал» тот факт, что можно сделать что-то полезное не только для нас, но и для других ребят, которые будут работать с Lama после.
Существующие решения и аналоги
Конечно, не мы первые задумались об инструментальной поддержке этого языка. Есть и другие решения. Например, мы нашли два хороших плагина для VSCode: вот один, а вот второй.
Они оба поддерживают подсветку синтаксиса, проверку синтаксической корректности файла, а также некоторые сниппеты кода. Все это уже сильно облегчает написание кода на Lama — без этой поддержки программировать приходится просто в блокноте без каких-либо подсказок редактора.
Обычно молодые языки развиваются очень динамично, и Lama — не исключение. Из-за этого на некоторых конструкциях плагины, к сожалению, подсвечивают некорректные ошибки. Например, если посмотреть на код стандартной библиотеки языка версии 1.10, то можно получить синтаксическую ошибку:
К тому же не все хотят устанавливать себе VSCode ради одного курса, в то время как IntelliJ IDEA у большинства студентов уже есть.
Стек технологий
Так как мы решили писать плагин для IntelliJ IDEA, долго выбирать технологии не пришлось. Для интеграции плагина со средой разработки мы использовали IntelliJ Platform Plugin SDK, а для генерации парсера языка Lama — другой инструмент от Jetbrains, Grammar Kit. К сожалению, это спорное решение, так как автоматизация процесса генерации парсера оказалась нетривиальной задачей. Также Grammar Kit самостоятельно не разрешает конфликты, связанные с наличием левой рекурсии, как это делают некоторые другие генераторы, например, ANTLR. Однако у Grammar Kit имеется и значительное преимущество — генерация парсера, совместимого с IntelliJ Platform по интерфейсам.
Как мы организовали работу в команде
Перед началом работы мы определили минимальную функциональность, которую хотели бы видеть в плагине:
ассоциация файлов — у файлов Lama свой тип, и хочется, чтобы IDE знала об этом;
лексинг и парсинг — так мы получим привычную для сред разработки подсветку синтаксиса и синтаксических ошибок при работе с языком;
хоть сколько-то информативные сообщения об ошибках. Те, кто имели дело с подобными задачами, представляют, как хорошо получить подсказку, а не указание на неожиданный токен X в правиле Y.
Кроме этого, мы накидали идей и для более продвинутой версии:
code completion — удобство, в котором сложно себе отказать;
переход от использования переменных/функций к их определению и наоборот.
Каждый из нас выбрал себе по задаче, и мы приступили к работе, большая часть которой велась очно в одном из офисов JetBrains. Большая — это с 11 до 19, два раза в день мы прерывались на митинги для синхронизации процесса. На митингах был ведущий — невыспавшийся в тон студентам куратор магистратуры. На этих встречах мы обозначали сложности и результаты, определяли, что будем делать дальше: какие-то задачи откладывали на потом, другие же, наоборот, приоритезировали. Само собой, после 19:00 хакатон не заканчивался: мы расходились по домам и продолжали работу.
Что мы сделали
Во время хакатона мы успели реализовать большинство из поставленных задач. Остановимся на каждой из них.
Во-первых, IntelliJ IDEA признала Lama в качестве языка программирования. Можно убедиться, что файлы Lama теперь — это не какой-то сырой текстовый файлик, а файл со своим расширением и даже иконкой!
Во-вторых, была реализована поддержка лексического и синтаксического анализа .lama файлов. Как уже упоминалось, для генерации парсера языка Lama мы использовали Grammar Kit. Парсер необходим плагину для того, чтобы анализировать .lama файлы и, в частности, находить синтаксические ошибки. Как правило, генераторы парсеров требуют от пользователя описать синтаксические правила языка в некоторой нотации. Grammar Kit использует собственную нотацию, правила содержатся в .bnf файлах (подробнее можно почитать по ссылке).
Один из важнейших этапов синтаксического анализа исходного кода — это построение дерева разбора программы. Однако перед построением такого дерева парсер зачастую требует выделить лексемы в коде или выполнить так называемый лексический анализ. В случае Grammar Kit правила выделения лексем, или как их еще называют токенов, можно задать все в той же bnf нотации. Затем по этим правилам генерируется
JFlex файл, по которому генерируется лексер. Если процесс покажется слишком усложненным, можно сразу использовать JFlex и генерировать лексер.
Несмотря на неудобства при использовании, Grammar Kit имеет большое преимущество при реализации парсера для плагина к IntelliJ IDEA. Дело в том, что сгенерированный парсер совместим с интерфейсами, которые использует IntelliJ IDEA для анализа файлов с исходным кодом. Благодаря этому сгенерированный парсер без каких-либо дополнительных ухищрений можно использовать в плагине.
В третьих, мы сделали подсветку синтаксиса — одно из важнейших удобств редактора и IDE. Она основана на результатах как лексического, так и синтаксического анализа. Так, в примере ниже подсветка для имени функции отличается от подсветки параметров. Еще подсвечиваются парные скобки и парные ключевые слова (do\od, if\fi и т.д.)
В-четвертых, мы реализовали автодополнение кода. В платформе IntelliJ предусмотрены два разных способа добавления этой функциональности. Первый способ — регистрация фиксированного набора слов, например, ключевых слов языка, которые будут предлагаться пользователям в любом месте программы:
Второй способ более продвинутый, он основывается на разрешении ссылок. Разрешение ссылок — это возможность перейти от места использования элемента, например, переменной или функции, к месту его определения. Оно позволяет в том числе сделать зависимое от окружения автодополнение кода, предлагая пользователям только те элементы, которые доступны в строчке, где находится каретка.
Сделать разрешение ссылок за хакатон мы так и не успели, это оказалось довольно сложно в реализации. Но нам хотелось поддержать хотя бы автодополнение функций из стандартной библиотеки Lama. Это удалось легко решить первым способом, просто захардкодив все библиотечные функции. Таким образом, наш плагин поддерживает автокомплит ключевых слов и функций стандартной библиотеки:
Вся реализованная функциональность уже делает программирование на Lama гораздо более приятным, чем раньше. Да, такая важная деталь, как разрешение ссылок еще не работает, но в будущем мы планируем доделать и эту часть. Если у кого-то возникнет интерес к расширению и доработке плагина — будем только рады!
Проблемы, с которыми мы столкнулись
Как это обычно бывает, самая большая сложность — соотнести желания и возможности в рамках планирования суточной деятельности. В первый день хакатона мы хотели уместить и каркас плагина, и лексер, и парсер, и объединить всё вместе. Поддержка стороннего языка в IDEA, работа с Grammar Kit — всё это новые для команды задачи, и нужно было учесть время на погружение в контекст. Не говоря уже о том, что для наших задач неплохо бы хорошо знать язык, а у нас только Арсений работал с Lama раньше. Как итог, не все дневные планы удавалось реализовывать в полной мере. Но понимание своих возможностей пришло довольно скоро, мы стали лучше конкретизировать планы, работа пошла споро.
Кроме этого просчета с планированием, других серьезных проблем в команде не было. Разве что мы столкнулись с мелкими неудобствами: один из участников в преддверии хакатона уехал из Петербурга, так что ему пришлось работать дистанционно. Так у нас в команде появился лучший собственный аутсорсер.
Подведение итогов и личные впечатления
Было весело! Это увлекательное испытание себя — работаешь вместе с командой и днем, и вечером, не замечаешь, как быстро проходит время. Часть нашей команды не без оснований считает, что хорошо, что хакатон длится всего три дня, а не больше :)
Мы остались довольны полученным результатом. Поскольку этот плагин будут использовать как авторы, так и другие студенты и заинтересованные лица, дальнейшая работа над ним представляется реальной. Хотелось бы доработать полноценный резолв, расширить возможности auto-complete, ну и сделать что-нибудь еще интересное.