{"id":20884596,"url":"https://github.com/adam-mcdaniel/sage","last_synced_at":"2025-04-08T08:15:02.072Z","repository":{"id":50417926,"uuid":"483696398","full_name":"adam-mcdaniel/sage","owner":"adam-mcdaniel","description":"A programming language that's wise beyond its bytes!🌱🌿🪴","archived":false,"fork":false,"pushed_at":"2025-03-09T06:30:09.000Z","size":89969,"stargazers_count":499,"open_issues_count":9,"forks_count":17,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-01T05:36:56.848Z","etag":null,"topics":["algebraic-data-types","c","compiler","frontend","mobile","pattern-matching","polymorphism","portable","rust","structural-typing","turing-tarpit","wasm","web","x86-64"],"latest_commit_sha":null,"homepage":"https://adam-mcdaniel.net/sage-website","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adam-mcdaniel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-20T14:49:35.000Z","updated_at":"2025-03-29T16:55:49.000Z","dependencies_parsed_at":"2024-02-10T19:27:41.732Z","dependency_job_id":"590ae3db-e80f-43ef-bc29-aba32e5c1ea7","html_url":"https://github.com/adam-mcdaniel/sage","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adam-mcdaniel%2Fsage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adam-mcdaniel%2Fsage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adam-mcdaniel%2Fsage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adam-mcdaniel%2Fsage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adam-mcdaniel","download_url":"https://codeload.github.com/adam-mcdaniel/sage/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247801175,"owners_count":20998339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algebraic-data-types","c","compiler","frontend","mobile","pattern-matching","polymorphism","portable","rust","structural-typing","turing-tarpit","wasm","web","x86-64"],"created_at":"2024-11-18T08:10:36.749Z","updated_at":"2025-04-08T08:15:02.030Z","avatar_url":"https://github.com/adam-mcdaniel.png","language":"Rust","readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003e🌿🌱\u003cb\u003eThe Sage Programming Language\u003c/b\u003e🪴🍃\u003c/h1\u003e\n  \u003cp\u003e\n    \u003cstrong\u003eSage advice for your coding conundrums!\u003c/strong\u003e\n  \u003c/p\u003e\n  \u003cp float=\"left\"\u003e\n    \u003cimg src=\"./assets/code1_redone.png\" width=\"26.5%\"/\u003e\n    \u003ca href=\"https://adam-mcdaniel.net/sage-website\"\u003e\u003cimg src=\"./assets/sage.png\" width=\"69.5%\"/\u003e\u003c/a\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n    \u003ca href=\"https://adam-mcdaniel.github.io/sage-website/playgrounds/playground/\"\u003e\u003cb\u003e\u003ci\u003eUse the online compiler playground!\u003c/i\u003e\u003c/b\u003e\u003c/a\u003e\n    | \u003ca href=\"https://discord.gg/rSGkM4bcdP\"\u003e\u003cb\u003e\u003ci\u003eJoin the Discord server!\u003c/i\u003e\u003c/b\u003e\u003c/a\u003e\n    | \u003ca href=\"https://www.youtube.com/watch?v=QdnxjYj1pS0\"\u003e\u003cb\u003e\u003ci\u003eCheck out a video covering Sage!\u003c/i\u003e\u003c/b\u003e\u003c/a\u003e\n  \u003c/p\u003e\n  \u003c!-- [***Here's a link to the online compiler playground!***](https://adam-mcdaniel.net/sage)\n  [***Here's a link to the online compiler playground!***](https://adam-mcdaniel.net/sage) --\u003e\n\u003c/div\u003e\n\n\n\n## Table of Contents\n\n- [Community](#community)\n- [What is Sage?](#what-is-sage)\n- [Why Sage?](#why-sage)\n- [How useful is Sage?](#how-useful-is-sage)\n- [How do I use Sage?](#how-do-i-use-sage)\n- [What does Sage look like?](#what-does-sage-look-like)\n- [Feature Roadmap](#feature-roadmap)\n- [Where can I learn more?](#where-can-i-learn-more)\n- [How do I contribute?](#how-do-i-contribute)\n- [About the Author](#about-the-author)\n\n## Community\n\nJoin the [Discord server](https://discord.gg/rSGkM4bcdP) to chat about Sage! Let us know if you have any thoughts or comments about the language!\n\n## What is Sage?\n\nSage is a programming language that tries to be maximally portable, expressive, and intuitive. It borrows some aspects of Rust, C, and Python. It currently has an x86 compiler backend, a C source backend, and a VM interpreter backend [which can run on the web](https://adam-mcdaniel.github.io/sage-website/playgrounds/playground/).\n\n\u003cdiv align=\"center\"\u003e\n  \u003cp float=\"left\"\u003e\n    \u003cimg src=\"./assets/code2_redone.png\" width=\"32.5%\"/\u003e\n    \u003cimg src=\"./assets/code1_redone.png\" width=\"30.1%\"/\u003e\n    \u003cimg src=\"./assets/code3_redone.png\" width=\"32.75%\"/\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\nSage is licensed under the [MIT License](LICENSE), and has been under development since April 2022.\n\n## Why Sage?\n\nSage is very portable -- run it on your thermostat! Here's the complete list of core virtual machine instructions and their C equivalents:\n\n| Instruction | C Equivalent    |\n| ----------- | --------------- |\n| `while`     | `while (reg[0]) {` |\n| `if`        | `if (reg[0]) {`    |\n| `else`      | `} else {`      |\n| `end`       | `}`             |\n| `set N_0, N_1, ..., N_X`     | `reg[0] = N_0; reg[1] = N_1; ... reg[x] = N_X;` |\n| `call`      | `funs[reg[0]]();`  |\n| `ret`       | `return;`       |\n| `load N`    | `memcpy(reg, tape_ptr, N * sizeof(cell));` |\n| `store N`   | `memcpy(tape_ptr, reg, N * sizeof(cell));` |\n| `move N`    | `tape_ptr += N;`   |\n| `where`     | `reg[0].p = tape_ptr;`   |\n| `deref`     | `push(tape_ptr); tape_ptr = *tape_ptr;` |\n| `refer`     | `tape_ptr = pop();` |\n| `index N`   | `for (int i=0; i\u003cN; i++) reg[i].p += tape_ptr-\u003ei;` |\n| `offset O, N` | `for (int i=0; i\u003cN; i++) reg[i].p += O;` |\n| `swap N` | `for (int i=0; i\u003cN; i++) swap(reg + i, tape_ptr + i);` |\n| `add N` | `for (int i=0; i\u003cN; i++) reg[i].i += tape_ptr[i].i;` |\n| `sub N` | `for (int i=0; i\u003cN; i++) reg[i].i -= tape_ptr[i].i;` |\n| `mul N` | `for (int i=0; i\u003cN; i++) reg[i].i *= tape_ptr[i].i;` |\n| `div N` | `for (int i=0; i\u003cN; i++) reg[i].i /= tape_ptr[i].i;` |\n| `rem N` | `for (int i=0; i\u003cN; i++) reg[i].i %= tape_ptr[i].i;` |\n| `or N` | `for (int i=0; i\u003cN; i++) reg[i].i \\|\\|= tape_ptr[i].i;` |\n| `and N` | `for (int i=0; i\u003cN; i++) reg[i].i \u0026\u0026= tape_ptr[i].i;` |\n| `not N` | `for (int i=0; i\u003cN; i++) reg[i].i = !reg[i].i;` |\n| `bitand N` | `for (int i=0; i\u003cN; i++) reg[i].i \u0026= tape_ptr[i].i;` |\n| `bitor N` | `for (int i=0; i\u003cN; i++) reg[i].i \\|= tape_ptr[i].i;` |\n| `bitxor N` | `for (int i=0; i\u003cN; i++) reg[i].i ^= tape_ptr[i].i;` |\n| `lsh N` | `for (int i=0; i\u003cN; i++) reg[i].i \u003c\u003c= tape_ptr[i].i;` |\n| `l-rsh N` | `for (int i=0; i\u003cN; i++) reg[i].i = (uint64_t)reg[i].i \u003e\u003e tape_ptr[i].i;` |\n| `a-rsh N` | `for (int i=0; i\u003cN; i++) reg[i].i \u003e\u003e= tape_ptr[i].i;` |\n| `gez N` | `for (int i=0; i\u003cN; i++) reg[i].i = reg[i].i \u003e= 0;` |\n\nThe compiler can target this limited \"core\" instruction set, with an expanded \"standard\" instruction set for floating point operations and foreign functions. The core instruction set is designed to be as simple as possible for anyone to implement their own backend. [Try to see if you can implement it yourself for your backend of choice!](https://github.com/adam-mcdaniel/sage/blob/main/src/targets/c.rs)\n\nThe virtual machine has some important optimization properties: 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. This makes the instruction set capable of applying LLVM's optimizations while being *much easier* to implement. **Sage's innovation is in the backend, not the frontend.**\n\nThis combination of simplicity and capacity for optimization was my motivation for creating Sage. I wanted to create a virtual machine with the largest **speed + expression + portability** to **implementation difficulty** ratio, and a high level language that could compile to it. I think Sage is a good solution to this problem.\n\nThis project is based on some ideas I had while working on [Harbor](https://github.com/adam-mcdaniel/harbor) for a hackathon.\n\n## How useful is Sage?\n\nSage is a very young project, and is not ready for production. It's still possible to write very useful programs in it, though.\n\n[SageOS is an operating system with a userspace written in Sage.](https://github.com/adam-mcdaniel/sage-os) Its graphical shell and presentation app (both written in Sage) use the FFI to draw to the screen, receive input from the mouse and keyboard, interact with the filesystem, and schedule new processes. [You can look at the shell code here.](https://github.com/adam-mcdaniel/sage/tree/main/examples/sage-os/shell.sg)\n\n[![Shell1](assets/shell1.png)](https://github.com/adam-mcdaniel/sage-os)\n[![Shell2](assets/shell2.png)](https://github.com/adam-mcdaniel/sage-os)\n\nThe presentation app parses PPM image files from the filesystem and renders them to the screen. [You can look at the presentation code here.](https://github.com/adam-mcdaniel/sage/tree/main/examples/sage-os/presentation.sg)\n\n[![Presentation](assets/presentation.png)](https://github.com/adam-mcdaniel/sage-os)\n\nSage's foreign function interface is simple and can directly call C functions or backend-specific builtins. Check out the [web-demo](https://adam-mcdaniel.net/sage)'s foreign function interface example that calls some JavaScript code to draw graphics or alert the user!\n\n## How do I use Sage?\n\nTo start using sage, install it with cargo:\n\n```bash\n$ cargo install --git https://github.com/adam-mcdaniel/sage\n```\n\nThen, you can run a sage file with the `sage` command:\n\n```bash\n$ sage examples/frontend/interactive-calculator.sg\n```\n\nYou can also compile a sage file to C with the `--target` flag:\n\n```bash\n$ sage examples/frontend/interactive-calculator.sg --target c\n$ # Or `-t c` for short\n$ sage examples/frontend/interactive-calculator.sg -tc\n$ gcc out.c -o out\n$ ./out\n```\n\nCheck out the [code for the web-demo](https://github.com/adam-mcdaniel/sage/tree/main/examples/web) to see how to use Sage in a web page.\n\n## What does Sage look like?\n\nHere's an example using the `collections` submodule of Sage's builtin `std` module!\nThe example uses a custom struct `Point` as the key for a `HashMap` instance.\n\n```rs\nfrom std.collections import *;\n\nstruct Point {\n    x: Float,\n    y: Float\n}\n\nimpl Point {\n    fun new(x: Float, y: Float): Point {\n        return {x=x, y=y};\n    }\n\n    fun move(\u0026mut self, dx: Float, dy: Float) {\n        self.x += dx;\n        self.y += dy;\n    }\n}\n\n\nfun main() {\n    let mut hm = HashMap.make\u003cPoint, Int\u003e();\n\n    hm.insert(Point.new(4.0, 5.0), 5);\n    hm.insert(Point.new(1.0, -1.0), -100);\n\n    hm.println();\n    let idx = Point.new(1.0, -1.0);\n    if let of Some(result) = hm.get(idx) {\n        println(idx, \" -\u003e \", *result);\n    } else {\n        println(\"Could not find hm[\", idx, \"]\");\n    }\n}\n\nmain();\n```\n\nHere's an example of Sage's structural typing: a `Rectangle` can be created by concatenating the fields of a `Position` and a `Size`!\n\n```rs\nfun main() {\n    // Add the position and the size to get a rectangle\n    let rect = Position.make(10, 20) + Size.make(30, 40);\n\n    // Print the rectangle and its stats\n    println(\"Rectangle: \", rect);\n    println(\"Area:      \", rect.area()); \n    println(\"Perimeter: \", rect.perimeter());\n}\n\n// A rectangle has an \\`x\\` and \\`y\\` position, a \\`width\\`, and a \\`height\\`.\nstruct Rectangle {\n    x: Int,\n    y: Int,\n    width: Int,\n    height: Int\n}\n\nimpl Rectangle {\n    // Calculate the area of the rectangle\n    fun area(\u0026self): Int { self.width * self.height }\n\n    // Calculate the perimeter of the rectangle\n    fun perimeter(\u0026self): Int { 2 * (self.width + self.height) }\n}\n\n// A type for representing the dimensions of a 2D shape\nstruct Size {\n    width: Int,\n    height: Int\n}\n\nimpl Size {\n    // Create a new size with the given width and height\n    fun make(width: Int, height: Int): Size { { width=width, height=height } }\n}\n\n// A type for representing the position of a 2D shape\nstruct Position {\n    x: Int,\n    y: Int\n}\n\nimpl Position {\n    // Create a new position with the given x and y coordinates\n    fun make(x: Int, y: Int): Position { { x=x, y=y } }\n}\n\nmain();\n```\n\nHere's an example of Sage's pattern matching: it's easy to deconstruct a value using `match`, `if let`, or a simple `let` binding. Sage's `match` expressions are very powerful!\n\n```rs\n// Create a C-like enum\nenum Direction {\n    North, South, East, West\n}\n\n// Pattern match over a tuple of a Direction, Int, and struct\nmatch (Direction of South, 2, {x = 5, y = -6}) {\n    (of North, _, _)\n    | (of East, _, _)\n    | (of West, _, _)\n    | (of South, 3, _) =\u003e print(\"Incorrect!\\\\n\"),\n    (of South, 2, {x = 5, y = -6}) =\u003e {\n        // This will be the branch that matches\n        print(\"Correct!\\\\n\");\n    },\n    _ =\u003e print(\"Incorrect!\\\\n\")\n}\n\n// Create a polymorphic Rust-like enum\nenum Option\u003cT\u003e {\n    Some(T),\n    Nothing\n}\n\n// Define a fallible division operation\nfun divide(n: Int, d: Int): Option\u003cInt\u003e {\n    if (d == 0) {\n        return Option\u003cInt\u003e of Nothing;\n    } else {\n        return Option\u003cInt\u003e of Some(n / d);\n    }\n}\n\n// Match over a division operation with an if-let statement\nif let of Some(n) = divide(6, 2) {\n    print(\"6 / 2 = \", n, \"\\\\n\");\n} else {\n    print(\"6 / 2 = undefined\\\\n\");\n}\n```\n\nGo to the [web-demo](https://adam-mcdaniel.github.io/sage-website/playgrounds/playground/) or the [examples/frontend](https://github.com/adam-mcdaniel/sage/tree/main/examples/frontend) folder to see more code examples.\n\n## Feature Roadmap\n\n- [x] Compiler Backends\n  - [ ] LLVM (highly desired!)\n  - [x] C (fully-implemented but unoptimized)\n  - [x] Interpreter (fully-implemented but unoptimized)\n  - [x] Web Backend\n    - [x] Interpreter\n    - [ ] Visual demo like the [web-demo](https://adam-mcdaniel.net/harbor) for [Harbor](https://github.com/adam-mcdaniel/harbor)\n- [x] SIMD vector instruction support\n- [x] Static variables and constant expressions\n- [x] Conditional compilation\n- [x] Polymorphic functions\n- [x] Mutability checks\n- [x] Rust-like `enum`s\n- [x] Pattern `match`ing\n- [x] Structural typing\n- [x] Associated constants and methods\n- [x] Recursive polymorphic types\n- [ ] Iterators and list/vector/array comprehensions\n- [ ] Hindley-Milner type inference\n- [ ] VSCode extension (syntax highlighting, code completion, etc.)\n- [ ] Typeclasses\n- [ ] `no-std` implementation of compiler\n- [x] `const` generics\n- [x] Modules\n- [x] A standard library\n  - [ ] Type Reflection Module\n  - [x] Collections Module\n  - [ ] Networking Module\n  - [ ] Filesystem Module\n  - [ ] Graphics Module\n  - [ ] Audio Module\n  - [ ] GUI Module\n  - [ ] WebAssembly Module\n  - [ ] Foreign Function Interface Module (create backend with `.toml` file)\n  - [x] Memory Management Module\n- [x] Better frontend parser (switch to [Nom](https://crates.io/crates/nom)?)\n- [ ] A package manager\n- [x] AST Macros\n- [ ] C frontend (compile C to Sage VM)\n- [ ] Self-hosting implementation\n\n## Where can I learn more?\n\nYou can read [my blog post](https://adam-mcdaniel.github.io/blog/compilers-for-the-future) (~20 minute read) about the programming language to learn more about the implementation!\n\n[Here's a 23 minute YouTube video that covers how compilers work, and delves into Sage!](https://www.youtube.com/watch?v=QdnxjYj1pS0)\n\nJoin the [Discord server](https://discord.gg/rSGkM4bcdP) to chat about Sage!\n\n## How do I contribute?\n\nIf you want to contribute, you can open an issue or a pull request. [Adding backends for other architectures is a great way to contribute!](https://github.com/adam-mcdaniel/sage/blob/main/src/targets/c.rs) We also need a VSCode syntax highlighting extension!\n\n## About the Author\n\n[I'm a computer science PhD student](https://adam-mcdaniel.net) at the [University of Tennessee, Knoxville🍊](https://www.youtube.com/watch?v=-8MlEo02u54). Rust is my favorite language, and [I've](https://github.com/adam-mcdaniel/oakc) [written](https://github.com/adam-mcdaniel/harbor) [many](https://github.com/adam-mcdaniel/tsar) [other](https://github.com/adam-mcdaniel/free) [compilers](https://github.com/adam-mcdaniel/xasm). This is the last project I started as a teenager, and I was the only author to touch any of the code up to version `v0.0.2-alpha` (12/25/2023)! I'm looking for work opportunities for Summer 2024 (after I finish my Masters degree), so if you're interested in hiring me, please reach out to me at [amcdan23@vols.utk.edu](mailto:amcdan23@vols.utk.edu)!\n","funding_links":[],"categories":["Rust"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadam-mcdaniel%2Fsage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadam-mcdaniel%2Fsage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadam-mcdaniel%2Fsage/lists"}