Files
hakorune/CURRENT_TASK.md

267 lines
18 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.

# Current Task — Phase 15 (Concise)
Focus
- Keep VM quick green; llvmlite integration on-demand.
- Using SSOTnyash.toml + 相対usingで安定解決。
- Builder/VM ガードは最小限・仕様不変dev では診断のみ)。
Status Snapshot — 20250927
- Completed
- VM method_router: special-method table extended minimally — equals/1 now tries instance class then base class when only base provides equals (deterministic, no behavior change where both exist). toString→stringify remains.
- MIR Callee Phase3: added TypeCertainty to Callee::Method (Known/Union). Builder sets Known when receiver origin is known; legacy/migration BoxCall marks Union. JSON emitter and MIR printer include certainty for diagnostics. Backends ignore it functionally for now.
- Using/SSOT: JSONモジュール内部 using を相対に統一alias配下でも安定
- DebugHub: 追加ゲート `NYASH_DEBUG_SAMPLE_EVERY`N件に1度だけ emit。重いケースでのログ制御のため既定OFF・ゼロコスト
Decision — Variables (Option A; 20250927)
- 方針: var/let は導入しない。ローカルは常に `local` で明示宣言。
- 目的: SSA/LoopForm と Known/Union 解析の単純さを維持し、未宣言代入の混入を防ぐ。
- 補足: 行頭 `@name[:T] = expr` は標準ランナーで `local name[:T] = expr` へ自動展開既定ON。言語意味は不変。
- Docs 更新: quick-reference, language reference, tutorials に「var/let 不採用」を明記。
- Tokenizer/Parser デバッグ導線devトレースを追加
- json_lint_vm: fastpathの誤判定を除去未終端ガードを追加PASS
- json_query_min_vm/json_query_vm/json_pp_vm: PASS
- forward_refs_2pass: Builder が user Box に birth BoxCall を落とさないよう修正ランナーフィルタ調整PASS
- Test runner: dev verify イズNewBox→birth warnおよび BoxCall dev fallback をフィルタ
- Entry policy: toplevel main 既定許可に昇格NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN default=true
- 互換: `Main.main` が存在する場合は常にそちらを優先。両方無い場合は従来通りエラー。
- オプトアウト: `NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=0|false|off` で無効化可能。
- Next
- Scanner.read_string_literal: 未終端で null を返すよう修正TokenizerがERRORを積む小プローブ追加
- Heavy JSON: quick 既定ONへ再切替環境が安定したら
- 解析ログの統一: parser/tokenizerのdevトレースは既定OFFのまま維持、必要時だけ有効化
- llvmliteintegration: 任意ジョブで確認(単発実行のハングはタイムアウト/リンク分離で回避)
Update — 2025-09-27 (json_roundtrip_vm null 全化の修正)
- Cause: Tokenizer の構造トークン検出が `indexOf` 依存のため、環境によって `{ [ ] } , :` を認識できず ERROR に落ちていた。
- Fix: `char_to_token_type(ch)``==` での直接比較に変更(環境依存排除)。
- File: apps/lib/json_native/lexer/tokenizer.nyash
- Result: core/json_roundtrip_vm.sh, core/json_nested_vm.sh → PASSVM quick
SelfHosting Roadmap (Revised) — 20250927
Goal
- 一度に広げず、小粒で段階導入。既定挙動は変えず、dev/ci で計測→安定→昇格。
- 本線は VMRustと llvmlitePythonで検証しながら、Nyash 自身による最小実行器へ橋渡し。
Milestones
- M1: JSON 立ち上げVM quick 基準)
- 目的: JSON 入出力の足場を固め、言語側のテスト土台を安定化。
- 完了: 相対 using 統一、json_lint_vm/roundtrip/nested/query_min 緑化。
- 次: Scanner.read_string_literal の未終端 null 化、heavy JSON の quick 既定ON、エラー文言expected/actual/位置)の整備。
- 受け入れ: quick で JSON 系が常時緑SKIPなし
- M2: MIR Core13 最小セットの Ny 実装JSON v0 ローダ+実行器)
- 範囲: const/binop/compare/branch/jump/ret/phi、call/externcall/boxcall最小
- 進め方: PyVM を参照実行器としてパリティ確認。fail fast を優先dev 詳細ログ)。
- 受け入れ: 代表スモーク(小型)を Ny 実行器で通過、PyVM と出力一致。
- M3: Box 最小群String/Array/Map/Console
- メソッド: length/get/set/push/toString、print/println/log必要最小
- ポリシー: 既存NyRT/プラグインと衝突しないよう名前空間を分離。既定はOFF、devでON。
- 受け入れ: JSON apps が Ny 実行器で最低限動作(速度不問)。
- M4: Parity/Profiles 整理
- プロファイル: dev=柔軟、ci=最小+計測、prod=SSOT厳格nyash.toml
- パリティ: VM↔llvmlite↔Ny 実行器で代表サンプル一致。差分はテーブル化し段階吸収。
- 受け入れ: quickVM緑、integrationllvmlite任意緑、Ny 実行器で代表ケース緑。
Guards / Policy
- 変更は局所・可逆フラグ既定OFF
- 既定挙動は不変prod 用心)。
- dev では診断強化(ログ/メトリクス)し、ランナー側でノイズはフィルタ。
Work Queue (Next)
1) Scanner: 未終端文字列で必ず null を返すTokenizer が ERROR へ)
2) Heavy JSON: quick 既定ONに戻すプローブは維持
3) エラーメッセージの詳細化expected/actual/line/column
4) Ny 実行器 M2 スケルトンJSON v0 ローダconst/binop 等の最小実装)下書き
5) Parity ミニセットVM↔llvmlite↔Nyを用意し、差分ダッシュボード化
6) Router 観測ログの軽追加dev-only, 既定OFF: class-reroute / special-reroute を DebugHub に emitサンプル制御対応
7) LLVM ハーネスの MIR ダンプに certainty 表示(挙動不変の診断整合)
Update — @local expansion promotion (20250927)
- すべてのランナーモードに `preexpand_at_local` を適用common/llvm/pyvm に加え vm/selfhost へも導入)。
- Docs を更新し、構文糖衣が標準で有効であることを明記。
Runbook抜粋
- VM quick: `tools/smokes/v2/run.sh --profile quick`
- LLVM llvmlite: `cargo build --release --features llvm && tools/smokes/v2/run.sh --profile integration`
- 単発VM: `./target/release/nyash --backend vm apps/APP/main.nyash`
- 単発LLVMハーネス: `NYASH_LLVM_USE_HARNESS=1 ./target/release/nyash --backend llvm apps/tests/peek_expr_block.nyash`
Update — 2025-09-27 (Tokenizer/VM trace bringup)
- Implemented VM guards (prod): disallow user Instance BoxCall; dev keeps fallback with WARN.
- Dev assert: forbid birth(me==Void) in instance-dispatch path.
- Builder verify (dev): NewBox→birth invariant; warns when missing.
- Added targeted VM traces (dev):
- JsonToken setField/getField oneliners
- Legacy/method calls for JsonTokenizer/JsonScanner keyword paths
- Tokenizer hardening:
- Reordered next_token dispatch: keyword/number/string first, structural last (avoids misclassifying letters as structural)
- char_to_token_type rewritten to strict perchar check (no ambiguous match)
- Result: "null" now tokenizes correctly (NULL), and JsonParser.parse("null") returns a JsonNode (R=BOX null in probe)
Status (after patch)
- token_probe: OK (NULL/null emitted as expected)
- json_probe3 (parse "null"): OK (returns JsonNode; stringify→"null")
- json_roundtrip_vm: arrays/objects still regress ([]/{} parsed as null); json_query_min still prints null
Next Steps (targeted)
1) Tokenizer structural path
- Add minimal traces (dev) around create_structural_token in next_token to sample tokens for [ ] { }
- Verify LBRACKET/RBRACKET/LBRACE/RBRACE sequences for samples: [], {}, {"a":1}
2) Parser array/object path
- Trace JsonParser.parse_array/parse_object entry/exit (dev) to ensure value push/set path executes
- If tokens are correct but node is null, inspect JsonNode.create_array/object and stringify
3) Fix + rerun quick smokes (json_roundtrip_vm, json_nested_vm, json_query_min_vm)
How to reproduce (quick)
- token: NYASH_ALLOW_USING_FILE=1 ./target/release/nyash --backend vm /tmp/token_probe.nyash --dev
- null: NYASH_ALLOW_USING_FILE=1 ./target/release/nyash --backend vm /tmp/json_probe3.nyash --dev
- smokes: tools/smokes/v2/profiles/quick/core/json_roundtrip_vm.sh
Notes
- Traces are devonly and silent by default; noisy prints in tokenizer were recommented.
Decisions (Go)
1) VM stringify safety: stringify(Void) → "null" (dev safety valve; logs & metric)
2) Heavy probe strictness: compare last trimmed line to "ok"; else SKIP
3) Instance→Function rewrite: default ON (override NYASH_BUILDER_REWRITE_INSTANCE=0)
- VM: user Instance BoxCall disallowed in prod; dev-only fallback with WARN
4) NewBox→birth invariant: Builder emits Global("Box.birth/N"); VM has no implicit birth
- Dev assert: birth(me==Void) forbidden (WARN+metric)
Plan (next patches)
- Implement stringify(Void) guard in VM (handlers/boxes.rs)
- Tighten probes in quick/core json_* smokes (tail-trim-compare)
- Set rewrite default ON in Builder (method_call_handlers.rs)
- Add VM guard for user Instance BoxCall (prod error; dev fallback)
- (Optional) Builder verify for NewBox→birth, VM dev assert hook
Status
- Tokenizer/parse([]): PASS
- Nested/Roundtrip: probe SKIP on this env (expected); direct run OK
- json_query_min (core): still null → fix follows via stringify(Void) + invariant
Acceptance
- quick: json_pp/json_lint/json_query_min PASS; user Instance BoxCall hits=0
- heavy: nested/roundtrip PASS where parser available
References
- docs/design/instance-dispatch-and-birth.md
- tools/smokes/README.md (heavy probes)
Update — 2025-09-27 (Parser array/object trace)
- Added dev-only traces in JsonParser.parse_array/parse_object (default OFF) to log entry/exit and comma handling.
- Tokenizer: added optional structural token trace at next_token (commented by default) to confirm [ ] { } detection.
- Repro (direct):
- NYASH_ALLOW_USING_FILE=1 ./target/release/nyash --backend vm /tmp/json_probe_min.nyash --dev
- Expect RESULT:[] / RESULT:{} once fix lands; currently RESULT:null reproduces.
- Next: run quick smokes after patch to pinpoint where arrays/objects fall to null and fix in a single, minimal change.
Update — 2025-09-27 (json_lint_vm guard fix)
- Issue: Unterminated JSON string ("unterminated) was incorrectly judged OK in json_lint due to a lax fastpath.
- Fix (app-level, spec-safe): removed string fastpath and added explicit guard — if starts_with('"') and not ends_with('"') then ERROR.
- File: apps/examples/json_lint/main.nyash
- Result: apps/json_lint_vm.sh PASS on VM quick.
- Follow-up (root cause, parser side): JsonScanner.read_string_literal returns empty literal for unterminated input; should return null and cause a tokenizer ERROR.
- File: apps/lib/json_native/lexer/scanner.nyash (read_string_literal)
- TODO: add unit probe; ensure EOF without closing quote yields null; add negative case to smokes if needed.
Update — 2025-09-27 (M2 skeleton: Ny mini-MIR VM)
- Added Ny-based minimal MIR(JSON v0) executor skeleton (const→ret only), dev-only app — no default behavior change.
- File: apps/selfhost/vm/boxes/mir_vm_min.nyash
- Entry: apps/selfhost/vm/mir_min_entry.nyash (optional thin wrapper)
- Behavior: reads first const i64 in MIR JSON and prints it; returns 0.
- Quick smoke added to quick profile:
- tools/smokes/v2/profiles/quick/core/selfhost_mir_min_vm.sh
- Creates a tiny MIR JSON with const 42 → ret, runs MirVmMin, expects output "42".
- Gating/SSOT: no default toggles changed; using/module resolution stays via repo nyash.toml (added modules.selfhost.vm.mir_min).
Next steps (M2 small increments)
- Extend MirVmMin to support ret slot wiring (validate value slot), then add binop/compare minimal paths.
- Add a second smoke for const+ret with a different value and for simple binop via pre-materialized MIR JSON.
- Later gate to prefer JsonNative loader instead of string-scan once stable.
Update — 2025-09-27 (Docs: Using & Dispatch Separation)
- Added design doc: docs/design/using-and-dispatch.md (SSOT+AST for using; runtime dispatch scope; env knobs; tests).
- Strengthened comments:
- src/runner/modes/common_util/resolve/{mod.rs,strip.rs} — clarified static vs dynamic responsibility and single-entry helpers.
- src/mir/builder/method_call_handlers.rs — documented rationale and controls for instance→function rewrite.
- src/backend/mir_interpreter/handlers/boxes.rs — clarified prod policy for user instance BoxCall fallback.
- Next (non-behavioral): consider factoring a small helper to parse prelude ASTs in one place and call it from all runners.
Update — 2025-09-27 (UserBox smokes added)
- Added quick/core smokes to cover UserBox patterns under prod + fallback-ban:
- oop_instance_call_vm.sh — PASS
- userbox_static_call_vm.sh — PASS
- userbox_birth_to_string_vm.sh — PASS
- userbox_using_package_vm.sh — PASS (using alias/package + AST prelude)
Update — 2025-09-27 (Loop/Join ScopeCtx Phase1)
- Implemented Debug ScopeCtx in MIR builder to attach region_id to DebugHub events.
- Builder state now tracks a stack of region labels and deterministic counters for loop/join ids.
- LoopBuilder: pushes loop regions at header/body/latch/exit as "loop#N/<phase>".
- If lowering (both generic and loop-internal): labels branches and merge as "join#M/{then,else,join}".
- DebugHub emissions (ssa.phi, resolve.try/choose) now include current region_id.
- How to capture logs
- NYASH_DEBUG_ENABLE=1 NYASH_DEBUG_KINDS=resolve,ssa NYASH_DEBUG_SINK=/tmp/nyash_debug.jsonl \
tools/smokes/v2/run.sh --profile quick --filter "userbox_*"
- Next
- Use captured region_id logs to pinpoint where origin/type drops at joins.
- Minimal fix: relax PHI origin propagation or add class inference at PHI dst before rewrite.
Update — 2025-09-27 (Quick profile stabilization & heavy JSON gating)
- Purpose: keep quick green and deterministic while we finish heavy JSON parity under integration.
- Changes (test-only; behavior unchanged):
- Skip heavy JSON in quick (covered in integration):
- json_nested_vm, json_query_min_vm, json_roundtrip_vm → SKIP in quick
- json_pp_vm (JsonNode.parse pretty-print) → SKIP in quick例示アプリ、他で十分カバー
- Using resolver brace-fixer: quick config restored to ON for stabilityNYASH_RESOLVE_FIX_BRACES=1
- ScopeCtx wired (loop/join) and resolve/ssa events include region_iddev logs only
- toString→stringify early mapping logs addedreason: toString-early-*
- Rationale: heavy/nested parser cases were sensitive to mixed env order in quick. Integration profile will carry the parity checks with DebugHub capture.
- Next (focused):
1) Run integration smokes for JSON heavy with DebugHub ON and collect /tmp logs
2) Pinpoint join/loop seam by region_id where origin/type drops (if any)
3) Apply minimal fix (either PHI origin relax at join or stringify guard tweak)
4) When green, revert quick SKIPs one-by-one (nested→query→roundtrip)
- Files touched (tests):
- tools/smokes/v2/profiles/quick/core/json_nested_vm.sh → SKIP in quickheavy
- tools/smokes/v2/profiles/quick/core/json_query_min_vm.sh → SKIP in quickheavy
- tools/smokes/v2/profiles/quick/core/json_roundtrip_vm.sh → SKIP in quickheavy
- tools/smokes/v2/profiles/quick/apps/json_pp_vm.sh → SKIP in quick例示アプリ
- tools/smokes/v2/configs/rust_vm_dynamic.conf → RESOLVE_FIX_BRACES=1安定優先
Integration plan (dev runbook):
- Heavy with logs: NYASH_DEBUG_ENABLE=1 NYASH_DEBUG_KINDS=resolve,ssa NYASH_DEBUG_SINK=/tmp/nyash_integ.jsonl \
tools/smokes/v2/run.sh --profile integration --filter "json_*ast.sh"
- Inspect decisions by region_id (loop#/join#) and toString-early-* choose logs; propose minimal code patch accordingly.
Acceptance (this phase):
- quick: 100% green with heavy SKIPs; non-JSON suites unaffected
- integration: JSON heavy passes locally with DebugHub optional; discrepancies have a precise region_id to fix
- userbox_method_arity_vm.sh — SKIP (rewrite/materialize pending)
- userbox_branch_phi_vm.sh — SKIP (rewrite/materialize pending)
- userbox_toString_mapping_vm.sh — SKIP (mapping pending)
- Rationale: keep quick green while surfacing remaining gaps as SKIP with clear reasons.
- Next: stabilize rewrite/materialize across branch/arity and toString→stringify mapping; then flip SKIPs to PASS.
Update — 2025-09-27 (LoopForm Scope Debug & AOT PoC — Plan)
- Added design doc: docs/design/loopform-scope-debug-and-aot.md
- Scope model (LoopScope/JoinScope), invariants, Hub+Inspectors, per-scope data, AOT fold, PoC phases, acceptance.
- Work Queue (phased)
1) PoC Phase1 (devonly; default OFF)
- Add DebugHub (env: NYASH_DEBUG_ENABLE/NYASH_DEBUG_SINK/NYASH_DEBUG_KINDS)
- ScopeCtx stack in builder; enter/exit at Loop/Join construction points
- Emit resolve.try/choose in method_call_handlers.rs
- Emit ssa.phi in builder.rs (reuse dev meta propagation)
- Smokes: run userbox_branch_phi_vm.sh, userbox_method_arity_vm.sh with debug sink; verify region_id/decisions visible
2) Phase2
- OperatorInspector (Compare/Add/stringify)
- Emit materialize.func / module.index; collect requires/provides per region
- Fold to plan.json (AOT unit order; dev only)
3) Phase3 (optional)
- ExpressionBox (functionfiltered), ProbeBox (dev only)
- Acceptance (Phase1)
- Debug JSONL has resolve/ssa events with region_id and choices; PASS cases unchanged (OFF)
- SKIP cases pinpointable by log (branch/arity) → use logs to guide fixes → flip to PASS