This is a story-like technical article about why and how I made this language experiment.
Context
It was a normal night, drinking my coffee, working on a Minecraft mod that adds a custom OBJ renderer. I was thinking it would be great if I could just have C++ or Rust doing this heavy work instead of Java… and then an idea came to me: surely by now there must be something that could do that exact job:
a coordinator between languages
I found a lot of options — Bazel, FFI, microservices, gRPC, WebAssembly, VM ecosystems, transpilers — but nothing really clicked. I would use FFI for speed, VMs for scalability, transpilers for flexibility, but I couldn't find something I could stick with and use everywhere.
My Take On This Problem
I wanted something where you describe what you want to do, and the language handles the annoying stuff for you.
So after that research, I decided to make my own thing — something I would learn once and use everywhere in my poly-language projects. And also as an excuse to learn C++.
My vision was to make a programming language.
A picture of what I was thinking about:
Idea / Vision (Now)
- a system where languages are connected together
- C++ / Rust / Python are not separated anymore
- one place to coordinate everything
- no manual FFI, no messy glue code everywhere
- focus on “what you want to do”, not “how to connect languages”
Implementation
You and I both know that the first step of every project is giving it the sh**tiest name possible, then calling it a day.
First Steps
That out of the way, I started building a custom lexer with a language I barely used before — fake it till you make it.
I was going hard on the OOP while also trying to keep Python-like simplicity. Somewhere along the way I got lost in parser design, ASTs, interpreters, and runtime systems — and realized I was accidentally building a real programming language instead of solving my original Minecraft mod problem.
Core Idea (How I Started Building It)
After all that mess, I switched to using ANTLR4 because:
- the grammar itself doubles as documentation (
.g4files) - it gave me an easier lexer/parser pipeline
ANTLR also made experimenting way faster because I could focus more on the language behavior instead of rewriting parser logic every 5 minutes.
At first, the interpreter directly walked the parse tree itself. Which worked… until it didn't.
I later realized there's a big difference between:
- “this parses correctly”
- and
- “this is architecturally sane”
So now there's a lot of future work involving proper AST lowering and separation between parsing and execution.
Friend Modules Concept
Friend modules are basically a fancy name for the FFI system mixed with automatic build planning.
They are declared like this:
friend math : cpp as mcpp;
This line tells EZ:
- there is a file called
math.cpp - compile it as part of the project
- refer to it in EZ code as
mcpp
Then we can use it like this:
print(mcpp.add(3,2));
The goal was to remove all the annoying manual setup:
- no handwritten headers
- no manual linking
- no
dlopen - no random shell scripts
Just:
"this module exists, use it"
The same idea extends to Python through auto-generated bridge code, though it's rougher around the edges.
Right now the system mostly supports primitive types correctly (int, float, boolean, etc.), but I already know things will get painful once structs, buffers, callbacks, or heap-managed objects enter the picture.
Because at the end of the day:
every abstraction eventually reaches the FFI wall.
Interpreter / Execution Model
EZ currently has two execution paths:
1. Interpreter Mode:
This directly walks the parse tree and executes the program.
It currently supports:
- variables
- arithmetic
- conditions
- loops
- functions
- returns
- friend module calls
This is the main development path right now because it lets me experiment quickly without rebuilding an entire compiler pipeline every time I change something.
2. Native / C Backend:
The second path translates EZ code into C code, then compiles it using clang.
This started mostly as an experiment to answer the question:
"Can this language actually compile into something native?"
Right now the C backend only supports a subset of the language and intentionally does not support friend calls yet.
There's also a backend comparison script that runs the same file through:
- the interpreter
- the native backend
Then compares the outputs to make sure they behave similarly.
Environment System
The friend modules problem made me think about a bigger issue: environment reproducibility. One drunken night with NixOS made it click.
I loved the small Docker-like environments you could create and how reproducible everything felt. That immediately made me think:
why isn't this feeling part of programming languages themselves?
The classic:
"works on my machine"
Issue becomes an absolute nightmare once multiple languages, compilers, runtimes, and dependencies get involved. Especially in poly-language projects.
So I started experimenting with making environments part of the language itself.
Example:
env native;
The idea is:
- the environment should be part of the program contract
- not just hidden setup instructions inside a README nobody reads
- reproducibility should be built into the workflow from the start
The language uses nix-shell to run its build plan and will eventually use a config file to pin each compiler and interpreter version for the project:
# EZ-Language Configuration
# Place in project root (.ezconfig) or home directory (~/.ezconfig)
# Project-level config overrides user-level config
[python]
# Python interpreter path (default: python3 from PATH)
executable = "python3"
[c]
# C compiler (default: clang)
compiler = "clang"
# Standard version (default: c11)
standard = "c11"
[cpp]
# C++ compiler (default: clang++)
compiler = "clang++"
# Standard version (default: c++17)
standard = "c++17"
[build]
# Output directory for friend modules (default: .ezbuild)
output_dir = ".ezbuild"
# Verbose build output (default: false)
verbose = false
# skip Nix env activation when set (default: false)
no_env = false
Right now the config system is still rough and partially ignored by the Nix environment — but the goal is clear:
"clone project → run project"
Without spending 3 hours fixing dependencies, compiler versions, or missing libraries.
Problems I Ran Into
A lot.
Some of the biggest ones:
- the interpreter directly walking the CST instead of a proper AST
- type marshalling for friend calls becoming ugly very quickly
- more segfaults and core dumps than I'd like to admit
- trying to keep the language simple while the backend complexity explodes
- parser/runtime/features growing way faster than the architecture itself
- adding grammar features before implementing them properly
- realizing “easy syntax” does NOT mean “easy implementation”
Also: FFI is terrifying.
The deeper I went into cross-language interaction, the more I understood why every existing solution feels complicated.
Languages fundamentally disagree on:
- memory ownership
- calling conventions
- threading
- exceptions
- object lifetimes
- type systems
So making them “just work together” cleanly is much harder than I originally thought — but doable.
Current State Of The Project
The project is still extremely experimental.
There's a lot of:
- messy code
- technical debt
- unfinished systems
- AI-assisted scaffolding
- “future me will fix this” moments
I'm also starting to hate the name — thinking of gluCore as a replacement.
But overall, the core idea works:
- friend modules work
- the interpreter works
- the native backend exists
- multi-language execution is happening
And honestly, that's already farther than I expected when this whole thing started from a late-night Minecraft modding session.
Conclusion
Somewhere between the Minecraft mod and the segfaults, this stopped being a language and started being something else — more of a coordination layer, a system that lets multiple languages work together without you managing the glue.
I don't even think this is a programming language in any traditional sense anymore. It still has functions and variable declarations, but it's become more and more like a runtime that manages and connects multiple languages. I'm not sure what to call that. Maybe that's the point.
Whether it's useful to anyone else, I genuinely don't know. But the core idea works, and that's already further than a late-night coffee session had any right to get.
If you want to dig into the mess — or help make it less of one — the repo is linked at the top.
Also: I got accused of writing AI slop when I tried more structured technical articles on Reddit, so I figured — why not just embrace the chaos? Hopefully it made this more fun to read, and hopefully I don't get accused of being a robot this time.

Top comments (0)