UNPKG

jsdoc-type-pratt-parser

Version:

[![Npm Package](https://badgen.net/npm/v/jsdoc-type-pratt-parser)](https://www.npmjs.com/package/jsdoc-type-pratt-parser) [![Test Status](https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/actions/workflows/test.yml/badge.svg?branch=main)]

71 lines (61 loc) 2.25 kB
import type { Token } from './Token.js' import type { Rule } from './LexerRules.js' const breakingWhitespaceRegex = /^\s*\n\s*/ export class Lexer { private readonly text: string = '' public readonly lexerRules: Rule[] public readonly current: Token public readonly next: Token public readonly previous: Token | undefined public static create (lexerRules: Rule[], text: string): Lexer { const current = this.read(lexerRules, text) text = current.text const next = this.read(lexerRules, text) text = next.text return new Lexer(lexerRules, text, undefined, current.token, next.token) } private constructor (lexerRules: Rule[], text: string, previous: Token | undefined, current: Token, next: Token) { this.lexerRules = lexerRules this.text = text this.previous = previous this.current = current this.next = next } private static read (lexerRules: Rule[], text: string, startOfLine = false): { text: string, token: Token } { startOfLine ||= breakingWhitespaceRegex.test(text) const start = text.length const initialWhitespace = (/^\s+/u).exec(text)?.[0] ?? '' text = text.trimStart() const trimmed = start - text.length for (const rule of lexerRules) { const partial = rule(text) if (partial !== null) { const initialLines = initialWhitespace.split('\n') const currentLines = partial.text.split('\n') const token = { ...partial, startOfLine, reduced: trimmed + partial.text.length, line: initialLines.length + currentLines.length - 2, column: currentLines.length === 1 /* c8 ignore next 3 -- Defaults are for TS */ ? (initialLines.at(-1)?.length ?? 0) + (currentLines.at(-1)?.length ?? 0) : (currentLines.at(-1)?.length ?? 0) } text = text.slice(token.text.length) return { text, token } } } throw new Error('Unexpected Token ' + text) } remaining (): string { return this.next.text + this.text } advance (): Lexer { const next = Lexer.read(this.lexerRules, this.text) return new Lexer( this.lexerRules, next.text, this.current, this.next, next.token ) } }