DEV Community

Bartosz Osiej
Bartosz Osiej

Posted on

I built a programming language that compiles to Python, Bash, and binary

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:

  1. Run directly (like Python)
  2. Compile to Python (for ecosystem access)
  3. Compile to Bash (for system scripting)
  4. Compile to binary (for performance)

One source file (.ext) → three targets. That's Externum.

Externum = Python_readability  Binary_performance  Bash_control
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

Missing an implementation? Compile error. Wrong return type? Compile error.

Macros

macro SQ(x) { (x) * (x) }
print(SQ(5))  # expands to print((5) * (5))
Enter fullscreen mode Exit fullscreen mode

Textual expansion before parsing — like C macros but with Python syntax.

Concurrency

ch = chan()
spawn(worker(ch))
send(ch, v)
recv(ch)
Enter fullscreen mode Exit fullscreen mode

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 ◄───────────┘
Enter fullscreen mode Exit fullscreen mode

No server. No API keys. No network requests. The transpiler runs inside Pyodide — Python compiled to WebAssembly. Write Externum code, click Run, see output.

→ Try it now

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:

  1. License keys — HMAC-SHA256 signed
  2. Watermark — author/app/build/source-hash in every file
  3. Tamper detection — source SHA-256 + artifact self-hash
  4. 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
Enter fullscreen mode Exit fullscreen mode

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

  1. Lexing is harder than you think — especially with bracket-aware indentation, bash blocks, and f-strings
  2. Type systems are beautiful — the ownership checker taught me more about Rust's borrow checker than any tutorial
  3. WebAssembly changes everything — running a full language transpiler in the browser with zero server cost
  4. Community-driven language design works — the /define bot has already added 3 new stdlib functions

Try it

pip install externum
externum repl

# Or try in your browser:
# https://bartoszosiej.github.io/externum/
Enter fullscreen mode Exit fullscreen mode

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)