roll-parser 2.3.2 → 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +175 -170
  3. package/dist/cli/args.d.ts +35 -0
  4. package/dist/cli/args.d.ts.map +1 -0
  5. package/dist/cli/format.d.ts +20 -0
  6. package/dist/cli/format.d.ts.map +1 -0
  7. package/dist/cli/index.d.ts +8 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli.js +2608 -0
  10. package/dist/cli.js.map +28 -0
  11. package/dist/errors.d.ts +42 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/evaluator/evaluator.d.ts +121 -0
  14. package/dist/evaluator/evaluator.d.ts.map +1 -0
  15. package/dist/evaluator/index.d.ts +8 -0
  16. package/dist/evaluator/index.d.ts.map +1 -0
  17. package/dist/evaluator/modifiers/compare.d.ts +15 -0
  18. package/dist/evaluator/modifiers/compare.d.ts.map +1 -0
  19. package/dist/evaluator/modifiers/crit-threshold.d.ts +28 -0
  20. package/dist/evaluator/modifiers/crit-threshold.d.ts.map +1 -0
  21. package/dist/evaluator/modifiers/explode.d.ts +48 -0
  22. package/dist/evaluator/modifiers/explode.d.ts.map +1 -0
  23. package/dist/evaluator/modifiers/keep-drop.d.ts +44 -0
  24. package/dist/evaluator/modifiers/keep-drop.d.ts.map +1 -0
  25. package/dist/evaluator/modifiers/reroll.d.ts +33 -0
  26. package/dist/evaluator/modifiers/reroll.d.ts.map +1 -0
  27. package/dist/evaluator/modifiers/sort.d.ts +23 -0
  28. package/dist/evaluator/modifiers/sort.d.ts.map +1 -0
  29. package/dist/evaluator/modifiers/success-count.d.ts +28 -0
  30. package/dist/evaluator/modifiers/success-count.d.ts.map +1 -0
  31. package/dist/index.d.ts +20 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +2560 -0
  34. package/dist/index.js.map +26 -0
  35. package/dist/lexer/lexer.d.ts +90 -0
  36. package/dist/lexer/lexer.d.ts.map +1 -0
  37. package/dist/lexer/tokens.d.ts +107 -0
  38. package/dist/lexer/tokens.d.ts.map +1 -0
  39. package/dist/parser/ast.d.ts +368 -0
  40. package/dist/parser/ast.d.ts.map +1 -0
  41. package/dist/parser/parser.d.ts +145 -0
  42. package/dist/parser/parser.d.ts.map +1 -0
  43. package/dist/rng/index.d.ts +8 -0
  44. package/dist/rng/index.d.ts.map +1 -0
  45. package/dist/rng/mock.d.ts +36 -0
  46. package/dist/rng/mock.d.ts.map +1 -0
  47. package/dist/rng/seeded.d.ts +40 -0
  48. package/dist/rng/seeded.d.ts.map +1 -0
  49. package/dist/rng/types.d.ts +24 -0
  50. package/dist/rng/types.d.ts.map +1 -0
  51. package/dist/roll.d.ts +51 -0
  52. package/dist/roll.d.ts.map +1 -0
  53. package/dist/testing.d.ts +11 -0
  54. package/dist/testing.d.ts.map +1 -0
  55. package/dist/testing.js +41 -0
  56. package/dist/testing.js.map +11 -0
  57. package/dist/types.d.ts +246 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/package.json +66 -43
  60. package/src/cli/args.ts +73 -0
  61. package/src/cli/format.ts +49 -0
  62. package/src/cli/index.ts +92 -0
  63. package/src/errors.ts +90 -0
  64. package/src/evaluator/evaluator.ts +1552 -0
  65. package/src/evaluator/index.ts +14 -0
  66. package/src/evaluator/modifiers/compare.ts +29 -0
  67. package/src/evaluator/modifiers/crit-threshold.ts +59 -0
  68. package/src/evaluator/modifiers/explode.ts +219 -0
  69. package/src/evaluator/modifiers/keep-drop.ts +151 -0
  70. package/src/evaluator/modifiers/reroll.ts +165 -0
  71. package/src/evaluator/modifiers/sort.ts +30 -0
  72. package/src/evaluator/modifiers/success-count.ts +59 -0
  73. package/src/index.ts +90 -0
  74. package/src/lexer/lexer.ts +374 -0
  75. package/src/lexer/tokens.ts +187 -0
  76. package/src/parser/ast.ts +628 -0
  77. package/src/parser/parser.ts +1239 -0
  78. package/src/rng/index.ts +8 -0
  79. package/src/rng/mock.ts +65 -0
  80. package/src/rng/seeded.ts +157 -0
  81. package/src/rng/types.ts +25 -0
  82. package/src/roll.ts +74 -0
  83. package/src/testing.ts +16 -0
  84. package/src/types.ts +237 -0
  85. package/bin/help.txt +0 -19
  86. package/bin/roll-parser.js +0 -23
  87. package/dist/roll-parser.js +0 -697
  88. package/dist/roll-parser.min.js +0 -1
  89. package/index.js +0 -24
  90. package/src/complex/parse.js +0 -37
  91. package/src/complex/parseAndRoll.js +0 -21
  92. package/src/complex/parseAndRollClassic.js +0 -20
  93. package/src/complex/parseAndRollSimple.js +0 -19
  94. package/src/complex/parseAndRollWod.js +0 -20
  95. package/src/complex/parseClassicRoll.js +0 -22
  96. package/src/complex/parseSimpleRoll.js +0 -21
  97. package/src/complex/parseWodRoll.js +0 -21
  98. package/src/converter.js +0 -45
  99. package/src/grammar.js +0 -14
  100. package/src/mapper.js +0 -50
  101. package/src/normalizer.js +0 -51
  102. package/src/object/Result.js +0 -23
  103. package/src/object/Roll.js +0 -26
  104. package/src/object/Type.js +0 -5
  105. package/src/object/WodRoll.js +0 -29
  106. package/src/parser.js +0 -43
  107. package/src/random.js +0 -22
  108. package/src/roller.js +0 -106
  109. package/src/stringifier.js +0 -33
@@ -0,0 +1,26 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/errors.ts", "../src/lexer/tokens.ts", "../src/lexer/lexer.ts", "../src/parser/ast.ts", "../src/parser/parser.ts", "../src/rng/seeded.ts", "../src/types.ts", "../src/evaluator/modifiers/compare.ts", "../src/evaluator/modifiers/crit-threshold.ts", "../src/evaluator/modifiers/explode.ts", "../src/evaluator/modifiers/keep-drop.ts", "../src/evaluator/modifiers/reroll.ts", "../src/evaluator/modifiers/sort.ts", "../src/evaluator/modifiers/success-count.ts", "../src/evaluator/evaluator.ts", "../src/roll.ts", "../src/index.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Common error base class and error codes for roll-parser.\n *\n * @module errors\n */\n\n/**\n * All known roll-parser error codes. Single source of truth — the\n * `RollParserErrorCode` type and the runtime `VALID_CODES` set are\n * both derived from this array.\n *\n * Lexer: `UNEXPECTED_CHARACTER`, `UNEXPECTED_IDENTIFIER`\n * Parser: `UNEXPECTED_TOKEN`, `UNEXPECTED_END`, `EXPECTED_TOKEN`,\n * `INVALID_MODIFIER_TARGET`, `INVALID_EXPLODE_TARGET`, `INVALID_REROLL_TARGET`,\n * `INVALID_SUCCESS_COUNT_TARGET`, `INVALID_SORT_TARGET`,\n * `INVALID_CRIT_THRESHOLD_TARGET`, `NESTED_VERSUS`, `INVALID_FUNCTION_ARITY`,\n * `AMBIGUOUS_DICE_CHAIN`, `MAX_DEPTH_EXCEEDED`\n * Evaluator: `INVALID_DICE_COUNT`, `INVALID_DICE_SIDES`, `DICE_LIMIT_EXCEEDED`,\n * `DIVISION_BY_ZERO`, `MODULO_BY_ZERO`, `UNKNOWN_OPERATOR`, `UNKNOWN_NODE_TYPE`,\n * `INVALID_MODIFIER_COUNT`, `EXPLODE_LIMIT_EXCEEDED`, `REROLL_LIMIT_EXCEEDED`,\n * `INVALID_THRESHOLD`, `NESTED_VERSUS`, `UNKNOWN_FUNCTION`, `UNDEFINED_VARIABLE`,\n * `INVALID_VARIABLE_VALUE`, `NON_FINITE_RESULT`\n */\nconst ROLL_PARSER_ERROR_CODES = [\n 'UNEXPECTED_CHARACTER',\n 'UNEXPECTED_IDENTIFIER',\n 'UNEXPECTED_TOKEN',\n 'UNEXPECTED_END',\n 'EXPECTED_TOKEN',\n 'INVALID_DICE_COUNT',\n 'INVALID_DICE_SIDES',\n 'DICE_LIMIT_EXCEEDED',\n 'DIVISION_BY_ZERO',\n 'MODULO_BY_ZERO',\n 'UNKNOWN_OPERATOR',\n 'UNKNOWN_NODE_TYPE',\n 'INVALID_MODIFIER_COUNT',\n 'INVALID_MODIFIER_TARGET',\n 'EXPLODE_LIMIT_EXCEEDED',\n 'INVALID_EXPLODE_TARGET',\n 'REROLL_LIMIT_EXCEEDED',\n 'INVALID_REROLL_TARGET',\n 'INVALID_SUCCESS_COUNT_TARGET',\n 'INVALID_SORT_TARGET',\n 'INVALID_CRIT_THRESHOLD_TARGET',\n 'INVALID_THRESHOLD',\n 'NESTED_VERSUS',\n 'INVALID_FUNCTION_ARITY',\n 'UNKNOWN_FUNCTION',\n 'UNDEFINED_VARIABLE',\n 'INVALID_VARIABLE_VALUE',\n 'AMBIGUOUS_DICE_CHAIN',\n 'MAX_DEPTH_EXCEEDED',\n 'NON_FINITE_RESULT',\n] as const;\n\nexport type RollParserErrorCode = (typeof ROLL_PARSER_ERROR_CODES)[number];\n\n/**\n * Base error class for all roll-parser errors.\n *\n * Provides a typed `code` field for programmatic error handling.\n * All library errors (`LexerError`, `ParseError`, `EvaluatorError`)\n * extend this class.\n */\nexport class RollParserError extends Error {\n readonly code: RollParserErrorCode;\n\n constructor(message: string, code: RollParserErrorCode) {\n super(message);\n this.name = 'RollParserError';\n this.code = code;\n }\n}\n\nconst VALID_CODES: Set<string> = new Set<string>(ROLL_PARSER_ERROR_CODES);\n\n/**\n * Type guard for roll-parser errors. Checks `instanceof` first, then\n * falls back to duck-typing for cross-realm safety.\n */\nexport function isRollParserError(value: unknown): value is RollParserError {\n if (value instanceof RollParserError) return true;\n return (\n value instanceof Error &&\n 'code' in value &&\n typeof (value as RollParserError).code === 'string' &&\n VALID_CODES.has((value as RollParserError).code)\n );\n}\n",
6
+ "/**\n * Token type definitions for the dice notation lexer.\n *\n * @module lexer/tokens\n */\n\n/**\n * Token types for dice notation.\n *\n * Grouped semantically. Numeric values are stable identifiers — the specific\n * numbers don't matter, but they must be unique.\n */\nexport enum TokenType {\n //\n // * Literals\n //\n\n /** Numeric literal: integer or decimal */\n NUMBER = 0,\n\n //\n // * Dice operators\n //\n\n /** Dice operator: 'd' or 'D' */\n DICE = 1,\n /** Percentile dice operator: 'd%' (alias for d100) */\n DICE_PERCENT = 2,\n /** Fate/Fudge dice operator: 'dF' */\n DICE_FATE = 3,\n\n //\n // * Arithmetic operators\n //\n\n /** Addition operator: '+' */\n PLUS = 4,\n /** Subtraction operator: '-' */\n MINUS = 5,\n /** Multiplication operator: '*' */\n MULTIPLY = 6,\n /** Division operator: '/' */\n DIVIDE = 7,\n /** Modulo operator: '%' */\n MODULO = 8,\n /** Power operator: '**' or '^' */\n POWER = 9,\n\n //\n // * Comparison operators\n //\n\n /** Greater than: '>' */\n GREATER = 10,\n /** Greater than or equal: '>=' */\n GREATER_EQUAL = 11,\n /** Less than: '<' */\n LESS = 12,\n /** Less than or equal: '<=' */\n LESS_EQUAL = 13,\n /** Equal: '=' */\n EQUAL = 14,\n\n //\n // * Grouping and punctuation\n //\n\n /** Left parenthesis: '(' */\n LPAREN = 15,\n /** Right parenthesis: ')' */\n RPAREN = 16,\n /** Argument separator: ',' */\n COMMA = 17,\n\n //\n // * Keep/drop modifiers\n //\n\n /** Keep highest modifier: 'kh' or 'k' */\n KEEP_HIGH = 18,\n /** Keep lowest modifier: 'kl' */\n KEEP_LOW = 19,\n /** Drop highest modifier: 'dh' */\n DROP_HIGH = 20,\n /** Drop lowest modifier: 'dl' */\n DROP_LOW = 21,\n\n //\n // * Explode modifiers\n //\n\n /** Standard explode: '!' */\n EXPLODE = 22,\n /** Compounding explode: '!!' */\n EXPLODE_COMPOUND = 23,\n /** Penetrating explode: '!p' */\n EXPLODE_PENETRATING = 24,\n\n //\n // * Reroll modifiers\n //\n\n /** Recursive reroll: 'r' */\n REROLL = 25,\n /** Reroll once: 'ro' */\n REROLL_ONCE = 26,\n\n //\n // * Success counting\n //\n\n /** Fail marker: 'f' */\n FAIL = 27,\n\n //\n // * Functions\n //\n\n /** Math function: 'floor', 'ceil', 'round', 'abs', 'max', 'min' */\n FUNCTION = 28,\n\n //\n // * Keywords\n //\n\n /** Versus operator: 'vs' */\n VS = 29,\n\n //\n // * Group boundaries\n //\n\n /** Left brace: '{' */\n LBRACE = 30,\n /** Right brace: '}' */\n RBRACE = 31,\n\n //\n // * Variables\n //\n\n /** Variable reference prefix: '@' */\n AT = 32,\n\n //\n // * Sort modifiers\n //\n\n /** Ascending sort: 's' or 'sa' */\n SORT_ASC = 33,\n /** Descending sort: 'sd' */\n SORT_DESC = 34,\n\n //\n // * Crit thresholds\n //\n\n /** Critical success threshold: 'cs' */\n CRIT_SUCCESS = 35,\n /** Critical failure threshold: 'cf' */\n CRIT_FAIL = 36,\n\n //\n // * End of input\n //\n\n /** End of input marker */\n EOF = 37,\n}\n\n/**\n * A token produced by the lexer.\n */\nexport type Token = {\n /** The type of this token */\n type: TokenType;\n /** The raw string value from input (lowercased for identifiers) */\n value: string;\n /** Zero-based start offset in the input string (UTF-16 code units) */\n position: number;\n /**\n * Zero-based end offset (exclusive). Not always `position + value.length` —\n * braced variables (`@{name}` stores only `name`) and case-normalized\n * identifiers consume more input than their `value` retains.\n */\n end: number;\n};\n",
7
+ "/**\n * Dice notation lexer with character-by-character scanning.\n *\n * @module lexer/lexer\n */\n\nimport type { RollParserErrorCode } from '../errors.js';\nimport { RollParserError } from '../errors.js';\nimport { type Token, TokenType } from './tokens.js';\n\n/**\n * Error thrown when the lexer encounters an invalid character.\n */\nexport class LexerError extends RollParserError {\n readonly position: number;\n readonly character: string;\n\n constructor(message: string, code: RollParserErrorCode, position: number, character: string) {\n super(`${message} at position ${position}: '${character}'`, code);\n this.name = 'LexerError';\n this.position = position;\n this.character = character;\n }\n}\n\n/** Known identifier keywords mapped to their token types. */\nconst IDENTIFIER_KEYWORDS: Record<string, TokenType> = {\n kh: TokenType.KEEP_HIGH,\n kl: TokenType.KEEP_LOW,\n k: TokenType.KEEP_HIGH,\n dh: TokenType.DROP_HIGH,\n dl: TokenType.DROP_LOW,\n d: TokenType.DICE,\n r: TokenType.REROLL,\n ro: TokenType.REROLL_ONCE,\n f: TokenType.FAIL,\n vs: TokenType.VS,\n floor: TokenType.FUNCTION,\n ceil: TokenType.FUNCTION,\n round: TokenType.FUNCTION,\n abs: TokenType.FUNCTION,\n max: TokenType.FUNCTION,\n min: TokenType.FUNCTION,\n s: TokenType.SORT_ASC,\n sa: TokenType.SORT_ASC,\n sd: TokenType.SORT_DESC,\n cs: TokenType.CRIT_SUCCESS,\n cf: TokenType.CRIT_FAIL,\n};\n\n/**\n * Builds a hint for identifiers that start with a known keyword. Maximal\n * munch merges adjacent modifiers when the first has no count — `4d6khs`\n * lexes as one identifier `khs` instead of `kh` + `s`. Point the user at the\n * explicit-count (or whitespace) split.\n */\nfunction buildIdentifierHint(identifier: string): string {\n for (let length = identifier.length - 1; length >= 1; length--) {\n const prefix = identifier.slice(0, length);\n if (IDENTIFIER_KEYWORDS[prefix] == null) continue;\n const rest = identifier.slice(length);\n return ` (did you mean '${prefix}' followed by '${rest}'? separate modifiers with a count or space, e.g. '${prefix}1${rest}')`;\n }\n return '';\n}\n\n/**\n * Lexer for dice notation.\n *\n * Produces a stream of tokens from an input string using character-by-character\n * scanning with maximal munch for multi-character tokens.\n */\nexport class Lexer {\n private pos = 0;\n private readonly input: string;\n\n constructor(input: string) {\n this.input = input;\n }\n\n /**\n * Tokenize the entire input and return all tokens.\n */\n tokenize(): Token[] {\n const tokens: Token[] = [];\n\n while (true) {\n const token = this.nextToken();\n tokens.push(token);\n if (token.type === TokenType.EOF) break;\n }\n\n return tokens;\n }\n\n /**\n * Get the next token from the input.\n */\n nextToken(): Token {\n this.skipWhitespace();\n\n if (this.isAtEnd()) {\n return this.createToken(TokenType.EOF, '');\n }\n\n const startPos = this.pos;\n const char = this.peek();\n\n // * Numbers\n if (this.isDigit(char)) {\n return this.scanNumber();\n }\n\n // * Identifiers (d, kh, kl, dh, dl, r, ro, f, vs, floor, ceil, ...)\n if (this.isAlpha(char)) {\n return this.scanIdentifier();\n }\n\n // * Variable reference\n if (char === '@') {\n return this.scanAt();\n }\n\n // * Operators and punctuation\n this.advance();\n\n switch (char) {\n case '+':\n return this.createTokenAt(TokenType.PLUS, char, startPos);\n case '-':\n return this.createTokenAt(TokenType.MINUS, char, startPos);\n case '*':\n if (this.match('*')) {\n return this.createTokenAt(TokenType.POWER, '**', startPos);\n }\n return this.createTokenAt(TokenType.MULTIPLY, char, startPos);\n case '/':\n return this.createTokenAt(TokenType.DIVIDE, char, startPos);\n case '%':\n return this.createTokenAt(TokenType.MODULO, char, startPos);\n case '^':\n return this.createTokenAt(TokenType.POWER, char, startPos);\n case '(':\n return this.createTokenAt(TokenType.LPAREN, char, startPos);\n case ')':\n return this.createTokenAt(TokenType.RPAREN, char, startPos);\n case ',':\n return this.createTokenAt(TokenType.COMMA, char, startPos);\n case '{':\n return this.createTokenAt(TokenType.LBRACE, char, startPos);\n case '}':\n return this.createTokenAt(TokenType.RBRACE, char, startPos);\n case '>':\n if (this.match('=')) {\n return this.createTokenAt(TokenType.GREATER_EQUAL, '>=', startPos);\n }\n return this.createTokenAt(TokenType.GREATER, char, startPos);\n case '<':\n if (this.match('=')) {\n return this.createTokenAt(TokenType.LESS_EQUAL, '<=', startPos);\n }\n return this.createTokenAt(TokenType.LESS, char, startPos);\n case '=':\n return this.createTokenAt(TokenType.EQUAL, char, startPos);\n case '!':\n if (this.match('!')) {\n return this.createTokenAt(TokenType.EXPLODE_COMPOUND, '!!', startPos);\n }\n if (!this.isAtEnd() && this.peek().toLowerCase() === 'p') {\n this.advance();\n return this.createTokenAt(TokenType.EXPLODE_PENETRATING, '!p', startPos);\n }\n return this.createTokenAt(TokenType.EXPLODE, char, startPos);\n default: {\n // Surrogate pairs (emoji, astral symbols) span two code units —\n // report the full code point instead of a lone surrogate ('�').\n const codePoint = this.input.codePointAt(startPos);\n const display = codePoint == null ? char : String.fromCodePoint(codePoint);\n throw new LexerError('Unexpected character', 'UNEXPECTED_CHARACTER', startPos, display);\n }\n }\n }\n\n // * Private helpers\n\n private skipWhitespace(): void {\n while (!this.isAtEnd() && this.isWhitespace(this.peek())) {\n this.advance();\n }\n }\n\n private scanNumber(): Token {\n const startPos = this.pos;\n let value = '';\n\n // Integer part\n while (!this.isAtEnd() && this.isDigit(this.peek())) {\n value += this.advance();\n }\n\n // Decimal part\n if (!this.isAtEnd() && this.peek() === '.' && this.isDigit(this.peekNext())) {\n value += this.advance(); // consume '.'\n while (!this.isAtEnd() && this.isDigit(this.peek())) {\n value += this.advance();\n }\n }\n\n return this.createTokenAt(TokenType.NUMBER, value, startPos);\n }\n\n /**\n * Scans an identifier using full-accumulation: collects all consecutive\n * alpha characters, then classifies the result against known keywords.\n *\n * Special cases run before/after the accumulation loop:\n * - `dF` / `Df` / `dF` / `DF` produces DICE_FATE. Must be handled BEFORE\n * the loop because `F` is alpha and would otherwise be greedily merged\n * into identifiers like `dfkh` (from `4dFkh2`) or `dfdf` (from `dFdF`).\n * Reserves the `d[fF]` prefix namespace for Fate dice.\n * - Bare `d` followed by `%` produces DICE_PERCENT. `%` is not alpha so the\n * accumulation loop stops naturally and the post-loop check handles it.\n */\n private scanIdentifier(): Token {\n const startPos = this.pos;\n\n const first = this.peek();\n const second = this.peekNext();\n if ((first === 'd' || first === 'D') && (second === 'f' || second === 'F')) {\n this.advance();\n this.advance();\n return this.createTokenAt(TokenType.DICE_FATE, 'df', startPos);\n }\n\n let value = '';\n\n while (!this.isAtEnd() && this.isAlpha(this.peek())) {\n value += this.advance();\n }\n\n const lower = value.toLowerCase();\n\n if (lower === 'd' && !this.isAtEnd() && this.peek() === '%') {\n this.advance();\n return this.createTokenAt(TokenType.DICE_PERCENT, 'd%', startPos);\n }\n\n const tokenType = IDENTIFIER_KEYWORDS[lower];\n if (tokenType != null) {\n return this.createTokenAt(tokenType, lower, startPos);\n }\n\n throw new LexerError(\n `Unexpected identifier${buildIdentifierHint(lower)}`,\n 'UNEXPECTED_IDENTIFIER',\n startPos,\n lower,\n );\n }\n\n /**\n * Scans a variable reference introduced by `@`.\n *\n * Two forms:\n * - Bare: `@name` where `name` matches `[A-Za-z_][A-Za-z0-9_]*` (case preserved).\n * - Braced: `@{name}` where `name` is any run of printable characters except\n * `}` and newline (permits spaces, hyphens, digits).\n *\n * Case is preserved — distinct from `scanIdentifier`, which lowercases the\n * captured value. The emitted token's `value` is the variable name without\n * the leading `@` or the surrounding braces.\n */\n private scanAt(): Token {\n const startPos = this.pos;\n this.advance(); // consume '@'\n\n let name: string;\n if (!this.isAtEnd() && this.peek() === '{') {\n this.advance(); // consume '{'\n const nameStart = this.pos;\n while (!this.isAtEnd() && this.peek() !== '}' && this.peek() !== '\\n') {\n this.advance();\n }\n if (this.isAtEnd() || this.peek() !== '}') {\n throw new LexerError('Unterminated @{...} variable', 'UNEXPECTED_CHARACTER', startPos, '@');\n }\n name = this.input.slice(nameStart, this.pos);\n this.advance(); // consume '}'\n } else {\n const nameStart = this.pos;\n if (this.isAtEnd() || !this.isIdentifierStart(this.peek())) {\n throw new LexerError('Empty @ variable name', 'UNEXPECTED_CHARACTER', startPos, '@');\n }\n this.advance();\n while (!this.isAtEnd() && this.isIdentifierPart(this.peek())) {\n this.advance();\n }\n name = this.input.slice(nameStart, this.pos);\n }\n\n return this.createTokenAt(TokenType.AT, name, startPos);\n }\n\n private peek(): string {\n return this.input[this.pos] ?? '';\n }\n\n private peekNext(): string {\n return this.input[this.pos + 1] ?? '';\n }\n\n private advance(): string {\n return this.input[this.pos++] ?? '';\n }\n\n private match(expected: string): boolean {\n if (this.isAtEnd()) return false;\n if (this.input[this.pos] !== expected) return false;\n this.pos++;\n return true;\n }\n\n private isAtEnd(): boolean {\n return this.pos >= this.input.length;\n }\n\n private isDigit(char: string): boolean {\n return char >= '0' && char <= '9';\n }\n\n private isAlpha(char: string): boolean {\n const c = char.toLowerCase();\n return c >= 'a' && c <= 'z';\n }\n\n private isIdentifierStart(char: string): boolean {\n return this.isAlpha(char) || char === '_';\n }\n\n private isIdentifierPart(char: string): boolean {\n return this.isAlpha(char) || this.isDigit(char) || char === '_';\n }\n\n private isWhitespace(char: string): boolean {\n return char === ' ' || char === '\\t' || char === '\\n' || char === '\\r';\n }\n\n // ? Both factories run after the token's characters were consumed, so\n // `this.pos` is the exclusive end offset.\n private createToken(type: TokenType, value: string): Token {\n return { type, value, position: this.pos, end: this.pos };\n }\n\n private createTokenAt(type: TokenType, value: string, position: number): Token {\n return { type, value, position, end: this.pos };\n }\n}\n\n/**\n * Tokenize a dice notation string.\n *\n * @param input - The dice notation to tokenize\n * @returns Array of tokens including EOF\n * @throws {LexerError} If an invalid character is encountered\n *\n * @example\n * ```typescript\n * const tokens = lex('2d20+5');\n * // [NUMBER(2), DICE, NUMBER(20), PLUS, NUMBER(5), EOF]\n * ```\n */\nexport function lex(input: string): Token[] {\n return new Lexer(input).tokenize();\n}\n",
8
+ "/**\n * AST node type definitions for the dice notation parser.\n *\n * @module parser/ast\n */\n\nimport type { ComparePoint } from '../types.js';\n\n/**\n * Source span carried by every AST node.\n *\n * `start` is inclusive, `end` exclusive, both in UTF-16 code units into the\n * original notation string. The parser sets both on every node it produces;\n * they are typed optional so hand-constructed ASTs (tests, programmatic\n * consumers) remain valid without positions.\n */\nexport type NodeSpan = {\n start?: number;\n end?: number;\n};\n\n/**\n * Numeric literal node.\n */\nexport type LiteralNode = NodeSpan & {\n type: 'Literal';\n value: number;\n};\n\n/**\n * Dice roll node.\n * Count and sides can be expressions to support computed dice like (1+1)d(3*2).\n */\nexport type DiceNode = NodeSpan & {\n type: 'Dice';\n count: ASTNode;\n sides: ASTNode;\n};\n\n/**\n * Fate/Fudge dice node (`dF`).\n * Each die produces a result in {-1, 0, +1}. No configurable sides.\n */\nexport type FateDiceNode = NodeSpan & {\n type: 'FateDice';\n count: ASTNode;\n};\n\n/**\n * Binary operation node.\n */\nexport type BinaryOpNode = NodeSpan & {\n type: 'BinaryOp';\n operator: '+' | '-' | '*' | '/' | '%' | '**';\n left: ASTNode;\n right: ASTNode;\n};\n\n/**\n * Unary operation node.\n */\nexport type UnaryOpNode = NodeSpan & {\n type: 'UnaryOp';\n operator: '-';\n operand: ASTNode;\n};\n\n/**\n * Keep/drop modifier node.\n * Wraps a dice expression with keep highest/lowest or drop highest/lowest.\n */\nexport type ModifierNode = NodeSpan & {\n type: 'Modifier';\n modifier: 'keep' | 'drop';\n selector: 'highest' | 'lowest';\n count: ASTNode;\n target: ASTNode;\n};\n\n/**\n * Exploding dice node (`!`, `!!`, `!p`, `!>Y`).\n * Wraps a dice expression with a standard, compounding, or penetrating\n * explosion. An absent `threshold` means \"explode on the die's maximum face\".\n */\nexport type ExplodeNode = NodeSpan & {\n type: 'Explode';\n variant: 'standard' | 'compound' | 'penetrating';\n threshold?: ComparePoint;\n target: ASTNode;\n};\n\n/**\n * Reroll node (`r<COND>`, `ro<COND>`).\n * Re-rolls dice that match a comparison condition. `once: true` for `ro`\n * keeps the second result regardless of match; `once: false` for `r`\n * re-rolls recursively until the condition no longer matches.\n */\nexport type RerollNode = NodeSpan & {\n type: 'Reroll';\n once: boolean;\n condition: ComparePoint;\n target: ASTNode;\n};\n\n/**\n * Success counting node (`>=T`, `>T`, `<T`, `<=T`, `=T`, with optional `f=F`).\n *\n * Transforms a dice pool into a success count: each die meeting `threshold`\n * adds +1, each die meeting `failThreshold` subtracts 1. Terminal — a\n * `SuccessCountNode` may not be wrapped by any postfix modifier, binary\n * operator, unary operator, versus operand, or function argument. The\n * `failThreshold` accepts any `CompareOp`; bare `fN` defaults to `operator: '='`.\n */\nexport type SuccessCountNode = NodeSpan & {\n type: 'SuccessCount';\n target: ASTNode;\n threshold: ComparePoint;\n failThreshold?: ComparePoint;\n};\n\n/**\n * Versus node (`<roll> vs <dc>`) — PF2e Degrees of Success.\n *\n * Both sides are full expressions. The `roll` side is evaluated and compared\n * against the `dc` side total, producing a `DegreeOfSuccess` with natural\n * d20 upgrade/downgrade applied when exactly one kept d20 appears on the\n * roll side. Lowest-precedence operator — chaining (`a vs b vs c`) is\n * rejected at parse time; nesting via parens (`a vs (b vs c)`) is rejected\n * at evaluation time.\n */\nexport type VersusNode = NodeSpan & {\n type: 'Versus';\n roll: ASTNode;\n dc: ASTNode;\n};\n\n/**\n * Math function call node (`floor(expr)`, `max(a, b, ...)`, etc.).\n *\n * Supports the fixed-arity functions `floor`, `ceil`, `round`, `abs`, and the\n * variadic functions `max`, `min` (minimum 2 args). Arity is validated at\n * parse time against a static table; by the time the evaluator sees a\n * `FunctionCallNode`, `args.length` is guaranteed to match the function.\n */\nexport type FunctionCallNode = NodeSpan & {\n type: 'FunctionCall';\n name: string;\n args: ASTNode[];\n};\n\n/**\n * Parenthesized group node (`(<expr>)`).\n *\n * Preserves explicit grouping typed by the user so that\n * `RollResult.expression` and `RollResult.rendered` round-trip through\n * `parse` without losing precedence information. Semantically transparent:\n * evaluation returns the inner expression's value unchanged.\n */\nexport type GroupedNode = NodeSpan & {\n type: 'Grouped';\n expression: ASTNode;\n};\n\n/**\n * Variable reference node (`@name` or `@{name with spaces}`).\n *\n * Resolves to a numeric value from the evaluator's `context` map at\n * evaluation time. Names are case-sensitive (`@StrMod` ≠ `@strmod`) — the\n * lexer preserves case in the `AT` token's `value`, distinct from other\n * identifier tokens which lowercase. Leaf node — no LED, never wraps a\n * sub-expression.\n */\nexport type VariableNode = NodeSpan & {\n type: 'Variable';\n name: string;\n};\n\n/**\n * Grouped-roll node (`{expr}`, `{expr1, expr2, ...}`).\n *\n * Distinct from `GroupedNode` (parenthesized wrapper) — a `GroupNode`\n * collects one or more sub-expressions whose evaluation semantics change\n * with the sub-roll count. `expressions.length === 1` is a passthrough\n * (flat-pool when wrapped by keep/drop); `expressions.length >= 2` treats\n * each sub-roll's subtotal as a compound die for keep/drop selection.\n */\nexport type GroupNode = NodeSpan & {\n type: 'Group';\n expressions: ASTNode[];\n};\n\n/**\n * Sort modifier node (`s`, `sa`, `sd`).\n *\n * Cosmetically reorders the dice produced by `target` in ascending or\n * descending order. Purely visual — does not affect `total`,\n * `successes`/`failures`, or any die-level flag (`kept`/`dropped`/\n * `critical`/`fumble`). Dropped dice retain their `dropped` flag and\n * appear in sorted position alongside kept dice.\n */\nexport type SortNode = NodeSpan & {\n type: 'Sort';\n order: 'ascending' | 'descending';\n target: ASTNode;\n};\n\n/**\n * Sentinel for bare `cs` / `cf` without a ComparePoint. Resolved to\n * `result === sides` (for critical) or `result === 1` (for fumble) at\n * evaluation time, using each die's own `sides`.\n */\nexport type CritThreshold = ComparePoint | 'default';\n\n/**\n * Critical threshold modifier node (`cs`, `cf`).\n *\n * Overrides the default `critical`/`fumble` flag logic for the dice\n * produced by `target`. Bare `cs`/`cf` uses the `'default'` sentinel\n * (max face / 1). Custom thresholds accept any ComparePoint. Chaining\n * collapses into a single node — `1d20cs=20cs=1cf>18` has two success\n * and one fail threshold. Display-only: does not change `total`,\n * explosion triggers, or success counting. `cs` and `cf` are independent\n * overrides — a side with no explicit thresholds keeps the default rule\n * (the evaluator substitutes the `'default'` sentinel at apply time).\n */\nexport type CritThresholdNode = NodeSpan & {\n type: 'CritThreshold';\n successThresholds: CritThreshold[];\n failThresholds: CritThreshold[];\n target: ASTNode;\n};\n\n/**\n * Union type of all AST nodes.\n */\nexport type ASTNode =\n | LiteralNode\n | DiceNode\n | FateDiceNode\n | BinaryOpNode\n | UnaryOpNode\n | ModifierNode\n | ExplodeNode\n | RerollNode\n | SuccessCountNode\n | VersusNode\n | FunctionCallNode\n | GroupedNode\n | VariableNode\n | GroupNode\n | SortNode\n | CritThresholdNode;\n\n/**\n * Type guard for LiteralNode.\n */\nexport function isLiteral(node: ASTNode): node is LiteralNode {\n return node.type === 'Literal';\n}\n\n/**\n * Type guard for DiceNode.\n */\nexport function isDice(node: ASTNode): node is DiceNode {\n return node.type === 'Dice';\n}\n\n/**\n * Type guard for FateDiceNode.\n */\nexport function isFateDice(node: ASTNode): node is FateDiceNode {\n return node.type === 'FateDice';\n}\n\n/**\n * Type guard for BinaryOpNode.\n */\nexport function isBinaryOp(node: ASTNode): node is BinaryOpNode {\n return node.type === 'BinaryOp';\n}\n\n/**\n * Type guard for UnaryOpNode.\n */\nexport function isUnaryOp(node: ASTNode): node is UnaryOpNode {\n return node.type === 'UnaryOp';\n}\n\n/**\n * Type guard for ModifierNode.\n */\nexport function isModifier(node: ASTNode): node is ModifierNode {\n return node.type === 'Modifier';\n}\n\n/**\n * Type guard for ExplodeNode.\n */\nexport function isExplode(node: ASTNode): node is ExplodeNode {\n return node.type === 'Explode';\n}\n\n/**\n * Type guard for RerollNode.\n */\nexport function isReroll(node: ASTNode): node is RerollNode {\n return node.type === 'Reroll';\n}\n\n/**\n * Type guard for SuccessCountNode.\n */\nexport function isSuccessCount(node: ASTNode): node is SuccessCountNode {\n return node.type === 'SuccessCount';\n}\n\n/**\n * Type guard for VersusNode.\n */\nexport function isVersus(node: ASTNode): node is VersusNode {\n return node.type === 'Versus';\n}\n\n/**\n * Type guard for FunctionCallNode.\n */\nexport function isFunctionCall(node: ASTNode): node is FunctionCallNode {\n return node.type === 'FunctionCall';\n}\n\n/**\n * Type guard for GroupedNode.\n */\nexport function isGrouped(node: ASTNode): node is GroupedNode {\n return node.type === 'Grouped';\n}\n\n/**\n * Type guard for VariableNode.\n */\nexport function isVariable(node: ASTNode): node is VariableNode {\n return node.type === 'Variable';\n}\n\n/**\n * Type guard for GroupNode.\n */\nexport function isGroup(node: ASTNode): node is GroupNode {\n return node.type === 'Group';\n}\n\n/**\n * Type guard for SortNode.\n */\nexport function isSort(node: ASTNode): node is SortNode {\n return node.type === 'Sort';\n}\n\n/**\n * Type guard for CritThresholdNode.\n */\nexport function isCritThreshold(node: ASTNode): node is CritThresholdNode {\n return node.type === 'CritThreshold';\n}\n\n/**\n * Wrapper kinds that `unwrapTransparent` can peel.\n *\n * \"Transparent\" is relative to the question being asked. `Modifier`/`Sort`/\n * `CritThreshold` are transparent for \"what is the underlying operand?\" when\n * deciding whether to reject a `Group` target — they preserve `containsDicePool`'s\n * answer for whatever they wrap. They are NOT transparent for \"is this a\n * `SuccessCount`?\" or \"is this a `Versus`?\", because the parsers that build\n * those wrappers already reject `SuccessCount`/`Versus` operands upstream.\n */\nexport type TransparentWrapperKind = 'Grouped' | 'Modifier' | 'Sort' | 'CritThreshold';\n\n/**\n * Walks `node` while its `.type` is in `kinds`, returning the first descendant\n * that is not one of the listed wrappers. Each caller picks the subset that\n * matches its rejection semantics — see `TransparentWrapperKind` for guidance.\n *\n * Used by parser reject helpers to look past wrappers when deciding whether\n * an operand violates a rule (e.g., `Group` cannot be the target of `cs`/`cf`,\n * even when wrapped in `Modifier` like `{1d6}kh1cs>5`).\n */\nexport function unwrapTransparent(\n node: ASTNode,\n kinds: readonly TransparentWrapperKind[],\n): ASTNode {\n let current = node;\n while (true) {\n switch (current.type) {\n case 'Grouped':\n if (!kinds.includes('Grouped')) return current;\n current = current.expression;\n break;\n case 'Modifier':\n if (!kinds.includes('Modifier')) return current;\n current = current.target;\n break;\n case 'Sort':\n if (!kinds.includes('Sort')) return current;\n current = current.target;\n break;\n case 'CritThreshold':\n if (!kinds.includes('CritThreshold')) return current;\n current = current.target;\n break;\n default:\n return current;\n }\n }\n}\n\n/**\n * Returns `true` only when `node`'s direct result is a dice pool —\n * `Dice`, `FateDice`, or a chained pool modifier (`Modifier` / `Explode` /\n * `Reroll`). Does NOT recurse through arithmetic wrappers (`BinaryOp`,\n * `UnaryOp`, `FunctionCall`), so `(1d6+5)` and `floor(1d6/2)` are rejected.\n *\n * Used by the parser to reject postfix pool-modifier targets (kh/kl/dh/dl,\n * !/!!/!p, r/ro) that wrap a non-pool expression. Operating on the inner\n * dice pool would silently drop the surrounding arithmetic.\n */\nexport function containsDicePool(node: ASTNode): boolean {\n switch (node.type) {\n case 'Dice':\n case 'FateDice':\n case 'Modifier':\n case 'Explode':\n case 'Reroll':\n return true;\n case 'Sort':\n case 'CritThreshold':\n return containsDicePool(node.target);\n case 'Grouped':\n return containsDicePool(node.expression);\n case 'Group':\n // ? Multi-sub-roll groups (`{a, b, c}kh1`) always accept: keep/drop\n // operates on subtotals, which are \"compound dice\" by definition —\n // even a literal-only `{3, 5, 7}kh1` is valid. Single-sub-roll\n // groups are the user's explicit opt-in to flat-pool semantics, so\n // we deep-walk through arithmetic that a raw `(1d6+5)kh1` would\n // reject. This is the `{}` escape hatch per Stage 3 spec.\n return node.expressions.length >= 2 || node.expressions.some(deepContainsDicePool);\n default:\n return false;\n }\n}\n\n/**\n * Deeper variant of `containsDicePool` that recurses through arithmetic and\n * function wrappers. Used from the `Group` case above (ordinary parenthesized\n * arithmetic `(1d6+5)kh1` must still reject, so the shallow `containsDicePool`\n * handles those directly) and from the Sort parser guard (sort accepts\n * `(1d6+2d8)s` per Stage 3 spec).\n */\nexport function deepContainsDicePool(node: ASTNode): boolean {\n switch (node.type) {\n case 'Dice':\n case 'FateDice':\n return true;\n case 'BinaryOp':\n return deepContainsDicePool(node.left) || deepContainsDicePool(node.right);\n case 'UnaryOp':\n return deepContainsDicePool(node.operand);\n case 'Modifier':\n case 'Explode':\n case 'Reroll':\n case 'SuccessCount':\n case 'Sort':\n case 'CritThreshold':\n return deepContainsDicePool(node.target);\n case 'Versus':\n return deepContainsDicePool(node.roll) || deepContainsDicePool(node.dc);\n case 'FunctionCall':\n return node.args.some(deepContainsDicePool);\n case 'Grouped':\n return deepContainsDicePool(node.expression);\n case 'Group':\n return node.expressions.length >= 2 || node.expressions.some(deepContainsDicePool);\n default:\n return false;\n }\n}\n\n/**\n * Returns `true` if the pool this node resolves to is (or wraps) a `FateDice`\n * pool. Walks through chained pool modifiers (`Modifier` / `Explode` /\n * `Reroll`) but not arithmetic wrappers — callers should run\n * `containsDicePool` first to reject those.\n *\n * Used by the parser to reject `!`, `!!`, `!p` applied to Fate pools\n * (`4dF!`, `(4dF)kh2!`, etc.). Fate explosion semantics are undefined, so\n * parse-time rejection is preferred over a silent evaluator no-op.\n *\n * Inside a `Group`, recursion uses `deepContainsFatePool` to mirror\n * `containsDicePool`'s deep walk through the same case — otherwise\n * `{4dF+1d6}cf` slips past the bare-Fate guard and the default fumble\n * check (`result === 1`) flips `+1` faces into fumbles.\n */\nexport function containsFatePool(node: ASTNode): boolean {\n switch (node.type) {\n case 'FateDice':\n return true;\n case 'Modifier':\n case 'Explode':\n case 'Reroll':\n case 'Sort':\n case 'CritThreshold':\n return containsFatePool(node.target);\n case 'Grouped':\n return containsFatePool(node.expression);\n case 'Group':\n return node.expressions.some(deepContainsFatePool);\n default:\n return false;\n }\n}\n\n/**\n * Deeper variant of `containsFatePool` that recurses through arithmetic and\n * function wrappers. Mirrors `deepContainsDicePool`. Used from\n * `containsFatePool`'s `Group` case so single-sub-roll groups containing\n * arithmetic-wrapped Fate (`{4dF+1d6}cf`) still trip the bare-Fate guard.\n *\n * Outside a `Group`, ordinary parenthesized arithmetic (`(4dF+1d6)cf`) is\n * already rejected upstream by shallow `containsDicePool`, so this helper\n * intentionally stays Group-internal.\n */\nexport function deepContainsFatePool(node: ASTNode): boolean {\n switch (node.type) {\n case 'FateDice':\n return true;\n case 'BinaryOp':\n return deepContainsFatePool(node.left) || deepContainsFatePool(node.right);\n case 'UnaryOp':\n return deepContainsFatePool(node.operand);\n case 'Modifier':\n case 'Explode':\n case 'Reroll':\n case 'SuccessCount':\n case 'Sort':\n case 'CritThreshold':\n return deepContainsFatePool(node.target);\n case 'Versus':\n return deepContainsFatePool(node.roll) || deepContainsFatePool(node.dc);\n case 'FunctionCall':\n return node.args.some(deepContainsFatePool);\n case 'Grouped':\n return deepContainsFatePool(node.expression);\n case 'Group':\n return node.expressions.some(deepContainsFatePool);\n default:\n return false;\n }\n}\n\n/**\n * Deep-walks a node to find any descendant `Group` with two or more\n * sub-expressions. Used by `rejectGroupTarget`'s single-sub-roll\n * passthrough so a multi-sub Group buried under arithmetic\n * (`{{1d6,2d8}+0}cs>5`), function calls (`{abs({1d6,2d8})}cs>5`), or any\n * other non-transparent wrapper still rejects with the same error code.\n *\n * Without this walk, the unwrap inside `rejectGroupTarget` only peels\n * `Grouped`/`Modifier`/`Sort`/`CritThreshold` — a multi-sub Group cloaked\n * in a `BinaryOp`/`UnaryOp`/`FunctionCall` revives issue #97.\n */\nexport function containsMultiSubGroup(node: ASTNode): boolean {\n switch (node.type) {\n case 'Group':\n return node.expressions.length >= 2 || node.expressions.some(containsMultiSubGroup);\n case 'BinaryOp':\n return containsMultiSubGroup(node.left) || containsMultiSubGroup(node.right);\n case 'UnaryOp':\n return containsMultiSubGroup(node.operand);\n case 'Modifier':\n case 'Explode':\n case 'Reroll':\n case 'SuccessCount':\n case 'Sort':\n case 'CritThreshold':\n return containsMultiSubGroup(node.target);\n case 'Versus':\n return containsMultiSubGroup(node.roll) || containsMultiSubGroup(node.dc);\n case 'FunctionCall':\n return node.args.some(containsMultiSubGroup);\n case 'Grouped':\n return containsMultiSubGroup(node.expression);\n default:\n return false;\n }\n}\n\n/**\n * Deep-walks a node to find any descendant `Versus`. Used by\n * `rejectVersusTarget`'s single-sub-roll Group passthrough so a buried\n * Versus (`{1+(1d20 vs 15)}cs>18`, `{abs(1d20 vs 15)}cs>18`,\n * `{-(1d20 vs 15)}kh1`) still rejects with `NESTED_VERSUS` instead of\n * silently dropping `versusMetadata` at the modifier consumer site.\n */\nexport function containsVersus(node: ASTNode): boolean {\n switch (node.type) {\n case 'Versus':\n return true;\n case 'BinaryOp':\n return containsVersus(node.left) || containsVersus(node.right);\n case 'UnaryOp':\n return containsVersus(node.operand);\n case 'Modifier':\n case 'Explode':\n case 'Reroll':\n case 'SuccessCount':\n case 'Sort':\n case 'CritThreshold':\n return containsVersus(node.target);\n case 'FunctionCall':\n return node.args.some(containsVersus);\n case 'Grouped':\n return containsVersus(node.expression);\n case 'Group':\n return node.expressions.some(containsVersus);\n default:\n return false;\n }\n}\n",
9
+ "/**\n * Pratt parser for dice notation.\n *\n * @module parser/parser\n */\n\nimport type { RollParserErrorCode } from '../errors.js';\nimport { RollParserError } from '../errors.js';\nimport { lex } from '../lexer/lexer.js';\nimport { type Token, TokenType } from '../lexer/tokens.js';\nimport type { CompareOp, ComparePoint } from '../types.js';\nimport type {\n ASTNode,\n BinaryOpNode,\n CritThreshold,\n CritThresholdNode,\n DiceNode,\n ExplodeNode,\n FateDiceNode,\n FunctionCallNode,\n GroupedNode,\n GroupNode,\n LiteralNode,\n ModifierNode,\n RerollNode,\n SortNode,\n SuccessCountNode,\n UnaryOpNode,\n VariableNode,\n VersusNode,\n} from './ast.js';\nimport {\n containsDicePool,\n containsFatePool,\n containsMultiSubGroup,\n containsVersus,\n deepContainsDicePool,\n isCritThreshold,\n isSuccessCount,\n unwrapTransparent,\n} from './ast.js';\n\n/**\n * Error thrown when the parser encounters invalid syntax.\n */\nexport class ParseError extends RollParserError {\n readonly position: number;\n readonly token: Token | undefined;\n\n constructor(message: string, code: RollParserErrorCode, position: number, token?: Token) {\n super(`${message} at position ${position}`, code);\n this.name = 'ParseError';\n this.position = position;\n this.token = token ?? undefined;\n }\n}\n\n/**\n * Binding power constants for operators.\n * Higher values bind tighter. Right < Left for right-associativity.\n *\n * Precedence order (lowest to highest):\n * - Versus (`vs`): 2-3 (lowest — full expressions on both sides)\n * - Addition/subtraction: 10\n * - Multiplication/division/modulo: 20\n * - Unary minus: 25 (binds to complete dice expr: -1d4 = -(1d4))\n * - Power: 30-31\n * - Modifiers (postfix): 35 (must be < DICE_RIGHT to bind to complete dice expr)\n * - Dice: 40-41\n */\nconst BP = {\n // Versus (left-associative, lowest precedence — `1d20+10 vs 25+10` = `(1d20+10) vs (25+10)`)\n VS_LEFT: 2,\n VS_RIGHT: 3,\n // Comparison operators used as the success-count LED. Must be below\n // ADD/MUL so `XdY+N>T` parses as `(XdY+N)>T` and fails the pool-target\n // guard with a clear error, instead of the `>` stealing `N` from the `+`.\n COMPARE: 8,\n // Addition/subtraction (left-associative)\n ADD_LEFT: 10,\n ADD_RIGHT: 11,\n // Multiplication/division/modulo (left-associative)\n MUL_LEFT: 20,\n MUL_RIGHT: 21,\n // Unary minus: between mul and power so -1d4 = -(1d4) not (-1)d4\n UNARY: 25,\n // Power (right-associative: left > right)\n POW_LEFT: 31,\n POW_RIGHT: 30,\n // Postfix modifiers: must be < DICE_RIGHT so they bind to complete dice expr\n MODIFIER: 35,\n // Dice operator (highest math precedence)\n DICE_LEFT: 40,\n DICE_RIGHT: 41,\n} as const;\n\n/**\n * Maximum expression nesting depth. Far beyond any human-authored notation —\n * exists so adversarial input like 20,000 nested parens throws a typed\n * `ParseError` instead of an uncaught `RangeError` stack overflow (which\n * would also break the `isRollParserError` contract). Bounding parse depth\n * also bounds AST depth, protecting the recursive AST walkers and evaluator.\n */\nconst MAX_PARSE_DEPTH = 128;\n\n/** Human-readable symbols for tokens named in `expect()` error messages. */\nconst TOKEN_DISPLAY: Partial<Record<TokenType, string>> = {\n [TokenType.LPAREN]: `'('`,\n [TokenType.RPAREN]: `')'`,\n [TokenType.LBRACE]: `'{'`,\n [TokenType.RBRACE]: `'}'`,\n [TokenType.COMMA]: `','`,\n};\n\n/**\n * Arity table for math functions. `min` and `max` are inclusive.\n * `POSITIVE_INFINITY` means unbounded (variadic).\n */\nconst FUNCTION_ARITY: Record<string, { min: number; max: number }> = {\n floor: { min: 1, max: 1 },\n ceil: { min: 1, max: 1 },\n round: { min: 1, max: 1 },\n abs: { min: 1, max: 1 },\n max: { min: 2, max: Number.POSITIVE_INFINITY },\n min: { min: 2, max: Number.POSITIVE_INFINITY },\n};\n\n/**\n * Pratt parser for dice notation.\n *\n * Uses binding power (precedence) to handle operator associativity and\n * precedence without left recursion issues.\n */\nexport class Parser {\n private readonly tokens: Token[];\n private pos = 0;\n private depth = 0;\n\n constructor(tokens: Token[]) {\n this.tokens = tokens;\n }\n\n /**\n * Parse the token stream into an AST.\n */\n parse(): ASTNode {\n if (this.peek().type === TokenType.EOF) {\n throw new ParseError('Unexpected end of input', 'UNEXPECTED_END', this.peek().position);\n }\n\n const ast = this.parseExpression(0);\n\n // Ensure we consumed all tokens\n if (this.peek().type !== TokenType.EOF) {\n const token = this.peek();\n throw new ParseError(\n `Unexpected token '${token.value}'`,\n 'UNEXPECTED_TOKEN',\n token.position,\n token,\n );\n }\n\n return ast;\n }\n\n /**\n * Parse an expression with minimum binding power.\n */\n private parseExpression(minBp: number): ASTNode {\n this.depth += 1;\n if (this.depth > MAX_PARSE_DEPTH) {\n throw new ParseError(\n `Expression nesting exceeds the maximum depth of ${MAX_PARSE_DEPTH}`,\n 'MAX_DEPTH_EXCEEDED',\n this.peek().position,\n this.peek(),\n );\n }\n\n try {\n let left = this.parseNud();\n\n while (this.hasTokens()) {\n const token = this.peek();\n const leftBp = this.getLeftBp(token);\n\n if (leftBp < minBp) break;\n\n this.advance();\n left = this.parseLed(left, token);\n }\n\n return left;\n } finally {\n this.depth -= 1;\n }\n }\n\n /**\n * NUD - Null Denotation.\n * Handles tokens that appear at the start of an expression (prefix position).\n */\n private parseNud(): ASTNode {\n const token = this.advance();\n\n switch (token.type) {\n case TokenType.NUMBER:\n return this.parseLiteral(token);\n\n case TokenType.MINUS:\n return this.parseUnaryMinus(token);\n\n case TokenType.DICE:\n return this.parsePrefixDice(token);\n\n case TokenType.DICE_PERCENT:\n return this.parsePrefixDicePercent(token);\n\n case TokenType.DICE_FATE:\n return this.parsePrefixFateDice(token);\n\n case TokenType.LPAREN:\n return this.parseGrouped(token);\n\n case TokenType.LBRACE:\n return this.parseGroup(token);\n\n case TokenType.FUNCTION:\n return this.parseFunctionCall(token);\n\n case TokenType.AT:\n return this.parseVariable(token);\n\n case TokenType.EOF:\n throw new ParseError('Unexpected end of input', 'UNEXPECTED_END', token.position);\n\n default:\n throw new ParseError(\n `Unexpected token '${token.value}'`,\n 'UNEXPECTED_TOKEN',\n token.position,\n token,\n );\n }\n }\n\n /**\n * LED - Left Denotation.\n * Handles tokens that appear between expressions (infix/postfix position).\n */\n private parseLed(left: ASTNode, token: Token): ASTNode {\n switch (token.type) {\n case TokenType.DICE:\n return this.parseInfixDice(left, token);\n\n case TokenType.DICE_PERCENT:\n return this.parseInfixDicePercent(left, token);\n\n case TokenType.DICE_FATE:\n return this.parseInfixFateDice(left, token);\n\n case TokenType.PLUS:\n case TokenType.MINUS:\n case TokenType.MULTIPLY:\n case TokenType.DIVIDE:\n case TokenType.MODULO:\n case TokenType.POWER:\n return this.parseBinaryOp(left, token);\n\n case TokenType.KEEP_HIGH:\n case TokenType.KEEP_LOW:\n case TokenType.DROP_HIGH:\n case TokenType.DROP_LOW:\n return this.parseModifier(left, token);\n\n case TokenType.EXPLODE:\n case TokenType.EXPLODE_COMPOUND:\n case TokenType.EXPLODE_PENETRATING:\n return this.parseExplode(left, token);\n\n case TokenType.REROLL:\n case TokenType.REROLL_ONCE:\n return this.parseReroll(left, token);\n\n case TokenType.SORT_ASC:\n case TokenType.SORT_DESC:\n return this.parseSort(left, token);\n\n case TokenType.CRIT_SUCCESS:\n case TokenType.CRIT_FAIL:\n return this.parseCritThreshold(left, token);\n\n case TokenType.GREATER:\n case TokenType.GREATER_EQUAL:\n case TokenType.LESS:\n case TokenType.LESS_EQUAL:\n case TokenType.EQUAL:\n return this.parseSuccessCount(left, token);\n\n case TokenType.VS:\n return this.parseVersus(left, token);\n\n default:\n throw new ParseError(\n `Unexpected infix token '${token.value}'`,\n 'UNEXPECTED_TOKEN',\n token.position,\n token,\n );\n }\n }\n\n // * Node parsers\n\n /**\n * Zero-width span for synthetic nodes (implicit counts, `d%` sides) that\n * have no source text of their own — anchored at the governing token.\n */\n private static syntheticLiteral(value: number, token: Token): LiteralNode {\n return { type: 'Literal', value, start: token.position, end: token.position };\n }\n\n private parseLiteral(token: Token): LiteralNode {\n return {\n type: 'Literal',\n value: Number.parseFloat(token.value),\n start: token.position,\n end: token.end,\n };\n }\n\n private parseUnaryMinus(token: Token): UnaryOpNode {\n const operand = this.parseExpression(BP.UNARY);\n this.rejectSuccessCountTarget(operand, token);\n return {\n type: 'UnaryOp',\n operator: '-',\n operand,\n start: token.position,\n end: operand.end ?? token.end,\n };\n }\n\n private parsePrefixDice(token: Token): DiceNode {\n // d20 → Dice(1, 20)\n const sides = this.parseExpression(BP.DICE_RIGHT);\n this.rejectSuccessCountTarget(sides, token);\n this.rejectVersusTarget(sides, token);\n return {\n type: 'Dice',\n count: Parser.syntheticLiteral(1, token),\n sides,\n start: token.position,\n end: sides.end ?? token.end,\n };\n }\n\n private parseInfixDice(left: ASTNode, token: Token): DiceNode {\n // 4d6 → Dice(4, 6)\n this.rejectSuccessCountTarget(left, token);\n this.rejectVersusTarget(left, token);\n this.rejectBareDiceChain(left, token);\n const sides = this.parseExpression(BP.DICE_RIGHT);\n this.rejectSuccessCountTarget(sides, token);\n this.rejectVersusTarget(sides, token);\n return {\n type: 'Dice',\n count: left,\n sides,\n start: left.start ?? token.position,\n end: sides.end ?? token.end,\n };\n }\n\n private parsePrefixDicePercent(token: Token): DiceNode {\n // d% → Dice(1, 100)\n return {\n type: 'Dice',\n count: Parser.syntheticLiteral(1, token),\n sides: Parser.syntheticLiteral(100, token),\n start: token.position,\n end: token.end,\n };\n }\n\n private parseInfixDicePercent(left: ASTNode, token: Token): DiceNode {\n // 2d% → Dice(2, 100)\n this.rejectSuccessCountTarget(left, token);\n this.rejectVersusTarget(left, token);\n this.rejectBareDiceChain(left, token);\n return {\n type: 'Dice',\n count: left,\n sides: Parser.syntheticLiteral(100, token),\n start: left.start ?? token.position,\n end: token.end,\n };\n }\n\n private parsePrefixFateDice(token: Token): FateDiceNode {\n // dF → FateDice(1)\n return {\n type: 'FateDice',\n count: Parser.syntheticLiteral(1, token),\n start: token.position,\n end: token.end,\n };\n }\n\n private parseInfixFateDice(left: ASTNode, token: Token): FateDiceNode {\n // 4dF → FateDice(4). Unlike parseInfixDice, there is no sides sub-parse,\n // so modifiers (`kh`, `dl`, …) naturally bind at the outer Pratt loop\n // without BP competition against a right-operand.\n this.rejectSuccessCountTarget(left, token);\n this.rejectVersusTarget(left, token);\n this.rejectBareDiceChain(left, token);\n return {\n type: 'FateDice',\n count: left,\n start: left.start ?? token.position,\n end: token.end,\n };\n }\n\n private parseGrouped(token: Token): GroupedNode {\n const expression = this.parseExpression(0);\n const close = this.expect(TokenType.RPAREN);\n return { type: 'Grouped', expression, start: token.position, end: close.end };\n }\n\n private parseGroup(startToken: Token): GroupNode {\n // ? `LBRACE`/`RBRACE`/`COMMA` all have `getLeftBp === -1`, so inner\n // `parseExpression(0)` calls terminate at the first `,` or `}` without\n // competing with modifier/arithmetic BPs.\n if (this.peek().type === TokenType.RBRACE) {\n throw new ParseError('Empty group', 'UNEXPECTED_TOKEN', startToken.position, startToken);\n }\n\n const expressions: ASTNode[] = [this.parseExpression(0)];\n while (this.peek().type === TokenType.COMMA) {\n this.advance();\n expressions.push(this.parseExpression(0));\n }\n\n if (this.peek().type !== TokenType.RBRACE) {\n const unterminated = this.peek();\n throw new ParseError(\n `Unterminated group: expected '}' or ','`,\n 'EXPECTED_TOKEN',\n unterminated.position,\n unterminated,\n );\n }\n const close = this.advance();\n\n return { type: 'Group', expressions, start: startToken.position, end: close.end };\n }\n\n private parseVariable(token: Token): VariableNode {\n return { type: 'Variable', name: token.value, start: token.position, end: token.end };\n }\n\n private parseFunctionCall(token: Token): FunctionCallNode {\n // `FUNCTION` has BP = -1 so callers stop here; `COMMA` and `RPAREN` also\n // terminate inner `parseExpression(0)` calls, so argument boundaries are\n // natural.\n this.expect(TokenType.LPAREN);\n\n const args: ASTNode[] = [];\n if (this.peek().type !== TokenType.RPAREN) {\n const first = this.parseExpression(0);\n this.rejectSuccessCountTarget(first, token);\n args.push(first);\n while (this.peek().type === TokenType.COMMA) {\n this.advance();\n const next = this.parseExpression(0);\n this.rejectSuccessCountTarget(next, token);\n args.push(next);\n }\n }\n\n const close = this.expect(TokenType.RPAREN);\n\n const arity = FUNCTION_ARITY[token.value];\n if (arity === undefined) {\n // ? Unreachable in practice: lexer only emits FUNCTION for registered\n // names. Kept defensive to keep parser/evaluator error-code contract\n // symmetrical.\n throw new ParseError(\n `Unknown function '${token.value}'`,\n 'UNKNOWN_FUNCTION',\n token.position,\n token,\n );\n }\n\n if (args.length < arity.min || args.length > arity.max) {\n const expected =\n arity.max === Number.POSITIVE_INFINITY\n ? `at least ${arity.min}`\n : arity.min === arity.max\n ? `${arity.min}`\n : `${arity.min}–${arity.max}`;\n throw new ParseError(\n `Function '${token.value}' expects ${expected} argument${arity.min === 1 && arity.max === 1 ? '' : 's'}, got ${args.length}`,\n 'INVALID_FUNCTION_ARITY',\n token.position,\n token,\n );\n }\n\n return {\n type: 'FunctionCall',\n name: token.value,\n args,\n start: token.position,\n end: close.end,\n };\n }\n\n private parseBinaryOp(left: ASTNode, token: Token): BinaryOpNode {\n this.rejectSuccessCountTarget(left, token);\n\n const operator = this.getOperatorSymbol(token);\n const rightBp = this.getRightBp(token);\n const right = this.parseExpression(rightBp);\n\n this.rejectSuccessCountTarget(right, token);\n\n return {\n type: 'BinaryOp',\n operator,\n left,\n right,\n start: left.start ?? token.position,\n end: right.end ?? token.end,\n };\n }\n\n /**\n * Rejects a dice token whose count operand is itself a bare (unparenthesized)\n * dice expression. `4d6d1` would otherwise silently parse as `(4d6)d1` —\n * roll 4d6, then use the result as a count of d1 dice — which is almost\n * never intended: every major dice dialect reads `4d6d1` as \"drop lowest 1\".\n * Both meanings stay reachable through explicit forms: `4d6dl1` to drop,\n * `(4d6)d1` for nested dice.\n */\n private rejectBareDiceChain(left: ASTNode, token: Token): void {\n switch (left.type) {\n case 'Dice':\n case 'FateDice':\n case 'Explode':\n case 'Reroll':\n case 'Modifier':\n case 'Sort':\n case 'CritThreshold':\n throw new ParseError(\n `Ambiguous dice chain: use 'dl'/'dh' to drop dice (4d6dl1) or parentheses for nested dice ((4d6)d1)`,\n 'AMBIGUOUS_DICE_CHAIN',\n token.position,\n token,\n );\n default:\n return;\n }\n }\n\n private rejectSuccessCountTarget(target: ASTNode, token: Token): void {\n // ? Narrow unwrap: only `Grouped`. A `SuccessCount` cannot live inside\n // `Modifier`/`Sort`/`CritThreshold` because each of those parsers calls\n // this same reject on their target before constructing the wrapper —\n // so widening the set here would never match.\n const node = unwrapTransparent(target, ['Grouped']);\n if (isSuccessCount(node)) {\n throw new ParseError(\n `Cannot apply modifier after success counting`,\n 'INVALID_SUCCESS_COUNT_TARGET',\n token.position,\n token,\n );\n }\n }\n\n /**\n * Rejects `GroupNode` (or a wrapper-cloaked group) as the target of `token`.\n * Explode, reroll, and crit-threshold wrap bare dice pools only — a group\n * is a container of sub-expressions, so these modifiers have no defined\n * semantics. Walks `Grouped`/`Modifier`/`Sort`/`CritThreshold` so wrappers\n * cannot smuggle a group past the check (`{1d6}kh1cs>5`, `({1d6})!`,\n * `{1d6}scs>5` all reject the same as `{1d6}!`/`{1d6}cs>5`).\n *\n * `singleSubRollPasses` opts the caller into the Stage 3 single-sub-roll\n * passthrough rule (STAGE3.md \"Group Semantics: Single vs Multi Sub-Roll\"):\n * a `Group` with one expression is the user's explicit flat-pool escape\n * hatch and is equivalent to its unwrapped form. Currently only\n * `parseCritThreshold` opts in — explode/reroll keep the strict reject so\n * existing notation contracts don't shift.\n */\n private rejectGroupTarget(\n target: ASTNode,\n token: Token,\n action: string,\n code: RollParserErrorCode,\n singleSubRollPasses = false,\n ): void {\n const node = unwrapTransparent(target, ['Grouped', 'Modifier', 'Sort', 'CritThreshold']);\n if (node.type !== 'Group') return;\n if (singleSubRollPasses && node.expressions.length === 1) {\n // ! Deep-walk the inner sub-expression — `unwrapTransparent` only peels\n // `Grouped`/`Modifier`/`Sort`/`CritThreshold`, so a multi-sub Group\n // buried under arithmetic (`{{1d6,2d8}+0}cs>5`), function calls\n // (`{abs({1d6,2d8})}cs>5`), or unary ops would otherwise revive the\n // exact dropped-die-flag bug from #97.\n const inner = node.expressions[0];\n if (inner != null && containsMultiSubGroup(inner)) {\n throw new ParseError(`Cannot ${action} a group`, code, token.position, token);\n }\n return;\n }\n throw new ParseError(`Cannot ${action} a group`, code, token.position, token);\n }\n\n private rejectVersusTarget(target: ASTNode, token: Token): void {\n // ? Versus produces a PF2e degree outcome — a terminal scalar, not a\n // valid input to dice count/sides/thresholds. Symmetric with\n // `rejectSuccessCountTarget`; wrappers like `floor(vs)+0` still\n // propagate `versusMetadata` via `mergeContext`, so this only blocks\n // `mergeMetaRolls` sites where metadata would silently vanish.\n // ? Narrow unwrap: only `Grouped`. `Modifier`/`Sort`/`CritThreshold`\n // cannot wrap a `Versus` because `containsDicePool` does not recurse\n // into `Versus`, so each of those parsers rejects the wrap upstream.\n const node = unwrapTransparent(target, ['Grouped']);\n if (node.type === 'Versus') {\n throw new ParseError(\n `Versus cannot be used as a meta-expression`,\n 'NESTED_VERSUS',\n token.position,\n token,\n );\n }\n // ! Single-sub-roll `Group` passthrough is the new sibling route —\n // `containsDicePool` recurses into Group's single sub-expression via\n // `deepContainsDicePool`, which traverses Versus's `roll`/`dc`. Deep\n // walk for any descendant Versus so `{1d20 vs 15}cs>18`,\n // `{1+(1d20 vs 15)}cs>18`, and `4d6>={abs(1d20 vs 15)}` reject too.\n if (node.type === 'Group' && node.expressions.length === 1) {\n const inner = node.expressions[0];\n if (inner != null && containsVersus(inner)) {\n throw new ParseError(\n `Versus cannot be used as a meta-expression`,\n 'NESTED_VERSUS',\n token.position,\n token,\n );\n }\n }\n }\n\n private parseModifier(target: ASTNode, token: Token): ModifierNode {\n this.rejectSuccessCountTarget(target, token);\n // ! Mirror `parseSort`/`parseCritThreshold` — keep/drop applied to a\n // Versus target silently drops `degree`/`natural` metadata. Pre-existing\n // for `(1d20 vs 15)kh1` (caught upstream by `containsDicePool` with a\n // different error code), but the single-sub-roll Group passthrough makes\n // `{1d20 vs 15}kh1` reachable past `containsDicePool` (Group's deep\n // walk recurses into Versus's roll/dc), so the explicit reject is the\n // only thing that closes the metadata-drop hole.\n this.rejectVersusTarget(target, token);\n\n // Keep/drop modifiers need a dice pool to select from. Wrapping arithmetic\n // (e.g. `(1d6+5)kh1`, `4d6+2kh3`) would silently drop user math.\n if (!containsDicePool(target)) {\n throw new ParseError(\n `Keep/drop modifiers require a dice pool target`,\n 'INVALID_MODIFIER_TARGET',\n token.position,\n token,\n );\n }\n\n const modifier =\n token.type === TokenType.KEEP_HIGH || token.type === TokenType.KEEP_LOW ? 'keep' : 'drop';\n\n const selector =\n token.type === TokenType.KEEP_HIGH || token.type === TokenType.DROP_HIGH\n ? 'highest'\n : 'lowest';\n\n // Default to 1 when no explicit count follows the modifier (e.g., 4d6kh → 4d6kh1)\n const nextToken = this.peek().type;\n const hasExplicitCount =\n nextToken === TokenType.NUMBER ||\n nextToken === TokenType.LPAREN ||\n nextToken === TokenType.AT;\n const count: ASTNode = hasExplicitCount\n ? this.parseExpression(BP.DICE_LEFT)\n : Parser.syntheticLiteral(1, token);\n this.rejectSuccessCountTarget(count, token);\n this.rejectVersusTarget(count, token);\n\n return {\n type: 'Modifier',\n modifier,\n selector,\n count,\n target,\n start: target.start ?? token.position,\n end: hasExplicitCount ? (count.end ?? token.end) : token.end,\n };\n }\n\n private parseExplode(target: ASTNode, token: Token): ExplodeNode {\n this.rejectSuccessCountTarget(target, token);\n\n // Groups have no explode semantics — reject outright. Must come before\n // `containsDicePool`, which recurses into `Group` and would otherwise\n // let `{4d6}!` slip through.\n this.rejectGroupTarget(target, token, 'explode', 'INVALID_EXPLODE_TARGET');\n\n // Explode needs a dice pool to explode on. Wrapping arithmetic (e.g.\n // `(1d6+5)!`, `floor(1d6/2)!`) would silently drop user math.\n if (!containsDicePool(target)) {\n throw new ParseError(\n `Explode modifier requires a dice pool target`,\n 'INVALID_EXPLODE_TARGET',\n token.position,\n token,\n );\n }\n\n // Fate dice (sides = 0) cannot explode — the symmetric -1/0/+1 range has\n // no natural \"max\" trigger, so semantics are undefined. Reject at parse\n // time rather than silently no-op in the evaluator.\n if (containsFatePool(target)) {\n throw new ParseError(\n `Fate dice cannot explode`,\n 'INVALID_EXPLODE_TARGET',\n token.position,\n token,\n );\n }\n\n // ? Reject nested explodes (e.g., `1d6!!!`) — a second explode token atop\n // an ExplodeNode has no meaningful semantics and is rejected per spec.\n if (target.type === 'Explode') {\n throw new ParseError(\n `Cannot chain explode modifiers`,\n 'INVALID_EXPLODE_TARGET',\n token.position,\n token,\n );\n }\n\n const variant: ExplodeNode['variant'] =\n token.type === TokenType.EXPLODE\n ? 'standard'\n : token.type === TokenType.EXPLODE_COMPOUND\n ? 'compound'\n : 'penetrating';\n\n const node: ExplodeNode = {\n type: 'Explode',\n variant,\n target,\n start: target.start ?? token.position,\n end: token.end,\n };\n if (this.isComparePointAhead()) {\n node.threshold = this.parseComparePoint();\n node.end = node.threshold.value.end ?? token.end;\n }\n return node;\n }\n\n private parseReroll(target: ASTNode, token: Token): RerollNode {\n this.rejectSuccessCountTarget(target, token);\n\n // Groups have no reroll semantics — reject outright. Must come before\n // `containsDicePool`, which recurses into `Group`.\n this.rejectGroupTarget(target, token, 'reroll', 'INVALID_REROLL_TARGET');\n\n // Reroll needs a dice pool to inspect. Wrapping arithmetic (e.g.\n // `(1d6+5)r<3`, `floor(1d6/2)ro<3`) would silently drop user math.\n if (!containsDicePool(target)) {\n throw new ParseError(\n `Reroll modifier requires a dice pool target`,\n 'INVALID_REROLL_TARGET',\n token.position,\n token,\n );\n }\n\n // A reroll token must be followed by a comparison — bare `r` / `ro` is invalid.\n if (!this.isComparePointAhead()) {\n throw new ParseError(\n `Expected comparison operator after '${token.value}'`,\n 'EXPECTED_TOKEN',\n token.position,\n token,\n );\n }\n\n const once = token.type === TokenType.REROLL_ONCE;\n const condition = this.parseComparePoint();\n\n return {\n type: 'Reroll',\n once,\n condition,\n target,\n start: target.start ?? token.position,\n end: condition.value.end ?? token.end,\n };\n }\n\n private parseSort(target: ASTNode, token: Token): SortNode {\n this.rejectSuccessCountTarget(target, token);\n this.rejectVersusTarget(target, token);\n\n // Sort is purely visual but still needs a dice pool to reorder —\n // `5s`, `(1+2)s`, or `floor(5)s` have no dice to touch. Uses the deep\n // guard so arithmetic-wrapped pools like `(1d6+2d8)s` are accepted per\n // Stage 3 spec, while pure literals/arithmetic reject.\n if (!deepContainsDicePool(target)) {\n throw new ParseError(\n `Sort modifier requires a dice pool target`,\n 'INVALID_SORT_TARGET',\n token.position,\n token,\n );\n }\n\n // ! Multi-sub-roll groups (`{a, b}s`, `({a, b})s`) need hierarchical\n // sort per Stage 3 spec §3 (sort dice within each sub-roll, then sort\n // sub-rolls by total) — `evalSort` only flat-sorts, so accepting the\n // syntax would silently ship non-spec behaviour. Reject at parse time\n // until the deferred Stage 4 implementation lands. Single-sub Groups\n // keep passing through (the unwrap returns a `Group` with one\n // expression, which is the user's flat-pool escape hatch).\n const base = unwrapTransparent(target, ['Grouped', 'Modifier', 'Sort', 'CritThreshold']);\n if (base.type === 'Group' && base.expressions.length >= 2) {\n throw new ParseError(\n `Sort modifier does not yet support multi-sub-roll groups`,\n 'INVALID_SORT_TARGET',\n token.position,\n token,\n );\n }\n\n const order: SortNode['order'] = token.type === TokenType.SORT_ASC ? 'ascending' : 'descending';\n\n // ? Chained sorts (`4d6ss`, `4d6sasd`) are allowed — sort is idempotent\n // when repeated in the same direction; a later `sd` after `s` just\n // overrides the order since both pass over the same pool.\n return {\n type: 'Sort',\n order,\n target,\n start: target.start ?? token.position,\n end: token.end,\n };\n }\n\n private parseCritThreshold(target: ASTNode, token: Token): CritThresholdNode {\n this.rejectSuccessCountTarget(target, token);\n this.rejectVersusTarget(target, token);\n\n // Multi-sub-roll groups have no crit-threshold semantics per Stage 3 spec\n // — a group there is a container of sub-roll subtotals, not a dice pool,\n // and applying cs/cf would override `critical`/`fumble` on dropped\n // sub-roll dice. Single-sub-roll groups pass through under the documented\n // flat-pool rule (`{1d20}kh1cs>18` ≡ `(1d20)kh1cs>18`). Must run before\n // `containsDicePool`, which recurses into `Group`.\n this.rejectGroupTarget(\n target,\n token,\n 'apply crit threshold to',\n 'INVALID_CRIT_THRESHOLD_TARGET',\n true,\n );\n\n // Shallow dice-pool check (bare dice only) — rejects `(1d6+2d8)cs>5`,\n // `5cs`, `(1+2)cs`, `floor(5)cs`. Matches explode/reroll behavior.\n // Note: if `target` already is a `CritThresholdNode`, `containsDicePool`\n // recurses into its `target`, so chained `cs`/`cf` naturally pass.\n if (!containsDicePool(target)) {\n throw new ParseError(\n `Crit threshold modifier requires a dice pool target`,\n 'INVALID_CRIT_THRESHOLD_TARGET',\n token.position,\n token,\n );\n }\n\n // Bare `cs`/`cf` resolve to a per-die default that assumes max-side / 1\n // semantics — incompatible with Fate dice (`{-1, 0, +1}`), where the bare\n // fumble check would flip the best face (`+1`) into a fumble. Custom\n // thresholds with explicit ComparePoints remain accepted. Mirrors the\n // Fate-explosion rejection above.\n if (!this.isComparePointAhead() && containsFatePool(target)) {\n throw new ParseError(\n `Bare cs/cf cannot apply to Fate dice`,\n 'INVALID_CRIT_THRESHOLD_TARGET',\n token.position,\n token,\n );\n }\n\n const threshold: CritThreshold = this.isComparePointAhead()\n ? this.parseComparePoint()\n : 'default';\n const end = threshold === 'default' ? token.end : (threshold.value.end ?? token.end);\n\n // ? Unwrap parens so `(1d20cs>19)cs=1` chains into the inner node. Without\n // unwrapping, the outer `cs` would create a second CritThresholdNode\n // wrapping the Grouped — the collapse-into-single-node design decision\n // from STAGE3.md §\"CritThreshold Collects Multiple Thresholds\" would\n // be subtly broken for any user who parenthesizes the chain.\n let chainTarget: ASTNode = target;\n while (chainTarget.type === 'Grouped') {\n chainTarget = chainTarget.expression;\n }\n if (isCritThreshold(chainTarget)) {\n if (token.type === TokenType.CRIT_SUCCESS) {\n chainTarget.successThresholds.push(threshold);\n } else {\n chainTarget.failThresholds.push(threshold);\n }\n chainTarget.end = end;\n return chainTarget;\n }\n\n return {\n type: 'CritThreshold',\n successThresholds: token.type === TokenType.CRIT_SUCCESS ? [threshold] : [],\n failThresholds: token.type === TokenType.CRIT_FAIL ? [threshold] : [],\n target,\n start: target.start ?? token.position,\n end,\n };\n }\n\n private parseSuccessCount(target: ASTNode, token: Token): SuccessCountNode {\n // Success counting is terminal: chaining (`>=5>=3`) has no semantics.\n this.rejectSuccessCountTarget(target, token);\n\n // Reject non-pool targets like `1>=3`, `(1+2)>=3`, `(1d6*2)>=10`, or\n // `(1d20 vs 15)>=1`. Success counting operates on a raw dice pool; any\n // arithmetic or composition wrapping would be silently ignored.\n if (!containsDicePool(target)) {\n throw new ParseError(\n `Success counting requires a dice pool target`,\n 'INVALID_SUCCESS_COUNT_TARGET',\n token.position,\n token,\n );\n }\n\n const operator = this.getCompareOp(token);\n // ? Threshold binding: `BP.DICE_LEFT` — see `parseComparePoint` JSDoc.\n const value = this.parseExpression(BP.DICE_LEFT);\n this.rejectSuccessCountTarget(value, token);\n this.rejectVersusTarget(value, token);\n const node: SuccessCountNode = {\n type: 'SuccessCount',\n target,\n threshold: { operator, value },\n start: target.start ?? token.position,\n end: value.end ?? token.end,\n };\n\n if (this.peek().type === TokenType.FAIL) {\n this.advance();\n if (this.isComparePointAhead()) {\n node.failThreshold = this.parseComparePoint();\n } else {\n // ? Same threshold binding as above (BP.DICE_LEFT).\n const failValue = this.parseExpression(BP.DICE_LEFT);\n this.rejectSuccessCountTarget(failValue, token);\n this.rejectVersusTarget(failValue, token);\n node.failThreshold = { operator: '=', value: failValue };\n }\n node.end = node.failThreshold.value.end ?? node.end ?? token.end;\n }\n\n return node;\n }\n\n private parseVersus(left: ASTNode, token: Token): VersusNode {\n this.rejectSuccessCountTarget(left, token);\n\n // ? Chained `a vs b vs c` has no semantics — a degree is a scalar, not a\n // comparable. Unwrap `Grouped` so `(a vs b) vs c` rejects at parse\n // time like the bare form; paren-nested DC (`a vs (b vs c)`) is still\n // caught by the evaluator via `mergeContext`.\n let leftChain: ASTNode = left;\n while (leftChain.type === 'Grouped') {\n leftChain = leftChain.expression;\n }\n if (leftChain.type === 'Versus') {\n throw new ParseError('Cannot chain versus operators', 'NESTED_VERSUS', token.position, token);\n }\n\n const dc = this.parseExpression(BP.VS_RIGHT);\n this.rejectSuccessCountTarget(dc, token);\n\n return {\n type: 'Versus',\n roll: left,\n dc,\n start: left.start ?? token.position,\n end: dc.end ?? token.end,\n };\n }\n\n // * Compare point utilities\n\n /**\n * Checks whether the next token is a comparison operator.\n */\n isComparePointAhead(): boolean {\n const type = this.peek().type;\n return (\n type === TokenType.GREATER ||\n type === TokenType.GREATER_EQUAL ||\n type === TokenType.LESS ||\n type === TokenType.LESS_EQUAL ||\n type === TokenType.EQUAL\n );\n }\n\n /**\n * Parses a comparison operator followed by a value expression.\n * Called by modifier parsers (explode, reroll, success counting).\n *\n * The threshold value is parsed at `BP.DICE_LEFT`, which binds tighter than\n * arithmetic. This keeps the comparison bound to the dice pool on the left\n * rather than letting arithmetic to the right be consumed into the\n * threshold. As a consequence, `1d6>=5+2` parses as `(1d6>=5)+2` with\n * threshold `5` — not `7`. Computed thresholds require parens:\n * `1d6>=(5+2)`. Same binding applies to `parseSuccessCount` below.\n *\n * @returns A ComparePoint with the operator and value AST node\n * @throws {ParseError} If the next token is not a comparison operator\n */\n parseComparePoint(): ComparePoint {\n const token = this.peek();\n const operator = this.getCompareOp(token);\n\n this.advance();\n\n const value = this.parseExpression(BP.DICE_LEFT);\n this.rejectSuccessCountTarget(value, token);\n this.rejectVersusTarget(value, token);\n\n return { operator, value };\n }\n\n private getCompareOp(token: Token): CompareOp {\n switch (token.type) {\n case TokenType.GREATER:\n return '>';\n case TokenType.GREATER_EQUAL:\n return '>=';\n case TokenType.LESS:\n return '<';\n case TokenType.LESS_EQUAL:\n return '<=';\n case TokenType.EQUAL:\n return '=';\n default:\n throw new ParseError(\n `Expected comparison operator but got '${token.value}'`,\n 'EXPECTED_TOKEN',\n token.position,\n token,\n );\n }\n }\n\n // * Helpers\n\n private getOperatorSymbol(token: Token): '+' | '-' | '*' | '/' | '%' | '**' {\n switch (token.type) {\n case TokenType.PLUS:\n return '+';\n case TokenType.MINUS:\n return '-';\n case TokenType.MULTIPLY:\n return '*';\n case TokenType.DIVIDE:\n return '/';\n case TokenType.MODULO:\n return '%';\n case TokenType.POWER:\n return '**';\n default:\n throw new ParseError(\n `Unknown operator '${token.value}'`,\n 'UNEXPECTED_TOKEN',\n token.position,\n token,\n );\n }\n }\n\n private getLeftBp(token: Token): number {\n switch (token.type) {\n case TokenType.VS:\n return BP.VS_LEFT;\n case TokenType.PLUS:\n case TokenType.MINUS:\n return BP.ADD_LEFT;\n case TokenType.MULTIPLY:\n case TokenType.DIVIDE:\n case TokenType.MODULO:\n return BP.MUL_LEFT;\n case TokenType.POWER:\n return BP.POW_LEFT;\n case TokenType.DICE:\n case TokenType.DICE_PERCENT:\n case TokenType.DICE_FATE:\n return BP.DICE_LEFT;\n case TokenType.KEEP_HIGH:\n case TokenType.KEEP_LOW:\n case TokenType.DROP_HIGH:\n case TokenType.DROP_LOW:\n case TokenType.EXPLODE:\n case TokenType.EXPLODE_COMPOUND:\n case TokenType.EXPLODE_PENETRATING:\n case TokenType.REROLL:\n case TokenType.REROLL_ONCE:\n case TokenType.SORT_ASC:\n case TokenType.SORT_DESC:\n case TokenType.CRIT_SUCCESS:\n case TokenType.CRIT_FAIL:\n return BP.MODIFIER;\n // Comparison operators act as LED-dispatched success-count modifiers\n // at the Pratt level. Sit below ADD/MUL so arithmetic on a dice pool\n // completes before success counting wraps it — `5d6+2>4` parses as\n // `(5d6+2)>4` and then cleanly fails the pool-target guard, rather\n // than the `>` stealing `2` from the `+`. Inside `parseComparePoint`\n // (called manually by explode/reroll) this BP is bypassed.\n case TokenType.GREATER:\n case TokenType.GREATER_EQUAL:\n case TokenType.LESS:\n case TokenType.LESS_EQUAL:\n case TokenType.EQUAL:\n return BP.COMPARE;\n case TokenType.RPAREN:\n case TokenType.EOF:\n // Punctuation and keywords that terminate expressions\n case TokenType.COMMA:\n case TokenType.FUNCTION:\n // Group boundaries: `}` closes the current group (consumed inside\n // `parseGroup`), and a stray `{` after a complete expression is an\n // error. Both terminate the outer Pratt loop at -1.\n case TokenType.LBRACE:\n case TokenType.RBRACE:\n return -1;\n default:\n return 0;\n }\n }\n\n private getRightBp(token: Token): number {\n switch (token.type) {\n case TokenType.VS:\n return BP.VS_RIGHT;\n case TokenType.PLUS:\n case TokenType.MINUS:\n return BP.ADD_RIGHT;\n case TokenType.MULTIPLY:\n case TokenType.DIVIDE:\n case TokenType.MODULO:\n return BP.MUL_RIGHT;\n case TokenType.POWER:\n return BP.POW_RIGHT;\n case TokenType.DICE:\n return BP.DICE_RIGHT;\n default:\n return 0;\n }\n }\n\n private peek(): Token {\n return (\n this.tokens[this.pos] ?? { type: TokenType.EOF, value: '', position: this.pos, end: this.pos }\n );\n }\n\n private advance(): Token {\n const token = this.peek();\n this.pos++;\n return token;\n }\n\n private expect(type: TokenType): Token {\n const token = this.peek();\n if (token.type !== type) {\n const expected = TOKEN_DISPLAY[type] ?? TokenType[type];\n const got = token.type === TokenType.EOF ? 'end of input' : `'${token.value}'`;\n throw new ParseError(\n `Expected ${expected} but got ${got}`,\n 'EXPECTED_TOKEN',\n token.position,\n token,\n );\n }\n return this.advance();\n }\n\n private hasTokens(): boolean {\n return this.peek().type !== TokenType.EOF;\n }\n}\n\n/**\n * Parse a dice notation string into an AST.\n *\n * @param notation - The dice notation to parse\n * @returns The root AST node\n * @throws {LexerError} If the input contains invalid characters\n * @throws {ParseError} If the input has invalid syntax\n *\n * @example\n * ```typescript\n * const ast = parse('2d6+3');\n * // { type: 'BinaryOp', operator: '+',\n * // left: { type: 'Dice', count: 2, sides: 6 },\n * // right: { type: 'Literal', value: 3 } }\n * ```\n */\nexport function parse(notation: string): ASTNode {\n const tokens = lex(notation);\n const parser = new Parser(tokens);\n return parser.parse();\n}\n",
10
+ "/**\n * Seedable RNG using xorshift128 algorithm.\n *\n * @module rng/seeded\n */\n\nimport type { RNG } from './types.js';\n\n/**\n * Seedable pseudo-random number generator using xorshift128.\n *\n * Produces reproducible sequences from identical seeds.\n * Period: 2^128 - 1\n *\n * @example\n * ```typescript\n * // Same seed = same sequence\n * const rng1 = new SeededRNG('test-seed');\n * const rng2 = new SeededRNG('test-seed');\n * rng1.nextInt(1, 6) === rng2.nextInt(1, 6); // true\n * ```\n */\nexport class SeededRNG implements RNG {\n private s0: number;\n private s1: number;\n private s2: number;\n private s3: number;\n\n constructor(seed?: string | number) {\n // Initialize state to zero, will be set by initState\n this.s0 = 0;\n this.s1 = 0;\n this.s2 = 0;\n this.s3 = 0;\n\n this.initState(seed);\n\n // Warm-up: discard first 20 values for better initial distribution\n for (let i = 0; i < 20; i++) {\n this.nextUint32();\n }\n }\n\n private initState(seed?: string | number): void {\n const numSeed =\n seed == null\n ? (Date.now() ^ (Math.random() * 0xffffffff)) >>> 0\n : typeof seed === 'string'\n ? this.hashString(seed)\n : seed >>> 0;\n\n // Split seed into 4 state values using splitmix32\n let s = numSeed;\n const state: number[] = [];\n\n for (let i = 0; i < 4; i++) {\n s = (s + 0x9e3779b9) >>> 0;\n let z = s;\n z = Math.imul(z ^ (z >>> 16), 0x85ebca6b) >>> 0;\n z = Math.imul(z ^ (z >>> 13), 0xc2b2ae35) >>> 0;\n state.push((z ^ (z >>> 16)) >>> 0);\n }\n\n this.s0 = state[0] ?? 0;\n this.s1 = state[1] ?? 0;\n this.s2 = state[2] ?? 0;\n this.s3 = state[3] ?? 0;\n\n // Ensure non-zero state (xorshift requires at least one non-zero)\n if (this.s0 === 0 && this.s1 === 0 && this.s2 === 0 && this.s3 === 0) {\n this.s0 = 1;\n }\n }\n\n private hashString(str: string): number {\n // djb2 hash algorithm\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash + str.charCodeAt(i)) >>> 0;\n }\n return hash;\n }\n\n private nextUint32(): number {\n // xorshift128 algorithm\n let t = this.s3;\n const s = this.s0;\n\n this.s3 = this.s2;\n this.s2 = this.s1;\n this.s1 = s;\n\n t ^= t << 11;\n t ^= t >>> 8;\n this.s0 = (t ^ s ^ (s >>> 19)) >>> 0;\n\n return this.s0;\n }\n\n next(): number {\n // Convert uint32 to [0, 1) float\n return this.nextUint32() / 0x100000000;\n }\n\n nextInt(min: number, max: number): number {\n // Handle inverted bounds\n const lo = min > max ? max : min;\n const hi = min > max ? min : max;\n\n const range = hi - lo + 1;\n\n // Single value case\n if (range <= 1) {\n return lo;\n }\n\n // Ranges wider than 2^32 need two draws — a single uint32 can never\n // produce the upper part of the range and would silently truncate it.\n if (range > 0x100000000) {\n return lo + this.nextBoundedWide(range);\n }\n\n // Rejection sampling for unbiased distribution\n // Avoids modulo bias by rejecting values that would cause uneven distribution\n const threshold = (0x100000000 - range) % range;\n let value: number;\n do {\n value = this.nextUint32();\n } while (value < threshold);\n\n return lo + (value % range);\n }\n\n /**\n * Unbiased sampling in `[0, range)` for ranges above 2^32, built from two\n * uint32 draws combined into a 53-bit integer (the largest width JS numbers\n * represent exactly). Ranges beyond 2^53 cannot be sampled without bias —\n * throw instead of silently degrading.\n */\n private nextBoundedWide(range: number): number {\n const MAX_53 = 2 ** 53;\n if (range > MAX_53) {\n throw new RangeError(`nextInt range ${range} exceeds 2^53 and cannot be sampled exactly`);\n }\n\n // Largest multiple of `range` below 2^53 — values at or above it are\n // rejected to avoid modulo bias.\n const limit = Math.floor(MAX_53 / range) * range;\n let value: number;\n do {\n // 32 high bits shifted up by 21 + top 21 bits of a second draw = 53 bits.\n value = this.nextUint32() * 0x200000 + (this.nextUint32() >>> 11);\n } while (value >= limit);\n\n return value % range;\n }\n}\n",
11
+ "/**\n * Shared type definitions for roll results and comparison primitives.\n *\n * @module types\n */\n\nimport type { ASTNode } from './parser/ast.js';\n\n/**\n * Comparison operator for compare points.\n */\nexport type CompareOp = '>' | '>=' | '<' | '<=' | '=';\n\n/**\n * A comparison threshold used by exploding dice, reroll, and success counting.\n *\n * The value is an ASTNode to support computed thresholds (e.g., `>=ceil(5)`),\n * matching the pattern used by DiceNode.count and DiceNode.sides.\n */\nexport type ComparePoint = {\n operator: CompareOp;\n value: ASTNode;\n};\n\n/**\n * A ComparePoint whose value has been evaluated to a number. Used in\n * `RollPart` where meta-expressions are already resolved.\n */\nexport type ResolvedComparePoint = {\n operator: CompareOp;\n value: number;\n};\n\n/**\n * A resolved crit threshold — `'default'` means the per-die default rule\n * (`result === sides` for critical, `result === 1` for fumble).\n */\nexport type ResolvedCritThreshold = ResolvedComparePoint | 'default';\n\n/**\n * Modifier flags applied to individual die results.\n */\nexport type DieModifier =\n | 'dropped'\n | 'kept'\n | 'exploded'\n | 'rerolled'\n | 'success'\n | 'failure'\n | 'meta';\n\n/**\n * PF2e Degree of Success. Produced by the `vs` operator when comparing a\n * roll against a Difficulty Class. Ordering is significant — natural 20\n * upgrades one step and natural 1 downgrades one step.\n */\nexport enum DegreeOfSuccess {\n CriticalFailure = 0,\n Failure = 1,\n Success = 2,\n CriticalSuccess = 3,\n}\n\n/**\n * Individual die roll result with metadata.\n */\nexport type DieResult = {\n /**\n * Number of sides on the die. Normal dice use `sides >= 1`. Fate/Fudge\n * dice use `sides = 0` as a sentinel — they have no configurable sides\n * and always produce results in {-1, 0, +1}.\n */\n sides: number;\n /** The rolled value */\n result: number;\n /**\n * Raw first roll before any mutation (e.g., compound-explode accumulation).\n * Only populated when `result` has been overwritten with a computed value.\n * Consumers that need the original face (nat-20 / nat-1 detection) should\n * read `initialResult ?? result`.\n */\n initialResult?: number;\n /** Modifiers applied to this die */\n modifiers: DieModifier[];\n /** True if rolled the maximum value (always false for Fate dice) */\n critical: boolean;\n /** True if rolled 1 (always false for Fate dice) */\n fumble: boolean;\n};\n\n/**\n * Per-spec keep/drop entry inside a flattened modifier chain. Counts are\n * resolved at evaluation time (meta-expressions like `kh(1d2)` become the\n * rolled number).\n */\nexport type ModifierSpec = {\n kind: 'keep' | 'drop';\n selector: 'highest' | 'lowest';\n count: number;\n};\n\n/**\n * Fields shared by every RollPart variant. `start`/`end` mirror the source\n * span of the AST node the part was evaluated from — present whenever the\n * AST came from `parse()`, absent on hand-built ASTs.\n */\ntype RollPartBase = {\n /** Sub-total this part contributed to its parent. */\n total: number;\n start?: number;\n end?: number;\n};\n\n/**\n * Structured breakdown of an evaluated expression, mirroring the AST 1:1 —\n * every ASTNode produces exactly one RollPart. Discriminants are lowercase\n * camelCase to distinguish evaluation-tree types from `ASTNode.type`\n * (PascalCase) at a glance.\n *\n * Invariants:\n * - `RollResult.parts.total === RollResult.total`.\n * - `successCount.total === successes - failures`.\n * - `literal.total === value` and `variable.total === value`.\n * - Each part's `rolls[]` shares `DieResult` references with\n * `RollResult.rolls[]`; both reflect post-evaluation state (explode\n * accumulation, reroll flags, keep/drop flags). No deep clone.\n *\n * Meta-expression sub-trees (`4d6kh(1d2)`, `(1+1)d6` counts/sides, computed\n * thresholds) are not surfaced as nested parts — their resolved numbers\n * appear in the owning part, and their dice are inspectable in\n * `RollResult.rolls` via the `'meta'` modifier tag.\n */\nexport type RollPart =\n | (RollPartBase & { type: 'literal'; value: number })\n | (RollPartBase & { type: 'variable'; name: string; value: number })\n | (RollPartBase & { type: 'dice'; count: number; sides: number; rolls: DieResult[] })\n | (RollPartBase & { type: 'fateDice'; count: number; rolls: DieResult[] })\n | (RollPartBase & { type: 'grouped'; inner: RollPart })\n | (RollPartBase & {\n type: 'binaryOp';\n operator: '+' | '-' | '*' | '/' | '%' | '**';\n left: RollPart;\n right: RollPart;\n })\n | (RollPartBase & { type: 'unaryOp'; operator: '-'; operand: RollPart })\n | (RollPartBase & { type: 'modifier'; specs: ModifierSpec[]; target: RollPart })\n | (RollPartBase & {\n type: 'explode';\n variant: 'standard' | 'compound' | 'penetrating';\n threshold?: ResolvedComparePoint;\n target: RollPart;\n })\n | (RollPartBase & {\n type: 'reroll';\n once: boolean;\n condition: ResolvedComparePoint;\n target: RollPart;\n })\n | (RollPartBase & {\n type: 'successCount';\n threshold: ResolvedComparePoint;\n failThreshold?: ResolvedComparePoint;\n target: RollPart;\n successes: number;\n failures: number;\n })\n | (RollPartBase & { type: 'versus'; roll: RollPart; dc: RollPart; degree: DegreeOfSuccess })\n | (RollPartBase & { type: 'functionCall'; name: string; args: RollPart[] })\n | (RollPartBase & { type: 'group'; parts: RollPart[]; keptIndices?: number[] })\n | (RollPartBase & { type: 'sort'; order: 'ascending' | 'descending'; target: RollPart })\n | (RollPartBase & {\n type: 'critThreshold';\n successThresholds: ResolvedCritThreshold[];\n failThresholds: ResolvedCritThreshold[];\n target: RollPart;\n });\n\n/** Convenience alias for consumers writing exhaustive switches. */\nexport type RollPartType = RollPart['type'];\n\n/**\n * Complete roll result with all metadata.\n */\nexport type RollResult = {\n /** Final computed total */\n total: number;\n /** Original input notation */\n notation: string;\n /** Normalized expression */\n expression: string;\n /** Rendered result with individual rolls shown */\n rendered: string;\n /** All individual die results */\n rolls: DieResult[];\n /** Structured breakdown of the evaluated expression, mirroring the AST 1:1. */\n parts: RollPart;\n /**\n * Number of dice tagged as success across the whole expression. Present\n * only when a success-counting modifier was used. Independent of `total` —\n * arithmetic on top of a success count (e.g. `5d6>=5 * 2`) affects `total`\n * but not `successes`.\n */\n successes?: number;\n /**\n * Number of dice tagged as failure across the whole expression. Present\n * only when a success-counting modifier with a fail threshold was used.\n */\n failures?: number;\n /**\n * PF2e Degree of Success. Present only when the expression used the `vs`\n * operator at the top level (e.g. `1d20+10 vs 25`).\n */\n degree?: DegreeOfSuccess;\n /**\n * Natural d20 value used for PF2e upgrade/downgrade — present only when\n * exactly one kept d20 was rolled on the roll side of a `vs` expression.\n */\n natural?: number;\n};\n\n/**\n * Options for the evaluate function.\n */\nexport type EvaluateOptions = {\n /** Original notation string (for result metadata) */\n notation?: string;\n /** Maximum total dice allowed per evaluation (default: 10,000) */\n maxDice?: number;\n /** Maximum explosion iterations allowed per die (default: 1,000) */\n maxExplodeIterations?: number;\n /** Maximum reroll iterations allowed per die (default: 1,000) */\n maxRerollIterations?: number;\n /** Variable context for `@name` / `@{name}` references (default: empty) */\n context?: Record<string, number>;\n /** Behavior when a referenced variable is missing from context (default: 'throw') */\n onMissingVariable?: 'throw' | 'zero';\n};\n",
12
+ "/**\n * Shared comparison helper for dice-pool modifiers.\n *\n * Both reroll and success-counting modifiers compare a die result against a\n * fixed threshold. Extracting the comparison keeps those modules free of\n * duplicated logic.\n *\n * @module evaluator/modifiers/compare\n */\n\nimport type { CompareOp } from '../../types.js';\n\n/**\n * Compares a die result against a fixed comparison threshold.\n */\nexport function matchesCondition(result: number, operator: CompareOp, value: number): boolean {\n switch (operator) {\n case '>':\n return result > value;\n case '>=':\n return result >= value;\n case '<':\n return result < value;\n case '<=':\n return result <= value;\n case '=':\n return result === value;\n }\n}\n",
13
+ "/**\n * Critical / fumble threshold modifier.\n *\n * Overrides the default `critical`/`fumble` flag logic for a dice pool.\n * `cs` and `cf` are independent (Roll20 semantics): the evaluator passes\n * `['default']` for a side with no explicit thresholds, so overriding one\n * side never wipes the other. An empty threshold array (not produced by the\n * evaluator) would force the corresponding flag to `false` on every die.\n * Meta dice (rolled to compute counts/sides/modifier args) are skipped so\n * their bookkeeping stays untouched.\n *\n * Display-only: does not alter `total`, explosion triggers, success\n * counting, or any other modifier flag. Dropped dice still participate —\n * their `critical`/`fumble` metadata reflects what they rolled, not\n * whether they contributed to the total.\n *\n * @module evaluator/modifiers/crit-threshold\n */\n\nimport type { DieResult, ResolvedCritThreshold } from '../../types.js';\nimport { matchesCondition } from './compare.js';\n\n// ? Re-exported for existing importers — the definition moved to types.ts so\n// the public RollPart union can reference it without a circular import.\nexport type { ResolvedCritThreshold } from '../../types.js';\n\n/**\n * Applies success/fail threshold arrays to a dice pool, overriding each\n * die's `critical` and `fumble` flags in place. A die matches `'default'`\n * on the success side when `result === sides && sides > 1`, and on the\n * fail side when `result === 1`. Meta dice are skipped.\n */\nexport function applyCritThresholds(\n dice: DieResult[],\n successThresholds: ResolvedCritThreshold[],\n failThresholds: ResolvedCritThreshold[],\n): void {\n for (const die of dice) {\n if (die.modifiers.includes('meta')) continue;\n\n die.critical = successThresholds.some((t) => matchesCrit(t, die));\n die.fumble = failThresholds.some((t) => matchesFumble(t, die));\n }\n}\n\nfunction matchesCrit(threshold: ResolvedCritThreshold, die: DieResult): boolean {\n if (threshold === 'default') {\n return die.result === die.sides && die.sides > 1;\n }\n return matchesCondition(die.result, threshold.operator, threshold.value);\n}\n\nfunction matchesFumble(threshold: ResolvedCritThreshold, die: DieResult): boolean {\n if (threshold === 'default') {\n // ? Mirrors `createDieResult` — a d1 always rolls 1, never a fumble.\n return die.result === 1 && die.sides > 1;\n }\n return matchesCondition(die.result, threshold.operator, threshold.value);\n}\n",
14
+ "/**\n * Exploding dice modifier implementations.\n *\n * Standard (`!`): re-roll on match, append each new die to the pool.\n * Compound (`!!`): re-roll on match, accumulate into the original die's `result`.\n * Penetrating (`!p`): re-roll on match, append with `result = rawRoll - 1`.\n *\n * @module evaluator/modifiers/explode\n */\n\nimport type { RNG } from '../../rng/types.js';\nimport type { CompareOp } from '../../types.js';\nimport type { DieResult } from '../../types.js';\nimport { EvaluatorError, type EvalEnv } from '../evaluator.js';\n\n/** Default maximum explosion iterations per die. */\nexport const DEFAULT_MAX_EXPLODE_ITERATIONS = 1_000;\n\n/**\n * Predicate deciding whether a die with the given latest raw roll continues\n * to explode. `sides` is passed separately because the default predicate\n * (\"explode on max face\") uses `result === sides`.\n */\nexport type ShouldExplode = (rawResult: number, sides: number) => boolean;\n\n/**\n * Builds an explosion predicate from an optional ComparePoint. When no\n * threshold is given, explode when the raw result equals the die's max face.\n */\nexport function buildShouldExplode(\n operator: CompareOp | undefined,\n thresholdValue: number | undefined,\n): ShouldExplode {\n if (operator == null || thresholdValue == null) {\n return (result, sides) => result === sides;\n }\n switch (operator) {\n case '>':\n return (result) => result > thresholdValue;\n case '>=':\n return (result) => result >= thresholdValue;\n case '<':\n return (result) => result < thresholdValue;\n case '<=':\n return (result) => result <= thresholdValue;\n case '=':\n return (result) => result === thresholdValue;\n }\n}\n\n/**\n * Rolls one explosion die, charging it against the global dice limit.\n */\nfunction rollExplosion(sides: number, rng: RNG, env: EvalEnv): number {\n if (env.totalDiceRolled + 1 > env.maxDice) {\n throw new EvaluatorError(\n `Total dice count ${env.totalDiceRolled + 1} exceeds limit of ${env.maxDice}`,\n 'DICE_LIMIT_EXCEEDED',\n 'Explode',\n );\n }\n env.totalDiceRolled += 1;\n return rng.nextInt(1, sides);\n}\n\nfunction explodeLimitError(maxIterations: number): EvaluatorError {\n return new EvaluatorError(\n `Explode iteration limit of ${maxIterations} exceeded`,\n 'EXPLODE_LIMIT_EXCEEDED',\n 'Explode',\n );\n}\n\n/**\n * Returns true when the die is eligible to start exploding: it must not\n * already be dropped by a prior modifier, and its `sides` must be rollable.\n *\n * The `sides < 1` branch is a defense-in-depth fallback — Fate dice\n * (sides = 0) are rejected at parse time via `INVALID_EXPLODE_TARGET`\n * (see `parseExplode` in `src/parser/parser.ts`), so this guard should\n * never fire during normal flow. Keeping it ensures `rng.nextInt(1, 0)`\n * can never be reached if a future AST path slips past the parser gate.\n */\nfunction canExplode(die: DieResult): boolean {\n if (die.modifiers.includes('dropped')) return false;\n if (die.sides < 1) return false;\n return true;\n}\n\n/**\n * Standard explode: append each new die to the pool. The original die keeps\n * its modifiers untouched; new dice carry `['exploded', 'kept']`.\n */\nexport function applyStandardExplode(\n pool: DieResult[],\n shouldExplode: ShouldExplode,\n rng: RNG,\n env: EvalEnv,\n): DieResult[] {\n const result: DieResult[] = [];\n\n for (const original of pool) {\n result.push(original);\n if (!canExplode(original)) continue;\n\n const sides = original.sides;\n let last = original.result;\n let iterations = 0;\n\n while (shouldExplode(last, sides)) {\n if (iterations >= env.maxExplodeIterations) {\n throw explodeLimitError(env.maxExplodeIterations);\n }\n const next = rollExplosion(sides, rng, env);\n result.push({\n sides,\n result: next,\n modifiers: ['exploded', 'kept'],\n critical: next === sides && sides > 1,\n fumble: next === 1 && sides > 1,\n });\n last = next;\n iterations += 1;\n }\n }\n\n return result;\n}\n\n/**\n * Compound explode: pool length stays the same. Each original die's `result`\n * accumulates every explosion roll, and gains the `'exploded'` modifier once\n * it actually exploded at least once.\n *\n * Mutates exploded dice in place — the same `DieResult` objects are shared\n * between `RollResult.rolls` and the `RollPart` tree, and both must reflect\n * post-explosion state.\n */\nexport function applyCompoundExplode(\n pool: DieResult[],\n shouldExplode: ShouldExplode,\n rng: RNG,\n env: EvalEnv,\n): DieResult[] {\n for (const original of pool) {\n if (!canExplode(original)) continue;\n\n const sides = original.sides;\n let accumulated = original.result;\n let last = original.result;\n let iterations = 0;\n let exploded = false;\n\n while (shouldExplode(last, sides)) {\n if (iterations >= env.maxExplodeIterations) {\n throw explodeLimitError(env.maxExplodeIterations);\n }\n const next = rollExplosion(sides, rng, env);\n accumulated += next;\n last = next;\n exploded = true;\n iterations += 1;\n }\n\n if (!exploded) continue;\n\n // ? `critical` and `fumble` keep referring to the original triggering\n // roll — after compounding the `result` is a sum.\n original.initialResult = original.result;\n original.result = accumulated;\n if (!original.modifiers.includes('exploded')) {\n original.modifiers = [...original.modifiers, 'exploded'];\n }\n }\n\n return pool;\n}\n\n/**\n * Penetrating explode: like standard, but each appended die stores\n * `result = rawRoll - 1`. The explosion predicate runs on the RAW roll\n * (pre-decrement), matching rpg-dice-roller convention.\n */\nexport function applyPenetratingExplode(\n pool: DieResult[],\n shouldExplode: ShouldExplode,\n rng: RNG,\n env: EvalEnv,\n): DieResult[] {\n const result: DieResult[] = [];\n\n for (const original of pool) {\n result.push(original);\n if (!canExplode(original)) continue;\n\n const sides = original.sides;\n let lastRaw = original.result;\n let iterations = 0;\n\n while (shouldExplode(lastRaw, sides)) {\n if (iterations >= env.maxExplodeIterations) {\n throw explodeLimitError(env.maxExplodeIterations);\n }\n const raw = rollExplosion(sides, rng, env);\n const stored = raw - 1;\n result.push({\n sides,\n result: stored,\n modifiers: ['exploded', 'kept'],\n critical: raw === sides && sides > 1,\n fumble: raw === 1 && sides > 1,\n });\n lastRaw = raw;\n iterations += 1;\n }\n }\n\n return result;\n}\n",
15
+ "/**\n * Keep/drop modifier implementations for dice pools.\n *\n * @module evaluator/modifiers/keep-drop\n */\n\nimport type { DieResult } from '../../types.js';\n\n/**\n * Marks all eligible dice as `'kept'`. Dice that already carry `'dropped'`\n * (e.g., intermediate rerolls, or the loser of a prior modifier) are left\n * untouched so those drops cannot be silently revived.\n */\nexport function markAllKept(dice: DieResult[]): DieResult[] {\n return dice.map((die) => {\n if (die.modifiers.includes('dropped')) return die;\n return {\n ...die,\n modifiers: die.modifiers.includes('kept') ? die.modifiers : [...die.modifiers, 'kept'],\n };\n });\n}\n\n/**\n * Returns indexed dice that are eligible for keep/drop selection — dice that\n * have not already been dropped by a preceding modifier (e.g. reroll's\n * intermediate dice carry `'dropped'` and must be ignored here).\n */\nfunction eligibleIndexed(dice: DieResult[]): { die: DieResult; index: number }[] {\n return dice\n .map((die, index) => ({ die, index }))\n .filter(({ die }) => !die.modifiers.includes('dropped'));\n}\n\n/**\n * Rebuilds a die's slot flags (`kept` / `dropped`) from the selection set.\n * Pre-dropped dice are returned unchanged so their state is preserved.\n */\nfunction applySelection(\n dice: DieResult[],\n selectionIndices: Set<number>,\n selectionMarker: 'kept' | 'dropped',\n): DieResult[] {\n const otherMarker = selectionMarker === 'kept' ? 'dropped' : 'kept';\n\n return dice.map((die, index) => {\n if (die.modifiers.includes('dropped')) return die;\n\n const isSelected = selectionIndices.has(index);\n const marker = isSelected ? selectionMarker : otherMarker;\n\n return {\n ...die,\n modifiers: [...die.modifiers.filter((m) => m !== 'kept' && m !== 'dropped'), marker],\n };\n });\n}\n\n/**\n * Drops every non-already-dropped die. Used by keep-N when N <= 0 and by\n * drop-N when N >= eligible.length.\n */\nfunction markAllDropped(dice: DieResult[]): DieResult[] {\n return dice.map((die) => {\n if (die.modifiers.includes('dropped')) return die;\n return {\n ...die,\n modifiers: [...die.modifiers.filter((m) => m !== 'kept'), 'dropped'],\n };\n });\n}\n\n/**\n * Applies keep highest modifier - keeps the N highest eligible dice, marks\n * others as dropped. Dice already marked `'dropped'` are left unchanged.\n *\n * @param dice - Array of die results\n * @param count - Number of dice to keep\n * @returns New array with appropriate modifiers applied\n */\nexport function applyKeepHighest(dice: DieResult[], count: number): DieResult[] {\n const eligible = eligibleIndexed(dice);\n\n if (count >= eligible.length) return markAllKept(dice);\n if (count <= 0) return markAllDropped(dice);\n\n const sorted = [...eligible].sort((a, b) => b.die.result - a.die.result);\n const keptIndices = new Set(sorted.slice(0, count).map((item) => item.index));\n\n return applySelection(dice, keptIndices, 'kept');\n}\n\n/**\n * Applies keep lowest modifier - keeps the N lowest eligible dice, marks\n * others as dropped. Dice already marked `'dropped'` are left unchanged.\n */\nexport function applyKeepLowest(dice: DieResult[], count: number): DieResult[] {\n const eligible = eligibleIndexed(dice);\n\n if (count >= eligible.length) return markAllKept(dice);\n if (count <= 0) return markAllDropped(dice);\n\n const sorted = [...eligible].sort((a, b) => a.die.result - b.die.result);\n const keptIndices = new Set(sorted.slice(0, count).map((item) => item.index));\n\n return applySelection(dice, keptIndices, 'kept');\n}\n\n/**\n * Applies drop highest modifier - drops the N highest eligible dice, keeps\n * the rest. Dice already marked `'dropped'` are left unchanged.\n */\nexport function applyDropHighest(dice: DieResult[], count: number): DieResult[] {\n const eligible = eligibleIndexed(dice);\n\n if (count <= 0) return markAllKept(dice);\n if (count >= eligible.length) return markAllDropped(dice);\n\n const sorted = [...eligible].sort((a, b) => b.die.result - a.die.result);\n const droppedIndices = new Set(sorted.slice(0, count).map((item) => item.index));\n\n return applySelection(dice, droppedIndices, 'dropped');\n}\n\n/**\n * Applies drop lowest modifier - drops the N lowest eligible dice, keeps\n * the rest. Dice already marked `'dropped'` are left unchanged.\n */\nexport function applyDropLowest(dice: DieResult[], count: number): DieResult[] {\n const eligible = eligibleIndexed(dice);\n\n if (count <= 0) return markAllKept(dice);\n if (count >= eligible.length) return markAllDropped(dice);\n\n const sorted = [...eligible].sort((a, b) => a.die.result - b.die.result);\n const droppedIndices = new Set(sorted.slice(0, count).map((item) => item.index));\n\n return applySelection(dice, droppedIndices, 'dropped');\n}\n\n/**\n * Calculates total from dice, excluding dropped dice.\n *\n * @param dice - Array of die results\n * @returns Sum of non-dropped dice\n */\nexport function sumKeptDice(dice: DieResult[]): number {\n return dice\n .filter((die) => !die.modifiers.includes('dropped'))\n .reduce((sum, die) => sum + die.result, 0);\n}\n",
16
+ "/**\n * Reroll modifier implementations.\n *\n * Recursive (`r`): re-roll matching dice until the condition no longer holds,\n * or the per-die iteration limit is reached.\n * Reroll-once (`ro`): re-roll matching dice exactly once, keeping the second\n * result regardless of whether it matches.\n *\n * @module evaluator/modifiers/reroll\n */\n\nimport type { RNG } from '../../rng/types.js';\nimport type { CompareOp, DieResult } from '../../types.js';\nimport { EvaluatorError, type EvalEnv } from '../evaluator.js';\nimport { matchesCondition } from './compare.js';\n\n/** Default maximum reroll iterations per die. */\nexport const DEFAULT_MAX_REROLL_ITERATIONS = 1_000;\n\nexport { matchesCondition };\n\n/**\n * Rolls a replacement die for the given sides, charging it against the global\n * dice limit. Fate dice (sides === 0) re-roll on the {-1, 0, +1} range.\n */\nfunction rollReplacement(sides: number, rng: RNG, env: EvalEnv): DieResult {\n if (env.totalDiceRolled + 1 > env.maxDice) {\n throw new EvaluatorError(\n `Total dice count ${env.totalDiceRolled + 1} exceeds limit of ${env.maxDice}`,\n 'DICE_LIMIT_EXCEEDED',\n 'Reroll',\n );\n }\n env.totalDiceRolled += 1;\n\n if (sides === 0) {\n const result = rng.nextInt(-1, 1);\n return {\n sides: 0,\n result,\n modifiers: [],\n critical: false,\n fumble: false,\n };\n }\n\n const result = rng.nextInt(1, sides);\n return {\n sides,\n result,\n modifiers: [],\n critical: result === sides && sides > 1,\n fumble: result === 1 && sides > 1,\n };\n}\n\nfunction rerollLimitError(maxIterations: number): EvaluatorError {\n return new EvaluatorError(\n `Reroll iteration limit of ${maxIterations} exceeded`,\n 'REROLL_LIMIT_EXCEEDED',\n 'Reroll',\n );\n}\n\n/**\n * True for dice eligible to start rerolling. Dropped dice (from a preceding\n * keep/drop modifier) are left alone.\n */\nfunction canReroll(die: DieResult): boolean {\n return !die.modifiers.includes('dropped');\n}\n\n/**\n * Returns the die's modifiers with any \"slot\" flags removed. Slot flags\n * (`kept`, `dropped`, `rerolled`) are controlled by the surrounding logic\n * and should be reassigned each pass.\n */\nfunction stripSlotFlags(modifiers: DieResult['modifiers']): DieResult['modifiers'] {\n return modifiers.filter((m) => m !== 'kept' && m !== 'dropped' && m !== 'rerolled');\n}\n\n/**\n * Applies recursive reroll: re-roll each matching die until it no longer\n * matches or the per-die iteration limit is reached. Intermediate dice are\n * appended to the output pool with `['rerolled', 'dropped']` so they:\n * 1. Render as strikethrough (via `renderDice`'s `'dropped'` check).\n * 2. Are excluded from `sumKeptDice`.\n * 3. Are ignored by subsequent keep/drop modifiers.\n */\nexport function applyRecursiveReroll(\n pool: DieResult[],\n operator: CompareOp,\n value: number,\n rng: RNG,\n env: EvalEnv,\n): DieResult[] {\n const result: DieResult[] = [];\n\n for (const original of pool) {\n if (!canReroll(original)) {\n result.push(original);\n continue;\n }\n\n let current = original;\n let iterations = 0;\n\n // ? Mutate flags in place — the same DieResult objects are shared with\n // the RollPart tree, and both views must reflect reroll state.\n while (matchesCondition(current.result, operator, value)) {\n if (iterations >= env.maxRerollIterations) {\n throw rerollLimitError(env.maxRerollIterations);\n }\n\n current.modifiers = [...stripSlotFlags(current.modifiers), 'rerolled', 'dropped'];\n result.push(current);\n\n current = rollReplacement(current.sides, rng, env);\n iterations += 1;\n }\n\n current.modifiers = [...stripSlotFlags(current.modifiers), 'kept'];\n result.push(current);\n }\n\n return result;\n}\n\n/**\n * Applies reroll-once: re-roll each matching die exactly once, keeping the\n * second result regardless of whether it matches. Non-matching dice pass\n * through with the `'kept'` slot flag.\n */\nexport function applyRerollOnce(\n pool: DieResult[],\n operator: CompareOp,\n value: number,\n rng: RNG,\n env: EvalEnv,\n): DieResult[] {\n const result: DieResult[] = [];\n\n for (const original of pool) {\n if (!canReroll(original)) {\n result.push(original);\n continue;\n }\n\n // ? Mutate flags in place — see `applyRecursiveReroll`.\n if (!matchesCondition(original.result, operator, value)) {\n original.modifiers = [...stripSlotFlags(original.modifiers), 'kept'];\n result.push(original);\n continue;\n }\n\n original.modifiers = [...stripSlotFlags(original.modifiers), 'rerolled', 'dropped'];\n result.push(original);\n\n const replacement = rollReplacement(original.sides, rng, env);\n replacement.modifiers = [...stripSlotFlags(replacement.modifiers), 'kept'];\n result.push(replacement);\n }\n\n return result;\n}\n",
17
+ "/**\n * Sort modifier implementation.\n *\n * Sort is purely cosmetic — it reorders the dice produced by its target in\n * ascending or descending order of `result` without touching any flag\n * (`kept`, `dropped`, `critical`, `fumble`, `rerolled`, `meta`) or the total.\n * Dropped dice stay in the pool and sort alongside kept dice so readers can\n * see where the dropped value landed in the ordered sequence.\n *\n * @module evaluator/modifiers/sort\n */\n\nimport type { DieResult } from '../../types.js';\n\n/**\n * Returns a sorted copy of `dice` in the given order, preserving every die's\n * original flags and metadata. Comparison is on `.result` — the raw face\n * value is what the user sees in rendered output, so ordering by raw value\n * matches the visual intent regardless of any `kept`/`dropped` flagging.\n *\n * Relies on `Array.prototype.sort` being stable — equal-valued dice retain\n * their original insertion order.\n */\nexport function sortDice(dice: DieResult[], order: 'ascending' | 'descending'): DieResult[] {\n const cmp =\n order === 'ascending'\n ? (a: DieResult, b: DieResult) => a.result - b.result\n : (a: DieResult, b: DieResult) => b.result - a.result;\n return [...dice].sort(cmp);\n}\n",
18
+ "/**\n * Success counting modifier.\n *\n * Transforms a dice pool into a signed success count: each die matching the\n * success `threshold` contributes +1, each die matching the optional\n * `failThreshold` contributes -1. When a single die matches both thresholds,\n * success wins (checked first).\n *\n * Dropped dice (from a preceding keep/drop or intermediate reroll) are\n * excluded from counting and are never tagged.\n *\n * Mutates the input pool in place to add `'success'` / `'failure'` modifier\n * flags — mirrors the mutation pattern of explode and reroll modifiers.\n *\n * @module evaluator/modifiers/success-count\n */\n\nimport type { CompareOp, DieResult } from '../../types.js';\nimport { matchesCondition } from './compare.js';\n\nexport type ResolvedThreshold = {\n operator: CompareOp;\n value: number;\n};\n\nexport type SuccessCountResult = {\n total: number;\n successes: number;\n failures: number;\n};\n\nexport function countSuccesses(\n dice: DieResult[],\n threshold: ResolvedThreshold,\n failThreshold?: ResolvedThreshold,\n): SuccessCountResult {\n let successes = 0;\n let failures = 0;\n\n for (const die of dice) {\n if (die.modifiers.includes('dropped')) continue;\n\n if (matchesCondition(die.result, threshold.operator, threshold.value)) {\n die.modifiers.push('success');\n successes += 1;\n continue;\n }\n\n if (\n failThreshold != null &&\n matchesCondition(die.result, failThreshold.operator, failThreshold.value)\n ) {\n die.modifiers.push('failure');\n failures += 1;\n }\n }\n\n return { total: successes - failures, successes, failures };\n}\n",
19
+ "/**\n * AST evaluator - transforms parsed AST into roll results.\n *\n * @module evaluator/evaluator\n */\n\nimport type { RollParserErrorCode } from '../errors.js';\nimport { RollParserError } from '../errors.js';\nimport type {\n ASTNode,\n BinaryOpNode,\n CritThreshold,\n CritThresholdNode,\n DiceNode,\n ExplodeNode,\n FateDiceNode,\n FunctionCallNode,\n GroupedNode,\n GroupNode,\n LiteralNode,\n ModifierNode,\n RerollNode,\n SortNode,\n SuccessCountNode,\n UnaryOpNode,\n VariableNode,\n VersusNode,\n} from '../parser/ast.js';\nimport { isModifier } from '../parser/ast.js';\nimport type { RNG } from '../rng/types.js';\nimport type {\n ComparePoint,\n DieResult,\n EvaluateOptions,\n ResolvedComparePoint,\n RollPart,\n RollResult,\n} from '../types.js';\nimport { DegreeOfSuccess } from '../types.js';\nimport { applyCritThresholds, type ResolvedCritThreshold } from './modifiers/crit-threshold.js';\nimport {\n applyCompoundExplode,\n applyPenetratingExplode,\n applyStandardExplode,\n buildShouldExplode,\n DEFAULT_MAX_EXPLODE_ITERATIONS,\n} from './modifiers/explode.js';\nimport {\n applyDropHighest,\n applyDropLowest,\n applyKeepHighest,\n applyKeepLowest,\n markAllKept,\n sumKeptDice,\n} from './modifiers/keep-drop.js';\nimport {\n applyRecursiveReroll,\n applyRerollOnce,\n DEFAULT_MAX_REROLL_ITERATIONS,\n} from './modifiers/reroll.js';\nimport { sortDice } from './modifiers/sort.js';\nimport { countSuccesses } from './modifiers/success-count.js';\n\n/**\n * Error thrown during AST evaluation.\n */\nexport class EvaluatorError extends RollParserError {\n readonly nodeType: string | undefined;\n /**\n * Source span of the tightest AST node that was being evaluated when the\n * error was thrown — stamped by `evalNode` on the way up, so the innermost\n * node wins. `undefined` when the AST was built without parser spans.\n */\n start: number | undefined;\n end: number | undefined;\n\n constructor(message: string, code: RollParserErrorCode, nodeType?: string) {\n super(message, code);\n this.name = 'EvaluatorError';\n this.nodeType = nodeType ?? undefined;\n this.start = undefined;\n this.end = undefined;\n }\n}\n\n/** Default maximum total dice allowed per evaluation. */\nexport const DEFAULT_MAX_DICE = 10_000;\n\nexport { DEFAULT_MAX_EXPLODE_ITERATIONS, DEFAULT_MAX_REROLL_ITERATIONS };\n\n/**\n * Per-evaluation shared environment (created once, shared across all branches).\n *\n * Exported for use by modifier implementations under `./modifiers/*`. Not part\n * of the public library API.\n */\nexport type EvalEnv = {\n readonly maxDice: number;\n readonly maxExplodeIterations: number;\n readonly maxRerollIterations: number;\n totalDiceRolled: number;\n /**\n * Set to `true` by `evalSuccessCount`. Propagates through the shared env\n * so `evaluate()` can include `successes`/`failures` fields even when no\n * die was tagged (impossible threshold).\n */\n hasSuccessCount: boolean;\n /**\n * `true` while the evaluator is inside a `VersusNode`'s roll or DC\n * sub-evaluation. `evalVersus` rejects nesting via this flag — catches\n * paren-nested versus (`1d20 vs (5 vs 3)`) that slip past the parser's\n * left-chain check.\n */\n insideVersus: boolean;\n /**\n * User-supplied variable map for `@name` / `@{name}` references. Always\n * defined — `evaluate()` defaults to an empty object so lookups can be\n * branch-free on presence.\n */\n readonly context: Readonly<Record<string, number>>;\n /**\n * Behavior when a referenced variable is missing from `context`. Always\n * defined — `evaluate()` defaults to `'throw'`.\n */\n readonly onMissingVariable: 'throw' | 'zero';\n};\n\n/**\n * Per-branch mutable accumulator for tracking rolls and output during recursion.\n *\n * @internal exported for targeted `mergeMetaRolls` tests only; not a public API.\n */\nexport type EvalContext = {\n rolls: DieResult[];\n expressionParts: string[];\n renderedParts: string[];\n /**\n * Populated by `evalVersus` with the resolved degree and natural value.\n * `evaluate()` reads this from the top-level ctx to surface `degree` and\n * `natural` on the final `RollResult`. Only populated when `vs` is the\n * root of the expression.\n */\n versusMetadata?: {\n degree: DegreeOfSuccess;\n natural: number | undefined;\n dcTotal: number;\n };\n};\n\n/**\n * Flattened representation of a keep/drop modifier for chain evaluation.\n * Superset of the public `ModifierSpec` (adds the notation `code`).\n */\ntype ModifierSpec = {\n modifier: 'keep' | 'drop';\n selector: 'highest' | 'lowest';\n count: number;\n code: string;\n};\n\n/**\n * Every branch returns its numeric total AND the `RollPart` it contributes\n * to the structured breakdown — TypeScript exhaustiveness guarantees no\n * branch can forget to produce a part.\n */\ntype EvalResult = {\n total: number;\n part: RollPart;\n};\n\n/**\n * Copies an AST node's source span onto a part (spread into the literal).\n * Empty when the AST was built without parser spans.\n */\nfunction partSpan(node: ASTNode): { start?: number; end?: number } {\n if (node.start === undefined || node.end === undefined) return {};\n return { start: node.start, end: node.end };\n}\n\n/** Maps internal modifier specs to the public `RollPart` spec shape. */\nfunction toPublicSpecs(\n specs: ModifierSpec[],\n): { kind: 'keep' | 'drop'; selector: 'highest' | 'lowest'; count: number }[] {\n return specs.map((spec) => ({ kind: spec.modifier, selector: spec.selector, count: spec.count }));\n}\n\n/**\n * Creates a new die result with critical/fumble detection.\n */\nfunction createDieResult(sides: number, result: number): DieResult {\n // ? `sides > 1` guards both flags — a d1 always rolls 1, so it is neither\n // an exceptional max (critical) nor an exceptional min (fumble).\n return {\n sides,\n result,\n modifiers: [],\n critical: result === sides && sides > 1,\n fumble: result === 1 && sides > 1,\n };\n}\n\n/**\n * Creates a Fate/Fudge die result. Uses `sides = 0` as a sentinel — Fate dice\n * have no max-face concept, so `critical` and `fumble` are always `false`.\n */\nfunction createFateDieResult(result: number): DieResult {\n return {\n sides: 0,\n result,\n modifiers: [],\n critical: false,\n fumble: false,\n };\n}\n\n/**\n * Renders dice results for display. Marker priority: dropped wins over\n * success/failure (dropped dice are never counted), success wins over\n * failure (a die cannot be both). Example: `[~~1~~, **6**, __1__, 3]`.\n *\n * Dice tagged `'meta'` (rolled to compute sub-expression parameters such as\n * count/sides/threshold) are hidden from the rendered output — they exist in\n * `RollResult.rolls` for audit, not for display.\n */\nfunction renderDice(dice: DieResult[]): string {\n const parts = dice\n .filter((die) => !die.modifiers.includes('meta'))\n .map((die) => {\n if (die.modifiers.includes('dropped')) {\n return `~~${die.result}~~`;\n }\n if (die.modifiers.includes('success')) {\n return `**${die.result}**`;\n }\n if (die.modifiers.includes('failure')) {\n return `__${die.result}__`;\n }\n return String(die.result);\n });\n return `[${parts.join(', ')}]`;\n}\n\n/**\n * Forwards rolls from a throwaway sub-expression context into the parent\n * audit trail, tagging them as `'meta'` + `'dropped'`. Meta dice are dice\n * rolled to compute parameters (dice count, sides, threshold, modifier\n * count) — they consume RNG and count against `maxDice`, so they must be\n * inspectable. Tagging them `'dropped'` keeps totals correct via\n * `sumKeptDice`; `'meta'` lets renderers hide them and lets callers\n * distinguish them from ordinary pool dice.\n *\n * `'success'`/`'failure'` tags are stripped here as defense-in-depth against\n * a SuccessCount leaking into a meta sub-expression (parser rejects all such\n * wrappings; this strip ensures a future parse regression cannot leak tags\n * into the top-level `successes`/`failures` scan).\n */\n/** @internal exported for targeted defense-in-depth tests only. */\nexport function mergeMetaRolls(parent: EvalContext, source: EvalContext): void {\n for (const die of source.rolls) {\n parent.rolls.push({\n ...die,\n modifiers: [\n ...die.modifiers.filter(\n (m) => m !== 'kept' && m !== 'dropped' && m !== 'success' && m !== 'failure',\n ),\n 'meta',\n 'dropped',\n ],\n });\n }\n}\n\n/**\n * Evaluates an AST node, returning its total and `RollPart` while updating\n * the context.\n *\n * Errors bubbling up get the source span of the tightest node that was being\n * evaluated — the innermost `evalNode` frame stamps first, outer frames leave\n * an already-stamped error untouched.\n */\nfunction evalNode(node: ASTNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n try {\n return evalNodeInner(node, rng, ctx, env);\n } catch (error) {\n if (error instanceof EvaluatorError && error.start === undefined && node.start !== undefined) {\n error.start = node.start;\n error.end = node.end;\n }\n throw error;\n }\n}\n\nfunction evalNodeInner(node: ASTNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n switch (node.type) {\n case 'Literal':\n return evalLiteral(node, ctx);\n\n case 'Dice':\n return evalDice(node, rng, ctx, env);\n\n case 'FateDice':\n return evalFateDice(node, rng, ctx, env);\n\n case 'BinaryOp':\n return evalBinaryOp(node, rng, ctx, env);\n\n case 'UnaryOp':\n return evalUnaryOp(node, rng, ctx, env);\n\n case 'Modifier':\n return evalModifier(node, rng, ctx, env);\n\n case 'Explode':\n return evalExplode(node, rng, ctx, env);\n\n case 'Reroll':\n return evalReroll(node, rng, ctx, env);\n\n case 'SuccessCount':\n return evalSuccessCount(node, rng, ctx, env);\n\n case 'Versus':\n return evalVersus(node, rng, ctx, env);\n\n case 'FunctionCall':\n return evalFunctionCall(node, rng, ctx, env);\n\n case 'Grouped':\n return evalGrouped(node, rng, ctx, env);\n\n case 'Group':\n return evalGroup(node, rng, ctx, env);\n\n case 'Sort':\n return evalSort(node, rng, ctx, env);\n\n case 'CritThreshold':\n return evalCritThreshold(node, rng, ctx, env);\n\n case 'Variable':\n return evalVariable(node, ctx, env);\n\n default: {\n const exhaustive: never = node;\n throw new EvaluatorError(\n `Unknown node type: ${(exhaustive as ASTNode).type}`,\n 'UNKNOWN_NODE_TYPE',\n (exhaustive as ASTNode).type,\n );\n }\n }\n}\n\nfunction evalLiteral(node: LiteralNode, ctx: EvalContext): EvalResult {\n const { value } = node;\n ctx.expressionParts.push(String(value));\n ctx.renderedParts.push(String(value));\n return { total: value, part: { type: 'literal', value, total: value, ...partSpan(node) } };\n}\n\n/**\n * Re-derives whether a variable name needs braces in its rendered form.\n *\n * The lexer accepts `@name` (bare) or `@{name with spaces}` (braced) but\n * strips the braces from the captured value. To round-trip through `rendered`\n * we re-derive bracedness from the name shape — anything outside the bare\n * identifier grammar implies the user wrote braces (or would need them).\n */\nfunction variableNeedsBraces(name: string): boolean {\n return !/^[A-Za-z_][A-Za-z0-9_]*$/.test(name);\n}\n\n/**\n * Looks up a variable in `env.context` and resolves missing keys per\n * `env.onMissingVariable`. The resolved scalar is the variable's value;\n * `expression` shows the resolved number (mirrors how literals render),\n * while `rendered` keeps the original `@name` (or `@{name}`) annotated with\n * the resolved value in brackets so readers can attribute the number.\n */\nfunction evalVariable(node: VariableNode, ctx: EvalContext, env: EvalEnv): EvalResult {\n const present = Object.hasOwn(env.context, node.name);\n if (!present) {\n if (env.onMissingVariable === 'throw') {\n throw new EvaluatorError(\n `Undefined variable: ${node.name}`,\n 'UNDEFINED_VARIABLE',\n 'Variable',\n );\n }\n const display = variableNeedsBraces(node.name) ? `@{${node.name}}` : `@${node.name}`;\n ctx.expressionParts.push('0');\n ctx.renderedParts.push(`${display}[0]`);\n return {\n total: 0,\n part: { type: 'variable', name: node.name, value: 0, total: 0, ...partSpan(node) },\n };\n }\n\n const value = env.context[node.name] as number;\n if (!Number.isFinite(value)) {\n throw new EvaluatorError(\n `Invalid variable value: ${node.name} = ${value}`,\n 'INVALID_VARIABLE_VALUE',\n 'Variable',\n );\n }\n const display = variableNeedsBraces(node.name) ? `@{${node.name}}` : `@${node.name}`;\n ctx.expressionParts.push(String(value));\n ctx.renderedParts.push(`${display}[${value}]`);\n return {\n total: value,\n part: { type: 'variable', name: node.name, value, total: value, ...partSpan(node) },\n };\n}\n\n/**\n * RNG draw order: `count` expression → `sides` expression → pool dice\n * (one `nextInt` per die, left-to-right). Meta-expressions on `count`/`sides`\n * (e.g. `(1+1)d(3*2)`) draw before the pool. For modifier-argument\n * meta-expressions like `4d6kh(1d2)`, `flattenModifierChain` draws the\n * modifier args first, then `evalModifier` calls `evalDice` for the base\n * pool. See `.claude/rules/rng.md` for the full draw-order spec.\n */\nfunction evalDice(node: DiceNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n const countCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const count = evalNode(node.count, rng, countCtx, env).total;\n mergeMetaRolls(ctx, countCtx);\n\n const sidesCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const sides = evalNode(node.sides, rng, sidesCtx, env).total;\n mergeMetaRolls(ctx, sidesCtx);\n\n if (!Number.isInteger(count) || count < 0) {\n throw new EvaluatorError(`Invalid dice count: ${count}`, 'INVALID_DICE_COUNT', 'Dice');\n }\n if (!Number.isInteger(sides) || sides < 1) {\n throw new EvaluatorError(`Invalid dice sides: ${sides}`, 'INVALID_DICE_SIDES', 'Dice');\n }\n\n if (env.totalDiceRolled + count > env.maxDice) {\n throw new EvaluatorError(\n `Total dice count ${env.totalDiceRolled + count} exceeds limit of ${env.maxDice}`,\n 'DICE_LIMIT_EXCEEDED',\n 'Dice',\n );\n }\n env.totalDiceRolled += count;\n\n const dice: DieResult[] = [];\n for (let i = 0; i < count; i++) {\n const result = rng.nextInt(1, sides);\n dice.push(createDieResult(sides, result));\n }\n\n const markedDice = markAllKept(dice);\n ctx.rolls.push(...markedDice);\n\n const total = sumKeptDice(markedDice);\n const notation = `${count}d${sides}`;\n\n ctx.expressionParts.push(notation);\n ctx.renderedParts.push(`${notation}${renderDice(markedDice)}`);\n\n return {\n total,\n part: { type: 'dice', count, sides, rolls: markedDice, total, ...partSpan(node) },\n };\n}\n\nfunction evalFateDice(node: FateDiceNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n const countCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const count = evalNode(node.count, rng, countCtx, env).total;\n mergeMetaRolls(ctx, countCtx);\n\n if (!Number.isInteger(count) || count < 0) {\n throw new EvaluatorError(`Invalid dice count: ${count}`, 'INVALID_DICE_COUNT', 'FateDice');\n }\n\n if (env.totalDiceRolled + count > env.maxDice) {\n throw new EvaluatorError(\n `Total dice count ${env.totalDiceRolled + count} exceeds limit of ${env.maxDice}`,\n 'DICE_LIMIT_EXCEEDED',\n 'FateDice',\n );\n }\n env.totalDiceRolled += count;\n\n const dice: DieResult[] = [];\n for (let i = 0; i < count; i++) {\n const result = rng.nextInt(-1, 1);\n dice.push(createFateDieResult(result));\n }\n\n const markedDice = markAllKept(dice);\n ctx.rolls.push(...markedDice);\n\n const total = sumKeptDice(markedDice);\n const notation = `${count}dF`;\n\n ctx.expressionParts.push(notation);\n ctx.renderedParts.push(`${notation}${renderDice(markedDice)}`);\n\n return {\n total,\n part: { type: 'fateDice', count, rolls: markedDice, total, ...partSpan(node) },\n };\n}\n\n/**\n * Propagates `versusMetadata` onto a parent so `degree`/`natural` survive\n * wrappers like `floor(...)`, `(vs) + 0`, or `-(vs)`. Throws `NESTED_VERSUS`\n * if the parent already carries metadata — two versus results cannot occupy\n * the same `RollResult`. No-op when `metadata` is `undefined`.\n *\n * Use this directly when the caller has already pushed (or transformed) `rolls`\n * itself — e.g. `evalSort`, `evalCritThreshold`, `evalGroupModifier`. For the\n * default case where the child's raw rolls flow up unchanged, use\n * `mergeContext` instead.\n */\nfunction propagateMetadata(parent: EvalContext, metadata: EvalContext['versusMetadata']): void {\n if (!metadata) return;\n if (parent.versusMetadata) {\n throw new EvaluatorError(\n 'Multiple versus operators in the same expression',\n 'NESTED_VERSUS',\n 'Versus',\n );\n }\n parent.versusMetadata = metadata;\n}\n\n/**\n * Merges a child sub-context back into its parent. Copies `rolls` and\n * delegates `versusMetadata` propagation to `propagateMetadata`.\n *\n * Does not merge `expressionParts` / `renderedParts` — each wrapper formats\n * those with its own operator/function syntax.\n */\nfunction mergeContext(parent: EvalContext, child: EvalContext): void {\n parent.rolls.push(...child.rolls);\n propagateMetadata(parent, child.versusMetadata);\n}\n\nfunction evalBinaryOp(node: BinaryOpNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n const leftCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const rightCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n\n const left = evalNode(node.left, rng, leftCtx, env);\n const right = evalNode(node.right, rng, rightCtx, env);\n\n mergeContext(ctx, leftCtx);\n mergeContext(ctx, rightCtx);\n\n const leftExpr = leftCtx.expressionParts.join('');\n const rightExpr = rightCtx.expressionParts.join('');\n const leftRendered = leftCtx.renderedParts.join('');\n const rightRendered = rightCtx.renderedParts.join('');\n\n ctx.expressionParts.push(`${leftExpr} ${node.operator} ${rightExpr}`);\n ctx.renderedParts.push(`${leftRendered} ${node.operator} ${rightRendered}`);\n\n const total = applyBinaryOperator(node.operator, left.total, right.total);\n\n return {\n total,\n part: {\n type: 'binaryOp',\n operator: node.operator,\n left: left.part,\n right: right.part,\n total,\n ...partSpan(node),\n },\n };\n}\n\nfunction applyBinaryOperator(\n operator: BinaryOpNode['operator'],\n left: number,\n right: number,\n): number {\n switch (operator) {\n case '+':\n return left + right;\n case '-':\n return left - right;\n case '*':\n return left * right;\n case '/':\n if (right === 0) {\n throw new EvaluatorError('Division by zero', 'DIVISION_BY_ZERO', 'BinaryOp');\n }\n return left / right;\n case '%':\n if (right === 0) {\n throw new EvaluatorError('Modulo by zero', 'MODULO_BY_ZERO', 'BinaryOp');\n }\n return left % right;\n case '**':\n return left ** right;\n default: {\n const exhaustive: never = operator;\n throw new EvaluatorError(`Unknown operator: ${exhaustive}`, 'UNKNOWN_OPERATOR', 'BinaryOp');\n }\n }\n}\n\nfunction evalUnaryOp(node: UnaryOpNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n const innerCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const inner = evalNode(node.operand, rng, innerCtx, env);\n\n mergeContext(ctx, innerCtx);\n\n const innerExpr = innerCtx.expressionParts.join('');\n const innerRendered = innerCtx.renderedParts.join('');\n\n ctx.expressionParts.push(`-${innerExpr}`);\n ctx.renderedParts.push(`-${innerRendered}`);\n\n const total = -inner.total;\n\n return {\n total,\n part: { type: 'unaryOp', operator: '-', operand: inner.part, total, ...partSpan(node) },\n };\n}\n\nfunction evalGrouped(node: GroupedNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n const innerCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const inner = evalNode(node.expression, rng, innerCtx, env);\n\n mergeContext(ctx, innerCtx);\n\n ctx.expressionParts.push(`(${innerCtx.expressionParts.join('')})`);\n ctx.renderedParts.push(`(${innerCtx.renderedParts.join('')})`);\n\n return {\n total: inner.total,\n part: { type: 'grouped', inner: inner.part, total: inner.total, ...partSpan(node) },\n };\n}\n\n/**\n * Evaluates a grouped roll `{expr1, expr2, ...}`.\n *\n * Each sub-expression is evaluated in an isolated context, then its rolls\n * and `versusMetadata` propagate up via `mergeContext`. Sub-roll subtotals\n * sum to the group's total. When the group is the base target of a\n * keep/drop modifier with `expressions.length >= 2`, `evalModifier`\n * intercepts first and never calls this function — dual semantics\n * (flat-pool vs sub-roll) are decided there.\n */\nfunction evalGroup(node: GroupNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n const subExprs: string[] = [];\n const subRendered: string[] = [];\n const subParts: RollPart[] = [];\n let total = 0;\n\n for (const expr of node.expressions) {\n const subCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const sub = evalNode(expr, rng, subCtx, env);\n mergeContext(ctx, subCtx);\n subExprs.push(subCtx.expressionParts.join(''));\n subRendered.push(subCtx.renderedParts.join(''));\n subParts.push(sub.part);\n total += sub.total;\n }\n\n ctx.expressionParts.push(`{${subExprs.join(', ')}}`);\n ctx.renderedParts.push(`{${subRendered.join(', ')}}`);\n\n // ? No `keptIndices` — bare groups (and single-sub passthroughs) perform\n // no sub-roll selection; only `evalGroupModifier` sets it.\n return { total, part: { type: 'group', parts: subParts, total, ...partSpan(node) } };\n}\n\nfunction evalFunctionCall(\n node: FunctionCallNode,\n rng: RNG,\n ctx: EvalContext,\n env: EvalEnv,\n): EvalResult {\n const argCtxs: EvalContext[] = [];\n const argResults: EvalResult[] = [];\n\n for (const arg of node.args) {\n const argCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n argResults.push(evalNode(arg, rng, argCtx, env));\n argCtxs.push(argCtx);\n }\n\n for (const argCtx of argCtxs) {\n mergeContext(ctx, argCtx);\n }\n\n const argExprs = argCtxs.map((c) => c.expressionParts.join(''));\n const argRendereds = argCtxs.map((c) => c.renderedParts.join(''));\n\n ctx.expressionParts.push(`${node.name}(${argExprs.join(', ')})`);\n ctx.renderedParts.push(`${node.name}(${argRendereds.join(', ')})`);\n\n const total = applyFunction(\n node.name,\n argResults.map((r) => r.total),\n );\n\n return {\n total,\n part: {\n type: 'functionCall',\n name: node.name,\n args: argResults.map((r) => r.part),\n total,\n ...partSpan(node),\n },\n };\n}\n\nfunction applyFunction(name: string, values: number[]): number {\n switch (name) {\n case 'floor':\n return Math.floor(requireUnaryArg(name, values));\n case 'ceil':\n return Math.ceil(requireUnaryArg(name, values));\n case 'round':\n // ? Delegates to `Math.round`, which rounds half-values toward +∞\n // (IEEE-754 half-up). So `round(2.5) === 3` but `round(-2.5) === -2`,\n // not `-3`. Users needing symmetric rounding must compose via `floor`.\n return Math.round(requireUnaryArg(name, values));\n case 'abs':\n return Math.abs(requireUnaryArg(name, values));\n case 'max':\n return Math.max(...values);\n case 'min':\n return Math.min(...values);\n default:\n throw new EvaluatorError(`Unknown function: ${name}`, 'UNKNOWN_FUNCTION', 'FunctionCall');\n }\n}\n\nfunction requireUnaryArg(name: string, values: number[]): number {\n const [x] = values;\n if (x === undefined) {\n // ? Unreachable: parser validates arity before evaluation. Defensive for\n // `noNonNullAssertion`.\n throw new EvaluatorError(\n `Function '${name}' requires an argument`,\n 'UNKNOWN_FUNCTION',\n 'FunctionCall',\n );\n }\n return x;\n}\n\n/**\n * Walks a nested ModifierNode chain, collecting specs outermost-first,\n * then reverses to notation order (innermost-first).\n */\nfunction flattenModifierChain(\n node: ModifierNode,\n rng: RNG,\n ctx: EvalContext,\n env: EvalEnv,\n): { specs: ModifierSpec[]; baseTarget: ASTNode } {\n const specs: ModifierSpec[] = [];\n let current: ASTNode = node;\n\n while (isModifier(current)) {\n const countCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const modCount = evalNode(current.count, rng, countCtx, env).total;\n mergeMetaRolls(ctx, countCtx);\n\n if (!Number.isInteger(modCount) || modCount < 0) {\n throw new EvaluatorError(\n `Invalid modifier count: ${modCount}`,\n 'INVALID_MODIFIER_COUNT',\n 'Modifier',\n );\n }\n\n const code =\n current.modifier === 'keep'\n ? current.selector === 'highest'\n ? 'kh'\n : 'kl'\n : current.selector === 'highest'\n ? 'dh'\n : 'dl';\n\n specs.push({ modifier: current.modifier, selector: current.selector, count: modCount, code });\n current = current.target;\n }\n\n specs.reverse();\n return { specs, baseTarget: current };\n}\n\n/**\n * Applies a single modifier spec to a dice pool.\n */\nfunction applyModifierSpec(dice: DieResult[], spec: ModifierSpec): DieResult[] {\n if (spec.modifier === 'keep') {\n return spec.selector === 'highest'\n ? applyKeepHighest(dice, spec.count)\n : applyKeepLowest(dice, spec.count);\n }\n return spec.selector === 'highest'\n ? applyDropHighest(dice, spec.count)\n : applyDropLowest(dice, spec.count);\n}\n\n/**\n * Applies each modifier independently to the full dice pool\n * and merges drop sets via union. A die is dropped if ANY modifier dropped it.\n *\n * Mutates each die's flags in place — the same `DieResult` objects are\n * shared between `RollResult.rolls` and the `RollPart` tree. The per-spec\n * appliers still work on copies internally (each spec must see the\n * unmodified pool), only the merged outcome is written back.\n */\nfunction mergeDropSets(baseDice: DieResult[], specs: ModifierSpec[]): DieResult[] {\n const droppedIndices = new Set<number>();\n\n for (const spec of specs) {\n const result = applyModifierSpec(baseDice, spec);\n for (let i = 0; i < result.length; i++) {\n if (result[i]?.modifiers.includes('dropped')) {\n droppedIndices.add(i);\n }\n }\n }\n\n baseDice.forEach((die, index) => {\n die.modifiers = droppedIndices.has(index)\n ? [...die.modifiers.filter((m) => m !== 'kept' && m !== 'dropped'), 'dropped']\n : [...die.modifiers.filter((m) => m !== 'dropped' && m !== 'kept'), 'kept'];\n });\n\n return baseDice;\n}\n\n/**\n * Builds the notation string for an explode modifier, e.g. `!`, `!!>=3`, `!p>5`.\n */\nfunction formatExplodeCode(\n variant: ExplodeNode['variant'],\n threshold: ComparePoint | undefined,\n thresholdValue: number | undefined,\n): string {\n const marker = variant === 'standard' ? '!' : variant === 'compound' ? '!!' : '!p';\n if (threshold == null || thresholdValue == null) return marker;\n return `${marker}${threshold.operator}${thresholdValue}`;\n}\n\nfunction evalExplode(node: ExplodeNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n const targetCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const target = evalNode(node.target, rng, targetCtx, env);\n const targetExpr = targetCtx.expressionParts.join('');\n\n let thresholdValue: number | undefined;\n if (node.threshold != null) {\n const thresholdCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n thresholdValue = evalNode(node.threshold.value, rng, thresholdCtx, env).total;\n mergeMetaRolls(ctx, thresholdCtx);\n }\n\n const code = formatExplodeCode(node.variant, node.threshold, thresholdValue);\n\n const buildPart = (total: number): RollPart => {\n const part: RollPart = {\n type: 'explode',\n variant: node.variant,\n target: target.part,\n total,\n ...partSpan(node),\n };\n if (node.threshold != null && thresholdValue !== undefined) {\n part.threshold = { operator: node.threshold.operator, value: thresholdValue };\n }\n return part;\n };\n\n // No-op when the target produced no dice (e.g., `(1+2)!`).\n if (targetCtx.rolls.length === 0) {\n ctx.expressionParts.push(`${targetExpr}${code}`);\n ctx.renderedParts.push(`${targetExpr}${code}`);\n return { total: target.total, part: buildPart(target.total) };\n }\n\n const shouldExplode = buildShouldExplode(node.threshold?.operator, thresholdValue);\n\n const expanded =\n node.variant === 'standard'\n ? applyStandardExplode(targetCtx.rolls, shouldExplode, rng, env)\n : node.variant === 'compound'\n ? applyCompoundExplode(targetCtx.rolls, shouldExplode, rng, env)\n : applyPenetratingExplode(targetCtx.rolls, shouldExplode, rng, env);\n\n ctx.rolls.push(...expanded);\n ctx.expressionParts.push(`${targetExpr}${code}`);\n // ? Include the explode code in rendered output so readers can attribute\n // the extra dice. Modifier rendering (kh/dl) skips its code because\n // dropped dice are visible; explosion-origin is otherwise invisible.\n ctx.renderedParts.push(`${targetExpr}${code}${renderDice(expanded)}`);\n\n const total = sumKeptDice(expanded);\n return { total, part: buildPart(total) };\n}\n\nfunction evalReroll(node: RerollNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n const targetCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const target = evalNode(node.target, rng, targetCtx, env);\n const targetExpr = targetCtx.expressionParts.join('');\n\n const thresholdCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const thresholdValue = evalNode(node.condition.value, rng, thresholdCtx, env).total;\n mergeMetaRolls(ctx, thresholdCtx);\n\n const code = `${node.once ? 'ro' : 'r'}${node.condition.operator}${thresholdValue}`;\n const condition: ResolvedComparePoint = {\n operator: node.condition.operator,\n value: thresholdValue,\n };\n\n // No-op when the target produced no dice (e.g., `(1+2)r<5`).\n if (targetCtx.rolls.length === 0) {\n ctx.expressionParts.push(`${targetExpr}${code}`);\n ctx.renderedParts.push(`${targetExpr}${code}`);\n const total = sumKeptDice(targetCtx.rolls);\n return {\n total,\n part: {\n type: 'reroll',\n once: node.once,\n condition,\n target: target.part,\n total,\n ...partSpan(node),\n },\n };\n }\n\n const pool = node.once\n ? applyRerollOnce(targetCtx.rolls, node.condition.operator, thresholdValue, rng, env)\n : applyRecursiveReroll(targetCtx.rolls, node.condition.operator, thresholdValue, rng, env);\n\n ctx.rolls.push(...pool);\n ctx.expressionParts.push(`${targetExpr}${code}`);\n ctx.renderedParts.push(`${targetExpr}${code}${renderDice(pool)}`);\n\n const total = sumKeptDice(pool);\n return {\n total,\n part: {\n type: 'reroll',\n once: node.once,\n condition,\n target: target.part,\n total,\n ...partSpan(node),\n },\n };\n}\n\n/**\n * Evaluates a sort modifier. Purely visual — sorts the dice produced by\n * `node.target` in ascending or descending order of `result` without\n * changing the total or any die-level flag. Dropped dice participate in\n * the sort alongside kept dice, preserving their `'dropped'` marker.\n *\n * Rendering mirrors `evalExplode` / `evalModifier`: emits\n * `<targetExpr><code>[<sortedDice>]`, replacing any inline dice brackets\n * the target itself rendered. Multi-sub-roll Group targets (`{4d6, 3d6}s`)\n * are rejected at parse time with `INVALID_SORT_TARGET` until hierarchical\n * per-sub-roll sorting (Stage 3 spec §3 \"Group interaction\") is implemented.\n */\nfunction evalSort(node: SortNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n const targetCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const target = evalNode(node.target, rng, targetCtx, env);\n\n const sortedRolls = sortDice(targetCtx.rolls, node.order);\n\n ctx.rolls.push(...sortedRolls);\n propagateMetadata(ctx, targetCtx.versusMetadata);\n\n const code = node.order === 'ascending' ? 's' : 'sd';\n const targetExpr = targetCtx.expressionParts.join('');\n\n ctx.expressionParts.push(`${targetExpr}${code}`);\n ctx.renderedParts.push(`${targetExpr}${code}${renderDice(sortedRolls)}`);\n\n return {\n total: target.total,\n part: {\n type: 'sort',\n order: node.order,\n target: target.part,\n total: target.total,\n ...partSpan(node),\n },\n };\n}\n\n/**\n * Evaluates a critical/fumble threshold modifier. Pure post-processing:\n * evaluates the target in an isolated context, resolves each threshold's\n * ComparePoint value (including meta-expressions, which consume RNG draws\n * AFTER the target pool), then overrides `critical`/`fumble` flags on the\n * produced dice in place.\n *\n * Independent overrides (Roll20 semantics): `cs` thresholds replace only the\n * crit criteria and `cf` thresholds replace only the fumble criteria. When a\n * side has no explicit threshold, the `'default'` rule applies — so\n * `1d20cf<3` keeps the default nat-20 crit. Bare `cs`/`cf` uses the\n * `'default'` sentinel resolved per-die to `result === sides` or\n * `result === 1`.\n *\n * Renders `<targetExpr><codes>[<dice>]`, mirroring `evalSort`/`evalExplode`.\n */\nfunction evalCritThreshold(\n node: CritThresholdNode,\n rng: RNG,\n ctx: EvalContext,\n env: EvalEnv,\n): EvalResult {\n const targetCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const target = evalNode(node.target, rng, targetCtx, env);\n\n const successResolved = node.successThresholds.map((t) => resolveCritThreshold(t, rng, ctx, env));\n const failResolved = node.failThresholds.map((t) => resolveCritThreshold(t, rng, ctx, env));\n\n // Independent overrides: a side with no explicit threshold falls back to\n // the default rule instead of being wiped by the other side's override.\n const successApplied: ResolvedCritThreshold[] =\n successResolved.length > 0 ? successResolved : ['default'];\n const failApplied: ResolvedCritThreshold[] = failResolved.length > 0 ? failResolved : ['default'];\n\n applyCritThresholds(targetCtx.rolls, successApplied, failApplied);\n\n ctx.rolls.push(...targetCtx.rolls);\n propagateMetadata(ctx, targetCtx.versusMetadata);\n\n const targetExpr = targetCtx.expressionParts.join('');\n const codes = [\n ...successResolved.map((t) => (t === 'default' ? 'cs' : `cs${t.operator}${t.value}`)),\n ...failResolved.map((t) => (t === 'default' ? 'cf' : `cf${t.operator}${t.value}`)),\n ].join('');\n\n ctx.expressionParts.push(`${targetExpr}${codes}`);\n ctx.renderedParts.push(`${targetExpr}${codes}${renderDice(targetCtx.rolls)}`);\n\n return {\n total: target.total,\n part: {\n type: 'critThreshold',\n successThresholds: successResolved,\n failThresholds: failResolved,\n target: target.part,\n total: target.total,\n ...partSpan(node),\n },\n };\n}\n\nfunction resolveCritThreshold(\n threshold: CritThreshold,\n rng: RNG,\n ctx: EvalContext,\n env: EvalEnv,\n): ResolvedCritThreshold {\n if (threshold === 'default') return 'default';\n const thresholdCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const resolved = evalNode(threshold.value, rng, thresholdCtx, env).total;\n mergeMetaRolls(ctx, thresholdCtx);\n if (!Number.isFinite(resolved)) {\n throw new EvaluatorError(\n `Invalid crit threshold: ${resolved}`,\n 'INVALID_THRESHOLD',\n 'CritThreshold',\n );\n }\n return { operator: threshold.operator, value: resolved };\n}\n\nfunction evalModifier(node: ModifierNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n const { specs, baseTarget } = flattenModifierChain(node, rng, ctx, env);\n\n // Multi-sub-roll group: keep/drop operates on sub-roll subtotals as if\n // each subtotal were a compound die. Single-sub-roll groups fall through\n // to the flat-pool path below — `evalGroup` evaluates the inner expression\n // into `targetCtx.rolls`, and `mergeDropSets` selects individual dice.\n if (baseTarget.type === 'Group' && baseTarget.expressions.length >= 2) {\n return evalGroupModifier(node, baseTarget, specs, rng, ctx, env);\n }\n\n const targetCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const target = evalNode(baseTarget, rng, targetCtx, env);\n\n const mergedDice = mergeDropSets(targetCtx.rolls, specs);\n\n ctx.rolls.push(...mergedDice);\n\n const total = sumKeptDice(mergedDice);\n\n const targetExpr = targetCtx.expressionParts.join('');\n const modifierCodes = specs.map((s) => `${s.code}${s.count}`).join('');\n\n ctx.expressionParts.push(`${targetExpr}${modifierCodes}`);\n ctx.renderedParts.push(`${targetExpr}${renderDice(mergedDice)}`);\n\n return {\n total,\n part: {\n type: 'modifier',\n specs: toPublicSpecs(specs),\n target: target.part,\n total,\n ...partSpan(node),\n },\n };\n}\n\n/**\n * Strips per-die markdown markers from an already-rendered sub-roll string.\n * Used when a whole group sub-roll is dropped: the outer `~~...~~` wrap\n * supersedes inner success (`**`), failure (`__`), and dropped (`~~`)\n * markers, and leaving them in place would nest strikethroughs or show\n * success highlights inside a dropped span.\n */\nfunction stripInnerMarkers(rendered: string): string {\n return rendered\n .replace(/\\*\\*(-?\\d+)\\*\\*/g, '$1')\n .replace(/__(-?\\d+)__/g, '$1')\n .replace(/~~(-?\\d+)~~/g, '$1');\n}\n\n/**\n * Evaluates a keep/drop modifier chain whose base target is a multi\n * sub-roll group. Each sub-roll is evaluated in isolation so its subtotal\n * and dice are captured separately. Synthetic dice — one per sub-roll,\n * `result = subtotal` — feed `mergeDropSets` to pick kept/dropped indices.\n * Dropped sub-rolls' inner dice are re-flagged `'dropped'` so `sumKeptDice`\n * on the propagated rolls still agrees with the group total, and the\n * rendered form wraps them in strikethrough `~~...~~`.\n */\nfunction evalGroupModifier(\n node: ModifierNode,\n group: GroupNode,\n specs: ModifierSpec[],\n rng: RNG,\n ctx: EvalContext,\n env: EvalEnv,\n): EvalResult {\n type SubRoll = {\n subtotal: number;\n part: RollPart;\n rolls: DieResult[];\n expr: string;\n rendered: string;\n versusMetadata: EvalContext['versusMetadata'];\n };\n\n const subRolls: SubRoll[] = group.expressions.map((expr) => {\n const subCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const sub = evalNode(expr, rng, subCtx, env);\n return {\n subtotal: sub.total,\n part: sub.part,\n rolls: subCtx.rolls,\n expr: subCtx.expressionParts.join(''),\n rendered: subCtx.renderedParts.join(''),\n versusMetadata: subCtx.versusMetadata,\n };\n });\n\n // ? Synthetic dice carry `sides = 0` as a sentinel — they're never\n // surfaced in `ctx.rolls`, only used as input to `mergeDropSets`. Any\n // `critical`/`fumble` flags would be meaningless for a subtotal.\n const syntheticDice: DieResult[] = subRolls.map((sub) => ({\n sides: 0,\n result: sub.subtotal,\n modifiers: [],\n critical: false,\n fumble: false,\n }));\n\n const mergedSynthetic = mergeDropSets(syntheticDice, specs);\n\n const outerRendered: string[] = [];\n const keptIndices: number[] = [];\n let total = 0;\n\n for (let i = 0; i < subRolls.length; i++) {\n const sub = subRolls[i] as SubRoll;\n const synth = mergedSynthetic[i] as DieResult;\n const isDropped = synth.modifiers.includes('dropped');\n\n if (isDropped) {\n // Flag every inner die dropped so propagated rolls match the total.\n // Keep existing `'kept'` stripped — the sub-roll didn't contribute,\n // so its die-level kept annotation no longer applies. `'success'` /\n // `'failure'` are stripped too: the top-level successes/failures scan\n // must not count dice from a sub-roll that was dropped. Mutated in\n // place — the same objects live in the sub-roll's RollPart.\n for (const die of sub.rolls) {\n die.modifiers = [\n ...die.modifiers.filter(\n (m) => m !== 'kept' && m !== 'dropped' && m !== 'success' && m !== 'failure',\n ),\n 'dropped',\n ];\n }\n ctx.rolls.push(...sub.rolls);\n outerRendered.push(`~~${stripInnerMarkers(sub.rendered)}~~`);\n } else {\n keptIndices.push(i);\n ctx.rolls.push(...sub.rolls);\n outerRendered.push(sub.rendered);\n total += sub.subtotal;\n }\n\n // Propagate Versus metadata only from kept sub-rolls — `RollResult.degree`\n // must reflect dice that contributed to `RollResult.total`. Two kept\n // versus sub-rolls still collide here via the `NESTED_VERSUS` guard\n // inside `propagateMetadata`.\n if (!isDropped) {\n propagateMetadata(ctx, sub.versusMetadata);\n }\n }\n\n const subExprStrs = subRolls.map((s) => s.expr);\n const modifierCodes = specs.map((s) => `${s.code}${s.count}`).join('');\n\n ctx.expressionParts.push(`{${subExprStrs.join(', ')}}${modifierCodes}`);\n // ? Mirror `evalModifier`'s flat-pool rendering: modifier codes live in\n // `expressionParts` only — the per-sub strikethrough already signals\n // which sub-rolls were kept vs dropped.\n ctx.renderedParts.push(`{${outerRendered.join(', ')}}`);\n\n // ? `keptIndices` lives on the inner `group` part (it describes sub-roll\n // selection), even though the outer modifier evaluation computed it —\n // the accepted model leak from STAGE3.md §5. Dropped sub-rolls keep\n // their complete parts; consumers filter by `keptIndices`.\n const groupPart: RollPart = {\n type: 'group',\n parts: subRolls.map((s) => s.part),\n keptIndices,\n total,\n ...partSpan(group),\n };\n\n return {\n total,\n part: {\n type: 'modifier',\n specs: toPublicSpecs(specs),\n target: groupPart,\n total,\n ...partSpan(node),\n },\n };\n}\n\nfunction resolveThreshold(\n value: ASTNode,\n rng: RNG,\n ctx: EvalContext,\n env: EvalEnv,\n role: 'threshold' | 'fail threshold',\n): number {\n const thresholdCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const resolved = evalNode(value, rng, thresholdCtx, env).total;\n mergeMetaRolls(ctx, thresholdCtx);\n\n if (!Number.isFinite(resolved)) {\n throw new EvaluatorError(`Invalid ${role}: ${resolved}`, 'INVALID_THRESHOLD', 'SuccessCount');\n }\n\n return resolved;\n}\n\nfunction evalSuccessCount(\n node: SuccessCountNode,\n rng: RNG,\n ctx: EvalContext,\n env: EvalEnv,\n): EvalResult {\n // ? Flag tracks syntactic presence of success-count notation, not pool size —\n // set before any early return so empty pools still populate successes/failures.\n env.hasSuccessCount = true;\n\n const targetCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const target = evalNode(node.target, rng, targetCtx, env);\n const targetExpr = targetCtx.expressionParts.join('');\n\n const thresholdValue = resolveThreshold(node.threshold.value, rng, ctx, env, 'threshold');\n const failValue =\n node.failThreshold != null\n ? resolveThreshold(node.failThreshold.value, rng, ctx, env, 'fail threshold')\n : undefined;\n\n const code = `${node.threshold.operator}${thresholdValue}${\n failValue != null ? `f${failValue}` : ''\n }`;\n\n const buildPart = (total: number, successes: number, failures: number): RollPart => {\n const part: RollPart = {\n type: 'successCount',\n threshold: { operator: node.threshold.operator, value: thresholdValue },\n target: target.part,\n successes,\n failures,\n total,\n ...partSpan(node),\n };\n if (failValue != null && node.failThreshold != null) {\n part.failThreshold = { operator: node.failThreshold.operator, value: failValue };\n }\n return part;\n };\n\n // No-op when the target produced no dice in its pool (`0d6>=4`).\n // `containsDicePool` should already reject dice-less targets at parse\n // time, but guard defensively. `targetValue` is 0 for an empty pool, so\n // the `total === successes - failures` invariant holds.\n if (targetCtx.rolls.length === 0) {\n ctx.expressionParts.push(`${targetExpr}${code}`);\n ctx.renderedParts.push(`${targetExpr}${code}`);\n return { total: target.total, part: buildPart(target.total, 0, 0) };\n }\n\n const result = countSuccesses(\n targetCtx.rolls,\n { operator: node.threshold.operator, value: thresholdValue },\n failValue != null && node.failThreshold != null\n ? { operator: node.failThreshold.operator, value: failValue }\n : undefined,\n );\n\n ctx.rolls.push(...targetCtx.rolls);\n ctx.expressionParts.push(`${targetExpr}${code}`);\n ctx.renderedParts.push(`${targetExpr}${code}${renderDice(targetCtx.rolls)}`);\n\n return {\n total: result.total,\n part: buildPart(result.total, result.successes, result.failures),\n };\n}\n\n/**\n * Extracts the \"natural\" d20 value from a roll-side dice pool. Returns the\n * single value when exactly one primary kept d20 is present; otherwise\n * `undefined`.\n *\n * Excludes dropped (`kh`/`kl`/`dh`/`dl`/`r`/`ro`) dice — these aren't the\n * final kept result. Explosion continuation dice (appended by standard/\n * penetrating explode, tagged `'exploded'` with no `initialResult`) are not\n * primaries either — `1d20! vs DC` keeps the natural from the original d20.\n * Compound explode accumulates into the original die and sets\n * `initialResult`, so it stays a primary and the raw first face is used.\n * Multiple primary kept d20s (e.g., `1d20+1d20`) yield `undefined` so no\n * ambiguous upgrade/downgrade is applied.\n */\nfunction extractNatural(rolls: DieResult[]): number | undefined {\n // Rerolled intermediates are always stamped `['rerolled', 'dropped']`\n // (see `modifiers/reroll.ts`), so filtering by `'dropped'` covers them.\n const primaries = rolls.filter(\n (d) =>\n d.sides === 20 &&\n !d.modifiers.includes('dropped') &&\n !(d.modifiers.includes('exploded') && d.initialResult === undefined),\n );\n if (primaries.length !== 1) return undefined;\n const die = primaries[0];\n return die?.initialResult ?? die?.result;\n}\n\n/**\n * PF2e degree of success: compares `total` to `dc` at three thresholds and\n * applies natural 20 upgrade / natural 1 downgrade with clamping.\n */\nfunction calculateDegree(total: number, dc: number, natural: number | undefined): DegreeOfSuccess {\n let degree: DegreeOfSuccess;\n if (total >= dc + 10) degree = DegreeOfSuccess.CriticalSuccess;\n else if (total >= dc) degree = DegreeOfSuccess.Success;\n else if (total > dc - 10) degree = DegreeOfSuccess.Failure;\n else degree = DegreeOfSuccess.CriticalFailure;\n\n if (natural === 20 && degree < DegreeOfSuccess.CriticalSuccess) degree++;\n if (natural === 1 && degree > DegreeOfSuccess.CriticalFailure) degree--;\n\n return degree;\n}\n\nfunction degreeLabel(degree: DegreeOfSuccess): string {\n switch (degree) {\n case DegreeOfSuccess.CriticalFailure:\n return 'Critical Failure';\n case DegreeOfSuccess.Failure:\n return 'Failure';\n case DegreeOfSuccess.Success:\n return 'Success';\n case DegreeOfSuccess.CriticalSuccess:\n return 'Critical Success';\n }\n}\n\nfunction evalVersus(node: VersusNode, rng: RNG, ctx: EvalContext, env: EvalEnv): EvalResult {\n if (env.insideVersus) {\n throw new EvaluatorError('Cannot nest versus operators', 'NESTED_VERSUS', 'Versus');\n }\n\n env.insideVersus = true;\n try {\n const rollCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const rollResult = evalNode(node.roll, rng, rollCtx, env);\n // ? Extract natural from rollCtx directly — the roll-side pool is isolated\n // here, so no index slicing on the merged parent pool is needed.\n const natural = extractNatural(rollCtx.rolls);\n\n const dcCtx: EvalContext = { rolls: [], expressionParts: [], renderedParts: [] };\n const dcResult = evalNode(node.dc, rng, dcCtx, env);\n\n const degree = calculateDegree(rollResult.total, dcResult.total, natural);\n\n ctx.rolls.push(...rollCtx.rolls, ...dcCtx.rolls);\n\n const rollExpr = rollCtx.expressionParts.join('');\n const dcExpr = dcCtx.expressionParts.join('');\n const rollRendered = rollCtx.renderedParts.join('');\n const dcRendered = dcCtx.renderedParts.join('');\n\n ctx.expressionParts.push(`${rollExpr} vs ${dcExpr}`);\n ctx.renderedParts.push(`${rollRendered} vs ${dcRendered}`);\n ctx.versusMetadata = { degree, natural, dcTotal: dcResult.total };\n\n return {\n total: rollResult.total,\n part: {\n type: 'versus',\n roll: rollResult.part,\n dc: dcResult.part,\n degree,\n total: rollResult.total,\n ...partSpan(node),\n },\n };\n } finally {\n env.insideVersus = false;\n }\n}\n\n/**\n * Evaluates a parsed AST and returns the roll result.\n *\n * @param ast - The parsed AST node\n * @param rng - Random number generator to use for dice rolls\n * @param options - Optional evaluation options\n * @returns Complete roll result with total and metadata\n *\n * @example\n * ```typescript\n * const ast = parse('2d6+3');\n * const rng = new SeededRNG('test');\n * const result = evaluate(ast, rng);\n * console.log(result.total); // Sum of dice plus 3\n * ```\n */\nexport function evaluate(ast: ASTNode, rng: RNG, options: EvaluateOptions = {}): RollResult {\n const maxDice =\n options.maxDice != null && Number.isFinite(options.maxDice) && options.maxDice > 0\n ? Math.floor(options.maxDice)\n : DEFAULT_MAX_DICE;\n\n const maxExplodeIterations =\n options.maxExplodeIterations != null &&\n Number.isFinite(options.maxExplodeIterations) &&\n options.maxExplodeIterations >= 0\n ? Math.floor(options.maxExplodeIterations)\n : DEFAULT_MAX_EXPLODE_ITERATIONS;\n\n const maxRerollIterations =\n options.maxRerollIterations != null &&\n Number.isFinite(options.maxRerollIterations) &&\n options.maxRerollIterations >= 0\n ? Math.floor(options.maxRerollIterations)\n : DEFAULT_MAX_REROLL_ITERATIONS;\n\n const context = options.context ?? {};\n const onMissingVariable = options.onMissingVariable ?? 'throw';\n\n const env: EvalEnv = {\n maxDice,\n maxExplodeIterations,\n maxRerollIterations,\n totalDiceRolled: 0,\n hasSuccessCount: false,\n insideVersus: false,\n context,\n onMissingVariable,\n };\n const ctx: EvalContext = {\n rolls: [],\n expressionParts: [],\n renderedParts: [],\n };\n\n const { total, part } = evalNode(ast, rng, ctx, env);\n\n if (!Number.isFinite(total)) {\n throw new EvaluatorError(\n `Result is not a finite number: ${total}`,\n 'NON_FINITE_RESULT',\n ast.type,\n );\n }\n\n const expression = ctx.expressionParts.join('');\n // ? Versus replaces the numeric total with the degree label in the rendered\n // form; `RollResult.total` remains the numeric roll total.\n const trailing = ctx.versusMetadata ? degreeLabel(ctx.versusMetadata.degree) : String(total);\n const rendered = `${ctx.renderedParts.join('')} = ${trailing}`;\n\n const result: RollResult = {\n total,\n notation: options.notation ?? expression,\n expression,\n rendered,\n rolls: ctx.rolls,\n parts: part,\n };\n\n if (env.hasSuccessCount) {\n let successes = 0;\n let failures = 0;\n for (const die of ctx.rolls) {\n if (die.modifiers.includes('success')) successes += 1;\n else if (die.modifiers.includes('failure')) failures += 1;\n }\n result.successes = successes;\n result.failures = failures;\n }\n\n if (ctx.versusMetadata) {\n result.degree = ctx.versusMetadata.degree;\n if (ctx.versusMetadata.natural !== undefined) {\n result.natural = ctx.versusMetadata.natural;\n }\n }\n\n return result;\n}\n",
20
+ "/**\n * Main public API for rolling dice expressions.\n *\n * @module roll\n */\n\nimport type { RNG } from './rng/types.js';\nimport type { EvaluateOptions, RollResult } from './types.js';\nimport { evaluate } from './evaluator/evaluator.js';\nimport { lex } from './lexer/lexer.js';\nimport { Parser } from './parser/parser.js';\nimport { SeededRNG } from './rng/seeded.js';\n\n/**\n * Options for the roll function.\n */\nexport type RollOptions = {\n /** Custom RNG instance (takes precedence over seed) */\n rng?: RNG;\n /** Seed for deterministic rolls (ignored if rng provided) */\n seed?: string | number;\n /** Maximum total dice allowed per evaluation (default: 10,000) */\n maxDice?: number;\n /** Maximum explosion iterations allowed per die (default: 1,000) */\n maxExplodeIterations?: number;\n /** Maximum reroll iterations allowed per die (default: 1,000) */\n maxRerollIterations?: number;\n /** Variable context for `@name` / `@{name}` references (default: empty) */\n context?: Record<string, number>;\n /** Behavior when a referenced variable is missing from context (default: 'throw') */\n onMissingVariable?: 'throw' | 'zero';\n};\n\n/**\n * Parses and evaluates a dice notation string.\n *\n * @param notation - Dice notation (e.g., \"2d6+3\", \"4d6kh3\")\n * @param options - Optional configuration (RNG or seed)\n * @returns Complete roll result with total and metadata\n *\n * @example\n * ```typescript\n * // Random roll\n * const result = roll('2d6+3');\n * console.log(result.total); // 5-15\n *\n * // Seeded for reproducibility\n * const r1 = roll('4d6', { seed: 'test' });\n * const r2 = roll('4d6', { seed: 'test' });\n * r1.total === r2.total; // true\n *\n * // Custom RNG for testing\n * const result = roll('1d20', { rng: createMockRng([15]) });\n * result.total; // 15\n * ```\n */\nexport function roll(notation: string, options: RollOptions = {}): RollResult {\n const rng = options.rng ?? new SeededRNG(options.seed);\n const tokens = lex(notation);\n const ast = new Parser(tokens).parse();\n const evalOptions: EvaluateOptions = { notation };\n if (options.maxDice != null) evalOptions.maxDice = options.maxDice;\n if (options.maxExplodeIterations != null) {\n evalOptions.maxExplodeIterations = options.maxExplodeIterations;\n }\n if (options.maxRerollIterations != null) {\n evalOptions.maxRerollIterations = options.maxRerollIterations;\n }\n if (options.context != null) evalOptions.context = options.context;\n if (options.onMissingVariable != null) {\n evalOptions.onMissingVariable = options.onMissingVariable;\n }\n return evaluate(ast, rng, evalOptions);\n}\n",
21
+ "/**\n * Roll Parser - Dice notation parser for tabletop RPGs.\n *\n * @module roll-parser\n */\n\n// * Error hierarchy\nexport { RollParserError, isRollParserError } from './errors.js';\nexport type { RollParserErrorCode } from './errors.js';\n\n// * Lexer exports\nexport { LexerError } from './lexer/lexer.js';\n\n// * Parser exports\nexport { parse, ParseError } from './parser/parser.js';\nexport type {\n ASTNode,\n BinaryOpNode,\n DiceNode,\n NodeSpan,\n ExplodeNode,\n FateDiceNode,\n FunctionCallNode,\n GroupedNode,\n LiteralNode,\n ModifierNode,\n RerollNode,\n SuccessCountNode,\n SortNode,\n CritThresholdNode,\n GroupNode,\n UnaryOpNode,\n VariableNode,\n VersusNode,\n} from './parser/ast.js';\nexport {\n isBinaryOp,\n isCritThreshold,\n isDice,\n isExplode,\n isFateDice,\n isFunctionCall,\n isGroup,\n isGrouped,\n isLiteral,\n isModifier,\n isReroll,\n isSort,\n isSuccessCount,\n isUnaryOp,\n isVariable,\n isVersus,\n} from './parser/ast.js';\n\n// * RNG exports\nexport type { RNG } from './rng/types.js';\nexport { SeededRNG } from './rng/seeded.js';\n\n// * Evaluator exports\nexport {\n DEFAULT_MAX_DICE,\n DEFAULT_MAX_EXPLODE_ITERATIONS,\n DEFAULT_MAX_REROLL_ITERATIONS,\n evaluate,\n EvaluatorError,\n} from './evaluator/evaluator.js';\nexport type {\n CompareOp,\n ComparePoint,\n DieModifier,\n DieResult,\n EvaluateOptions,\n ModifierSpec,\n ResolvedComparePoint,\n ResolvedCritThreshold,\n RollPart,\n RollPartType,\n RollResult,\n} from './types.js';\nexport { DegreeOfSuccess } from './types.js';\n\n// * Public API\nexport { roll } from './roll.js';\nexport type { RollOptions } from './roll.js';\n\n// ? Named import — Bun's bundler tree-shakes the JSON module down to the\n// single used property, so the full manifest is not embedded in dist.\nimport { version } from '../package.json';\n\nexport const VERSION: string = version;\n"
22
+ ],
23
+ "mappings": "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",
24
+ "debugId": "46432B1558207A2664756E2164756E21",
25
+ "names": []
26
+ }