hek, the language tool
The compiler's own CLI, for editors, pre-commit hooks and answering whether an edit changed anything.
hek is heklang’s own tool: a separate binary from a separate crate, for editor
integration, pre-commit and the digest.
You do not need it to run a hekla project. hekla check and hekla test run the same
compiler and add the runtime’s own rules on top.
curl -fsSL https://hekla.tqwewe.com/install.sh | sh -s -- hek
or cargo install hek.
Usage
hek [check|test|fmt|digest] [--boundaries] [--check]
[--packed|--hash|--json] [--tests] [path|-]
path is a directory or a single .hk file, and defaults to the current directory. Every
file under it is one module of one program, and declaration order across them does not
matter.
With no subcommand, hek does both check and test.
Subcommands
hek check |
parse every .hk file under path as one program |
hek test |
the same, then run every test declaration in it |
hek fmt |
rewrite every .hk file under path canonically |
hek digest |
print what that program does, with everything else taken away |
Flags
| Flag | With | |
|---|---|---|
--boundaries |
check |
print what each command guards, transitively |
--check |
fmt |
name what would change and write nothing |
--packed |
digest |
print the canonical form the hash covers |
--hash |
digest |
print only the hash |
--json |
digest |
print the form as JSON |
--tests |
digest |
include the test declarations |
--packed, --hash and --json are three ways of reading one digest, so passing more than
one is an error rather than a precedence puzzle. Any of the four digest flags on another
subcommand is an error too.
Reading from stdin
hek fmt -
Formats one module from stdin onto stdout, which is what format-on-save wants. It fails rather than printing nothing when the module does not parse, so a broken buffer is never silently emptied.
hek digest - reads one module the same way.
check
hek check
commands/connect-shop.hk:11:18 [unknown-member] no method `trm` on String
commands/connect-shop.hk:18:8 [not-declared] event @shop.reconneced is not declared
commands/ship-order.hk:8:6 [type-mismatch] expected Bool, found String
3 errors
Every mistake is reported, not only the first. See Diagnostics for the full code list and how to read an extent.
--boundaries
hek check --boundaries
One line per command naming what it guards, transitively through every guard it reaches.
This is the way to see what a deep guard chain actually costs before it shows up as a
409.
fmt
Formatting changes whitespace and nothing else, and that is checked by re-lexing both sides. It reads the tree-sitter grammar rather than the parser.
The rules are few enough to state: a group is one line or one line each, blank lines are yours, and a comment is a line.
What it deliberately does not do: remove parentheses, break a dot chain, break a boolean condition, hug a last argument, re-wrap a comment, align columns. And there are no options at all, which is the point.
hek fmt --check
names what would change and writes nothing. That is the pre-commit gate.
digest
The digest is a deterministic rendering of what a program does, with everything that does
not affect behaviour taken away. const, refusal, guard and secret are inlined and do
not appear.
hek digest --hash
Two programs with the same hash do the same thing, so this answers “was that refactor actually a no-op” cheaply, before running anything expensive.
--tests includes the test declarations, which are otherwise their own section and outside
the hash.
Exit status
0 |
read fine and passed |
1 |
read fine and did not pass, or could not read at all |
The distinction between those two 1s is visible in where the output goes: a program that
did not pass reports diagnostics on stdout, and a failure to look at all goes to stderr with
a hek: prefix.
digest is the exception. Its stdout carries the document and nothing else, so that
--packed | sha256sum matches --hash, and its diagnostics go to stderr unprefixed.
hek check does not fail on a failing test, because a test that fails is a program that
parsed. hek test does.
Editor support
There is no language server yet. The tree-sitter grammar is what editors use for
highlighting, and hek fmt - is what they use to format on save.
Editor setup has the configuration for Helix, Neovim, Zed, VS Code and Emacs.
In CI
hek fmt --check
hekla check .
hekla test .
Note the last two are hekla, not hek. The two tools have different rule sets, and a
program can pass hek check and fail hekla check. See
hekla, the runtime.