Open-source project
adam-mcdaniel/sage avatar
adam-mcdaniel/sage

Sage: a portable language built around a deliberately tiny virtual machine

A programming language that's wise beyond its bytes!🌱🌿🪴

559 stars17 forksRustMIT

At a glance

What is it?
Sage is an MIT-licensed Rust-implemented programming language whose virtual machine uses a zero-address instruction set small enough to reimplement, while retaining enough information to recover an LLVM-like three-address representation and its optimisations. It suits a compiler hobbyist or embedded target, and the project says plainly that it is not production ready.
Who is it for?
Sage is worth reading if you are interested in how language design trade-offs between portability and optimisation capability, because the core idea is specific and defensible, a zero-address code that is trivial to implement yet preserves the information needed to recover an LLVM-like three-address representation, and because the core instruction set is small enough that the documentation invites you to write your own backend.
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

What the language is, and where the effort actually goes

Sage is a programming language that tries to be maximally portable, expressive and intuitive, and it borrows some aspects of Rust, C and Python.

The current implementation has three backends: an x86 compiler backend, a C source backend, and a VM interpreter backend, and the VM backend can run on the web, which is what powers the online compiler playground the project links to.

The author is direct about where the interesting part is. Sage's innovation is in the backend, not the frontend. The motivation was to create a virtual machine with the largest ratio of speed, expression and portability to implementation difficulty, and a high level language that could compile to it.

That framing explains a lot about the repository. There is a CORE.md at the top level, which is the document you would expect to describe the core instruction set, and a docs/ directory, an examples/ directory broken into asm, frontend, lir, sage-os, test-output, vm and web, and a benches/ directory. There is a build-docs.dunesh script and a build.rs. The examples/frontend directory is the front end, examples/lir is a low-level intermediate representation, examples/vm the virtual machine, and examples/asm the assembly output.

The language is MIT licensed and has been under development since April 2022. The package metadata gives the version as 0.1.1-alpha with edition 2021, and the binary is a single sage executable at src/cli.rs. The recent release tags are v1.1.0-alpha from 2024-09-08, v0.1.0-alpha from 2024-09-04 and v0.0.4-alpha from 2024-03-23, and the last push to the repository was on 2026-05-18.

The topic list is the most revealing summary of the design, and it includes algebraic data types, structural typing, pattern matching and polymorphism alongside turing-tarpit, compiler, frontend, wasm, web, mobile and x86-64. That combination, expressive type features on one side and a deliberately minimal machine on the other, is the project in one line.

The core instruction set, and why small is the point

The project publishes the complete list of core virtual machine instructions together with their C equivalents, and that table is the clearest statement of the design philosophy. A few rows look like this:

text
| `while`     | `while (reg[0]) {` |
| `if`        | `if (reg[0]) {`    |
| `load N`    | `memcpy(reg, tape_ptr, N * sizeof(cell));` |
| `store N`   | `memcpy(tape_ptr, reg, N * sizeof(cell));` |

Two patterns run through the whole table. Control flow is a zero-address machine, where the condition lives in register zero, and the memory operations work on a tape: a flat tape of cells, a tape pointer, and a register file, with load and store copying between the two, move advancing the tape pointer, where saving the pointer into a register, and deref and refer pushing and popping it.

The arithmetic instructions are uniform. add, sub, mul, div, rem, or, and, not, bitand, bitor, bitxor, lsh, l-rsh, a-rsh and gez are all the same shape, a loop over the registers applying an operation against the cell at the tape pointer, and even the bit shifts with a separate right-shift for logical and arithmetic shift come in pairs, one of which explicitly casts to uint64_t.

That regularity is what makes the set implementable. A backend for this instruction set is a loop over an array of function pointers, and the project says the core instruction set is designed to be as simple as possible for anyone to implement their own backend, and invites the reader to try implementing it for a backend of choice, pointing at the existing C backend as the example.

There is also an expanded standard instruction set for floating point operations and foreign functions, so the core stays small and the extensions stay optional.

The claim about LLVM, and why zero-address code is not the usual objection

The technical argument for the design is in the documentation, and it is the part that makes the project more than an interesting toy.

The claim is that although Sage's VM is a very simple zero-address-code representation, it preserves all the information to reconstruct an LLVM-like three-address-code representation of the original higher level IR. That makes the instruction set capable of applying LLVM's optimizations while being much easier to implement.

This is the point worth dwelling on, because zero-address machines are normally a dead end. A stack machine is easy to implement and hard to optimise, because everything is implicit in the order of operations. A three-address machine is easy to optimise and harder to implement. Sage claims to be able to have both, by choosing an encoding that keeps the information needed to rebuild the three-address form, rather than throwing it away the way a stack machine does.

If that reconstruction works, then a backend can be written at two different levels. A simple backend interprets the zero-address form directly, which is small, portable and fast to write, and a more ambitious backend reconstructs the three-address form and hands it to an existing optimiser, which gets the mature optimisations without the mature implementation cost.

The author is careful about the claim, describing it as an important optimisation property of the virtual machine rather than as a completed feature, and the examples directory has a dedicated lir/ subdirectory, which is where the low-level intermediate representation lives. That directory is the place to look for the evidence behind the claim.

The project also says the idea came from working on Harbor during a hackathon, which is the sort of provenance that explains a design with one very specific bet in it.

Using it: installation, the playground, and SageOS

Installation is a cargo install from the Git repository:

bash
$ cargo install --git https://github.com/adam-mcdaniel/sage

It is not a published crate, so the toolchain is the prerequisite, and the source has to be built. The README continues with how to run a sage file, and the project also points at an online compiler playground, a Discord server, and a video covering the language.

The demonstration project is SageOS, an operating system with a userspace written in Sage. Its graphical shell and presentation application are both written in Sage, and they use the foreign function interface to draw to the screen, receive input from the mouse and keyboard, interact with the filesystem, and schedule new processes. The shell source is in the examples directory of this repository, and the presentation application parses PPM image files from the filesystem and renders them to the screen.

That is a substantial demonstration, because a graphical shell and a presentation app are exactly the kind of programs that need real foreign calls, real process management and real input handling, and writing them in the language under test is a far better exercise than a hello world.

The foreign function interface itself is described as simple, and it can directly call C functions or backend-specific builtins. The web demo has a foreign function interface example that calls JavaScript code to draw graphics or alert the user, which shows the same interface serving a completely different host environment. The C source backend and the web VM backend therefore have different sets of backend-specific builtins, and the interface is what stays constant.

The author is honest about the limits in the same place: Sage is a very young project, and is not ready for production, though it is still possible to write very useful programs in it.

Where Sage is the wrong tool

The first limit is stated by the project itself and should be the first thing a reader takes in. Sage is very young and is not ready for production. The version scheme is a set of alpha releases, the package version is 0.1.1-alpha while the release tags reach v1.1.0-alpha, and the two numbers do not agree, which is a sign of a project where the release and package versioning are still being sorted out.

The second is the scope of the ecosystem. A language needs a standard library, a package manager, a debugger, an editor support story and a community, and none of that is in this repository. The tools listed in the topics, the playground and the Discord server, are the beginning of an ecosystem rather than an ecosystem. A developer evaluating a language for work needs a much longer list than a compiler, a VM and a documentation site.

The third is the dependence on a single author. The project is one person's work, with the author writing the language, the compiler, the backends, the operating system demonstration and the documentation. That is fine for a research language, and it is a concentration risk for anything else. The same applies to the LLVM reconstruction claim, which is the technical centre of the design and is developed by one person.

The fourth is that the C source backend and the x86 backend mean two different performance stories. A program compiled through the C backend inherits whatever the C compiler does with it, and a program running on the VM backend is interpreted, and neither is the fully optimised three-address path the design is aiming at. So the language's real-world performance depends on which backend you use and how far the reconstruction work has got, and the documentation is honest that this is where the innovation is still in progress.

And the fifth is the scope of the demonstration. SageOS is a real operating system with a Sage userspace, which is an impressive artefact, but it is also a project with its own repository, its own issues and its own pace. Following Sage means following several projects at once, and a team that wants a language to use tomorrow is looking in the wrong place.

Editorial conclusion

Sage is worth reading if you are interested in how language design trade-offs between portability and optimisation capability, because the core idea is specific and defensible, a zero-address code that is trivial to implement yet preserves the information needed to recover an LLVM-like three-address representation, and because the core instruction set is small enough that the documentation invites you to write your own backend. It is the wrong tool for production work, and the project says so. Before you rely on it, check three things: that you accept the alpha status, with the package version at 0.1.1-alpha and the recent release tags at v1.1.0-alpha, v0.1.0-alpha and v0.0.4-alpha, and the explicit statement that the project is very young and not ready for production; that you have a Rust toolchain, since installation is a cargo install from the Git repository rather than a published crate; and that you read CORE.md and the examples directory, which contains the frontend, low-level intermediate representation, virtual machine, assembly, web and SageOS examples, because those are where the actual language surface is documented rather than in the README.

Frequently asked questions

How do I install the Sage programming language?

It is installed with cargo from the Git repository rather than from a published crate: cargo install --git https://github.com/adam-mcdaniel/sage. You need a Rust toolchain, since the language is implemented in Rust, and the project also offers an online compiler playground that runs on the web VM backend.

What is the Sage core instruction set designed for?

It is designed to be as simple as possible so that anyone can implement their own backend for it, and the project publishes the complete list of core instructions with their C equivalents. The compiler can target this limited core set, with an expanded standard instruction set for floating point operations and foreign functions.

Is Sage ready for production use?

The project documentation states that Sage is a very young project and is not ready for production, though it is still possible to write useful programs in it. The package version is 0.1.1-alpha and the release tags are alpha builds, the most recent being v1.1.0-alpha from 2024-09-08.

Official sources

  1. adam-mcdaniel/sage on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
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/adam-mcdaniel-sage.svg)](https://hysenlabs.com/projects/adam-mcdaniel-sage)

Was this useful?