Open-source project
sampsyo/bril avatar
sampsyo/bril

bril is a compiler intermediate representation built to be extended

an educational compiler intermediate representation

800 stars337 forksRustMIT

At a glance

What is it?
Bril, the Big Red Intermediate Language, is a teaching IR for a graduate compilers course, with JSON as its canonical form, a Deno reference interpreter, a Python text format and a repository full of alternative implementations and optimisation passes. It is MIT licensed, publishes no releases, and is designed to be small enough that a student can change it in a week.
Who is it for?
Instructors and students who want a compiler course to share one artifact across languages should adopt bril, because the JSON canonical form and the interpreter make it cheap to write new backends and optimisations, and the repository already contains enough alternative implementations to use as reference material.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 159 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A teaching IR whose defining property is that it is easy to change

Bril, which stands for the Big Red Intermediate Language, is a compiler IR made for teaching CS 6120, a graduate compilers course. The README is explicit that it is an extremely simple instruction-based IR that is meant to be extended.

That last clause is the design brief. Bril is not trying to be a good intermediate representation in the abstract. It is trying to be an IR that a student can extend in an afternoon without first understanding a production compiler's data structures.

The two decisions that make that work are visible in the README. The first is the canonical representation: JSON, which the README says makes it easy to build tools from scratch to manipulate it. A tool that reads and writes JSON needs no parser, no code generator and no type definitions, which is exactly the barrier that stops students writing the tool they need for their project.

The second is the scale. There is an instruction-based core and little else, so the surface a student has to understand before changing anything is small.

The repository contains the documentation, including a language reference document, and infrastructure for Bril itself. The README points at a wiki page of documentation at capra.cs.cornell.edu/bril, with the language reference at a separate path, and a quick start for the main tools.

The audience is therefore twofold: the instructor who wants one shared artifact for a course, and the student who wants to build an optimisation, a type checker or a new backend without fighting infrastructure.

The interpreter is Deno, the text format is Python, and both read stdin

The tooling is split by language, and the split is practical rather than ideological.

The reference interpreter is the piece you want first, and the README says you want the IR interpreter, which uses Deno. It is installed with a single command:

bash
    $ deno install -g brili.ts

Deno then tells you to add $HOME/.deno/bin to your $PATH, and after that you have brili, which takes a Bril program as JSON on stdin and executes it. That description of the interface is the whole contract: JSON in, execution out.

The human-editable text form of Bril is handled by a separate pair of tools, the parser and pretty printer, which are in Python. The README recommends installing them with uv, and the instructions are to install uv, go to the bril-txt directory and type:

bash
    $ uv tool install .

The tools are called bril2json and bril2txt, and they too take input on stdin and produce output on stdout.

So the pipeline is text to JSON and back, with brili executing the JSON. The separation matters for teaching, because a student can write an optimiser that reads bril2txt output, rewrites it and emits text, and the rest of the toolchain never notices.

Two more tools exist at the top level of the repository. ts2bril.ts compiles a TypeScript-ish source into Bril, and brilck.ts is a type checker. Both are Deno programs installed with deno install -g, and ts2bril needs the --allow-env and --allow-read permissions flags.

One tree, many implementations: Rust, OCaml, Swift, LLVM

The repository listing is the most unusual thing about Bril, and it is where the teaching value multiplies.

There are complete alternative implementations in several languages. bril-rs is a Rust implementation, bril-ocaml an OCaml one, bril-swift a Swift one and bril-llvm a backend targeting LLVM. The TypeScript one, bril-ts, is the reference implementation behind brili.ts. Alongside them sit brilir, brilirs and bril2json-rs, which look like further Rust-based tooling, plus fastbril and flat-bril, which suggest a faster and a flattened variant of the format.

There is also brench, a benchmarking harness, a bracket directory, a type-infer directory and a bril-vim directory, which is an editor mode for the text format.

The examples directory is the other half of the story, and its file names describe a curriculum in dataflow analysis and SSA construction. There are cfg.py and cfg_dot.py for control flow graphs, dom.py for dominators, df.py for dataflow, form_blocks.py for basic blocks, from_ssa.py and is_ssa.py, to_ssa.py and to_ssa_crude.py for the two routes to SSA, lvn.py for local value numbering, tdce.py for dead code elimination, normalize.py for normalisation and util.py for shared helpers, plus a ssa_brench.toml and ssa_plot.json.

For a course, that is a menu of assignments with reference implementations sitting next to them. For a learner, it is a set of worked examples of how a pass is written against this IR.

The licences follow the same cooperative logic. The repository is MIT licensed, with a LICENSE file at the root, and the README is structured so that a student can write the missing piece and the rest of the ecosystem keeps working.

Tests run through turnt, and the Makefile refuses to run without the tools

The test setup is where the teaching orientation shows most clearly, because it is designed so that a student can change the IR without breaking the course's expectations.

The tests live in the test directory and use turnt, a tool that lets you write the expected output for individual commands. It is installed with uv:

bash
    $ uv tool install turnt

A single test runs with a command of the form turnt test/interp/core/tiny.bril, and the full suite requires the type checker and the TypeScript compiler first:

bash
    $ deno install -g brilck.ts
    $ deno install -g --allow-env --allow-read ts2bril.ts

after which you type make test.

The Makefile shows the scope of the suite through its file globs. The TESTS variable covers parsing and printing, the TypeScript front end tests, the type checker tests, and then every interpreter variant: interp, interp-char, interp-float, interp-mem, interp-mixed, interp-spec, interp-ssa and interp-dynamic, each with core, char, float, mem, mixed, spec and ssa subtrees. Benchmarks and the example programs are included in the same run.

That last part is the design point. Because there are several implementations, the test suite has to pass on all of them, so the IR semantics are pinned down by behaviour rather than by specification alone. A student who changes the semantics of an instruction finds out immediately, in several implementations at once.

The check target is separate and cheaper. It runs bril2json on each file and pipes the result into brilck, which validates that the program type checks, without executing anything.

The book is built with mdbook and deployed over rsync

The documentation is part of the repository rather than a separate site, and the Makefile builds it.

The book target removes the book directory and runs mdbook build, and the repository carries a book.toml at the root, which is the mdbook configuration file. The docs directory holds the sources, and the compiled site is what the deploy target publishes.

That deploy target is a plain rsync to a directory on a course web host, with the destination given as courses:coursewww/capra.cs.cornell.edu/htdocs/bril, using a named host for the SSH connection and a set of flags that include --delete so the published tree matches the local one exactly. It depends on the book target, so publishing implies building.

The rest of the Makefile covers the TypeScript implementation and the release artefacts. The ts target changes into the bril-ts directory and runs yarn followed by yarn build, and there is a clean target.

Two things are worth noting for anyone reading the repository rather than using it. The TypeScript implementation is built with yarn inside bril-ts even though the rest of the toolchain is installed with uv and deno, so a contributor needs both. And the deploy target hard-codes a course host, which tells you where the canonical documentation lives and who owns it.

For a course instructor, the practical value is that the documentation, the interpreter and the tests are one repository. Change the language, rebuild the book, and the reference the students read matches the code they run.

Where bril is the wrong tool

The limits come from the purpose, and they are severe if you are not teaching.

First, the IR is not production material. It is described as extremely simple, and the language reference documents a deliberately small instruction set. A real compiler needs types, memory models, calling conventions, vectors and a much larger instruction vocabulary, and Bril has none of those beyond what brilck checks. Building a serious compiler on Bril means growing it into something else.

Second, there is no stability promise and no release cadence. The repository has no GitHub releases at all, the documentation is the canonical artefact rather than a versioned package, and the last push was on 2026-05-18. A course that pins to a commit will drift from a course that pins to the branch.

Third, the implementations are uneven by nature. The tree holds implementations in Rust, OCaml, Swift, TypeScript and an LLVM backend, plus several variants that appear to be faster or flatter. Those are written and maintained by different people, and the README does not promise that they all support the same feature set. The Makefile's own error message for a missing executable says to refer to the documentation for installation instructions or to run a subset of the tests manually with turnt, which is a small hint that not every combination is expected to work.

Fourth, the toolchain is three runtimes. Deno for the interpreter and the type checker, uv for the Python tools and turnt, and yarn for building the TypeScript implementation. For a course that teaches compilers, that is a fair trade. For a one-off tool, it is a lot of setup.

On the positive side, the MIT licence and the JSON canonical form mean that anything you build on top of Bril, including a compiler or a research prototype, is yours to keep and to publish.

Editorial conclusion

Instructors and students who want a compiler course to share one artifact across languages should adopt bril, because the JSON canonical form and the interpreter make it cheap to write new backends and optimisations, and the repository already contains enough alternative implementations to use as reference material. It is the wrong tool for a production compiler, since the IR is deliberately minimal and the project is a teaching artifact with no release cadence and no stability promise. Before building on it, read the language reference for the instruction set you intend to target, and check that the interpreter or the backend you need actually covers the features your course requires, because the implementations in the tree are maintained by different people at different speeds.

Frequently asked questions

How do I install the Bril reference interpreter?

The interpreter is a Deno program. Run deno install -g brili.ts, then add $HOME/.deno/bin to your PATH. You end up with brili, which takes a Bril program as JSON on stdin and executes it.

How do I install the Bril text format tools?

The parser and pretty printer are in Python and the README recommends uv. Install uv, go to the bril-txt directory and run uv tool install ., which gives you bril2json and bril2txt, both of which read stdin and write stdout.

How do I run the Bril test suite?

Install turnt with uv tool install turnt, then install the type checker and the TypeScript compiler with deno install -g brilck.ts and deno install -g --allow-env --allow-read ts2bril.ts, and run make test. A single test can be run with turnt against one .bril file.

Which languages does Bril have implementations in?

The repository contains a TypeScript reference implementation behind brili.ts, plus implementations in Rust, OCaml, Swift and an LLVM backend, along with variants such as fastbril and flat-bril and a TypeScript front end called ts2bril.ts.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. sampsyo/bril on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sampsyo-bril.svg)](https://hysenlabs.com/projects/sampsyo-bril)

Was this useful?