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
6.9 KiB
User Macros (MacroBoxSpec) — Phase 2
Status: PoC complete; PyVM sandbox route wired. This guide explains how to author and run user macros in Nyash.
Quickstart
- Register user macros (recommended minimal env):
NYASH_MACRO_ENABLE=1NYASH_MACRO_PATHS=apps/macros/examples/echo_macro.hako
- Run your program as usual (macro expansion happens once before MIR):
./target/release/hakorune --backend vm apps/tests/ternary_basic.hako
Environment overview (recommended minimal set)
-
NYASH_MACRO_ENABLE=1(既定ON) -
NYASH_MACRO_PATHS=...(カンマ区切りのNyashマクロファイル) -
NYASH_MACRO_STRICT=1(既定: 厳格) -
NYASH_MACRO_TRACE=0|1(開発用トレース) -
Runner route is default(self‑hosting優先)。内部子ルートは非推奨(
NYASH_MACRO_BOX_CHILD_RUNNER=0でのみ有効)。
Backward compat (deprecated)
NYASH_MACRO_BOX_NY=1+NYASH_MACRO_BOX_NY_PATHS=...→ 今後はNYASH_MACRO_PATHSを使ってね
Philosophy
- Hybrid approach: built-in (Rust) for minimal/core derives; user macros in Nyash (PyVM) for flexibility.
- Deterministic, sandboxed execution: default denies IO/NET/ENV.
- Unified interface: AST JSON v0 + MacroCtx. Expansion occurs pre-MIR.
MacroCtx (MVP)
- Rust側に最小の
MacroCtxとMacroCapsを用意(将来のAPI統合のため)。 - フィールド/メソッド(MVP):
MacroCtx::from_env()→ 環境からcapabilitiesを組み立て(親プロセス)ctx.gensym(prefix)→ 衛生識別子生成ctx.report(level, message)→ 開発用レポート(標準エラー)ctx.get_env(key)→ 環境取得(NYASH_MACRO_CAP_ENV=1のときのみ)
- 実行契約(PoC):ランナーは
expand(json, ctx)を優先し、失敗した場合はexpand(json)にフォールバックします(後方互換)。
Authoring a Macro
Create a Nyash file that defines MacroBoxSpec with a static expand(json[, ctx]) returning a JSON string (AST JSON v0):
static box MacroBoxSpec {
static function expand(json, ctx) {
// json: string (AST JSON v0)
// ctx: string (JSON; {caps:{io,net,env}} MVP). Optional for backward compatibility.
// return: string (AST JSON v0)
return json // identity for MVP
}
}
Example (repo): apps/macros/examples/echo_macro.hako.
Editing template (string literal uppercasing)
- Example:
apps/macros/examples/upper_string_macro.hako - Behavior: if a string literal value starts with
UPPER:, the suffix is uppercased.- Input:
print("UPPER:hello")→ Output:print("HELLO")
- Input:
Running your Macro
Register and run via env (simple):
export NYASH_MACRO_ENABLE=1
export NYASH_MACRO_PATHS=apps/macros/examples/echo_macro.hako
# Run your program (macro expansion happens before MIR)
./target/release/hakorune --backend vm apps/tests/ternary_basic.hako
Self‑host path(NYASH_USE_NY_COMPILER=1)での前展開(開発用)
NYASH_USE_NY_COMPILER=1 \
NYASH_MACRO_SELFHOST_PRE_EXPAND=1 \
NYASH_VM_USE_PY=1 \
./target/release/hakorune --backend vm apps/tests/ternary_basic.hako
Notes: 現状は PyVM ルートのみ対応。NYASH_VM_USE_PY=1 が必須。
CLI プロファイル(推奨)
--profile dev(既定相当: マクロON/厳格ON)--profile lite(マクロOFFの軽量モード)--profile ci|strict(マクロON/厳格ON)- 例:
./target/release/hakorune --profile dev --backend vm apps/tests/ternary_basic.hako
- 例:
Notes
- Built-in child route (stdin JSON -> stdout JSON) remains available when
NYASH_MACRO_BOX_CHILD_RUNNER=0. - Internal child can receive ctx via env:
NYASH_MACRO_CTX_JSON='{"caps":{"io":false,"net":false,"env":true}}' - CLI からも指定可能:
--macro-ctx-json '{"caps":{"io":false,"net":false,"env":true}}' - Strict mode:
NYASH_MACRO_STRICT=1(default) fails build on macro child error/timeout; set0to fallback to identity. - Timeout:
NYASH_NY_COMPILER_TIMEOUT_MS(default2000).
Testing
- Smokes (v2):
tools/smokes/v2/run.sh --profile quick --filter "macro" - Golden (identity):
tools/test/golden/macro/identity_user_macro_golden.sh - Golden (upper string):
tools/test/golden/macro/upper_string_user_macro_golden.sh - Golden (array prepend 0):
tools/test/golden/macro/array_prepend_zero_user_macro_golden.sh - Golden (map insert tag):
tools/test/golden/macro/map_insert_tag_user_macro_golden.sh - Negative (timeout strict fail): covered by v2 smokes (legacy paths removed)
- Negative (invalid JSON strict/non‑strict): covered by v2 smokes(legacy paths removed)
Array/Map editing examples
- Array prepend zero:
apps/macros/examples/array_prepend_zero_macro.hako- Transforms every
{"kind":"Array","elements":[...]}into one with a leading0literal element. - Example input:
print([1, 2])→ Expanded: elements[0, 1, 2].
- Transforms every
- Map insert tag:
apps/macros/examples/map_insert_tag_macro.hako- Transforms every
{"kind":"Map","entries":[...]}by inserting the first entry{k:"__macro", v: "on"}. - Example input:
print({"a": 1})→ Expanded entries:[{"__macro":"on"}, {"a":1}].
- Transforms every
Inspect Expanded AST
./target/release/hakorune --dump-expanded-ast-json apps/tests/ternary_basic.hako
Outputs AST JSON v0 after expansion; use this for golden comparison.
AST JSON v0 Schema
See docs/reference/ir/ast-json-v0.md for the minimal schema used in Phase 2.
Troubleshooting
- Child timeout: increase
NYASH_NY_COMPILER_TIMEOUT_MSor simplify macro code; strict mode fails fast. - Invalid JSON from child: ensure
expand(json)returns a valid AST JSON v0 string. - No changes observed: confirm your macro is registered and the runner route is enabled.
- Capability denied: set caps explicitly(デフォルトは全OFF)
NYASH_MACRO_CAP_IO=1→ IO系Box(File/Path/Dir)許可NYASH_MACRO_CAP_NET=1→ NET系Box(HTTP/Socket)許可NYASH_MACRO_CAP_ENV=1→MacroCtx.get_env許可(将来拡張)
Roadmap
- MacroCtx capabilities (io/net/env) expressed via nyash.toml per-macro.
- Diagnostics: JSONL tracing (
NYASH_MACRO_TRACE_JSONL) and span/source maps. - Golden tests for expanded JSON; strict mode as default.
Capabilities (io/net/env)
Purpose: restrict side‑effects and ensure deterministic macro expansion.
- Default: all OFF (io=false, net=false, env=false)
- Behavior:
- io=false → no FileBox/FS access inside macro; AST JSON only
- net=false → no Http/Socket inside macro
- env=false → MacroCtx.getEnv disabled; child inherits scrubbed env
- Planned configuration (nyash.toml): see
docs/reference/macro/capabilities.md - PoC mapping: child is always
NYASH_VM_USE_PY=1,NYASH_DISABLE_PLUGINS=1, timeout viaNYASH_NY_COMPILER_TIMEOUT_MS
Top-level static MacroBoxSpec (safety)
- 既定では無効(
NYASH_MACRO_TOPLEVEL_ALLOW=0)。Box宣言なしでstatic function MacroBoxSpec.expandを受理したい場合は--macro-top-level-allowを指定してください。