Files
hakorune/docs/guides/macro-system.md

102 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Macro System (Phase 16) — Quickstart
Status: MVP available behind environment gates (default OFF). This page describes how to enable and use the initial features (derive, test runner, expansion dump) and the developerfacing Pattern/Quote API preview.
## Enabling/disabling macros
- Default: ON
- Disable: `NYASH_MACRO_DISABLE=1` or `NYASH_MACRO_ENABLE=0|false|off`
- Debug trace: `NYASH_MACRO_TRACE=1`
- CLI shortcut for debug: `--expand` (prints pre/post AST, and sets trace)
## Derive (MVP)
- Provided derives: `Equals`, `ToString`
- Control via env:
- `NYASH_MACRO_DERIVE=Equals,ToString` (default when unset)
- `NYASH_MACRO_DERIVE_ALL=1` (force all derives)
- Behavior:
- Injects `equals(__ny_other)` and `toString()` into Box declarations when not already present.
- Public-only: derives operate on public fields only (Philosophy: Box independence / loose coupling).
- No changes to MIR instruction set; expansion happens on AST, then compiled as usual.
Example
```
NYASH_MACRO_ENABLE=1 ./target/release/nyash --backend vm apps/APP/main.nyash
```
## Test runner (MVP)
- CLI: `--run-tests` → enable macro engine and inject a test harness main
- Discovery targets:
- Toplevel functions with names `test_*`
- Box static/instance methods `test_*`
- Filtering: `--test-filter SUBSTR` or `NYASH_TEST_FILTER=SUBSTR`
- Entry policy when a main exists:
- `--test-entry wrap` → rename original `main` to `__ny_orig_main`, run tests then call original
- `--test-entry override` → replace entry with test harness only
- Force apply even if a main exists: `NYASH_TEST_FORCE=1`
- Return policy in wrap mode:
- `--test-return {tests|original}` or `NYASH_TEST_RETURN`
- `tests` (default): harness returns number of failed tests
- `original`: return the original main result (tests still run)
- Parameterized tests (MVP): `NYASH_TEST_ARGS_DEFAULTS=1` injects integer `0` defaults for each parameter (static/instance)
- Exit code: number of failed tests (0 = green)
Examples
```
# run all tests in a file
./target/release/nyash --run-tests apps/tests/my_tests.nyash
# filter + wrap entry + default arg injection
NYASH_MACRO_ENABLE=1 NYASH_TEST_ARGS_DEFAULTS=1 \
./target/release/nyash --run-tests --test-filter http --test-entry wrap apps/tests/my_tests.nyash
```
## Expansion dump
```
./target/release/nyash --expand --dump-ast apps/tests/ternary_basic.nyash
```
Shows pre/post expansion AST (debug only).
## Developer API (preview)
- Pattern/Quote primitives are available to bootstrap macro authorship.
- TemplatePattern:
- Bind placeholders using `$name` inside a template AST.
- OrPattern: alternation of templates.
- Variadic `$...name` supported at any position inside call/array argument lists; binds the variable-length segment to a pseudo list (`ASTNode::Program`).
- Unquote:
- Replace `$name` with the bound AST.
- Splice `$...name` into call/array argument lists.
- Array/Map nodes participate in pattern/unquote (map keys must match literally; values can bind via `$name`).
### JSON test args (advanced)
For `--run-tests`, you can supply per-test arguments and instance construction details via `NYASH_TEST_ARGS_JSON`.
Shapes:
- Simple list (as before): `{ "test_name": [1, "s", true], "Box.method": [ 0, 1 ] }`
- Detailed object:
- `{ "Box.method": { "args": [ ... ], "instance": { "ctor": "new|birth", "args": [ ... ], "type_args": ["T", "U"] } } }`
- Typed values inside args:
- `{ "i": 1 }`, `{ "f": 1.2 }`, `{ "s": "x" }`, `{ "b": true }`, `null`
- Arrays/Maps as value: `{ "array": [1, 2, 3] }`, `{ "map": { "k": 1, "k2": {"s":"v"} } }`
- Call/method/var literals: `{ "call": "fn", "args": [...] }`, `{ "method": "m", "object": {"var":"obj"}, "args": [...] }`, `{ "var": "name" }`
Diagnostics:
- When JSON cannot be mapped or arity mismatches, warnings are printed with `[macro][test][args]` and the specific test may be skipped unless `NYASH_TEST_ARGS_DEFAULTS=1` is set.
Notes
- Textual `quote(code)` is supported as a convenience via the existing parser, but `$name` placeholders should be built in AST templates directly.
- This API will evolve; treat as experimental until the stable `macro_box` interface is finalized.
## Expansion Safety (Depth/Cycle)
- The macro engine applies a bounded number of expansion passes and stops on fixpoint.
- Environment tuning:
- `NYASH_MACRO_MAX_PASSES` (default 32)
- `NYASH_MACRO_CYCLE_WINDOW` (default 8) — detect cycles across recent states
- `NYASH_MACRO_TRACE=1` — pass-by-pass logging