A fast, modern systems language with elegant syntax that compiles to Zig.
Zag is a systems language project focused on clean, expressive syntax without giving up explicit control, predictable performance, or native compilation. The initial strategy is straightforward: compile Zag to Zig, and let the Zig toolchain own the lower half of the stack.
This keeps the early implementation narrow and practical. Zag can focus on syntax, structure, lowering, and semantics that feel good to write, while Zig handles code generation, linking, cross-compilation, and platform details.
Zag does not need to copy the exact syntax of rip-lang, but it should preserve the same ethos: whitespace-sensitive structure, succinct expression-oriented code, routines that naturally yield values when those values are used, and a bias toward removing ceremony when the meaning is already obvious.
Types should follow the same spirit. They can be optional in Zag source, selective where useful, and resolved before final Zig emission. That means the language can stay low-ceremony at the surface while still producing the concrete types that Zig requires underneath.
Most systems languages inherit a lot of their surface shape from C, whether or not that syntax is actually required for performance. Zag starts from a different assumption:
- fast code does not require ugly syntax
- explicit semantics do not require excessive ceremony
- a beautiful surface language can still lower to efficient native code
The goal is not to hide low-level reality. The goal is to make systems programming feel structurally elegant.
Zag should feel like Rip, even in a different runtime and compilation world.
- whitespace-sensitive and structurally clean
- concise by default
- expressions yield values when they are used
- routines yield values when they are used
- obvious code should stay short
- power and clarity matter more than inherited ceremony
The point is not to imitate JavaScript semantics. The point is to preserve the feeling of writing in a language that values succinctness, expressiveness, and compositional power.
That also means leaving JavaScript-specific features behind when they do not belong in a systems language. Zag should not carry over component, render, or reactive assignment/effect features into this project.
At the same time, being a systems language should not force every program down to bare-metal minimalism. Zag should be able to offer optional capability packs for things like regex support, where the language can enable a high-performance substrate module instead of pretending every project should invent its own engine from scratch.
Zag is not trying to replace Zig on day one. It is using Zig as the initial backend substrate.
That means Zag can inherit:
- native code generation
- optimization
- cross-compilation
- linking
- C interop
- executable, library, and test workflows
This is the same leverage pattern that makes rip-lang -> JavaScript practical: own the language, target a mature platform, and postpone backend complexity until it is justified.
Module boundaries should also follow the Zig approach rather than JavaScript-style import and export conventions.
That does not rule out higher-level conveniences. It means those conveniences should be modeled as explicit, opt-in capabilities that lower cleanly into the Zig ecosystem.
The initial pipeline is:
Zag source
-> S-expressions
-> normalized S-expressions
-> type resolution
-> generated Zig source
-> zig build-exe / zig test / zig build-lib
The key design choice is that S-expressions are not an optional side format. They are the first structural representation of the program. That makes the compiler easier to normalize, transform, and reason about.
Another key design choice is that types can be optional in source but not optional by codegen time. The compiler should preserve explicit annotations, infer missing types where safe, and reject unresolved cases before emitting Zig.
Another key design choice is that the core language can stay small while optional capability packs provide additional power. A regex pack is the clearest early example: if a program uses regex features, the compiler can enable a performant base module and expose the corresponding forms without bloating the core language for everyone else.
The bootstrap compiler works end-to-end — 56-rule grammar, ~95% of day-to-day Zig expressible:
./bin/zag test/examples/hello.zag # emit Zig source (default)
./bin/zag -t test/examples/hello.zag # dump token stream
./bin/zag -s test/examples/hello.zag # print S-expressions
./bin/zag -r test/examples/hello.zag # compile and runWhat works now: fun/sub, if (prefix + postfix), while, for/for *item, match (range/enum patterns), enum (plain + tagged unions), struct/packed struct (fields, defaults, methods), error sets, type, test, pub/extern/export/packed, try/catch/??, captures (as/|val|), defer/errdefer, comptime/inline, =/=!/+=/-=/*=, typed params, return types, ?T/*T/[]T/!T, @builtins, array literals, pipe |>, range .., break :label/continue :label/return, unreachable/undefined, lambdas, struct literals, pointer deref ptr.*, implicit call with prefix -/!.
Type resolution: symbol table from fun/sub declarations, void-call detection (clean _ = removal), typeOf() inference for var binding types, declaration warnings for untyped pub/extern boundaries.
Define the public language thesis and repo structure.✓Specify a tiny source language subset.✓Lower that subset into raw S-expressions.✓- Normalize S-expressions into canonical forms.
Resolve required types for the minimal subset.✓ (basic)Emit valid Zig for the minimal subset.✓- Only introduce a more explicit core IR when the compiler truly needs it.
- building a custom machine-code backend
- targeting Zig internal IRs directly
- designing every advanced feature up front
- overcommitting to ownership, effects, macros, or comptime semantics before the bootstrap compiler exists
- carrying over JS UI/reactivity constructs that do not belong in systems
Zag - forcing every non-core feature into the core language instead of using opt-in capability packs
docs/syntax.md— language reference (the cheat sheet)docs/architecture.md— pipeline, grammar engine, file roles, build commandsdocs/roadmap.md— project status, what's done, bucket listdocs/stages.md— stage ownership: what the rewriter, grammar, and compiler each ownnexus— grammar DSL reference and parser generatordocs/types.md— type system directiondocs/target.md— Zig construct catalog from real-world embedded codebasedocs/lessons.md— design lessons from rip-lang, slash, mumps (historical reference)docs/zig-notes.md— how Zig's own frontend works (reference)