You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
From interpreted language to compiled native binaries.
Each milestone ships independently. Nothing breaks between releases.
Current State: v0.4.3 — Shipping, With Backend Gaps
Status: Shipped
Component
State
Details
Tree-walk interpreter
Complete
Full language support, 238+ builtins
Bytecode VM
Partial
Fast backend for a supported subset; unsupported constructs are blocked
JIT (Cranelift)
Partial
Integer-heavy functions on the same supported subset as the VM
Standard library
18 modules
238+ functions across math, fs, crypto, db, http, jwt, mysql, etc.
HTTP server
Complete
axum + tokio, decorator routing, WebSocket, per-request interpreter fork (~32k req/sec on trivial handlers; CPU-bound handlers scale with CPU count up to the interpreter overhead ceiling)
HTTP client
Complete
reqwest, JSON, all methods, SSRF guard with DNS pinning
Type checker
Gradual
Arity + type warnings, --strict turns them into hard errors
Tests
644 Rust + 631 Forge
Verified locally; one Forge test is intentionally skipped
forge run app.fg # Tree-walk interpreter (default)
forge run --vm app.fg # Bytecode VM
forge run --jit app.fg # JIT for integer functions, VM fallback
forge run --profile app.fg # VM execution with profiling report
forge build app.fg # Writes app.fgc bytecode to disk
forge run app.fgc # Loads and executes compiled bytecode
forge build --native app.fg # Builds a native launcher (runtime still required)
What Doesn't
VM/JIT support a real subset of the language; the interpreter remains the full-fidelity runtime
Several AST features still compile only on the interpreter side (for example: interfaces/give blocks, safe/retry/timeout blocks, scheduler/watch/agent features)
JIT only natively compiles integer-heavy functions; broader programs rely on VM fallback
No AOT compilation
forge build --native is currently a launcher, not a standalone binary
Backend parity coverage has started, but it is not yet a full-language corpus
Execution Focus: Next 90 Days
The next phase is about maturity, not breadth.
Top Priorities
Unified semantics layer between parser, interpreter, VM, JIT, and future AOT
Full VM parity for the most-used language features
Real package and module correctness
Stronger type system foundations
Standalone native compilation path
30-Day Outcomes
Land a backend parity corpus in CI
Close the highest-value VM gaps (closure correctness, remaining safety-block gaps, remaining destructuring gaps)
Improve local dependency and module behavior (forge install, lockfiles, cycle detection, caching)
Strengthen LSP navigation and strict-mode diagnostics
90-Day Outcomes
Reduce backend divergence materially
Make Forge a reliable multi-file, dependency-bearing project language
Improve typed tooling and diagnostics
Establish the runtime/codegen scaffolding for real standalone native builds
This is the public execution focus. Tactical sequencing, issue breakdown, and internal dependency ordering can evolve as implementation reveals constraints.
Milestone 1: v0.3 — Bytecode Persistence & VM Parity
Goal:forge build app.fg produces a .fgc file. forge run app.fgc loads and executes it. VM reaches feature parity with the interpreter.
Why this first: Everything after this depends on having a solid, serializable bytecode format and a VM that can run real programs.
VM channel builtins: channel(), send(), receive(), close()
VM channel extras: try_send(), try_receive(), select()
VM async coordination: await_all(), await_timeout()
VM time() builtin
VM parity: all parity test fixtures pass on VM backend
Profiler integrated, --profile flag works
Auto-JIT for hot integer functions
Commit Breakdown (M1)
m1-001: feat(bytecode): define binary format spec and magic bytes
m1-002: feat(serialize): implement chunk serialization to binary
m1-003: feat(serialize): implement chunk deserialization from binary
m1-004: feat(cli): forge build writes .fgc files
m1-005: feat(cli): forge run loads .fgc files
m1-006: test(serialize): round-trip serialization tests
m1-007: feat(vm): compile destructuring statements
m1-008: feat(vm): add TryEnter/TryExit/ThrowError opcodes
m1-009: feat(vm): implement full try-catch in compiler + VM
m1-010: feat(vm): wire all stdlib modules into VM dispatch
m1-011: feat(vm): implement upvalue capture for closures
m1-012: fix(vm): clean up unused Pop/GetLocal/SetLocal
m1-013: test(vm): interpreter-VM parity test suite
m1-014: feat(profiler): extend with timing and type tracking
m1-015: feat(vm): wire profiler into call_value
m1-016: feat(cli): add --profile flag
m1-017: feat(vm): auto-JIT for hot integer functions
Milestone 2: v0.4 — JIT Expansion
Goal: JIT compiles functions with strings, arrays, objects, and floats — not just integers. Hot functions automatically promote to native code.
Why this matters: This is where performance goes from "Python-speed" to "Go-speed" for compute-heavy code. The JIT handles 90% of real functions, not just toy integer math.
Phase 2.1 — NaN-Boxing Value Representation
Task
Files
Description
2.1.1
src/vm/nanbox.rs (new)
Implement NaN-boxed 64-bit value type: doubles use IEEE 754, non-doubles encoded in NaN payload bits. Tags: Int (48-bit), Bool, Null, Pointer (48-bit heap ref)
Swap VM's Value enum to use NaN-boxed u64 internally, keeping the same public API
2.1.4
src/vm/machine.rs
Update all opcode handlers to work with NaN-boxed values
2.1.5
Tests
Exhaustive NaN-boxing tests: encode/decode round-trips for all types, edge cases (NaN, Infinity, max int, null pointer)
Why NaN-boxing: One uniform 64-bit value that fits in a register. No heap allocation for primitives. No branch on type tag for arithmetic. This is what LuaJIT and JavaScriptCore use.
64-bit layout:
Float: standard IEEE 754 double (if not NaN)
Int: [1111...1][01][48-bit signed int]
Bool: [1111...1][10][0 or 1]
Null: [1111...1][11][0]
Pointer: [1111...1][00][48-bit pointer]
Monomorphization: specialize generic functions for concrete types at call sites
3.4.3
src/typechecker.rs
Generic constraint checking: <T: Comparable>
3.4.4
Tests
Generic type tests: identity, map, filter, custom generics
Milestone 3 Deliverables
Type annotations enforced (gradual — unannotated code still works)
Type inference for local variables and function signatures
Option<T> with Some/None (no more raw null)
Interface satisfaction checking
Basic generics with monomorphization
Type errors reported at compile time with source locations
Commit Breakdown (M3)
m3-001: feat(types): TypeAnnotation enum in AST
m3-002: feat(types): bidirectional type inference engine
m3-003: feat(types): type environment with scope tracking
m3-004: feat(types): function signature inference
m3-005: feat(types): annotation validation (inferred vs declared)
m3-006: test(types): type inference test suite
m3-007: feat(types): Option<T> with Some/None variants
m3-008: feat(types): null safety enforcement
m3-009: feat(types): interface satisfaction checking
m3-010: feat(types): generic type parameter parsing
m3-011: feat(types): monomorphization
m3-012: test(types): generics and interface tests
Milestone 4: v0.6 — Concurrency
Goal:spawn runs real concurrent tasks. Channels for communication. Async/await for I/O.
Why here: Before native compilation (M5), concurrency needs to work correctly at the VM level. Native code inherits whatever concurrency model the VM uses.
Phase 4.1 — Green Threads on Tokio
Task
Files
Description
4.1.1
src/vm/green.rs
Replace synchronous scheduler with tokio::spawn. Each green thread gets its own register file and call stack
4.1.2
src/vm/green.rs
Message passing: send(thread_id, value) and receive() -> value with bounded channels
4.1.3
src/vm/machine.rs
OpCode::Spawn creates a real tokio task, returns a thread handle
4.1.4
src/vm/machine.rs
OpCode::Yield — cooperative yield point, returns control to scheduler
Async tests: concurrent fetches, file I/O with await
Milestone 4 Deliverables
spawn { } runs real concurrent tasks on tokio
Channels for inter-task communication
await suspends tasks for I/O
Select/multiplex on channels
No data races (values are copied or moved, not shared)
Milestone 5: v0.7 — AOT Native Compilation
Goal:forge build app.fg produces a standalone native binary. No Forge runtime needed to run it.
Why this is the big one: This is the jump from "scripting language" to "systems language." The binary runs without the forge CLI, ships as a single file, starts instantly, runs at near-Rust speed.
Compile all builtin functions as extern "C" functions callable from native code: forge_println(*str), forge_array_new(count) -> *arr, forge_fetch(*url) -> *response, etc.
5.1.2
src/runtime/libforge.rs
GC interface for native code: forge_gc_alloc(size) -> *ptr, forge_gc_root(ptr), forge_gc_unroot(ptr)
Performance benchmarks published (vs Go, Python, Node, Lua)
8.7
Security audit
8.8
"The Forge Book" — comprehensive documentation
Milestone 9: v1.1 — Language Evolution
Goal: Richer data structures, enforced generics, composable iteration, and structured concurrency. Make Forge a language you can write real algorithms in.
Tasks
Task
Description
9.1
Tuples: (a, b, c) literal syntax, destructuring, type annotations
9.2
Set type: set([1,2,3]), .add(), .has(), .remove(), set operations
9.3
Map with any-key: map({ [key]: value }), non-string keys, .get(), .set()
9.4
Iterator protocol: .stream() on collections, lazy .filter()/.map()/.take()/.collect()
9.5
Enum methods: impl blocks on type algebraic variants