A small configuration language for Zig: ZON with let, if and templates over a context, evaluated to a struct, always finishing.
struthio CONTRIBUTING.md
5.4 kB · 142 lines
Markdown
at main

Contributing to struthio #

Thank you for wanting to help. This file covers what you need to know to make a change and get it accepted. README.md says what struthio is and how it is used.

Where to send changes #

Report issues and send pull requests to the Tangled mirror: https://tangled.org/jcollie.dev/struthio.

Setting up #

Everything is pinned in the Nix flake, Zig 0.17.0 included:

$ git clone https://git.jcollie.dev/jeff/struthio.git
$ cd struthio
$ nix develop

The development shell has zig, reuse, tree-sitter, zon2nix, kcov and the rest. Without Nix, you need Zig 0.17.0 and nothing else to build and test the library and the command; zig build fetches the dependencies named in build.zig.zon.

Before you send a change #

CI runs these, and a change has to pass all of them:

$ reuse lint                            # every file has a license
$ zig fmt --check --exclude zig-pkg .   # Zig is formatted
$ zig build test --summary all          # unit, golden, fuzz-seed and server tests
$ zig build check                       # compiles what nothing else builds
$ zig build fuzz-run -- --iterations 60000
$ nix build                             # the package; runs the tests in the sandbox
$ nix flake check                       # the tree-sitter grammar

nix build and nix flake check see only files git knows about. git add a new file before running them, or the build fails as if the file were missing.

Where things are #

Path What
src/root.zig The public API: Program, evalSource, Options, format
src/Tokenizer.zig, src/Parser.zig, src/ast.zig Source to tree; names and @include are resolved here
src/eval.zig, src/builtins.zig, src/value.zig Evaluating the tree, and the built-in functions
src/host.zig, src/decode.zig Reading the context by reflection, and decoding into the caller's type
src/format.zig struthio fmt and outline, with a parser of its own that keeps every token
src/Diagnostic.zig Error messages and positions
src/main.zig, src/lsp.zig The struthio command: fmt and the language server
tests/golden/ Whole programs and what they must evaluate to or fail with
tests/fuzz.zig, tools/fuzz.zig Fuzz targets, and a reproducible loop that drives them
tree-sitter-struthio/ The tree-sitter grammar and editor queries

Making changes #

Tests #

Every behavior change comes with a test. Unit tests sit at the bottom of the file they test; src/tests.zig holds tests of the language as a whole.

A golden test is a program in tests/golden/NAME.struthio, with either NAME.zon (what it must evaluate to) or NAME.err (the diagnostic it must fail with, as line:column: message). Add it to cases in tests/golden.zig. A program that evaluates must already be formatted, so run zig build run -- fmt tests/golden/ on it.

Errors #

Anything a program can get wrong is an error with a Diagnostic, never a panic. Messages are short and lowercase, say what was found, and point at the place in the source where the problem is.

The language #

A change to the syntax touches more than the parser. In the same change:

  • src/Parser.zig, and src/format.zig's parser, which has to accept the same programs in the same shapes. A test checks that formatting never changes a program's tree.
  • tree-sitter-struthio/grammar.js, then tree-sitter generate in that directory, and commit what it writes to src/.
  • The queries in tree-sitter-struthio/queries/, then ./helix-queries.sh, and commit what it writes to queries/helix/.
  • A corpus test in tree-sitter-struthio/test/corpus/, run with tree-sitter test.
  • The language section of README.md.

nix flake check fails if src/ or queries/helix/ is out of date.

The language must not be able to loop or recurse. A feature that makes it possible for a program to run without finishing will not be accepted.

Fuzzing #

The targets in tests/fuzz.zig run on their seeds as part of zig build test. To search for problems:

$ zig build fuzz --fuzz                 # Zig's coverage-guided fuzzer
$ zig build fuzz-run -- --seconds 300   # the loop in tools/fuzz.zig

A crash input saved by either is a bug. Fix it and add the input as a seed.

Dependencies #

When build.zig.zon changes, regenerate the file Nix builds from and commit it along with the change:

$ zon2nix --17 --nix=build.zig.zon.nix build.zig.zon

Documentation #

The API documentation is generated from doc comments; read it with zig build docs-serve. A public declaration gets a doc comment. When behavior changes, update README.md to describe how things are now, not how they changed.

Licensing #

struthio is MIT licensed and follows REUSE. Every new file starts with an SPDX header like the ones already in the tree; a file that cannot hold one goes in REUSE.toml. By sending a change you agree to license it under the MIT license.

Commits #

The first line is a short summary in the imperative ("Add switch", "Give a float printed as ZON room for all of its digits"). The body explains what changed and why.