Projects

Language design / Runtime

03 / 09

elf

A small bytecode-interpreted language that gives C programs a familiar, table-centered layer for dynamic data, automation, and rapid iteration.

Status0.2.0-dev
Period2023—2026
Built withC / Bytecode VM / Language design
PROGRAM.ELF FUNCTION / CLOSURE
make_adder := fun(base) {
    ret fun(value) {
        ret base + value
    }
}

add_ten := make_adder(10)
result := add_ten(32)

Compilation path

  1. 01 Source
  2. 02 AST
  3. 03 IR
  4. 04 Bytecode
  5. 05 VM
01 / Language + pipeline

A compact C-like surface backed by a complete compiler pipeline and slot-based virtual machine.

02 / Intent

C remains the right tool when a system needs direct control over memory, layout, the operating system, or native performance. It becomes less pleasant when the work is mostly dynamic data, strings, configuration, automation, or logic that needs to change quickly.

Elf is not meant to replace C. It supplies the smaller dynamic layer I wanted inside native programs without asking a C programmer to adopt an unfamiliar surface grammar, object model, or large runtime ecosystem.

03 / Architecture

Elf compiles source before execution. Each stage makes the program more explicit, while temporary compiler structures and persistent runtime data have deliberately separate lifetimes.

01

Lexer / Parser

Tokens are produced on demand. The parser builds a source-located AST and interns names for cheap identity comparisons downstream.

02

IR lowering

Scopes, declarations, constants, closure captures, defers, labels, and jumps become a smaller and more explicit representation.

03

Bytecode backend

Slot allocation, frame sizing, branch patching, constant pools, and source maps are finalized into one executable module.

04

VM / C API

Slot-based frames execute bytecode while garbage-collected closures and native C functions share one callable value model.

04 / Engineering decisions

01

C and Elf, not C or Elf

C owns the host, runtime, and systems that require direct control. Elf handles the flexible layer where short iteration cycles and dynamic values matter more than native machinery.

02

One table, three views

Every value lives in one contiguous array. A separate open-addressed table maps keys to those array indices, allowing the same structure to behave as an array, map, or record without duplicating value storage.

03

Consistency over compatibility

Plain brackets now address the contiguous array view, while dot access addresses keyed values. Changing the earlier syntax removed a local convenience in favor of a rule that remains predictable across the language.

04

Transient compiler, persistent module

AST, IR, and module builders live in scratch storage and disappear after compilation. Only finalized bytecode, constants, source, and runtime objects survive in the owning state.

05 / Current reality

Elf is currently 0.2.0-dev and officially supports Windows x64. Its syntax and API remain unstable; parameter annotations and defaults are not yet enforced, runtime failures lack a protected-call boundary, compiled modules cannot be independently unloaded or serialized as portable bytecode, and the VM has no JIT. Garbage collection is synchronous mark-and-sweep, and there is no package ecosystem yet.