- name
- implement-feature
- description
- Use when adding a new Brainrot language feature — a keyword, operator, builtin function, or grammar construct. Covers the lexer→parser→AST→semantic-analyzer→interpreter pipeline and the fixture/expected-output test pattern this repo uses.
## When to Use
The user asks to add a new keyword, operator, control-flow construct, type, or
stdlib (`stdrot`) builtin, or to extend an existing one (e.g. implement one of
the ❌ rows in the README keyword table, like `gyatt`/enum or `chungus`/union).
## Step-by-Step Instructions
1. **Check scope first.** Read `README.md`'s keyword/preprocessor tables and
`docs/the-brainrot-programming-language.md` to see if the feature is already
partially implemented or has a reserved meme name. Grep `lang.l`/`lang.y`
for the token before assuming it's new.
2. **Lexer** (`lang.l`): add the token if it's a new keyword/operator.
3. **Grammar** (`lang.y`): add/extend the production rule. Run
`bison -d -Wcounterexamples lang.y -o lang.tab.c` mentally in mind that
shift/reduce conflicts will fail the build (`-Wcounterexamples`).
4. **AST** (`ast.c/h`): add the node type/constructor if the construct needs
new AST shape.
5. **Semantic analysis** (`semantic_analyzer.c/h`): add type-checking / scope
rules. This is the most bug-prone layer (see recent history of sanitizer
fixes) — mind ownership of any `String`/pointer values you allocate.
6. **Interpreter/visitor** (`interpreter.c/h`, `visitor.c/h`, or a new file
under `stdrot/` for a builtin): implement the runtime behavior.
7. **Wire builtins**: if adding a `stdrot` function, register it in
`stdrot/registry.c` and declare it in `stdrot/stdrot_api.h`.
8. **Add a test fixture**: create `test_cases/<feature>.brainrot` exercising
the happy path (and a separate file for an error case if relevant, following
the `semantic_error_*.brainrot` / `*_fail.brainrot` naming pattern).
9. **Add expected output**: run `./brainrot test_cases/<feature>.brainrot`
locally, verify the output is correct, then add it verbatim to
`tests/expected_results.json` keyed by the fixture's basename.
10. **Add an example** (optional but preferred for user-facing features) in
`examples/` and link it from `examples/README.md`.
11. **Update docs**: mark the feature ✅ in `README.md`'s table and describe it
in `docs/the-brainrot-programming-language.md` if it's a builtin/keyword.
12. **Build and test**: `make && make test && make valgrind`. All three must
pass — the build uses `-Werror -fsanitize=address,undefined`. Also run
`make format-check` (or `make format` to fix) — CI's `lint` job blocks on
any diff.
13. **Open the PR using `.github/PULL_REQUEST_TEMPLATE.md`**: fill in every
section (Description, Related Issue, Type of Change, Checklist) — don't
submit a bare description.
## Conventions and Best Practices
- Match the meme-naming spirit but don't invent new slang without checking
`TRUTH.md`/README for an already-agreed name; ask the user if unsure.
- Keep grammar rules narrow — prefer extending an existing production over
duplicating one, to avoid new shift/reduce conflicts.
- Follow the C style in [AGENTS.md](../../../AGENTS.md): 4-space indent,
snake_case, Allman braces, ~80 cols.
- New allocations go through `lib/arena.c` or `lib/mem.c` where the surrounding
code already does, for consistency with existing memory-safety fixes.
## Important Notes
- Never hand-edit `lang.tab.c`, `lang.tab.h`, or `lex.yy.c` — they're
regenerated by `make` and gitignored.
- If the feature can't be fully implemented, don't half-wire it silently
(e.g. token added but no grammar rule) — either finish the slice end-to-end
or clearly flag what's stubbed.
Ver no GitHub