Parent
Part of the MagicAST restructure milestone — a pre-TDD architectural refactor to eliminate merge-conflict hotspots so ~10 parallel agent worktrees can each add a new MTG ability/effect/keyword as a self-contained new file with zero edits to existing shared files.
This is Phase 1 of 5. The overall pattern across phases is attribute-driven registration discovered via reflection at startup. This phase is the smallest and exists partly to build the project's attribute-discovery muscle before tackling harder phases.
What to build
Today, the tokenizer maintains a hard-coded literal table of structural keywords (the _structuralKeywords field inside OracleTokenizer.cs, currently around lines 17–44). Adding a structural keyword is an edit to that shared file — a merge-conflict hotspot when multiple agents work in parallel.
Replace the inline table with self-contained registrations, one per structural keyword. The tokenizer discovers them at startup. Two acceptable implementation paths; pick (i) unless you find a concrete reason to prefer (ii):
- (i, preferred) Attribute on a per-keyword class. Example shape:
[StructuralKeyword("when")] public static class WhenKeyword {}. The tokenizer scans the assembly for [StructuralKeyword]-decorated types at startup and builds the dispatch table once.
- (ii) Embedded JSON resource shipped with the assembly. The tokenizer loads it on first use.
Path (i) is preferred because it gives compile-time safety on keyword names and matches the attribute-driven pattern used by later phases.
Each keyword lives in its own file under (suggested) libs/magic-ast/Parsing/Tokens/Keywords/ or similar — exact directory layout is implementer's choice as long as the goal is met.
Acceptance criteria
Blocked by
None — can start immediately.
Parent
Part of the MagicAST restructure milestone — a pre-TDD architectural refactor to eliminate merge-conflict hotspots so ~10 parallel agent worktrees can each add a new MTG ability/effect/keyword as a self-contained new file with zero edits to existing shared files.
This is Phase 1 of 5. The overall pattern across phases is attribute-driven registration discovered via reflection at startup. This phase is the smallest and exists partly to build the project's attribute-discovery muscle before tackling harder phases.
What to build
Today, the tokenizer maintains a hard-coded literal table of structural keywords (the
_structuralKeywordsfield insideOracleTokenizer.cs, currently around lines 17–44). Adding a structural keyword is an edit to that shared file — a merge-conflict hotspot when multiple agents work in parallel.Replace the inline table with self-contained registrations, one per structural keyword. The tokenizer discovers them at startup. Two acceptable implementation paths; pick (i) unless you find a concrete reason to prefer (ii):
[StructuralKeyword("when")] public static class WhenKeyword {}. The tokenizer scans the assembly for[StructuralKeyword]-decorated types at startup and builds the dispatch table once.Path (i) is preferred because it gives compile-time safety on keyword names and matches the attribute-driven pattern used by later phases.
Each keyword lives in its own file under (suggested)
libs/magic-ast/Parsing/Tokens/Keywords/or similar — exact directory layout is implementer's choice as long as the goal is met.Acceptance criteria
OracleTokenizer.csno longer contains a literal list of structural keyword strings.OracleTokenizer.csor any other existing file.tools/test/magic-ast/) remains green or improves — no regressions intest-baseline.json.Blocked by
None — can start immediately.