CONTRIBUTING.md
Rama main · réplica de lectura del repositorio original.
# Contributing to Zen C
Thanks for contributing! This file covers the repository's expectations,
especially for changes to the compiler itself (`src/`).
## Compiler conventions
The compiler is intentionally written to be **coherent**: one rule per
concern, applied everywhere. When changing compiler code, follow these.
### Error handling
| Class | Macro | Behavior |
| :-- | :-- | :-- |
| Fatal / syntax | `zpanic_at(token, "…")` | Aborts (or delegates to the LSP handler in fault-tolerant mode). |
| Warning | `zwarn_at(token, "…")` | Non-fatal diagnostic. |
| Semantic (typechecker) | `tc_error(tc, token, "…")` | Recoverable type error. |
| Semantic (parser, recoverable) | `zerror_at(token, "…")` | Recoverable non-fatal error. |
- `"Expected …"` syntax errors use `zpanic_at`, consistently.
- Every error path that returns `NULL`/an error node must already have emitted
a diagnostic.
### Symbol mangling
- The one canonical mangler is `mangle_method_symbol(base, trait, method)` in
`src/parser/struct/struct_shared.c`. Use it everywhere; never re-implement
`%s__%s` + `merge_underscores` inline.
- A method beginning with `_` keeps its triple underscore (`Struct___method`)
so it cannot collide with `Struct__method`.
- `merge_underscores` collapses runs of **four or more** underscores; a run of
exactly three is preserved (it encodes `__` + a leading-`_` name).
### Memory management
- Use `xmalloc` / `xcalloc` / `xrealloc` / `xstrdup` (arena allocation);
`zfree` is a no-op (arena memory is reclaimed all at once).
- `arena.h` macro-redirects bare `malloc` / `realloc` / `calloc` to the arena,
so a bare `free()` on a redirected pointer is an **invalid free**. Frees on
arena memory are `zfree` (no-op).
- Use the explicit `libc_malloc` / `libc_free` / `libc_realloc` escape hatches
for short-lived buffers that should be heap-managed (e.g. `realpath` results,
cJSON's allocator), and pair them correctly.
### Recursion safety
- Guard unbounded recursion with `RECURSION_GUARD` / `RECURSION_GUARD_TOKEN`.
- Recursive type/AST walkers that aren't parser-bounded carry a depth
parameter (see `sync_type_linkage_depth`).
### Field naming
- Discriminant fields use `kind` (`ASTNode.kind`, `Token.kind`, `Type.kind`,
`CValue.kind`, the literal union's `kind`). `field.type` is a type-name
string, not a discriminant.
- Count fields use `<X>_count` (`arg_count`, `binding_count`,
`capture_count`, `output_count`, `generic_param_count`).
### Dead code
- No consecutive duplicate `return` statements; no code after an unconditional
return; no empty `if`/`while` bodies without an explanatory comment.
- Run `clang-format` (enforced by the CI Lint job) and the fuzzer before
landing compiler changes.
## Development workflow
- `make` builds the compiler; `make test` runs the full suite.
- `make fuzz-libfuzzer-build` builds the libFuzzer target; the nightly
`Scheduled Fuzzing` workflow runs it.
- Keep changes in small, focused commits. The `std` library (Zen C), the
website docs, and the awesome-zenc examples live in separate repositories.