Phase 20.18 — Result(ケースバイケース)+ 軽量糖衣 + Null/Void 固定
目的(要約)
- 「全部 Result は重い」を回避しつつ、一貫した失敗取り扱いを提供する。
- Null/Void の言語レベル固定(予約語)と VM 値表現(Null タグ)を導入し、欠落/手続きの意味を明確化。
- ケース別の最小主義:検索=sentinel、境界=Fail‑Fast+try_系、変換/I/O=Result 既定。
- 糖衣は左辺だけ(
let a?=/a!=)に限定し、ゼロアロケーションで Lowering。
適用範囲(MVP)
- Null/Void の固定(言語+VM)
- 言語:
null,voidを予約語にする(リテラル)。 - MIR JSON v0:
Constに{"type":"Null"|"Void"}を追加。 - VM/Interpreter:
VMValue::Nullを追加(0 アロケーション、比較高速)。
- 言語:
- 既定挙動(SSOT)
String.indexOf/1→ not found は-1(sentinelのまま)。Array.get/1→ 範囲外はnull(Fail しない)。Array.pop/0→ 空配列はnull(Fail しない)。Array.set/2→ i<0 または i>len はE_OOB、i==len は append、0<=i<len は置換。戻りはvoid。Map.get/1→ 欠落はnull(Fail しない)。Map.set/2→ 不正キー=E_INVALID_KEY、不正値=E_INVALID_VALUE、戻りはvoid。Map.delete/1→ 削除値 ornull。Map.clear/0→void。
- 追加API(5つ)
Array.try_get/1,Array.try_pop/0Map.try_get/1String.to_i64/0,String.to_f64/0
糖衣(任意・軽実装)
let r = arr.try_get(0)… Resultのままlet x? = arr.try_get(0)…ok→値 / err→VoidBoxlet x! = arr.try_get(0)…ok→値 / err→即Failif let ok(v) = arr.try_get(0) { … } else { … }
実装方針(段階導入)
- Phase A(本フェーズ)
- Null/Void: 予約語・MIR・VM の三層で固定(VMValue::Null、singleton 変換)。
- Core/Gate‑C: Array/Map の SSOT へ挙動を収束(上記 既定挙動)。
- Parser: 左辺の
?/!とif let ok(..)を受理。 - Lowering:
?/!/if-let を branch/select に展開(ゼロアロケーション)。 - Verifier: 例外タグ
E_OOB/E_EMPTY/E_NOT_FOUND/E_PARSEを安定化。 - Gate:
HAKO_TRY_API=1(既定OFF)でスモーク有効化。
- Phase B(20.19+ 任意)
- MIR/LLVM を“値版Result”
{i1 ok, T payload}に寄せる(SROA/mem2reg 合流) - Box化は保存/境界(FFI/ABI)のみで行いゼロコスト化を徹底
- MIR/LLVM を“値版Result”
受入れ基準(MVP)
- quick(opt‑in)で try_* + 糖衣(
?/!/if-let ok)スモークが緑。 - Fail‑Fastタグが安定(E_OOB/E_EMPTY/E_NOT_FOUND/E_PARSE)。
- Array/Map の SSOT(Null/void 既定)が Gate‑C/Core/VM で一致。
完了サマリ(2025‑10‑29 現在)
- Bridge‑B(Ny/Core直行): include ベースで安定。Gate‑C(Core) の file/pipe は緑。
- Core canary(直行): array_get/push/set_get は緑。string indexOf bang は TTL 互換で緑(タグ優先、未到達時は -1/rc=0 を暫定許容)。
- Runner: Core ラッパー出力はタグ行を優先採用。Gate‑C(Core) はタグ→stderr+rc=1、数値→rc=(num&0xFF)。
- Docs: VM README/Smokes README/CURRENT_TASK を更新(Bridge‑B方針、カナリア導線、TTL注記)。
残タスク(短期)
- Core からの Fail‑Fast を state 経由の戻り値へ統一して、タグを必ず last line にする(print 依存解消)。
- 上記完了後、string indexOf bang の TTL 互換(-1容認)を撤去し、タグ必須に戻す。
ノート
- 20.17 は self‑hosting 完了を優先。実装は本フェーズでまとめて入れる。
- 糖衣は左辺のみ(公開名の二重化を避ける)。Result は段階で“値版”へ移行予定。
Plugins への影響(互換ポリシー)
ABI 変更は不要(Box 戻りのまま)。ただし意味論は SSOT に合わせる:
- ArrayBox(プラグイン実装がある場合)
- get: 範囲外→NullBox、pop: 空→NullBox、push/set/clear: 戻りは VoidBox。
- set: i<0 or i>len は
E_OOB。i==len は append、0<=i<len は置換。
- MapBox(プラグイン実装がある場合)
- get: 欠落→NullBox、delete: 削除値 or NullBox、clear: VoidBox、set: VoidBox。
- set: Null key/不正型→
E_INVALID_KEY、不正値→E_INVALID_VALUE。暗黙変換は禁止。
Core/Gate‑C が先行で SSOT を満たすため、プラグインが未更新でも Gate‑C(Core) 直行経路は安定。VM 経路でプラグイン実装が呼ばれる場合は、上記の意味論に合わせて段階更新する。