feat(parser): Phase 285A1.4 & A1.5 - Weak field sugar + Parser hang fix
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>
This commit is contained in:
@ -180,9 +180,140 @@ Phase 285A1 は Phase 285 の一部として、weak field 処理の基盤を整
|
||||
|
||||
**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:
|
||||
1. `src/parser/declarations/box_def/members/methods.rs:21-30`
|
||||
2. `src/parser/declarations/box_def/members/constructors.rs:27-34` (init)
|
||||
3. `src/parser/declarations/box_def/members/constructors.rs:101-108` (pack)
|
||||
4. `src/parser/declarations/box_def/members/constructors.rs:138-145` (birth)
|
||||
5. `src/parser/items/functions.rs:34-51`
|
||||
6. `src/parser/items/static_items.rs:72-87`
|
||||
|
||||
**Vulnerable Code Pattern**:
|
||||
```rust
|
||||
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:
|
||||
|
||||
```rust
|
||||
/// 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 function
|
||||
- `tools/smokes/v2/profiles/quick/parser/phase285_param_type_annotation_nohang.sh` - Timeout smoke test
|
||||
|
||||
**Modified Files** (8):
|
||||
1. `src/parser/common/mod.rs` - Module declaration (moved common.rs → common/mod.rs)
|
||||
2. `src/parser/declarations/box_def/members/methods.rs` - Replaced 12 lines with 1 call
|
||||
3. `src/parser/declarations/box_def/members/constructors.rs` - Replaced 3 loops (init/pack/birth)
|
||||
4. `src/parser/items/functions.rs` - Replaced 20 lines with 2 lines
|
||||
5. `src/parser/items/static_items.rs` - Replaced 22 lines with 2 lines
|
||||
6. `apps/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`
|
||||
```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](../../../architecture/phase-33-modularization.md))
|
||||
- Phase 285: Box lifecycle ([phase-285/README.md](README.md))
|
||||
- `src/mir/builder/weak_field_validator.rs`: 実装本体
|
||||
- `src/mir/builder/fields.rs`: 呼び出し側
|
||||
- `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 実装本体
|
||||
|
||||
Reference in New Issue
Block a user