Gandora
Gandora is the project for gan, a compiler for an Elixir-flavored language
that produces readable Python. You write Elixir-style modules, pattern
matching, pipelines, and hygienic defmacro macros; deployment is ordinary
Python managed by uv with the standard .venv layout. Where Elixir reaches
its host platform through :erlang calls, Gandora reaches Python through
the $ sigil: $math.sqrt(2.0) compiles to import math plus math.sqrt(2.0)
with no wrapper code.
defmodule App.Mathy do
@moduledoc "Math helpers showing patterns and interop."
def fact(0), do: 1
def fact(n) when n > 0, do: n * fact(n - 1)
def norm(xs) do
xs
|> sum_squares()
|> then_sqrt()
end
defp sum_squares(xs) do
$functools.reduce(fn acc, x -> acc + x * x end, xs, 0)
end
defp then_sqrt(x), do: $math.sqrt(x)
end
compiles to plain Python with multi-clause dispatch as a match statement,
private functions as _-prefixed functions, and the interop as direct
imports — no Gandora runtime is needed to execute the output.
The practical guide is the language manual
(中文版). Design decisions are recorded as
Gandora Enhancement Proposals in geps/:
- GEP-0000 — the proposal process and translation policy (中文)
- GEP-0001 — language identity, surface
syntax, module naming, configuration, and the
ganCLI (中文) - GEP-0002 — the hygienic macro system (中文)
- GEP-0003 — Python interop (中文)
- GEP-0004 — structs (frozen dataclasses) and module attributes (中文)
- GEP-0005 — sigils (
~w,~s,~r, and the raw embedded-Python~python) (中文) - GEP-0006 — publishing packages as ordinary PyPI wheels, with macros shipped as source and zero runtime (中文)
- GEP-0007 — Markdown
@docwith locale variants, doctests compiled to native Python doctests,gan doc/gan test(中文) - GEP-0008 — definition-generating
macros,
use/__using__, and thedefattr/@on_definitionattribute system (中文) - GEP-0009 — the
~<lang>embedded-language family (~sql,~markdown, ...) with EEx-style<%= %>splices (中文) - GEP-0010 — the standard library
(std/):
Enum,String,Map,List,Keywordas an ordinary PyPI package (中文) - GEP-0011 — multi-arity name groups
and
\\default parameters (中文) - GEP-0012 — gandora-core: the compiler as a Python extension, quoted terms as native data — tooling is written in Gandora itself (中文)
- GEP-0013 — the
gantask runner (mix/cargo role), a Gandora program in tools/gan; the Rust binary is the stage-0 compilerganc(中文) - GEP-0014 —
try/rescue/after,loop/recur/break, and theinoperator (中文) - GEP-0015 —
gan-lsp, the language server written in Gandora (tools/lsp), plus the VS Code client (editors/vscode) (中文)
English GEPs are normative; the synchronized Chinese translations are
generated with scripts/translate-gep.py (a DeepSeek-backed translator
configured by .env) and human-reviewed per GEP-0000-R030.
Requirements
- Rust 1.85 or newer (to build the compiler)
- Python 3.11 or newer
uvfor Python development (optional but recommended)
Quick start
uv tool install gandora-tool # gan — the task runner (written in Gandora)
uv tool install gandora-lang # ganc — the stage-0 compiler it delegates to
gan init my-app # adds gandora-std to dependencies
cd my-app
gan run src/main.gan
(Or build from source: cargo build --release.)
gan init creates a uv-compatible project: pyproject.toml owns Python
metadata and dependencies, gandora.jsonc owns the compiler configuration,
and sources live under src/. gan run compiles into .gandora/cache/ and
executes with .venv/bin/python, uv run python, or python3 — whichever
is available first.
gan check # parse, expand, analyze; no output written
gan build # compile every module into dist/
gan expand src/x.gan # show a module after macro expansion
gan compile src/x.gan --out build/
The v0 surface
Modules (defmodule, one per file, path-derived names), def/defp with
multi-clause pattern dispatch and when guards, defmacro with
quote/unquote/unquote_splicing and default hygiene (var! escapes),
atoms, strings with #{} interpolation, lists, tuples, maps, keyword lists,
ranges, the |> pipe, if/unless/case/cond/with, anonymous
functions and captures (&Mod.fun/1, &(&1 + 1)), destructuring =,
alias/import/require, the interop forms of GEP-0003 (:module
calls, pyimport, postfix expr.name(...), @decorate), and the
GEP-0004 data declarations: defstruct (a frozen @dataclass with
%Mod{...} literals, patterns, and %Mod{s | f: v} updates) plus module
attributes (@app $flask.Flask("__main__") compiles to a module-level
binding, so @decorate @app.route("/") works like hand-written Python).
GEP-0005 adds sigils: ~w(a b c) word lists, ~s(...) strings,
~r/\d+/ compiled Python regexes, and ~python(sum(i*i for i in range(n)))
— a raw sigil that splices one verbatim Python expression into the
output, Gandora's rendering of Osiris's embedded-language sigils.
Anything outside the surface produces a diagnostic naming the construct
(GEP-0001-R007) rather than a silent mistranslation. See
examples/tour for a working multi-module program.
Publishing a package
A Gandora package is an ordinary PyPI wheel (GEP-0006):
gan init --package acme-text
cd acme-text # write modules under src/acme_text/
gan build # compiles into pkg/, emits marker + .gan sources
uv build && uv publish # standard hatchling wheel, standard PyPI
A live example is gandora-text,
installable straight from GitHub with
uv add git+https://github.com/mjason/gandora-text. Consumers then use
it from Gandora:
require AcmeText.Core # macros: expanded at compile time from the
alias AcmeText.Core # .gan sources shipped in the wheel
Core.hello("world") # functions: a plain `import acme_text.core`
The wheel introduces no runtime: its .py modules are self-contained,
Python-only consumers can use them without knowing Gandora exists, and
macro expansion leaves nothing behind at runtime. The compiler discovers
installed packages by reading their gandora.toml markers from
.venv — it never imports or executes package code.
Data mapping
| Gandora | Python |
|---|---|
:atom |
"atom" (interned string) |
nil / true / false |
None / True / False |
| list / tuple / map | list / tuple / dict |
keyword list [a: 1] |
[("a", 1)] |
a..b |
range(a, b + 1) |
Only false and nil are falsy (Elixir semantics); the generated code
inserts explicit truthiness checks where needed.
Repository layout
crates/core— the compiler library;crates/gan— the stage-0 CLIganc;crates/core-py— thegandora_corePython extensiontools/gan— the task runner;tools/lsp— the language server (both written in Gandora);editors/vscode— the VS Code clientdocs/— the language manual (+docs/local/zh/translations)geps/— Gandora Enhancement Proposals (+geps/local/zh/translations)examples/tour— a runnable multi-module exampletests/e2e.rs— end-to-end tests driving the real binaryscripts/translate-gep.py— the GEP translation tool
cargo test # unit + end-to-end tests
Status
v0.1.0: GEP-0001..0011 are implemented and tested — the language and
CLI, hygienic macros with the full metaprogramming surface
(definition-generating macros, use/__using__, defattr/
@on_definition), structs, sigils and embedded languages with
<%= %> splices, wheel-based package publication, bilingual docs with
native doctests, multi-arity functions with \\ defaults, and the
standard library (std/, uv add gandora-std). Deferred:
protocols, comprehensions, try/rescue, binaries, a formatter, an
LSP.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gandora_lang-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: gandora_lang-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 664.7 kB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2633df861581423014d4c353ff4d91d71f1f818fc4363f39add01459a714c02
|
|
| MD5 |
1456c942354109b467f8d56f8c09394d
|
|
| BLAKE2b-256 |
94a41d6765c0d9ac37f80298a5baa524cc5fc2a5df4d0023cdcec8fc3d13d022
|
Provenance
The following attestation bundles were made for gandora_lang-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on mjason/gandora
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gandora_lang-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
e2633df861581423014d4c353ff4d91d71f1f818fc4363f39add01459a714c02 - Sigstore transparency entry: 2331202303
- Sigstore integration time:
-
Permalink:
mjason/gandora@fc9ef69c0dec7f507bfe2476c4cadf9d8096afa0 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/mjason
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@fc9ef69c0dec7f507bfe2476c4cadf9d8096afa0 -
Trigger Event:
push
-
Statement type: