I built a programming language that compiles to Python, Bash, and binary
And you can try it in your browser right now.
Why?
Most programming language tutorials stop at a calculator. I wanted something real — a language that could:
- Run directly (like Python)
- Compile to Python (for ecosystem access)
- Compile to Bash (for system scripting)
- Compile to binary (for performance)
One source file (.ext) → three targets. That's Externum.
Externum = Python_readability ⊕ Binary_performance ⊕ Bash_control
What it looks like
Externum looks like Python but compiles to three targets:
import mathx
import strings
class Fire(Pokemon):
def __init__(self, name, hp=50):
Pokemon.__init__(self, name, ["fire"], hp)
fire_team = [p.name for p in squad if p.is_type("fire")]
weakest = min(squad, key=lambda p: p.hp)
nums = [f for f in fibonacci(10) if f % 2 == 0]
If you can read Python, you can read Externum. But under the hood, it's a full compiler pipeline:
source (.ext) → Lexer → tokens → Parser → AST → Compiler → python/bash/binary
The hard part: NV2.0 Hard Mode
The real challenge wasn't the basic language — it was adding a hard mode that turns Externum into something genuinely difficult:
Ownership
p: Ptr[Int] = alloc(Int)
@p = 42
print(@p) # 42
free(p) # double-free after this = compile error
Yes, manual memory management in a Python-like language. The type checker enforces single-ownership semantics at compile time.
Traits
trait Speaker:
def speak(self) -> Str
impl Speaker for Dog:
def speak(self) -> Str:
return "woof"
Missing an implementation? Compile error. Wrong return type? Compile error.
Macros
macro SQ(x) { (x) * (x) }
print(SQ(5)) # expands to print((5) * (5))
Textual expansion before parsing — like C macros but with Python syntax.
Concurrency
ch = chan()
spawn(worker(ch))
send(ch, v)
recv(ch)
Thread-backed channels with compile-time safety.
The browser playground
Here's where it gets interesting. Externum runs entirely in your browser:
┌──────────────┐ ┌────────────────┐ ┌────────────────┐
│ Code Editor │───►│ Externum (.ext) │───►│ Pyodide (WASM) │
│ (browser) │ │ transpiler │ │ Python runtime │
└──────────────┘ └────────────────┘ └────────────────┘
│ │
└───────────── stdout / stderr ◄───────────┘
No server. No API keys. No network requests. The transpiler runs inside Pyodide — Python compiled to WebAssembly. Write Externum code, click Run, see output.
The issue-command bot
Here's something unique: you can extend the language from GitHub Issues.
-
/run print(2 + 2)— executes Externum code in CI -
/define clamp(x, lo, hi) if x < lo: return lo ...— adds a new stdlib function via PR
The bot parses Issue comments, generates a PR with the new function + tests, and runs the full 192-test suite before merge. The language evolves through community contributions.
DRM system
Every protected build carries a full defense-in-depth stack:
- License keys — HMAC-SHA256 signed
- Watermark — author/app/build/source-hash in every file
- Tamper detection — source SHA-256 + artifact self-hash
- Obfuscation — string literals encoded through a runtime helper
externum compile app.ext --protect --app-id game --author buffy --secret s3cret
EXTERNUM_LICENSE=<key> externum run app.ext --protect
Stats
| Metric | Count |
|---|---|
| Unit tests | 192 |
| Stdlib modules | 7 (structs, strings, mathx, fs, jsonx, net, drm) |
| Compilation targets | 3 (Python, Bash, binary) |
| PyPI downloads | 189+ |
| Docker images | GHCR |
Tech stack
- Python 3.10+ — the implementation language
- Zero dependencies — everything from stdlib
- Pyodide — browser runtime via WebAssembly
- GitHub Actions — CI/CD with cosign signing, SLSA provenance, SBOM
- OpenSSF Scorecard — automated supply-chain security
What I learned
- Lexing is harder than you think — especially with bracket-aware indentation, bash blocks, and f-strings
- Type systems are beautiful — the ownership checker taught me more about Rust's borrow checker than any tutorial
- WebAssembly changes everything — running a full language transpiler in the browser with zero server cost
-
Community-driven language design works — the
/definebot has already added 3 new stdlib functions
Try it
pip install externum
externum repl
# Or try in your browser:
# https://bartoszosiej.github.io/externum/
Built by Bartosz Osiej — 19, Poland, open to first paid role. Everything here is deployed infrastructure, not a tutorial.
Star the repo: github.com/BartoszOsiej/externum
Top comments (0)