A1.4: Add sugar syntax `public weak parent` ≡ `public { weak parent }`
A1.5: Fix parser hang on unsupported `param: Type` syntax
Key changes:
- A1.4: Extend visibility parser to handle weak modifier (fields.rs)
- A1.5: Shared helper `parse_param_name_list()` with progress-zero detection
- A1.5: Fix 6 vulnerable parameter parsing loops (methods, constructors, functions)
- Tests: Sugar syntax (OK/NG), parser hang (timeout-based)
- Docs: lifecycle.md, EBNF.md, phase-285a1-boxification.md
Additional changes:
- weak() builtin implementation (handlers/weak.rs)
- Leak tracking improvements (leak_tracker.rs)
- Documentation updates (lifecycle, types, memory-finalization, etc.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
10 KiB
Phase 285A1: Weak Field Validator Boxification
Status: ✅ Complete (2025-12-24)
Goal
Phase 285A1 の weak field 処理を専用 Box に箱化し、以下を実現:
- 単一責任: weak field 契約検証のみを担当
- テスト容易性: 独立してテスト可能
- 再利用性: 他の箇所でも使える
Implementation
新規ファイル
src/mir/builder/weak_field_validator.rs
/// Phase 285A1: Weak Field Contract Validator Box
///
/// 単一責任: weak field の契約検証のみ
/// - 読み込み時: WeakRef 型注釈
/// - 書き込み時: 型契約検証(WeakRef/Void のみ許可)
pub(super) struct WeakFieldValidatorBox;
impl WeakFieldValidatorBox {
/// Weak field 読み込み時の型注釈を追加
pub(super) fn annotate_read_result(
type_ctx: &mut TypeContext,
dst: ValueId,
) {
// Phase 285A1: Mark the result as WeakRef type
type_ctx.value_types.insert(dst, MirType::WeakRef);
}
/// Weak field への代入を検証(3つの許可ケース)
///
/// Phase 285A1 Fail-Fast 契約:
/// - **許可**: WeakRef (weak() または weak field 読み込み)
/// - **許可**: Void (クリア操作)
/// - **禁止**: BoxRef (weak() なしの Box)
/// - **禁止**: プリミティブ型
/// - **禁止**: 型追跡されていない値
pub(super) fn validate_assignment(
value_type: Option<&MirType>,
box_name: &str,
field_name: &str,
) -> Result<(), String> {
// 3つの許可ケースを検証
// Fail-Fast: エラーは即座に返す
}
}
特徴:
- Phase 33 の箱化モジュール化と同じ思想(単一責任、明確な境界)
- 充実したコメント(目的、契約、例)
- 単体テスト完備(5つのテストケース)
変更ファイル
src/mir/builder/fields.rs
Before (277行):
check_weak_field_assignment()メソッド(232-277行)- 読み込み時の型注釈(inline)
- 書き込み時の型検証(inline)
After (237行):
WeakFieldValidatorBox::annotate_read_result()呼び出しWeakFieldValidatorBox::validate_assignment()呼び出し- 40行削減(-14.4%)
src/mir/builder.rs
モジュール宣言追加:
mod weak_field_validator; // Phase 285A1: Weak field contract validator
Contract Enforcement
読み込み契約
// Phase 285A1: weak field 読み込みは WeakRef 型を返す(自動昇格なし)
WeakFieldValidatorBox::annotate_read_result(&mut self.type_ctx, dst);
書き込み契約
3つの許可ケース:
- WeakRef:
weak()または weak field 読み込みの結果 - Void: クリア操作(
me.next = Void) BoxRef: 禁止 - エラーメッセージでweak()使用を提案
エラーメッセージ例:
Cannot assign Box (StringBox) to weak field 'Node.next'.
Use weak(...) to create weak reference: me.next = weak(value)
Tests
単体テスト(5つ)
test_validate_weakref_allowed: WeakRef 許可test_validate_void_allowed: Void 許可test_validate_boxref_forbidden: BoxRef 禁止test_validate_untracked_forbidden: 型追跡なし禁止test_validate_primitive_forbidden: プリミティブ禁止
動作確認
# ビルド成功
cargo build --release
# Finished `release` profile [optimized] target(s) in 1m 23s
# 基本機能確認
echo 'static box Main { main() { print("Hello"); return 0 } }' > test.hako
./target/release/hakorune test.hako
# Output: Hello
# RC: 0
# フィールドアクセス確認
# Box with fields works correctly
Architecture Benefits
単一責任(SRP)
- Before:
fields.rsが weak field 処理を含む(複数責任) - After:
WeakFieldValidatorBoxが検証のみ担当
テスト容易性
- Before:
fields.rs全体のテストが必要 - After:
WeakFieldValidatorBox単独でテスト可能
再利用性
- Before:
check_weak_field_assignment()はMirBuilderメソッド - After:
WeakFieldValidatorBoxはどこからでも使える
明確な境界
fields.rs
├─ フィールド読み込み/書き込みロジック
└─ WeakFieldValidatorBox::validate_assignment() 呼び出し
↓
weak_field_validator.rs
└─ weak field 契約検証のみ
Code Quality
Phase 33 思想の継承
- 単一責任: 1つの Box = 1つの関心事
- 明確な境界: 入力/出力が明確
- 充実したコメント: 目的、契約、例
- Fail-Fast: エラーは即座に返す(フォールバック禁止)
メトリクス
- 行数削減: 277行 → 237行(-40行、-14.4%)
- モジュール化: 1ファイル → 2ファイル(責任分離)
- テストカバレッジ: 0 → 5単体テスト
Phase 285 Context
Phase 285A1 は Phase 285 の一部として、weak field 処理の基盤を整備:
- Phase 285 Goal: Box lifecycle / weakref / finalization / GC conformance
- Phase 285A1 Scope: weak field 契約検証の箱化
- Status: P0 (docs-only) → 実装進行中
Note: weak field 構文(weak next: Node)は未実装。Phase 285 P1 で実装予定。
A1.5: Parser Hang Fix - Parameter Type Annotations ✅
Status: ✅ Complete (2025-12-24)
Problem
During Phase 285A1.4 implementation, discovered critical parser bug:
- User writes:
setParent(p: Node) { ... } - Parser hangs infinitely at COLON token (no advance on unexpected token)
- Workaround required removing type annotation →
setParent(p) { ... }→ Works
Root Cause
6 identical vulnerable parameter parsing loops across the parser codebase:
src/parser/declarations/box_def/members/methods.rs:21-30src/parser/declarations/box_def/members/constructors.rs:27-34(init)src/parser/declarations/box_def/members/constructors.rs:101-108(pack)src/parser/declarations/box_def/members/constructors.rs:138-145(birth)src/parser/items/functions.rs:34-51src/parser/items/static_items.rs:72-87
Vulnerable Code Pattern:
while !p.match_token(&TokenType::RPAREN) && !p.is_at_end() {
must_advance!(p, _unused, "method parameter parsing");
if let TokenType::IDENTIFIER(param) = &p.current_token().token_type {
params.push(param.clone());
p.advance(); // ← Only advances on IDENTIFIER
}
// ⚠️ COLON token: not IDENTIFIER, not COMMA, not RPAREN → NO ADVANCE → INFINITE LOOP
if p.match_token(&TokenType::COMMA) {
p.advance();
}
}
EBNF Spec Finding: params grammar undefined in EBNF.md, : TYPE is for return type only
Solution: Shared Helper Function (DRY Principle)
Created src/parser/common/params.rs with common parameter parsing logic:
/// Parse parameter name list with Fail-Fast on unexpected tokens
///
/// Parses: IDENT (',' IDENT)*
/// Rejects: Type annotations, unexpected tokens, malformed comma sequences
pub(crate) fn parse_param_name_list(
p: &mut NyashParser,
context: &str, // "method", "constructor", "function" for error messages
) -> Result<Vec<String>, ParseError>
Key Features:
- Progress-zero detection: Tracks token position, errors if stuck (prevents infinite loops)
- Explicit token handling: All token types (IDENTIFIER, COMMA, other) explicitly matched
- Fail-Fast: Either advances or errors (no infinite loop possible)
- Unified error messages: Context parameter customizes messages per call site
Files Modified
New Files (2):
src/parser/common/params.rs(~90 lines) - Helper functiontools/smokes/v2/profiles/quick/parser/phase285_param_type_annotation_nohang.sh- Timeout smoke test
Modified Files (8):
src/parser/common/mod.rs- Module declaration (moved common.rs → common/mod.rs)src/parser/declarations/box_def/members/methods.rs- Replaced 12 lines with 1 callsrc/parser/declarations/box_def/members/constructors.rs- Replaced 3 loops (init/pack/birth)src/parser/items/functions.rs- Replaced 20 lines with 2 linessrc/parser/items/static_items.rs- Replaced 22 lines with 2 linesapps/tests/phase285_parser_param_type_annot_should_not_hang.hako- Regression test
Net Change: +90 new - 72 removed + 6 calls = +24 lines (with better error handling!)
Tests
Regression Test: apps/tests/phase285_parser_param_type_annot_should_not_hang.hako
box TestNode {
value: IntegerBox
// ❌ Should error immediately (type annotation not supported)
setParent(p: Node) {
return 0
}
}
Smoke Test: tools/smokes/v2/profiles/quick/parser/phase285_param_type_annotation_nohang.sh
- Timeout: 3 seconds (detects hang)
- Expected: Parse error within 1 second
- Validation: Error message mentions "Unexpected token COLON" and "Parameter type annotations not supported"
Result: ✅ PASS
✅ PASS: Parser correctly rejects param type annotations without hanging
Error Message Examples
Before (infinite hang):
🚨 PARSER INFINITE LOOP DETECTED at method parameter parsing
After (clear error):
❌ Parse error: Unexpected token COLON, expected ',' or ')' in method parameter list.
Note: Parameter type annotations are not supported.
Architecture Benefits
DRY Principle:
- Before: 6 identical vulnerable loops (72 lines total)
- After: 1 helper function (~90 lines) + 6 one-line calls
Maintainability:
- Future fixes only need 1 location
- Unified error messages (single source of truth)
- Progress-zero detection guaranteed in one place
Safety:
- No infinite loop possible (Fail-Fast guaranteed)
- All token types explicitly handled (no silent fallthrough)
- Context-aware error messages (better UX)
References
- Phase 33: Box Theory Modularization (phase-33-modularization.md)
- Phase 285: Box lifecycle (phase-285/README.md)
src/mir/builder/weak_field_validator.rs: A1.1 実装本体src/mir/builder/fields.rs: A1.1 呼び出し側src/parser/common/params.rs: A1.5 実装本体src/parser/declarations/box_def/members/fields.rs: A1.2-A1.4 実装本体