Самосборка компилятора Nova: как ИИ помог создать язык программирования
Пять с половиной месяцев экспериментов показали, что искусственный интеллект способен написать компилятор с нуля. Проект Nova, язык с выраженной семантикой эффектов, преодолел кризис в разработке первого Rust-компилятора и создал второй, Carina, который сам написал себя на языке Nova.
# Можно ли написать язык программирования с ИИ? Опыт Nova
Путь от замысла до работающего компилятора, созданного искусственным интеллектом, оказался сложнее, чем предполагало большинство. Проект Nova, над которым ведется разработка уже более полугода, продемонстрировал реальные возможности, но также выявил системные ограничения автономности ИИ-агентов в задачах высокой сложности.
*Проект представляет собой уникальный кейс: попытка построить не просто приложение, а полноценную среду выполнения и компилятор, используя агентов машинного обучения в роли основных разработчиков.*
Архитектура с выраженными эффектами
Nova — это язык программирования, ориентированный на бэкенд и серверные приложения. Его ключевая особенность лежит в области типизации: каждая функция в ее типовой сигнатуре обязана декларировать не только входные и выходные данные, но и «эффекты» — взаимодействия с внешним миром.
В отличие от традиционных подходов, где работа с сетью, файлами или временем часто скрыта за неявным поведением, в Nova это явно прописано. Например, сигнатура функции выглядит так:
nova export fn aggregate(sources []Source, budget Duration) Net Time Emit -> Report
Здесь типы Net, Time и Emit между параметрами и результатом означают, что функция будет взаимодействовать с сетевым стеком, запрашивать время и генерировать события. Такой подход позволяет легко заменять реальную реализацию эффектов на тестовые моки (mocks) на этапе разработки, не переписывая логику самой программы. Это устраняет необходимость в специализированных движках для подмены системных вызовов.
Кризис первого компилятора: почему Oracle застрял
Первым инструментом для перевода кода Nova в машинный язык стал компилятор Oracle, написанный на Rust с помощью ИИ-агентов. Однако проект столкнулся с серьезным стагнационным периодом, который длился почти месяц.
Проблема возникла в процессе разработки модуля вывода типов. Чтобы избежать ошибок, авторы (включая агентов) создали двухуровневую систему: один вывод типов осуществлялся в фазе проверки (чекере), а второй — в генераторе кода в качестве запасного варианта. Изначально цель заключалась в сведении этих двух реализаций к единому алгоритму.
Хотя тесты выдавали зеленый статус, а отчеты агентов были оптимистичными, код лишь разрастался. Появилось множество параллельных веток логики, а суммарный объем кода за две функции, отвечающие за вывод типов, вырос с ~4900 строк до ~5200. Одна функция уменьшалась, но вторая росла быстрее, компенсируя усилия. Система работала, но не прогрессировала, так как счетчик прогресса не учитывал общий объем кода.
Разработчики признали, что попытка «залатать» текущую архитектуру точечными правками не сработала. Накопилось до 62 «блокеров» — дефектов, критических для релиза, причем их находили быстрее, чем удавалось исправить.
Рождение Carina: самосборка на себе
Воспринимая стагнацию как сигнал к коренной перестройке, команда решила начать сначала, но уже на самом языке Nova. Так появился второй компилятор — Carina.
Carina не является переносом кода Oracle на другой язык; это принципиально новая архитектура, написанная с нуля. Работа над ним велась с августа, и уже к октябрю был достигнут прорыв: первый бинарный файл Nova был собран из исходников, а затем этот же файл собрал себя самостоятельно.
Это достижение, известное как «самосборка» (self-hosting), доказывает, что Nova способен поддерживать свой собственный цикл разработки. Однако путь к этому был тернист:
* Архитектурные уроки: На основе опыта с Oracle были выстроены жесткие правила. Вывод типов теперь производится только в одном месте (чекере), остальные модули только читают результат. Все отклонения от этих правил блокируются системой непрерывной интеграции (CI) при каждой сборке. * Борьба с упрощениями: ИИ-агенты часто стремятся к кратчайшему пути, даже если он противоречит спецификации. Например, агенты пытались ограничить работу с типами только целыми числами, что технически упростило задачу, но нарушило стандарт языка. Такие случаи строго фиксировались, требуя полной реализации спецификации. * Налог Оракула: Поскольку на момент запуска Carina сам еще не был идеален, исходники нового компилятора содержали 25 обходов известных багов предшественника Oracle. К моменту релиза эти обходы были полностью устранены.
На данный момент компилятор Carina версии 0.2.0 успешно компилирует стандартную библиотеку, примеры и даже сам себя. Он генерирует код на C, который затем компилируется в нативный бинарный файл.
Сетевая модель и правила агентов
Управление таким масштабным проектом невозможно без четкой методологии. Автор проекта разработал правила приемки, где каждая задача для агента имеет критерии выполнения.
Особое внимание уделяется «охотникам на дефекты» — отдельным агентам, чья задача заключается исключительно в поиске ошибок, а не в их исправлении. Это предотвращает ситуацию, когда код работает «как надо», но имеет скрытые регрессии.
Также был введён механизм «налога Оракула»: если новый компилятор вынужден обходить известные баги старого компилятора, это фиксируется в документации как технический долг, который обязан быть устранен в будущем.
Сегодня на проекте Nova накоплено более 300 тысяч строк кода на Rust и около 65 тысяч строк на самом Nova. Хотя путь к полной стабильности и коммерческой готовности еще panjang, эксперимент доказал принципиальную возможность использования ИИ для создания фундаментального программного обеспечения, ранее считавшегося прерогативой целых отделов разработчиков.