Разработка собственных языков и языковых серверов может быть сложной и рутинной задачей. Langium — инструмент на TypeScript, который упрощает создание предметно‑ориентированных языков (DSL) с готовым LSP‑сервером.
Меня зовут Денис Маматин, я работаю в R&D‑отделе СберТеха. В ходе разработки одного из наших проектов мы столкнулись с необходимостью создания собственного DSL, и в этом нам существенно помог Langium. В этой статье я рассмотрю, как устроена грамматика Langium, как создать первый проект и какие преимущества он даёт разработчику.
Langium: быстрое создание языков и LSP‑серверов
В предыдущей статье статье я рассматривал Language Server Protocol (LSP) — протокол, стандартизирующий взаимодействие между языковым сервером и IDE, а также приводил пример написания простого языкового сервера.
Однако функциональность таких серверов часто пересекается (например, операции переименования переменных или отображение hover‑подсказок). Поэтому логично использовать инструмент, который возьмёт на себя рутинную часть работы и ускорит разработку.
С этой задачей отлично справляется Langium.
Langium — это «language engineering tool» с открытым исходным кодом, написанный на TypeScript и работающий под Node.js. Он поддерживает LSP и позволяет создавать предметно‑ориентированные языки (Domain‑Specific Languages, DSL) с готовым языковым сервером, который легко расширяется и интегрируется в VS Code.
Гибкость Langium достигается благодаря использованию внедрения зависимостей (Dependency Injection) — это позволяет заменять любые компоненты и сервисы фреймворка, на которых основана реализация языкового сервера.
Файл грамматики
Любой язык начинается с грамматики — набора правил, определяющих, какие последовательности символов считаются корректными. Например, выражение const x=1 допустимо в JavaScript, но не в Python.
Текст программы проверяется на соответствие этим правилам, и в случае ошибок парсер сообщает о несоответствии. Далее из корректного текста строится AST (Abstract Syntax Tree) — внутренняя структура, представляющая содержание файла без несущественных элементов (пробелов, комментариев и так далее).
Сердце любого проекта Langium — это файл грамматики, по которому автоматически генерируется языковой сервер.
Ниже приведён пример минимальной грамматики:
grammar HelloWorld
hidden terminal WS: /\s+/;
terminal ID: /[_a-zA-Z][\w]*/;
entry Model: (persons+=Person | greetings+=Greeting)*;
Person:
'person' name=ID;
Greeting:
'Hello' person=[Person] '!';
Ей соответствует следующий пример входного файла:
person John
person Jane
Hello John!
Hello Jane!
Разберём грамматику построчно.
Заголовок
grammar HelloWorld
Определяет имя грамматики, на основе которого будут сгенерированы файлы и классы на TypeScript.
Лексические правила
Далее описываются терминалы — правила, по которым текст разбивается на токены. Например, в строке Hello John! лексер должен понять, где заканчивается имя и начинается !.
Терминал для имени:
terminal ID: /[_a-zA-Z][\w]*/;
Он описывает, что идентификатор начинается с буквы или подчёркивания и продолжается любыми буквами, цифрами или подчёркиваниями. При разборе John! лексер создаст токен ID(John), а ! станет отдельным токеном.
Терминал пробелов:
hidden terminal WS: /\s+/;
Регулярное выражение \s+ обозначает любые пробельные символы. Ключевое слово hidden указывает, что такие токены не передаются парсеру — они нужны только для разделения слов.
Грамматические правила
После терминалов описываются синтаксические правила вида Name: Body. Одно из них должно быть главным (отмечается entry).
entry Model: (persons+=Person | greetings+=Greeting)*;
Это правило говорит, что документ может содержать произвольное количество (*) сущностей двух типов: Person и Greeting.
Далее определяются конкретные конструкции:
Person:
'person' name=ID;
Greeting:
'Hello' person=[Person] '!';
Правило Person описывает создание нового объекта с именем, а Greeting — обращение к уже существующему ([Person] указывает на ссылку, а не создание нового объекта). Таким образом, Hello John! ссылается на person John.
После генерации из этой грамматики Langium создаст интерфейсы TypeScript:
interface Model {
persons: Person[];
greetings: Greeting[];
}
interface Person {
name: string;
}
interface Greeting {
person: Person;
}
Подробную документацию по синтаксису грамматики можно найти здесь.
Создание первого проекта Langium
-
Установите Yeoman и генератор Langium:
npm i -g yo generator-langium -
Запустите генератор:
yo langiumYeoman задаст несколько вопросов:
Extension name — имя расширения и директории проекта.
Language name — имя грамматики и префикс для сгенерированных файлов.
File extensions — расширения файлов DSL (через запятую).
VS Code extension — создание VS Code расширения.
CLI — добавление интерфейса командной строки.
Web worker — поддержка работы в браузере.
Language tests — генерация шаблонов тестов.
-
После генерации структура проекта будет следующей:
hello-world ├── README.md ├── package.json ├── packages │ ├── cli — CLI для запуска языка из терминала │ ├── extension — VS Code расширение (подсветка, автодополнение и т. д.) │ └── language — грамматика, правила и AST └── tsconfig.json -
Чтобы протестировать расширение в VS Code:
Откройте проект в VS Code.
Запустите задачу «Run Extension» (F5).
В новом окне создайте файл с расширением
.hello.Вставьте пример из предыдущего раздела. IDE сразу предоставит подсветку, автодополнение и диагностику ошибок.
На рисунке ниже можно увидеть пример создания и работы с файлом person.hello в VS Code.

После создания файла person.hello редактор распознаёт его как DSL. Ключевые слова (person, Hello) подсвечиваются согласно семантике языка, идентификаторы имён (John, Jane) распознаются как ссылки на сущности Person. При вводе текста VS Code в реальном времени выполняет парсинг и валидацию: например, если написать Hello Daniel!, не объявив person Daniel, редактор сразу подсветит ошибку «unresolved reference» и укажет проблемное место волнистым подчёркиванием. Аналогично, синтаксические ошибки (пропущенный!, опечатка в ключевом слове) диагностируются мгновенно, без запуска отдельной сборки.
Подводя итоги
Langium предоставляет современный и гибкий подход к созданию предметно‑ориентированных языков и языковых серверов. Он снимает с разработчика необходимость вручную реализовывать стандартные функции LSP, позволяя сосредоточиться на логике самого языка.
Полезные ресурсы
Комментарии (2)

Ares_ekb
14.01.2026 15:22Возможно кому-нибудь пригодится, я прикручивал Langium к Monaco Editor (это редактор из VS Code только в браузере). В теории всё должно быть просто, но мне очень не хватало минималистичных примеров, поэтому запилил свои (исходники).
Мы используем его для редактирования моделей: раз, два. Поэтому нам был нужен не только редактор, но и принтер из AST обратно в код
cmyser
ооо я пробовал его, очень сложный, в итоге сам писал и tree-sitter и lsp
это конечно очень нишевая тема, очень мало инфы и примеров, респект за освещение, инструменты делать - боль, а поддерживать - еще большая боль