Pegium is a language engineering toolkit for C++20 with built-in support for parsing, AST/CST construction, references, validation, formatting, and language-server features.
Pegium is strongly inspired by Langium, and many of the core concepts are intentionally similar. The main difference is that Pegium centers on a PEG-based parser DSL in C++, instead of Langium's TypeScript grammar and parser stack.
- Semantics First: Pegium lets you shape the semantic model of your language directly through C++ AST types plus grammar assignments, while still keeping CST data available for source-aware tooling.
- Explicit Services, Customizable by Design: Pegium exposes parser, scoping, validation, workspace, formatting, and LSP behavior through visible service objects instead of hiding the wiring behind heavy code generation.
- Parser to Editor in One Toolkit: The same document model supports parsing, linking, diagnostics, formatting, completion, rename, references, and other editor features.
Prerequisites: a C++20 compiler, CMake 3.14 or later. Node.js is only
needed if you want to build the VS Code extension (-DVSCODE=ON, the default).
Scaffold a new language with a single command — no cloning required:
curl -fsSLO https://ydaveluy.github.io/pegium/pegium-new.cmake && \
cmake -DNAME=MyLang -DEXT=.ml -P pegium-new.cmake
cd mylang && cmake -B build && cmake --build build -j
./build/mylang-cli example/hello.mlThe script creates a mylang/ directory with a working "Hello world" grammar,
CLI, LSP server, and VS Code extension, pulling Pegium in via FetchContent.
| Flag | Default | Description |
|---|---|---|
NAME |
(required) | PascalCase C++ identifier for your language (e.g. MyLang) |
EXT |
.<lowercased-name> |
File extension, must start with . (e.g. -DEXT=.ml) |
DIR |
<lowercased-name> |
Output directory (e.g. -DDIR=my-project) |
LSP |
ON |
Build the LSP server; pass -DLSP=OFF to skip |
VSCODE |
ON |
Scaffold the VS Code extension; pass -DVSCODE=OFF to skip |
CLI |
ON |
Build the CLI tool; pass -DCLI=OFF to skip |
PEGIUM_TAG |
main |
Pegium tag/commit to pin (e.g. -DPEGIUM_TAG=v1.2.0) |
Pegium is consumed via CMake FetchContent (or add_subdirectory). As of
v0.1.0 it intentionally ships no install() rules and no find_package(pegium)
config — pin a tag and pull it into your build:
include(FetchContent)
FetchContent_Declare(
pegium
GIT_REPOSITORY https://github.com/ydaveluy/pegium.git
GIT_TAG v0.1.0
)
FetchContent_MakeAvailable(pegium)
target_link_libraries(my_language PUBLIC pegium::core)Available targets: pegium::core (parser, workspace, references), pegium::lsp
(language server), pegium::cli (CLI/test helpers), pegium::converters.
Requires a C++20 compiler.
Open the repository root in VS Code, go to Run and Debug, pick one of
Run Arithmetics Extension, Run DomainModel Extension,
Run Requirements Extension, or Run Statemachine Extension, then press
F5.
On the first launch, VS Code runs the matching Prepare ... Extension task for
you: it configures CMake, builds the example language server, installs the
extension dependencies if needed, and compiles the VS Code extension.
VS Code then opens a new Extension Development Host window on the corresponding example workspace, so you can immediately try the language features on the shipped sample files.
If you are new to the project, the best documentation entry points are:
You can find the Pegium documentation on the documentation website.
The documentation is organized into several sections:
- Introduction: what Pegium is, why it exists, and how it relates to Langium
- Learn: the recommended workflow for building a language with Pegium
- Recipes: targeted guides for customization tasks such as scoping, validation, caching, and multiple languages
- Reference: canonical documentation for grammar, services, semantic model, and document lifecycle
- Examples: the shipped example languages and what each one demonstrates
The documentation sources live in docs/ in this repository.
Pegium ships several end-to-end examples in this repository:
- arithmetics: a compact expression language with evaluator, formatter, CLI, and LSP server
- DomainModel: a modeling DSL with qualified names, formatter rules, and rename support
- requirements: a multi-language example showing shared workspace behavior and cross-language references
- statemachine: a modeling language that emphasizes validation and editor integration
Pegium and Langium ship the same four example languages, so they can be compared directly. Each language is built through the full document pipeline (parse → index → scope → link → validate) from byte-identical generated inputs, averaged over 3 iterations. The workspace benchmarks hand many self-contained files of one language to the framework's document builder at once, as a single small (~250 KB) and large (~12 MB) startup build — Pegium parallelizes those builds across all cores. Pegium also parallelizes a single document's linking and validation across cores, which the large single-file build below exercises (at smaller sizes those phases are sub-millisecond, so per-document parallelization cannot outrun its own dispatch overhead; the gain surfaces only once the document is large).
Each table reports the full build time and the throughput (MiB/s) for both engines, plus the Langium-over-Pegium speedup; the workspace tables also report the peak resident memory (RSS) of each build. Lower time / higher throughput / lower memory is better. RSS includes each runtime's baseline — Node/V8 carries a fixed multi-tens-of-MiB heap Pegium's native process does not — so read it alongside how it grows with input size. Langium 4.3.0 / Node.js 26.
Single-file full build, small (~64 KiB):
| language | pegium time | pegium throughput | langium time | langium throughput | speedup |
|---|---|---|---|---|---|
| arithmetics | 3.12 ms | 20.0 MiB/s | 279 ms | 0.2 MiB/s | ~90× |
| domainmodel | 1.17 ms | 53.5 MiB/s | 151 ms | 0.4 MiB/s | ~129× |
| requirements | 1.30 ms | 48.1 MiB/s | 40 ms | 1.6 MiB/s | ~30× |
| statemachine | 1.26 ms | 49.6 MiB/s | 79 ms | 0.8 MiB/s | ~62× |
Single-file full build, large (~1 MiB):
| language | pegium time | pegium throughput | langium time | langium throughput | speedup |
|---|---|---|---|---|---|
| arithmetics | 45 ms | 22.3 MiB/s | 33.6 s | 0.03 MiB/s | ~750× |
| domainmodel | 15 ms | 66.7 MiB/s | 24.7 s | 0.04 MiB/s | ~1648× |
| requirements | 18 ms | 54.6 MiB/s | 1.1 s | 0.87 MiB/s | ~63× |
| statemachine | 17 ms | 58.7 MiB/s | 6.0 s | 0.17 MiB/s | ~354× |
Langium's single-document scope resolution scales superlinearly with cross-reference density: the 16× jump from the small to the large single file inflates its build time only ~30× for reference-light requirements but up to ~160× for reference-dense domainmodel, whereas Pegium's grows roughly linearly (~13–14×). The workspace tables below, which spread the same volume across many files, are the more representative shared-build comparison.
Workspace full build, ~250 KB (all files built simultaneously at startup):
| language | pegium time | pegium throughput | langium time | langium throughput | speedup | pegium RSS | langium RSS | RSS ratio |
|---|---|---|---|---|---|---|---|---|
| arithmetics | 1.69 ms | 148.1 MiB/s | 498 ms | 0.5 MiB/s | ~295× | 18 MiB | 211 MiB | ~12× |
| domainmodel | 1.20 ms | 208.9 MiB/s | 232 ms | 1.1 MiB/s | ~193× | 18 MiB | 186 MiB | ~10× |
| requirements | 3.03 ms | 82.8 MiB/s | 134 ms | 1.9 MiB/s | ~44× | 18 MiB | 174 MiB | ~10× |
| statemachine | 1.34 ms | 189.2 MiB/s | 212 ms | 1.2 MiB/s | ~158× | 18 MiB | 187 MiB | ~10× |
Workspace full build, ~12 MB (all files built simultaneously at startup):
| language | pegium time | pegium throughput | langium time | langium throughput | speedup | pegium RSS | langium RSS | RSS ratio |
|---|---|---|---|---|---|---|---|---|
| arithmetics | 43 ms | 278.9 MiB/s | 23.8 s | 0.5 MiB/s | ~553× | 615 MiB | 3.1 GiB | ~5× |
| domainmodel | 30 ms | 401.2 MiB/s | 10.1 s | 1.2 MiB/s | ~338× | 365 MiB | 2.1 GiB | ~6× |
| requirements | 98 ms | 122.5 MiB/s | 51.6 s | 0.2 MiB/s | ~527× | 338 MiB | 1.6 GiB | ~5× |
| statemachine | 30 ms | 397.1 MiB/s | 10.1 s | 1.2 MiB/s | ~336× | 404 MiB | 2.2 GiB | ~6× |
Numbers are indicative and hardware-dependent; reproduce them on your own machine with:
cmake --build build -j --target PegiumBench
# Uses a sibling ../langium checkout; pass --setup to clone + build the latest
# Langium and install the bench harness automatically.
python3 tools/compare_langium_bench.py --setupPegiumBench (under tests/bench/) and the Langium harness
(tools/langium-bench/bench-examples.mjs)
generate the same inputs and report the same format, which
tools/compare_langium_bench.py diffs into the
tables above.
Pegium is MIT licensed (c) 2024-2026 Yannick Daveluy.