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

6.8 KiB
Raw Blame 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


🎉 実装状況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

  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

@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.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_someopt._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
  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 (13,000+ words, implementation-ready)