Releases: Lord1Egypt/Heh
Release list
Heh π¨ v1.0.4
What's Changed
- release: Heh v1.0.4 security and static-correctness hardening by @Lord1Egypt in #37
- fix: release builds without an absent lockfile by @Lord1Egypt in #38
Full Changelog: v1.0.3...v1.0.4
Heh π¨ v1.0.3 β builds on the Rust it promises
Heh π¨ v1.0.3
A correctness and infrastructure release. No language change.
- Fixed: the crate did not build on the Rust version it claimed to support.
Cargo.tomlpromisesrust-version = "1.70", but the code used
std::iter::repeat_n(stable only since 1.82) and comparedExitCode
values. Anyone on Rust 1.70β1.81 runningcargo install heh-langhit a
compile error. Both are replaced, and the claim is now proven on every PR by
a CI job that builds with a real 1.70 toolchain. - CI runs the full suite on macOS and Windows as well as Linux β release
binaries ship for all three, and only one had ever been tested. Doing so
found three Windows-only harness bugs (CRLF in byte-exact fixtures, CRLF from
CPython in the arithmetic differential, and malformedfile://URLs), all
fixed..gitattributesnow pins LF for sources and fixtures. - CI also enforces
cargo clippy -- -D warnings; the tree is clippy-clean. - Documentation pruned from 18 markdown files to 6: the agent handoff kit and
per-release notes files were scaffolding for a build that is finished. Their
content lives on inAGENTS.mdandCHANGELOG.md. Fixed a dangling
docs/agent/TASK_MENU.mdreference inheh --help.
Install
cargo install heh-lang # the crate is heh-lang; the command is hehOr download a binary below β linux x86_64, Windows x86_64, macOS arm64 and
x86_64. Checksums in SHA256SUMS.txt.
License
MIT Β© Mohamed Mounir (Lord1Egypt)
Heh π¨ v1.0.2 β roughly twice as fast
Heh π¨ v1.0.2
A performance release. The frozen v1.0 language surface is unchanged β programs
behave exactly as before, just faster.
Roughly twice as fast
Three costs sat on the interpreter's hot path.
Integers now use a machine word until they need more. Every integer used to
allocate a heap vector of limbs, so a loop counter cost an allocation per step.
SPEC Β§5.1's implementation note asks for "a machine-word fast path with
automatic promotion to a bignum, so ordinary arithmetic runs at native speed" β
that is now what happens. Semantics are unchanged: integers are still
unbounded, and 2 ** 200 is still exact.
Interpreter-internal maps use a fast hasher. Variable lookup was running
SipHash β cryptographic strength, on nearly every instruction. std/hash
(SHA-256) is untouched and still a real hash.
Binding a name no longer allocates. Variable names are refcounted, so
binding a loop variable is a pointer bump instead of a string copy β two
million fewer allocations in a two-million-iteration loop.
| benchmark | v1.0.1 | v1.0.2 | vs CPython |
|---|---|---|---|
| fib | 104ms | 72ms | 0.35x β 0.62x |
| loop_sum | 751ms | 373ms | 0.27x β 0.57x |
| strings | 58ms | 41ms | 0.91x β 1.15x |
| maps | 205ms | 108ms | 0.38x β 0.51x |
| bigint | 11ms | 10ms | 3.00x |
Heh is now faster than CPython on string work and on arbitrary-precision
arithmetic, and roughly half its speed on loop-heavy code. The original design
target was β₯5Γ CPython, and this release still does not meet it β see below.
Integer arithmetic is now verified against CPython
tests/bignum_vs_python.rs runs every binary operator over 23 operands chosen
to sit exactly on the machine-word and limb boundaries β about 13,000
comparisons against CPython, whose integers are also unbounded and whose //
and % sign rules the spec adopts by name.
It caught a real bug in the first draft of the fast path: 1 // -2 returned
1 instead of -1. That test is now part of the suite.
Also fixed
sys.rand.bytes and sys.rand.int read only the lowest limb of their
arguments, so large values silently produced wrong bounds. They now use the
whole value and reject out-of-range input.
What is still slow, and why
Local variables are still looked up by name through a chain of scopes on
every access. A mature VM assigns each local a frame slot at compile time and
indexes an array instead. Doing that here needs a resolver pass that handles
shadowing across block scopes, match arm bindings, narrowing rebinds, and
closure capture β a subsystem rather than a patch, and exactly the kind of
change that ships subtle scoping bugs when rushed. It is the remaining path
toward the original performance target.
Install
cargo install heh-lang # the crate is heh-lang; the command is hehOr download a binary below β linux x86_64, Windows x86_64, macOS arm64 and
x86_64. Checksums in SHA256SUMS.txt.
License
MIT Β© Mohamed Mounir (Lord1Egypt)
Heh π¨ v1.0.1 β VM by default, clean recursion faults, four platforms
Heh π¨ v1.0.1
A patch release. The frozen v1.0 language surface is unchanged β this is
entirely implementation work, plus the first crates.io publish.
The bytecode VM is now the default, and covers the whole language
heh run executes on the bytecode VM; --tree-walk selects the reference
tree-walking evaluator. The VM previously punted three construct families back
to the tree-walker. It now encodes all of them:
- Closures become the same function value a named function is, capturing
the live scope. - Optional narrowing gets real block scopes, including the case where a
breakorcontinuejumps out of a narrowed block. - Field and index assignment (
p.x = v,l[i] = v, and nesting). Compound
forms duplicate the container and index rather than re-evaluating the index,
so an index expression's side effects cannot run twice.
Both engines share one call path and one set of field/index accessors, so they
cannot drift. Output remains byte-identical across the entire conformance
corpus, enforced by a differential test.
Runaway recursion is a fault, not a crash
Deep recursion used to abort the process with fatal runtime error: stack overflow and a core dump. SPEC Β§7.3 says a fault stops the program with a
diagnostic. Programs now run on a dedicated 256 MB stack with a call-depth
limit of 10,000, and both engines report E0202 identically. Legitimate deep
recursion β 9,000 frames β works fine.
Performance, honestly
benches/run.sh runs five benchmarks, each paired with an equivalent CPython
program whose answer must match before a timing is reported.
| benchmark | VM | tree-walk | CPython | VM vs tree-walk | VM vs CPython |
|---|---|---|---|---|---|
| fib | 112ms | 254ms | 37ms | 2.27x | 0.33x |
| loop_sum | 714ms | 967ms | 223ms | 1.35x | 0.31x |
| strings | 52ms | 56ms | 53ms | 1.08x | 1.02x |
| maps | 206ms | 208ms | 58ms | 1.01x | 0.28x |
| bigint | 10ms | 11ms | 31ms | 1.10x | 3.10x |
The VM beats the tree-walker on every benchmark, and beats CPython only on
arbitrary-precision arithmetic. The original design target was β₯5Γ CPython, and
this release does not meet it. The reason is structural rather than a
matter of tuning: every variable access is a string-keyed hash lookup up a
scope chain, and every integer heap-allocates, with no machine-word fast path β
something SPEC Β§5.1 explicitly invites an implementation to add. That is the
next performance milestone; the measurement harness now exists to prove it.
Also fixed
heh fmtmangled a closure nested inside a function, emitting a body at the
wrong indentation that would not re-parse.
Install
cargo install heh-lang # the crate is heh-lang; the command is hehThe crate is published as
heh-langbecausehehwas taken on crates.io
in 2022 by an unrelated project. The installed command is stillheh.
Or download a binary below β linux x86_64, Windows x86_64, macOS arm64 and
x86_64. Checksums in SHA256SUMS.txt.
License
MIT Β© Mohamed Mounir (Lord1Egypt)
Heh π¨ v1.0.0 β the language is frozen
Heh π¨ v1.0.0 β the language is frozen
Heh is a small programming language designed to stop changing. Nineteen
keywords, a spec that fits in eight printed pages against a hundred-page
budget, and a NEVER list fixed on day one. This release freezes the surface:
after v1.0, code that runs today runs unchanged forever.
What Heh is
- Easier than Python. Indentation blocks, inference everywhere except
function boundaries, one obvious way to do things. - Infinite by nature.
intis arbitrary-precision β overflow does not
exist.2 ** 200andfactorial(1000)are exact, with nothing to import.
Ranges may be unbounded:for i in 0..runs until youbreak. - Secure by default. All I/O flows from a single
Sysvalue handed to
main. A function that never receives it cannot touch the filesystem,
network, clock, or environment. Any capability can be revoked from the
command line (--deny-net), and revocation fails closed. - Reliable. Static types, errors as values (
ok/err/try), no
null, no exceptions, exhaustivematch. - Immortal. One binary, zero crates β Rust standard library only.
No package registry: dependencies are vendored into your repo and pinned by
SHA-256 inheh.lock, verified on every run.
Getting it
git clone https://github.com/Lord1Egypt/Heh && cd Heh
cargo build --release # target/release/heh β the whole toolchain
echo 'sys.print("Heh lives forever π¨")' > hello.heh
./target/release/heh run hello.hehThe toolchain
heh run Β· heh check Β· heh test Β· heh fmt Β· heh get Β· heh ast Β·
heh tokens β one binary, no configuration files, no options to argue about.
The formatter is canonical and comment-preserving. heh run --vm executes on
the bytecode VM, which is byte-identical to the tree-walking evaluator across
the entire conformance corpus.
Standard library
Eight pure modules β math, json, fmt, time, regex (RE2-style, no
backtracking), csv, hash (SHA-256, CRC32), debug β plus builtin methods
on str, list, and map. Anything effectful lives on Sys instead. The
complete frozen surface is in docs/STDLIB.md.
What v1.0 does not have
- No raw sockets. A socket is a handle with a lifetime, and Heh has no
resource-lifecycle construct; committing to one at the freeze would be a
permanent decision made in a hurry.sys.net.getcovers HTTP request and
response work. Sockets remain a candidate addition against the page budget. - No concurrency. When it arrives it will be structured and colorless β
async/awaitfunction coloring is on the NEVER list. - Everything else on the NEVER list (SPEC Β§1.2), permanently: null, exceptions,
integer overflow,eval, classes, macros, operator overloading, global
mutable state, a package server, implicit coercion.
Conformance
tests/corpus/ is the definition: an implementation that passes it is Heh.
The corpus grows and never shrinks. The spec, not the implementation, is
authoritative β where they disagreed during the v1.0 audit, the implementation
was fixed.
License
MIT Β© Mohamed Mounir (Lord1Egypt)