Язык программирования Ruby заслуженно считается одним из самых дружественных к разработчикам и элегантных языков. Его философия, ориентированная на удобство и гибкость, пользуется огромной популярностью у программистов по всему миру. Однако, несмотря на всю красоту языка, его внутренний механизм обработки исходного кода — парсер — на протяжении десятилетий оставался одной из самых проблемных частей экосистемы. В 2023 году команда Shopify предприняла масштабную работу по созданию нового Ruby-парсера, получившего название YARP (Yet Another Ruby Parser). Эта разработка обещает кардинально изменить способ работы с языком и значительно повысить качество и эффективность инструментов для Ruby-разработчиков.
До появления YARP парсер CRuby, который используется в стандартной реализации языка, имел ряд ограничений. Во-первых, поддержка и развитие существующего парсера были крайне непростыми из-за сложности кода и отсутствия достаточной документации. Во-вторых, его архитектура была устаревшей, что приводило к проблемам с переносимостью и работоспособностью в нестандартных условиях, а также к низкой устойчивости к синтаксическим ошибкам. В-третьих, существовал значительный разрыв в поведенческом согласовании парсеров, используемых в различных инструментах и альтернативных реализациях Ruby, что создавало сложности для разработчиков экосистемы. Одним из основных мотивирующих факторов для создания YARP стала необходимость повышения удобства сопровождения кода парсера.
Оригинальный парсер, разработанный на основе генератора Bison, имел огромный монолитный файл, насчитывающий около 14000 строк кода, в котором было очень сложно разобраться даже опытным разработчикам. Кроме того, далеко не все изменения удавалось вносить без риска нарушения других частей, что затрудняло быстрое исправление ошибок. Малое число активных участников, способных поддерживать парсер, создавало угрозу для его долгосрочной стабильности и развития. Непонятные и недостаточные ошибки синтаксиса зачастую становились преградой для разработки и усложняли применение современных инструментов анализа кода, включая язык серверы и статические анализаторы. Еще одной серьезной проблемой оставалась слабая tolerance к синтаксическим ошибкам.
В существующем парсере при обнаружении даже самых мелких ошибок прекращался разбор всего документа, и разработчик видел лишь первую из них. Это существенно снижало скорость отладки и исправления программ, поскольку исправлять приходилось каждую ошибку по отдельности. В реальной практике программисты часто сталкиваются с ситуациями, когда в одном файле содержится несколько ошибок, которые удобно было бы видеть одновременно. YARP проектировался, чтобы это изменить: новый парсер способен распознавать даже ошибочные участки и продолжать создание абстрактного синтаксического дерева, отражая все ошибки одновременно. Эта особенность значительно повышает комфорт и продуктивность программирования.
Для решения проблемы переносимости YARP был создан как самостоятельная, не зависящая от внутренностей CRuby компонента на языке С. Такой подход гарантирует возможность использования парсера в самых разных средах и инструментах, включая альтернативные реализации Ruby, такие как JRuby и TruffleRuby. Уникальным решением стало создание API для сериализации синтаксического дерева, что упрощает интеграцию и обмен информацией между парсером и инструментами на различных языках программирования. В результате получается единый стандарт разбора исходного кода Ruby, на который смогут опираться разработчики и поддерживающие инструменты по всему миру. Выбор языка С для написания YARP пал исходя из двух логичных причин.
Первая — техническая совместимость с любыми платформами и возможность легкой интеграции. Вторая — удобство сопровождения команды CRuby, большую часть которой составляют опытные разработчики, хорошо знакомые с С. Такой подход способствует высокой производительности и простоте поддержки при сохранении максимальной совместимости с существующей экосистемой. Новое ядро парсера выполнено в стиле рекурсивного спуска — ручной реализации, противопоставленной генераторам, таким как Bison. Эта концепция давно доказала свою эффективность в крупных языках программирования и позволяет гибко решать сложные задачи разборки, воспринимать контекст и создавать более понятные и устойчивые решения.
Логика рекурсивного спуска органично вписывается в требования Ruby, чья грамматика относится к контекстно-чувствительным, что затрудняло применение классических генераторов LR-парсеров. YARP не ограничивается лишь созданием нового ядра разбора, но и внедряет совершенно новую структуру представления абстрактного синтаксического дерева. Эта структура спроектирована таким образом, чтобы быть максимально информативной, удобной и расширяемой для любых инструментов — от статических анализаторов до IDE и форматеров кода. Важно, что новая совместная работа с командами JRuby и TruffleRuby позволила выстроить единое понимание метаданных в дереве, его сериализации и десериализации. Тестирование и отладка нового парсера проходили на реальных больших проектах, включая главный репозиторий Shopify, исходный код GitHub, а также самые популярные Ruby-гемы.
Такой всесторонний проверочный подход позволил добиться полной совместимости синтаксических деревьев с Ruby 3.3 и практически исключить несоответствия. Показатели производительности приятно удивили: YARP способен обрабатывать десятки тысяч файлов с минимальным расходом памяти и высокой скоростью. Практическое применение YARP уже расширяется: он внедряется в TruffleRuby, становится основным парсером в Syntax Tree и начинает интеграцию с другими ключевыми инструментами экосистемы Ruby. Благодаря своему универсальному дизайну парсер станет базой для развития новых возможностей разработки, улучшения качества анализа и повышения производительности работы со всеми инструментами, связанными с Ruby.
Помимо технических аспектов, важным эффектом от появления YARP станет объединение фрагментированной базы разработчиков, работающих с разными парсерами. Раньше создание и поддержка нескольких независимых парсеров приводила к дублированию усилий и несовместимости. Теперь же, имея единый современный и открытый парсер, сообщество сможет концентрировать знания и опыт, ускоряя развитие всего языка и связанных проектов. В будущем нас ожидает еще больше инноваций. Среди запланированных улучшений — дальнейшая оптимизация работы с памятью, такие как аллокация через арены, расширение возможностей по детальному отслеживанию ошибок с предсказательным сканированием, а также углубленная поддержка новых возможностей языка.
Появится возможность получения синтаксического дерева напрямую из Ruby 3.3 при помощи require "yarp", что откроет новые горизонты для экспериментов и создания продвинутых средств анализа. В заключение, переписывание парсера Ruby в форме YARP — это стратегический шаг вперед, который преодолевает многие вызовы, сдерживавшие развитие языка и экосистемы последние десятилетия. Он обеспечивает масштабируемость, облегчает поддержку, улучшает взаимодействие с инструментами и повышает качество опыта разработчиков. Это изменение может стать одной из ключевых вех в истории Ruby, открывая простор для новых инноваций и оказывая значительное влияние на дверь в мир Ruby-разработки.
Для всех заинтересованных в развитии языка и инструментария Ruby открывается простор для участия, тестирования и внедрения YARP. Его открытый исходный код и активное сообщество делают его перспективным проектом, способным преобразить будущее программирования на Ruby.