Files
hakorune/docs/private/roadmap/phases/phase-20-variant-box/@match-quick-start.md

461 lines
10 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.

# @match Macro Quick Start Guide
**✅ Status**: **Phase 19 完了2025-10-08** - match式 完全実装済み(@matchマクロではなく、正規match構文として
**For**: ~~Developers implementing @match macro~~ **実装完了記録**
**Time**: ~~6 days~~ **✅ 完了2025-10-08**
**Difficulty**: Medium
**Prerequisites**: Understanding of Rust parser, AST, macros
---
## 🎉 実装完了状況2025-10-08
-**match式 Parser**: `src/parser/expr/match_expr.rs` (392行)
-**Literal patterns**: 整数・文字列・bool対応
-**Type patterns**: Box型パターン対応
-**Guards**: `if` ガード条件対応
- ⚠️ **注意**: `@match`マクロ**ではなく**、正規`match`構文として実装
**使用例** (実装済み):
```hakorune
match result {
Ok(value) if value > 0 => print("Positive")
Ok(value) => print("Non-positive")
Err(e) => print("Error: " + e)
}
```
---
## 📋 Quick Links
- **Complete Spec**: [@match-macro-implementation-spec.md](./@match-macro-implementation-spec.md)
- **VariantBox Design**: [DESIGN.md](./DESIGN.md)
- **Existing Boxes**:
- [apps/lib/boxes/result.hako](../../../../apps/lib/boxes/result.hako)
- [apps/lib/boxes/option.hako](../../../../apps/lib/boxes/option.hako)
---
## 🎯 What You're Building
Transform this:
```hakorune
@match result {
Ok(v) => print("Success: " + v)
Err(e) => print("Error: " + e)
}
```
Into this:
```hakorune
if result._ok == 1 {
local v
v = result._val
print("Success: " + v)
} else if result._ok == 0 {
local e
e = result._err
print("Error: " + e)
} else {
print("[PANIC] non-exhaustive match on Result: unknown state")
}
```
---
## 🚀 6-Day Implementation Plan
### Day 1: Parser Foundation
**Goal**: Parse @match syntax without errors
**Tasks**:
1. Add `MatchPattern` to `ASTNode` enum
2. Add `Pattern` and `MatchArm` structs
3. Add `FatArrow` and `Underscore` tokens
4. Implement `parse_match_pattern()` method
**Files to Modify**:
- `src/ast.rs` - AST nodes
- `src/tokenizer.rs` - Token types
- `src/parser/statements/mod.rs` - Parser methods
**Test**:
```bash
# Should parse without error
echo '@match x { Ok(v) => v }' | ./target/release/hako --dump-ast -
```
### Day 2: Tag Comparison Generation
**Goal**: Generate if-conditions for patterns
**Tasks**:
1. Create field mapping registry
2. Implement tag comparison code
3. Generate if-condition AST nodes
**Hardcoded Mappings**:
```rust
// Result
Ok _ok==1, field: _val
Err _ok==0, field: _err
// Option
Some _is_some==1, field: _value
None _is_some==0
// Generic VariantBox
Variant _tag=="Variant", fields: _0, _1, ...
```
**Test**:
```hakorune
@match result { Ok(v) => v }
// Should generate: if result._ok == 1 { ... }
```
### Day 3: Variable Binding
**Goal**: Extract pattern variables to local declarations
**Tasks**:
1. Implement binding extraction
2. Generate `local` declarations
3. Generate field access code
4. Insert bindings at top of arm
**Test**:
```hakorune
@match point { Cartesian(x, y) => print(x + y) }
// Should generate:
// local x
// local y
// x = point._x
// y = point._y
```
### Day 4: Exhaustiveness Check
**Goal**: Add safety panic for unknown variants
**Tasks**:
1. Generate catch-all else clause
2. Generate panic message
3. Handle match-as-expression case
**Test**:
```hakorune
@match result { Ok(v) => v }
// Should generate final else:
// else { print("[PANIC] non-exhaustive match...") }
```
### Day 5: Basic Tests (8/15)
**Goal**: Verify core functionality
**Test Files**:
- Test 1-5: Basic matching
- Test 6-8: Variable binding
**Run**:
```bash
./target/release/hako apps/tests/match/test_result_basic.hako
./target/release/hako apps/tests/match/test_option_basic.hako
# ... etc
```
### Day 6: Edge Cases (7/15)
**Goal**: Handle corner cases
**Test Files**:
- Test 9-11: Exhaustiveness
- Test 12-15: Edge cases (loops, early return, etc.)
**Final Verification**:
```bash
# Run all match tests
bash tools/test_match_patterns.sh
# Run smoke tests
tools/smokes/v2/run.sh --profile quick
```
---
## 🔑 Key Implementation Points
### 1. AST Node Structure
```rust
// src/ast.rs
pub enum ASTNode {
// ... existing variants ...
MatchPattern {
scrutinee: Box<ASTNode>,
arms: Vec<MatchArm>,
span: Span,
},
}
pub struct MatchArm {
pub pattern: Pattern,
pub body: Vec<ASTNode>,
pub span: Span,
}
pub enum Pattern {
Variant {
name: String,
bindings: Vec<String>,
span: Span,
},
Wildcard {
span: Span,
},
}
```
### 2. Desugaring Algorithm (Simplified)
```rust
fn desugar_match(scrutinee: &ASTNode, arms: &[MatchArm]) -> ASTNode {
let mut if_chain = None;
// Build if/else chain (reverse order)
for arm in arms.iter().rev() {
let condition = generate_tag_check(scrutinee, &arm.pattern);
let bindings = generate_bindings(scrutinee, &arm.pattern);
let mut then_body = bindings;
then_body.extend(arm.body.clone());
if_chain = Some(ASTNode::If {
condition: Box::new(condition),
then_body,
else_body: if_chain.map(|node| vec![node]),
span: Span::unknown(),
});
}
// Add exhaustiveness panic
let panic = ASTNode::Print {
expression: Box::new(ASTNode::Literal {
value: LiteralValue::String("[PANIC] non-exhaustive match".to_string()),
span: Span::unknown(),
}),
span: Span::unknown(),
};
if let Some(ASTNode::If { else_body, .. }) = &mut if_chain {
*else_body = Some(vec![panic]);
}
if_chain.unwrap()
}
```
### 3. Field Mapping Function
```rust
fn get_field_mapping(variant: &str, binding_index: usize) -> String {
match variant {
"Ok" => "_val".to_string(),
"Err" => "_err".to_string(),
"Some" => "_value".to_string(),
"None" => panic!("None has no fields"),
_ => format!("_{}", binding_index), // Generic: _0, _1, ...
}
}
fn get_tag_check(variant: &str) -> (&str, &str) {
match variant {
"Ok" => ("_ok", "1"),
"Err" => ("_ok", "0"),
"Some" => ("_is_some", "1"),
"None" => ("_is_some", "0"),
_ => ("_tag", variant), // Generic: _tag == "Variant"
}
}
```
---
## 🧪 Testing Strategy
### Smoke Test Template
```hakorune
// apps/tests/match/test_NAME.hako
using "../../lib/boxes/result.hako"
static box Main {
main() {
// Setup
local r = Result.ok(42)
// Test @match
local result = @match r {
Ok(v) => v * 2
Err(e) => -1
}
// Assert
if result != 84 {
print("FAIL: Expected 84, got " + result)
return 1
}
print("PASS: test_NAME")
return 0
}
}
```
### Running Tests
```bash
# Single test
./target/release/hako apps/tests/match/test_result_basic.hako
# With MIR dump (verify desugaring)
./target/release/hako --dump-mir apps/tests/match/test_result_basic.hako
# All tests
for f in apps/tests/match/*.hako; do
echo "Testing $f..."
./target/release/hako "$f" || echo "FAILED: $f"
done
```
---
## 🚨 Common Pitfalls
### 1. Parser Order
**Problem**: `=>` tokenized as `>` + `=`
**Solution**: Tokenize `=>` as single `FatArrow` token first
### 2. Variable Scope
**Problem**: Pattern variables leak to outer scope
**Solution**: Each if-arm creates new scope (via if block)
### 3. Expression vs Statement
**Problem**: Match used as expression (returns value)
**Solution**: Introduce temporary variable, assign in each arm
### 4. Exhaustiveness False Positives
**Problem**: All cases covered, but panic still added
**Solution**: Phase 1: Always add panic (safe). Phase 2: Static analysis
### 5. Field Name Conflicts
**Problem**: Multiple variants with same field name
**Solution**: Use variant-specific field names (`_val` vs `_err`)
---
## 📊 Progress Checklist
### Day 1: Parser
- [ ] `MatchPattern` AST node added
- [ ] `Pattern` enum added
- [ ] `FatArrow` token added
- [ ] `parse_match_pattern()` implemented
- [ ] Can parse basic @match without error
### Day 2: Tag Comparison
- [ ] Field mapping registry created
- [ ] Tag check generation works
- [ ] If-condition AST generation works
- [ ] Can generate if/else skeleton
### Day 3: Variable Binding
- [ ] Binding extraction works
- [ ] `local` declarations generated
- [ ] Field access generated
- [ ] Bindings inserted correctly
### Day 4: Exhaustiveness
- [ ] Catch-all else clause works
- [ ] Panic message generated
- [ ] Match-as-expression works
- [ ] Null assignment in panic case
### Day 5: Basic Tests
- [ ] Test 1: Result basic - PASS
- [ ] Test 2: Option basic - PASS
- [ ] Test 3: 3-way variant - PASS
- [ ] Test 4: Expression - PASS
- [ ] Test 5: Multi-statement - PASS
- [ ] Test 6: Single binding - PASS
- [ ] Test 7: Multi binding - PASS
- [ ] Test 8: Shadowing - PASS
### Day 6: Edge Cases
- [ ] Test 9: Exhaustive - PASS
- [ ] Test 10: Non-exhaustive - PASS
- [ ] Test 11: Wildcard - PASS
- [ ] Test 12: 0-field variant - PASS
- [ ] Test 13: Nested if - PASS
- [ ] Test 14: Loop control - PASS
- [ ] Test 15: Early return - PASS
### Final
- [ ] All 15 tests PASS
- [ ] Smoke tests PASS
- [ ] Documentation complete
- [ ] Ready for production
---
## 🎓 Learning Resources
### Rust Parser References
- `src/parser/expressions.rs` - Expression parsing patterns
- `src/parser/statements/mod.rs` - Statement parsing
- `src/ast.rs` - AST node definitions
### Existing Macro Examples
- `src/macro/macro_box.rs` - MacroBox trait
- `apps/macros/loop_normalize_macro.nyash` - Complex desugaring
### Hakorune Box Examples
- `apps/lib/boxes/result.hako` - Result implementation
- `apps/lib/boxes/option.hako` - Option implementation
---
## 💡 Tips for Success
1. **Start Simple**: Test with 2-arm match first (Ok/Err)
2. **Use --dump-mir**: Verify desugared code constantly
3. **Incremental Testing**: Test each day's work immediately
4. **Reference Phase 16**: @derive implementation is similar pattern
5. **Ask Questions**: Consult complete spec for details
---
## 🆘 When Stuck
### Debug Commands
```bash
# See parsed AST
./target/release/hako --dump-ast test.hako
# See desugared code
./target/release/hako --dump-mir test.hako
# Verbose diagnostics
NYASH_CLI_VERBOSE=1 ./target/release/hako test.hako
```
### Common Issues
- **Parse Error**: Check tokenizer output
- **Wrong Desugaring**: Check field mapping registry
- **Test Failure**: Use --dump-mir to compare expected vs actual
---
**Ready to Start?** Begin with Day 1 tasks and refer to the complete spec for detailed algorithms!
**Questions?** Check [@match-macro-implementation-spec.md](./@match-macro-implementation-spec.md) for comprehensive details.