ajhahn.de
← Flash
Markdown 227 lines
<div align="center">

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/flash_logo_dark.png">
  <img src="assets/flash_logo_light.png" alt="Flash" width="240">
</picture>

<h1>Setup</h1>

<p><i>From clone to running compiler in two commands.</i></p>

<p>
  <a href="README.md"><b>README</b></a> ·
  <a href="VISION.md"><b>Vision</b></a> ·
  <a href="https://ajhahnde.github.io/Flash/"><b>Tutorial</b></a> ·
  <a href="REFERENCE.md"><b>Reference</b></a> ·
  <a href="COOKBOOK.md"><b>Cookbook</b></a> ·
  <b>Setup</b> ·
  <a href="VERSIONING.md"><b>Versioning</b></a> ·
  <a href="CHANGELOG.md"><b>Changelog</b></a> ·
  <a href="LICENSE.md"><b>License</b></a>
</p>

</div>

---

How to build and run the Flash compiler (`flashc`).

## Requirements

- **Zig 0.16.0**, exactly. The version is hard-pinned (see `.zigversion`)
  and the build fails fast on any other version. Install from
  [ziglang.org/download](https://ziglang.org/download/) or with a version
  manager (zigup / zvm / anyzig).

## Build

```sh
git clone https://github.com/ajhahnde/Flash.git
cd Flash
zig build
```

The `flashc` binary lands in `zig-out/bin/flashc`.

## Run

```sh
# version
zig-out/bin/flashc --version

# inspect the token stream
zig-out/bin/flashc --dump-tokens examples/clear.flash

# reformat a .flash file in place (--check reports without writing)
zig-out/bin/flashc fmt examples/hello.flash

# transpile a .flash file to Zig (lowered source on stdout)
zig build run -- examples/hello.flash

# the same, written to a file instead of stdout
zig-out/bin/flashc examples/hello.flash -o hello.zig

# transpile a whole source tree: every .flash under src/ lands in gen/ as a
# .zig twin mirroring its relative path; the first compile error stops the
# build with a non-zero exit
zig-out/bin/flashc build src gen
```

Compile errors print the offending source line with a `^` caret under the
exact spot (and a `~` tail when the error spans more than one character):

```
flashc: broken.flash:2:9: error: unknown name 'nope'
        _ = nope.sys.write()
            ^~~~
```

Pass `--plain-diagnostics` (any argument position) to get the bare
one-line `file:line:col: error: message` form instead — handy for
grep-style tooling that keys on one diagnostic per line.

### Tracing Zig errors back to Flash source

The emitted Zig is compiled by the Zig toolchain, so a type error caught
there is reported against the *generated* file. Pass `--anchors` (any
argument position) and every lowered top-level constant and function is
prefixed with a comment naming the Flash line it came from:

```sh
zig-out/bin/flashc --anchors examples/hello.flash > hello.zig
```

```zig
// hello.flash:12
export fn main(...) callconv(.c) noreturn {
```

A Zig error inside that function now reads back to `hello.flash:12` by
eye. The comment names the file only (no directories), and without the
flag the emitted bytes are unchanged.

## Using Flash in your own project

Flash compiles to readable Zig, so a Flash project is a Zig project with one
extra step: transpile the Flash sources, then let `zig build` compile the
result. A minimal layout:

```
my-project/
├── build.zig     — ordinary Zig build script (below)
├── src/          — your .flash sources
└── gen/          — the transpiled .zig twins (generated, ignorable)
```

`flashc build src gen` keeps `gen/` mirrored to `src/`, and this `build.zig`
wires the two steps together so `zig build` does both:

```zig
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Transpile every .flash file under src/ into gen/. Point the first
    // argument at your flashc binary (here: on PATH).
    const transpile = b.addSystemCommand(&.{ "flashc", "build", "src", "gen" });

    // Compile the generated Zig as an ordinary executable.
    const exe = b.addExecutable(.{
        .name = "my-app",
        .root_module = b.createModule(.{
            .root_source_file = b.path("gen/main.zig"),
            .target = target,
            .optimize = optimize,
        }),
    });
    exe.step.dependOn(&transpile.step);
    b.installArtifact(exe);
}
```

A compile error in any Flash source stops the transpile step non-zero, so
`zig build` halts with the Flash diagnostic — file, line, and caret —
before the Zig compiler ever runs. For errors the Zig toolchain catches in
the generated code, add `--anchors` to the `flashc build` command line and
each generated declaration carries a comment naming its Flash origin.

## Test

```sh
zig build test
```

Runs the per-module unit tests (lexer, parser, semantic checker, lowering, and
the formatter), the integration suite (`tests/`), the build-driver harness
(`zig build test-driver` — file outputs, exit codes, and flag composition),
and the Flash-source test suite together. The latter can also run on its own:

```sh
zig build test-flash
```

This transpiles each `.flash` file under `tests/flash/` with the freshly
built `flashc` and runs the emitted Zig `test` blocks — Flash code testing
itself through its own `test "name" { }` form.

## Self-hosting

The compiler's maintained source is Flash, under `selfhost/`. By convention
the handwritten Zig compiler under `src/` is *stage0* — the frozen bootstrap
seed that keeps a clean clone buildable with nothing but a Zig toolchain —
the compiler built from the Flash sources is *stage1* (`flashc-stage1`), and
the compiler stage1 builds from those same sources is *stage2*
(`flashc-stage2`). Six build steps drive and certify the bootstrap:

```sh
# build flashc-stage1: stage0 transpiles every selfhost module and the
# result is compiled as the self-hosted compiler
zig build stage1

# build flashc-stage2: the same composition, with stage1 as the transpiler —
# the self-hosted compiler compiling its own sources
zig build stage2

# transpile each selfhost module and run its Flash test blocks
# (also part of `zig build test`)
zig build test-selfhost

# transpile each standard-library module (std/) and run its Flash test
# blocks (also part of `zig build test`)
zig build test-std

# transpile each language-server module (tools/lsp/) and run its Flash
# test blocks (also part of `zig build test`)
zig build test-lsp

# build flashd, the Flash language server (diagnostics over stdio; see
# editors/nvim/README.md for the editor wiring)
zig build lsp

# run flashc and flashc-stage1 over every example, probe, and test source
# and assert byte-identical transpile, --dump-tokens, and fmt behaviour
zig build diff-corpus

# the bootstrap fixpoint: assert stage1 and stage2 emit byte-identical Zig
# over every selfhost source and example, deterministically across runs
zig build fixpoint
```

## Shell helpers (optional)

`flash.env.zsh` provides a `flash` verb dispatcher. Source it from your
shell profile:

```sh
echo "[[ -f $PWD/flash.env.zsh ]] && source $PWD/flash.env.zsh" >> ~/.zshrc
# then, from anywhere:
#   flash build | flash test | flash tokens examples/clear.flash | flash clean
```

---

[← Prev: Reference](REFERENCE.md) · [Next: Versioning →](VERSIONING.md)