ActionScript 3, revived. Native, ahead-of-time, and entirely of its own will.
A statically-typed, garbage-collected, ahead-of-time-compiled revival of
ActionScript 3 / ECMAScript 4, decoupled from Flash. You write .vlt
source; the volentscript compiler produces a native executable — no VM,
no interpreter. Written in Rust; LLVM backend via inkwell.
SPECS.md— the language definition (what to build).CLAUDE.md— process and phase gates (how it gets built).docs/— reference material (ES4 draft, AVM2 overview, avmplus source, ECMA-262 3rd ed., AS3 guides). Git-ignored;docs/SOURCES.mdrecords the set andlinks.mdthe origins.
| Component | Pin | Where enforced |
|---|---|---|
| LLVM | major 22 (brew llvm, tested 22.1.6) |
.cargo/config.toml, CI version check |
| inkwell | 0.9.x, feature llvm22-1 (llvm-sys 221) |
root Cargo.toml |
| Rust | edition 2024, MSRV 1.88 | rust-version in root Cargo.toml |
These three must move together. Don't let brew upgrade drift the LLVM major
without updating the inkwell feature, the LLVM_SYS_221_PREFIX variable name,
and the CI check in the same change.
brew install llvm # keg-only; major must be 22
cargo build --workspace
cargo test --workspace
cargo run -p volentscript -- --version.cargo/config.toml sets LLVM_SYS_221_PREFIX=/opt/homebrew/opt/llvm
(Apple Silicon default). It does not override an existing value — on Intel
macs or CI, export LLVM_SYS_221_PREFIX="$(brew --prefix llvm)" yourself.
crates/
span/ source positions, spans, source map
diagnostics/ error type, stable codes, rendering
lexer/ &str -> tokens
ast/ AST node types
parser/ tokens -> AST (recursive descent, ES4 grammar)
sema/ resolution, type checking, coercions -> typed AST
mir/ typed, desugared, backend-agnostic mid-level IR
codegen/ Backend trait + LLVM (inkwell) impl — only crate touching inkwell
runtime/ native runtime static lib (GC, dispatch, builtins, entry shim)
driver/ parse -> check -> lower -> codegen -> link orchestration
cli/ the `volentscript` binary
tests/ end-to-end golden tests (.vlt program + expected stdout/exit)
Layering: frontend crates never depend on codegen; inkwell types never
appear above codegen. #![forbid(unsafe_code)] everywhere except codegen
and runtime.
Seventeen gated phases (P0-P16), each ending green (fmt, clippy
-D warnings, full test suite). Everything SPECS §1-§11 mandates for v1
is built and tested.
Language. Classes, interfaces, inheritance with native vtable +
interface dispatch; reified generics (classes and functions,
monomorphized); null safety (T? with flow narrowing, incl. &&/||
and is-guard narrowing); closures and Function values;
try/catch/finally with a real Error hierarchy (setjmp unwinding);
dynamic classes (expandos, in, delete, object literals);
for..in / for each..in; namespaces — both the static layer
(declarations, URI identity, namespaced members, use namespace,
compile-time ns::name) and first-class Namespace values with
runtime-computed qualification via per-class reflection tables;
main():int program entry.
Stdlib (SPECS §6). String/Array/Vector full surface, Math, JSON,
RegExp (backtracking engine: backreferences, lazy quantifiers, UTF-16
indices), Date (constructors, local+UTC getters, avmplus string forms,
Date.UTC), and the CLI runtime: trace, System.args/exit/getenv/ time/gc/readLine, File IO (read/write/append/exists/remove/copy/ rename/mkdir/rmdir/list/isDirectory/size/mtime), blocking TCP sockets
(Socket.connect, ServerSocket.bind/accept, line-oriented reads).
Runtime. Conservative mark-sweep GC (safepoint-triggered,
stack/register/static-root scanning, kind-tagged blocks, size-class
pooling — 1.5 GB-churn stress holds ~34 MB RSS); UTF-16 strings; boxed
* values; catchable runtime errors.
Compiler. LLVM new-PM optimization pipeline (-O 0..3, default O2;
try-functions pinned optnone for setjmp safety; inline ToInt32 fast
paths — recursive int benchmark ~5x over unoptimized); Linux
cross-compilation via zig cc (--target x86_64/aarch64-unknown-linux-gnu,
full golden corpus byte-identical in Debian containers); ad-hoc
codesigning on macOS arm64; diagnostics with stable codes and caret
rendering throughout.
Second backend (Cranelift): deferred post-v1 — the v1 exception
scheme needs returns_twice, which Cranelift lacks (SPECS §11 DECISION).
The Backend trait boundary is verified mechanically: no frontend crate
depends on inkwell.
Grab a release tarball from the GitHub releases page (compiler binary + runtime staticlib + examples), or build from source (above). CI runs the full test matrix on every push; releases are cut from tags.
| Platform | Status |
|---|---|
| macOS arm64 host | supported — CI + release artifact |
| Linux x86-64 host | supported — CI + release artifact |
| Linux target | --target x86_64/aarch64-unknown-linux-gnu (zig-linked) |
| Windows target | --target x86_64-pc-windows-gnu (zig-linked .exe; golden corpus executed on Windows in CI) |
| Windows host | future — compiler-on-Windows needs an LLVM-22-on-Windows story |
Windows exception support is real, not emulated: the runtime ships its own
non-unwinding Win64 setjmp/longjmp pair (winjmp.rs) because msvcrt's
longjmp SEH-unwinds through frames that carry no unwind tables.
volentscript build tool.vlt # native executable ./tool
volentscript build tool.vlt -O 3 -o fast # optimization level
volentscript build tool.vlt --target x86_64-unknown-linux-gnu
volentscript run tool.vlt # compile + execute
volentscript check tool.vlt # type-check only
volentscript parse tool.vlt # AST dumpDebug aids: VS_DUMP_IR=1 (pre-optimization LLVM module),
VS_DUMP_IR_OPT=1 (post-pipeline), VS_GC_LOG=1 (per-collection stats).
First public numbers (Apple M4, hyperfine, identical verified outputs) live
in benchmarks/REPORT.md — VolentScript vs C, Rust,
Go, Java, Node, Bun and Deno, with an honest reading of every gap and the
optimization each one maps to. Highlights: within ~2x of C on tight numeric
loops; 6-12x behind on allocation/string-heavy code (boxed Vector storage
and UTF transcoding — both on the roadmap). Reproduce: benchmarks/run.sh.
Every run is archived by date under
benchmarks/reports/ so the language's
performance evolution stays on the record.
Eight ready-to-run projects live in examples/ —
from a Game of Life to a static-file web server and a mini SMTP pair,
every one a compiled native binary:
life — Conway in the terminal |
todo — JSON task manager |
vgrep — grep clone |
calc — REPL with a hand-written parser |
logstats — log analyzer |
httpd — web server |
mail — SMTP server + client |
chat — socket chat |
volentscript run examples/httpd/main.vlt 8080 examples/httpd/public
# serving examples/httpd/public on http://127.0.0.1:8080All examples are compiled and exercised in CI
(cargo test -p e2e --test examples).
cargo test --workspace — unit suites per crate plus the e2e golden
corpus in tests/ (each .vlt program with expected stdout + exit 0),
capped by tests/showcase.vlt, the whole-language golden test. Opt-in
extras: cross_linux (needs zig + docker). Known deviations from AS3/ES4
are documented per phase in the git history and SPECS.
MIT or Apache-2.0, at your option (LICENSE-MIT / LICENSE-APACHE).
Volen, the fire salamander — regrows anything you throw at him.