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

272 lines
6.8 KiB
Markdown
Raw Normal View History

# @enum Macro Implementation - Quick Start Guide
**✅ Status**: **Phase 19 完了2025-10-08** - @enum macro 完全実装済み
**Read this first**, then dive into the full spec: [@enum-macro-implementation-spec.md](./@enum-macro-implementation-spec.md)
---
## 🎉 実装状況2025-10-08完了
-**@enum macro**: 完全実装enum_parser.rs, macro/engine.rs
-**match式**: 完全実装match_expr.rs、literal/type patterns + guards対応
-**ResultBox Phase 1**: 実装完了apps/lib/boxes/result.hako, 103行
- ⚠️ **API競合**: 小文字版(Result.ok/err) vs @enum版(Result.Ok/Err) 共存中
**実装場所**:
- Parser: `src/parser/declarations/enum_parser.rs` (147行)
- Macro: `src/macro/engine.rs` (expand_enum_to_boxes関数)
- Match: `src/parser/expr/match_expr.rs` (392行)
---
## 30-Second Overview
**What**: Implement `@enum` macro that desugars to Box + Static Box
**How**: Macro-only (no IR changes, no VariantBox core)
**When**: ~~3-5 days~~ **✅ 完了2025-10-08**
---
## Core Design Pattern
### Input
```hakorune
@enum Result {
Ok(value)
Err(error)
}
```
### Output (Desugared)
```hakorune
box ResultBox {
_tag: StringBox // Discriminator
_value: Box // Ok's field
_error: Box // Err's field
birth() {
me._tag = ""
me._value = null
me._error = null
}
}
static box Result {
Ok(v) {
local r = new ResultBox()
r._tag = "Ok"
r._value = v
return r
}
Err(e) {
local r = new ResultBox()
r._tag = "Err"
r._error = e
return r
}
is_Ok(variant) { return variant._tag == "Ok" }
is_Err(variant) { return variant._tag == "Err" }
as_Ok(variant) {
if variant._tag != "Ok" {
print("[PANIC] Result.as_Ok: called on " + variant._tag)
return null
}
return variant._value
}
as_Err(variant) {
if variant._tag != "Err" {
print("[PANIC] Result.as_Err: called on " + variant._tag)
return null
}
return variant._error
}
}
```
---
## Key Rules
1. **Tag Field**: Always `_tag: StringBox` (discriminator)
2. **Field Naming**:
- Single field: `_value`
- Named fields: `_{field_name}` (e.g., `error``_error`)
- Multi-field: `_field1`, `_field2`, etc.
3. **All fields are Box-typed**: `Box` (runtime polymorphism)
4. **Constructors**: Variant name becomes static method
5. **Helpers**: `is_{Variant}(v)` and `as_{Variant}(v)` auto-generated
6. **Fail-Fast**: `as_*` panics if wrong variant
---
## Implementation Roadmap (5 Days)
### Day 1: Parser (6-8h)
- Add `@enum` token recognition
- Parse `@enum Name { Variant1(field) Variant2 }`
- Create AST nodes: `EnumDeclaration`, `EnumVariant`, `EnumField`
- Validation: duplicates, empty enum, reserved names
### Day 2: Macro Expansion (8-10h)
- Create `src/macro/enum_macro.rs`
- Implement `expand_enum()` → generates AST
- Generate data box (`{Name}Box` with `_tag` + all fields)
- Generate `birth()` method
### Day 3: Helpers (8-10h)
- Generate static box with constructors
- Generate `is_{Variant}()` methods
- Generate `as_{Variant}()` methods (single/multi-field)
- Handle edge cases (0-field variants, conflicts)
### Day 4: Tests (6-8h)
- 12 positive tests (basic, multi-variant, helpers, integration)
- 3 negative tests (errors)
- Test runner script
- Verify all tests pass
### Day 5: Integration (6-8h)
- Smoke tests
- Performance benchmark (vs old Option/Result)
- Migration guide
- Documentation update
---
## Files to Create/Modify
### New Files
- `src/parser/declarations/enum_parser.rs` - Parser logic
- `src/macro/enum_macro.rs` - Macro expansion
- `apps/lib/boxes/tests/enum_*.hako` - Test suite (8 files)
- `tools/run_enum_tests.sh` - Test runner
- `docs/guides/enum-migration-guide.md` - Migration guide
### Modified Files
- `src/parser/mod.rs` - Add enum parser invocation
- `src/parser/declarations/mod.rs` - Export enum parser
- `src/ast.rs` - Add `EnumDeclaration`, `EnumVariant`, `EnumField`
- `src/macro/mod.rs` - Integrate enum expansion
- `hako.toml` - Add v2 module aliases (optional)
---
## Critical Edge Cases
1. **Zero-field variant**: `None` → constructor takes no args
2. **Multi-field variant**: `as_*` returns `ArrayBox` with all fields
3. **Field conflicts**: Same field name across variants → shared storage (OK)
4. **Reserved names**: `birth`, `fini`, `new`, `me`, `this` → error
5. **Empty enum**: No variants → parse error
---
## Test Examples (Must Pass)
### Basic Usage
```hakorune
@enum Option { Some(value) None }
local opt = Option.Some(42)
print(opt._tag) // "Some"
print(opt._value) // "42"
if Option.is_Some(opt) {
local v = Option.as_Some(opt)
print(v) // "42"
}
```
### Panic Behavior
```hakorune
local err = Result.Err("failed")
local v = Result.as_Ok(err) // Panics!
// Output: [PANIC] Result.as_Ok: called on Err
// Returns: null
```
### Pattern Matching (Manual)
```hakorune
if result._tag == "Ok" {
print("Success: " + result._value)
}
if result._tag == "Err" {
print("Error: " + result._error)
}
```
---
## Migration Strategy (for existing Option/Result)
### Phase 1: Parallel Existence
- Keep old `option.hako` / `result.hako`
- Create new `option_v2.hako` / `result_v2.hako` with `@enum`
- Add module aliases in `hako.toml`
### Phase 2: Gradual Migration
- Migrate test files first
- Migrate non-critical tools
- Verify behavior parity
### Phase 3: Deprecation
- Rename old → `*_deprecated.hako`
- Rename v2 → main files
- Update all import sites
### Phase 4: Cleanup
- Delete deprecated files
- Update documentation
**Important**: NOT backward compatible. API changes:
- `Option.some(v)``Option.Some(v)` (capital S)
- `opt.is_some()``Option.is_Some(opt)` (static method)
- `opt._is_some``opt._tag == "Some"` (tag-based)
---
## Performance Expectations
- **String comparison**: Slightly slower than integer flags
- **Expected regression**: <10% (acceptable for MVP)
- **Future optimization**: String interning → pointer comparison
---
## Success Criteria
- [ ] All 12 positive tests pass
- [ ] All 3 negative tests catch errors
- [ ] Smoke tests pass
- [ ] Performance <10% regression
- [ ] Documentation complete
- [ ] Migration guide written
---
## Risk Mitigation
1. **Parser conflicts**: Test with `@local` in same file
2. **Macro order**: Run @enum expansion early (before other macros)
3. **Field naming**: Reserve `_` prefix, validate in parser
4. **Error messages**: Preserve source spans, show original @enum location
5. **Debugging**: Add `NYASH_MACRO_TRACE=1` output
---
## Next Steps
1. Read full spec: [@enum-macro-implementation-spec.md](./@enum-macro-implementation-spec.md)
2. Start with Day 1 (Parser changes)
3. Follow daily checklist
4. Ask questions early (don't guess)
---
**Full Specification**: [@enum-macro-implementation-spec.md](./@enum-macro-implementation-spec.md) (13,000+ words, implementation-ready)