Skip to content

build: prepare Stage 2 foundation #34

@edloidas

Description

@edloidas

Preparatory commit that establishes shared infrastructure for all Stage 2 features (#25). Must land before any individual Stage 2 feature work begins.

Token Allocation

Reorganize TokenType enum with all Stage 2 token IDs allocated upfront (31 total, semantically grouped). Existing tokens are renumbered for logical grouping:

Group Tokens
Literals NUMBER
Dice operators DICE, DICE_PERCENT, DICE_FATE
Arithmetic PLUS, MINUS, MULTIPLY, DIVIDE, MODULO, POWER
Comparison GREATER, GREATER_EQUAL, LESS, LESS_EQUAL, EQUAL
Grouping LPAREN, RPAREN, COMMA
Keep/drop KEEP_HIGH, KEEP_LOW, DROP_HIGH, DROP_LOW
Explode EXPLODE, EXPLODE_COMPOUND, EXPLODE_PENETRATING
Reroll REROLL, REROLL_ONCE
Success FAIL
Functions FUNCTION
Keywords VS
End EOF

ComparePoint Type

Define canonical ComparePoint in src/types.ts:

type CompareOp = '>' | '>=' | '<' | '<=' | '=';
type ComparePoint = { operator: CompareOp; value: ASTNode };

value is ASTNode (not number) to match the existing pattern where DiceNode.count and DiceNode.sides are both ASTNode. This supports computed thresholds (>=ceil(5)) and negative compare values (=-1 for Fate dice) via unary minus.

Lexer: Full-Accumulation scanIdentifier

Rewrite scanIdentifier from incremental peek-based scanning to full-accumulation: collect all consecutive alpha chars, then classify against a keyword lookup table. Resolves the d-in-round problem, d% scanning, f vs floor disambiguation, and all future identifier keywords.

Special cases after accumulation:

  • Bare d followed by %DICE_PERCENT
  • dfDICE_FATE

Operator Scanning

Add to the operator switch in nextToken():

  • Comparison: >, >= (maximal munch), <, <= (maximal munch), =
  • Explode: !, !! (maximal munch), !p/!P
  • Comma: ,

Parser: ComparePoint Utilities

Add two methods to the Parser class for use by Stage 2 modifier parsers:

  • isComparePointAhead(): boolean — peeks for comparison operator tokens
  • parseComparePoint(): ComparePoint — consumes operator + value expression

Comparison tokens get BP = -1 (terminators) so they never interfere with the main Pratt loop.

Rationale

All 8 Stage 2 features were planned in isolation and independently assigned conflicting token IDs starting at 15, used 3 different naming conventions for comparison tokens, and defined ComparePoint in 4 incompatible ways. A consilium review identified these as critical integration blockers. This issue resolves all cross-cutting conflicts in a single upfront pass.

See .claude/docs/STAGE2.md for the full design document.

Drafted with AI assistance

Metadata

Metadata

Assignees

Labels

improvementUpdate of the existing functionality

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions