Files
hakorune/docs/guides/macro-system.md
nyash-codex d7805e5974 feat(joinir): Phase 213-2 Step 2-2 & 2-3 Data structure extensions
Extended PatternPipelineContext and CarrierUpdateInfo for Pattern 3 AST-based generalization.

Changes:
1. PatternPipelineContext:
   - Added loop_condition: Option<ASTNode>
   - Added loop_body: Option<Vec<ASTNode>>
   - Added loop_update_summary: Option<LoopUpdateSummary>
   - Updated build_pattern_context() for Pattern 3

2. CarrierUpdateInfo:
   - Added then_expr: Option<ASTNode>
   - Added else_expr: Option<ASTNode>
   - Updated analyze_loop_updates() with None defaults

Status: Phase 213-2 Steps 2-2 & 2-3 complete
Next: Create Pattern3IfAnalyzer to extract if statement and populate update summary
2025-12-10 00:01:53 +09:00

139 lines
6.0 KiB
Markdown
Raw Permalink 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/hakorune --backend vm apps/APP/main.hako
```
## 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/hakorune --run-tests apps/tests/my_tests.hako
# filter + wrap entry + default arg injection
NYASH_MACRO_ENABLE=1 NYASH_TEST_ARGS_DEFAULTS=1 \
./target/release/hakorune --run-tests --test-filter http --test-entry wrap apps/tests/my_tests.hako
```
## Expansion dump
```
./target/release/hakorune --expand --dump-ast apps/tests/ternary_basic.hako
```
Shows pre/post expansion AST (debug only).
## Core Normalization (always-on when macros enabled)
Certain language sugars are normalized before MIR across all runners when the macro gate is enabled. These are not user macros and do not require any registration:
- for sugar → Loop
- `for(fn(){ init }, cond, fn(){ step }, fn(){ body })`
- Emits: `init; loop(cond){ body; step }`
- `init/step` also accept a single Assignment or Local instead of `fn(){..}`.
- foreach sugar → Loop
- `foreach(array_expr, "x", fn(){ body_with_x })`
- Expands into an index-based loop with `__ny_i`, and substitutes `x` with `array_expr.get(__ny_i)` inside body.
Normalization order (within the core pass):
1) for/foreach → 2) match(PeekExpr) → 3) loop tail alignment (carrier-like ordering; break/continue segments supported).
Notes:
- Backward-compat function names `ny_for` / `ny_foreach` are also accepted but `for` / `foreach` are preferred.
- This pass is part of the language pipeline; it is orthogonal to user-defined macros.
## 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`).
## MacroCtx (PoC)
User macros executed via the PyVM sandbox receive a second argument `ctx` in `expand(json, ctx)`:
- Shape (string): `{ "caps": { "io": bool, "net": bool, "env": bool } }`
- Policy: all caps default to false. The sandbox disables plugins and exposes a minimal Box API.
- Do not print to stdout from macros: the child process stdout is reserved for the expanded JSON.
- For diagnostics use stderr in the future; for now prefer silent operation or trace via the parent process.
Example (identity):
```
static box MacroBoxSpec {
name() { return "MacroCtxDemo" }
expand(json, ctx) { return json }
}
```
### 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