/** * Dice notation lexer with character-by-character scanning. * * @module lexer/lexer */ import type { RollParserErrorCode } from '../errors.js'; import { RollParserError } from '../errors.js'; import { type Token } from './tokens.js'; /** * Error thrown when the lexer encounters an invalid character. * * `position` is a zero-based UTF-16 offset into the input. It is deliberately * absent from `message` — read it from the field, or uniformly across all * roll-parser errors via `getErrorSpan`. * * Codes: `UNEXPECTED_CHARACTER` for a character that cannot start any token, * `UNEXPECTED_IDENTIFIER` for a word that is not a known keyword. * * @example * ```typescript * import { LexerError, roll } from 'roll-parser'; * * try { * roll('2d6+&'); * } catch (error) { * const typed = error as LexerError; * typed.code; // 'UNEXPECTED_CHARACTER' * typed.character; // '&' * typed.position; // 4 * } * ``` * * @category Errors */ export declare class LexerError extends RollParserError { /** Zero-based UTF-16 offset of the offending character in the input. */ readonly position: number; /** * The offending text — a single character for `UNEXPECTED_CHARACTER` (the * whole code point, so astral symbols are not split into surrogates), or * the unrecognized word for `UNEXPECTED_IDENTIFIER`. * * Not guaranteed to appear in `message` — errors that name a rule rather than * a character leave it out. */ readonly character: string; constructor(message: string, code: RollParserErrorCode, position: number, character: string, options?: ErrorOptions); } /** * Lexer for dice notation. * * Produces a stream of tokens from an input string using character-by-character * scanning with maximal munch for multi-character tokens. */ export declare class Lexer { private pos; private readonly input; constructor(input: string); /** * Tokenize the entire input and return all tokens. */ tokenize(): Token[]; /** * Get the next token from the input. */ nextToken(): Token; /** * Single- and two-character operators. The last resort in `nextToken`'s * dispatch, so an unrecognised character can only be a lexer error. */ private scanOperator; private skipWhitespace; private scanNumber; /** * Scans an identifier using full-accumulation: collects all consecutive * alpha characters, then classifies the result against known keywords. * * Special cases run before/after the accumulation loop: * - `dF` / `Df` / `dF` / `DF` produces DICE_FATE. Must be handled BEFORE * the loop because `F` is alpha and would otherwise be greedily merged * into identifiers like `dfkh` (from `4dFkh2`) or `dfdf` (from `dFdF`). * Reserves the `d[fF]` prefix namespace for Fate dice. * - Bare `d` followed by `%` produces DICE_PERCENT. `%` is not alpha so the * accumulation loop stops naturally and the post-loop check handles it. */ private scanIdentifier; /** * Scans a variable reference introduced by `@`. * * Two forms: * - Bare: `@name` where `name` matches `[A-Za-z_][A-Za-z0-9_]*` (case preserved). * - Braced: `@{name}` where `name` is any run of printable characters except * `}` and newline (permits spaces, hyphens, digits). * * Case is preserved — distinct from `scanIdentifier`, which lowercases the * captured value. The emitted token's `value` is the variable name without * the leading `@` or the surrounding braces. */ private scanAt; private peek; private peekNext; private advance; private match; private isAtEnd; private isDigit; private isAlpha; private isIdentifierStart; private isIdentifierPart; private isWhitespace; private createToken; private createTokenAt; } /** * Tokenizes a dice notation string. The first stage of the pipeline — * {@link parse} calls it for you; reach for `lex` directly only to build a * syntax highlighter or an editor integration. * * Notation is case-insensitive and whitespace-tolerant: `2D20 + 5` and * `2d20+5` produce the same tokens, and identifier tokens carry a lowercased * `value`. The one exception is `@name`, whose case is preserved. * * @param input - The dice notation to tokenize * @returns Every token in source order, always ending with one * `TokenType.EOF` token * @throws {LexerError} If an invalid character or unknown identifier is found * @throws {RollParserError} `INVALID_NOTATION_TYPE` when `input` is not a * string — raised before scanning, so it carries no position * * @example * ```typescript * import { lex, TokenType } from 'roll-parser'; * * const tokens = lex('2d20+5'); * tokens.length; // 6 — NUMBER DICE NUMBER PLUS NUMBER EOF * tokens[0]; // { type: TokenType.NUMBER, value: '2', position: 0, end: 1 } * tokens[1].type === TokenType.DICE; // true * tokens.at(-1)?.type === TokenType.EOF; // true * ``` * * @category Core */ export declare function lex(input: string): Token[]; //# sourceMappingURL=lexer.d.ts.map