6.8 KiB
6.8 KiB
@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
🎉 実装状況(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
@enum Result {
Ok(value)
Err(error)
}
Output (Desugared)
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
- Tag Field: Always
_tag: StringBox(discriminator) - Field Naming:
- Single field:
_value - Named fields:
_{field_name}(e.g.,error→_error) - Multi-field:
_field1,_field2, etc.
- Single field:
- All fields are Box-typed:
Box(runtime polymorphism) - Constructors: Variant name becomes static method
- Helpers:
is_{Variant}(v)andas_{Variant}(v)auto-generated - Fail-Fast:
as_*panics if wrong variant
Implementation Roadmap (5 Days)
Day 1: Parser (6-8h)
- Add
@enumtoken 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}Boxwith_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 logicsrc/macro/enum_macro.rs- Macro expansionapps/lib/boxes/tests/enum_*.hako- Test suite (8 files)tools/run_enum_tests.sh- Test runnerdocs/guides/enum-migration-guide.md- Migration guide
Modified Files
src/parser/mod.rs- Add enum parser invocationsrc/parser/declarations/mod.rs- Export enum parsersrc/ast.rs- AddEnumDeclaration,EnumVariant,EnumFieldsrc/macro/mod.rs- Integrate enum expansionhako.toml- Add v2 module aliases (optional)
Critical Edge Cases
- Zero-field variant:
None→ constructor takes no args - Multi-field variant:
as_*returnsArrayBoxwith all fields - Field conflicts: Same field name across variants → shared storage (OK)
- Reserved names:
birth,fini,new,me,this→ error - Empty enum: No variants → parse error
Test Examples (Must Pass)
Basic Usage
@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
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)
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.hakowith@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
- Parser conflicts: Test with
@localin same file - Macro order: Run @enum expansion early (before other macros)
- Field naming: Reserve
_prefix, validate in parser - Error messages: Preserve source spans, show original @enum location
- Debugging: Add
NYASH_MACRO_TRACE=1output
Next Steps
- Read full spec: @enum-macro-implementation-spec.md
- Start with Day 1 (Parser changes)
- Follow daily checklist
- Ask questions early (don't guess)
Full Specification: @enum-macro-implementation-spec.md (13,000+ words, implementation-ready)