### Install Parséman Source: https://matthew-dean.github.io/parseman/guide/getting-started Commands to install the library using common package managers. ```bash npm install parseman ``` ```bash pnpm add parseman ``` ```bash yarn add parseman ``` -------------------------------- ### Define and Run a Parser Source: https://matthew-dean.github.io/parseman/guide/getting-started Example of creating an HTTP request line parser using combinators like choice, sequence, and transform. ```ts import { literal, sequence, choice, regex, transform, parse } from 'parseman' const method = choice(literal('GET'), literal('POST'), literal('PUT'), literal('DELETE')) const target = regex(/[^\s]+/) const version = regex(/1\.[01]/) const requestLine = transform( sequence(method, literal(' '), target, literal(' HTTP/'), version), ([verb, , path, , ver]) => ({ verb, path, version: `HTTP/${ver}` }) ) parse(requestLine, 'GET /api/v1 HTTP/1.1') // { ok: true, value: { verb: 'GET', path: '/api/v1', version: 'HTTP/1.1' }, span: … } ``` -------------------------------- ### Configure CST Build Host Source: https://matthew-dean.github.io/parseman/reference/api Examples of using the generic CST host for structural node grammars, either with default settings or with specific collapse configurations. ```typescript run(rule, input, { build: cstBuildHost }) ``` ```typescript run(rule, input, { build: cstBuildHost({ collapse: ['SelectorList'] }) }) ``` -------------------------------- ### Parse behavior with expect Source: https://matthew-dean.github.io/parseman/guide/error-recovery Examples showing how expect handles valid and invalid input scenarios. ```typescript // "{ a: 1 }" → parses normally; expect(literal('}')) matches, contributes '}'. ``` ```typescript // "{ a: 1" → declList consumes "a: 1", then expect(literal('}')) fails. // Instead of aborting, it records: // { _tag: 'parseError', span: { start: 6, end: 6 }, expected: ['}'] } // and returns a zero-width success. The block node is still produced. ``` -------------------------------- ### Scanning with scanTo and balanced Source: https://matthew-dean.github.io/parseman/guide/combinators Examples of scanning text until a sentinel or matching balanced delimiters. ```typescript // [verify] import { scanTo, balanced, regex, parse } from 'parseman' parse(scanTo(regex(/[;}]/)), 'a b c; rest').value // → 'a b c' parse(balanced('(', ')'), '(a (b) c) rest').value // → '(a (b) c)' // The instructive failure: without a sentinel the scan fails, rather than // silently consuming everything — unless you ask for `orEOF`. parse(scanTo(regex(/;/)), 'no terminator').ok // → false parse(scanTo(regex(/;/), { orEOF: true }), 'no terminator').value // → 'no terminator' ``` -------------------------------- ### Configuring gating behavior in compile() Source: https://matthew-dean.github.io/parseman/guide/first-char-gating Examples of how to configure the gating diagnostic behavior during the compilation process. ```typescript compile(grammar) // default: 'warn' compile(grammar, undefined, { gating: 'off' }) // silence entirely compile(grammar, undefined, { gating: 'error' }) // fail the build (CI) const report = compile(grammar).gating // programmatic GatingReport for snapshots ``` -------------------------------- ### Install trivia for a single combinator Source: https://matthew-dean.github.io/parseman/guide/trivia Use parser() to apply trivia settings to a specific combinator or standalone parser. ```typescript import { parser, regex, trivia, sepBy, literal } from 'parseman' const ws = trivia(regex(/\s*/)) const list = parser({ trivia: ws }, sepBy(regex(/[a-z]+/), literal(','))) list.parse('foo , bar , baz') // { ok: true, value: ['foo','bar','baz'], … } ``` -------------------------------- ### Install trivia for a whole grammar Source: https://matthew-dean.github.io/parseman/guide/trivia Use rules() to set ambient trivia that applies to all terms within the grammar scope. ```typescript import { rules, sequence, sepBy, choice, literal, regex, trivia, oneOrMore, run } from 'parseman' const rw = trivia(oneOrMore(regex(/\s+/))) const g = rules({ trivia: rw }, (r) => ({ List: sequence(literal('['), r.items, literal(']')), items: sepBy(r.value, literal(',')), value: choice(r.List, regex(/[a-z]+/)), })) run(g.List, '[ a , [ b , c ] ]') // spaces skipped between every term run(g.value, ' a') // …and when you parse one rule on its own ``` -------------------------------- ### Standard JSON module import Source: https://matthew-dean.github.io/parseman/guide/macro-mode Example of standard JavaScript import attribute syntax used for JSON modules. ```typescript import data from './config.json' with { type: 'json' } ``` -------------------------------- ### Shared prefix detection patterns Source: https://matthew-dean.github.io/parseman/guide/natural-grammars Examples of various structures that Parséman can peer through to identify shared leading terms. ```typescript choice(sequence(regex(/::?/), a), sequence(regex(/::?/), b)) // bare choice(node('A', sequence(regex(/::?/), a), rA), node('B', sequence(regex(/::?/), b), rB)) choice(node('A', parser({ trivia }, sequence(regex(/::?/), a)), rA), // node + trivia node('B', parser({ trivia }, sequence(regex(/::?/), b)), rB)) choice(transform(sequence(literal('--'), a), fA), sequence(literal('--'), b)) ``` -------------------------------- ### CST Node Structure Example Source: https://matthew-dean.github.io/parseman/guide/ast Represents the structure of a CST node with children and leaf nodes. ```typescript { _tag: 'node', type: 'Expr', span: { start: 0, end: 5 }, state: null, children: [ { _tag: 'node', type: 'Num', span: { start: 0, end: 1 }, state: null, children: [{ _tag: 'leaf', value: '1', span: { start: 0, end: 1 } }] }, { _tag: 'leaf', value: '+', span: { start: 2, end: 3 } }, { _tag: 'node', type: 'Num', span: { start: 4, end: 5 }, state: null, children: [{ _tag: 'leaf', value: '2', span: { start: 4, end: 5 } }] }, ], } ``` -------------------------------- ### Run full benchmark suite Source: https://matthew-dean.github.io/parseman/guide/benchmarks Executes the complete performance comparison suite across all supported grammars and input sizes. ```bash pnpm bench ``` -------------------------------- ### Benchmark and Performance Commands Source: https://matthew-dean.github.io/parseman/guide/performance A collection of CLI commands for running parser benchmarks, generating regression reports, and checking performance regressions. ```bash pnpm bench # parser-to-parser comparison pnpm bench:parseman # Parseman interpreted vs compiled regression report pnpm bench:svg # chart-only benchmarks + regenerate assets/bench-*.svg pnpm bench:baseline # refresh the regression baseline + append a history snapshot pnpm bench:release-compare-svg # regenerate committed 0.26/0.27/0.28 release evidence SVGs pnpm bench:compile-grammars # regenerate the precompiled Peggy/Nearley/Jison parsers pnpm perf:guard # fast pre-commit CSS speed regression check node --import tsx bench/compose-dispatch.ts # composed-grammar first-char dispatch A/B ``` -------------------------------- ### Configuring Grammar for AST and CST Compilation Source: https://matthew-dean.github.io/parseman/guide/ast Demonstrates how to define a grammar once and compile it into two separate artifacts for AST and CST consumers using hostMode. ```typescript const factory = (g) => ({ /* … the whole grammar, written once … */ }) export const grammar = rules({ trivia: rw }, factory) // eval AST export const cstGrammar = rules({ trivia: rw, hostMode: 'cst' }, factory) // positioned CST ``` -------------------------------- ### Fallback to native regex engine Source: https://matthew-dean.github.io/parseman/guide/regex-lowering Example of a pattern that cannot be lowered and remains on the regex engine as a sticky regex. ```javascript const _re0 = /\S+/y // … _re0.lastIndex = _pos const _m0 = _re0.exec(input) if (_m0 === null) { /* fail */ } ``` -------------------------------- ### Initialize and Edit a Document Source: https://matthew-dean.github.io/parseman/guide/incremental Create an incremental document using a registry and root rule, then apply edits using byte offsets. ```typescript import { parseDoc } from 'parseman' const registry = { Expr, Num } // straight from rules() let doc = parseDoc(registry, 'Expr', src) doc.tree // your Node root, or null on failure doc.errors // ParseFail[], empty on success doc.input // the source string // edit(from, to, replacement) — two byte offsets into the OLD text + the // replacement. "Select from→to, type replacement" — the three things every // editor knows on each keystroke. Returns a NEW doc; the old one is untouched. doc = doc.edit(changeStart, changeStart + changeLength, newText) ``` -------------------------------- ### run(entry, input, options) Source: https://matthew-dean.github.io/parseman/reference/api Executes a parser on the provided input. When tolerant mode is enabled, the parser attempts to recover from errors within lists by skipping to inferred sync points. ```APIDOC ## run(entry, input, options) ### Description Executes the parser defined by `entry` against the `input` string. The `tolerant` option enables list recovery, allowing the parser to continue after encountering errors in `many`, `oneOrMore`, or `sepBy` combinators. ### Parameters - **entry** (Parser) - Required - The grammar entry point. - **input** (string) - Required - The input text to parse. - **options** (object) - Optional - Configuration object. - **tolerant** (boolean) - Optional - If true, activates list recovery mode. ``` -------------------------------- ### walk(root, visitor, ctx?) Source: https://matthew-dean.github.io/parseman/guide/ast Performs a depth-first traversal of the AST with enter and leave hooks. Returning false from the enter hook allows skipping a subtree. ```APIDOC ## walk(root, visitor, ctx?) ### Description Performs a depth-first traversal of the AST. Users can provide enter and leave hooks to process nodes. Returning false from the enter hook skips the current subtree. ### Signature `walk(root: T, visitor: { enter?: (node: T) => boolean | void, leave?: (node: T) => void }, ctx?: any)` ### Example ```typescript import { walk } from 'parseman' const leaves: string[] = [] walk(tree, { enter(node) { if (node._tag === 'leaf') leaves.push(node.value) }, }) ``` ``` -------------------------------- ### run(entry, input, opts?) Source: https://matthew-dean.github.io/parseman/reference/api Executes a grammar entry against the input, managing context such as trivia logs and grammar state. ```APIDOC ## run(entry, input, opts?) ### Description Runs a grammar entry (a rule function or interpreter combinator) against the input. It threads the standard context and returns a RunResult. ### Parameters - **entry** (any) - The grammar rule or combinator to run. - **input** (string) - The input string to process. - **opts** (object) - Optional configuration. - **build** (any) - The CST host. - **state** (any) - Initial grammar state. - **trivia** (any) - The grammar's trivia rule to skip whitespace/comments. ### Example ```ts const g = compose([base]) run(g.Value, '12 ', { trivia: g.rw }) ``` ``` -------------------------------- ### Handle Invalid Combinator Input Source: https://matthew-dean.github.io/parseman/guide/grammar-duplication Example of the error message thrown when passing a compiled artifact instead of a rules map to the analyzer. ```text analyzeDuplicationRules: rule 'Declaration' is not a combinator (no _def). This analysis walks the COMBINATOR TREE; the value returned by compose()/composeLeaf() is a fused, already-compiled artifact whose entries are parse functions. Pass the rules() map itself … ``` -------------------------------- ### cstBuildHost(opts?) Source: https://matthew-dean.github.io/parseman/reference/api Provides a generic CST host for structural node grammars, allowing configuration of node collapsing behavior. ```APIDOC ## cstBuildHost(opts?) ### Description Returns a host function for `run()` that produces uniform positioned CST nodes. It supports collapsing transparent one-child wrappers. ### Parameters - **opts** (object) - Optional - Configuration object. - **collapse** (boolean | string[] | CstCollapsePredicate) - Defines which nodes to collapse during CST construction. ``` -------------------------------- ### Development Commands Source: https://matthew-dean.github.io/parseman/guide/getting-started Common scripts for developing and testing the Parséman library. ```bash pnpm install pnpm test # Vitest — interpreter + compiler parity + ordered-choice semantics pnpm typecheck # TypeScript 7 pnpm build # ESM + CJS + .d.ts → dist/ pnpm bench # vs Peggy, Parsimmon, Chevrotain, Nearley, Jison pnpm docs:dev # this documentation site ``` -------------------------------- ### walk(root, visitor, ctx?) Source: https://matthew-dean.github.io/parseman/reference/api Performs a depth-first traversal of the tree. Calls visitor.enter before children and visitor.leave after children. ```APIDOC ## walk(root, visitor, ctx?) ### Description Performs a depth-first traversal of the tree. Calls `visitor.enter(node, parent, ctx)` before a node's children and `visitor.leave(node, parent, ctx)` after. Return `false` from `enter` to skip that node's subtree. ### Parameters - **root** (any) - The root node of the tree. - **visitor** (object) - An object containing `enter` and `leave` hook functions. - **ctx** (any) - Optional context object threaded through the traversal. ``` -------------------------------- ### parseDoc(registry, rootRule, src, options?) Source: https://matthew-dean.github.io/parseman/guide/incremental Initializes a new incremental document instance. ```APIDOC ## parseDoc(registry, rootRule, src, options?) ### Description Creates a new incremental document instance from a registry of rules and source text. ### Parameters - **registry** (object) - Required - The object returned by rules() containing parser functions. - **rootRule** (string) - Required - The name of the entry in the registry to parse from. - **src** (string) - Required - The source text to parse. - **options** (object) - Optional - Configuration options, such as { structuralReuse: boolean }. ### Response - **doc** (object) - An incremental document instance containing the tree, errors, and input. ``` -------------------------------- ### Swap output tree shapes with build hosts Source: https://matthew-dean.github.io/parseman/guide/extending Use a build host to switch between AST and CST output formats during grammar composition. ```typescript import { compose, cstBuildHost } from 'parseman' const parser = compose([base]) parser.Value('12', 0, {}) // → the grammar's own AST parser.Value('12', 0, { build: cstBuildHost }) // → a positioned CST node ``` -------------------------------- ### toEBNF(grammar, options?) Source: https://matthew-dean.github.io/parseman/reference/api Renders a grammar as W3C-style EBNF text. ```APIDOC ## toEBNF(grammar, options?) ### Description Render W3C-style EBNF text — one production per named rule. ### Parameters - **grammar** (rules() record or combinator) - Required - The grammar to render. - **options** (object) - Optional - Includes 'sort', 'root', 'order', 'includeTrivia', 'terminals', and 'regexDisplay'. ``` -------------------------------- ### Demonstrate ordered choice behavior Source: https://matthew-dean.github.io/parseman/guide/keywords Shows how the order of alternatives affects matching when prefixes are shared. ```typescript // [verify] import { choice, literal, regex, parse } from 'parseman' const op = choice(literal('instanceof'), literal('in'), literal('if')) parse(op, 'instanceof x').value // → 'instanceof' // Short arm first → it matches the prefix and the long arm is unreachable. const shadowed = choice(regex(/in/), regex(/instanceof/)) parse(shadowed, 'instanceof x').value // → 'in' ``` -------------------------------- ### Create a token with token() Source: https://matthew-dean.github.io/parseman/reference/api Wraps a parser to return the matched source text as a single token, collapsing internal CST leaves. ```ts token(sequence(literal('!'), regex(/important/i))) ``` -------------------------------- ### compile(combinator, mapFnSources?) Source: https://matthew-dean.github.io/parseman/reference/api JIT-compiles a combinator tree into an optimized JavaScript function at runtime. Returns a CompiledParser object with parsing methods and source metadata. ```APIDOC ## compile(combinator, mapFnSources?) ### Description JIT-compiles a combinator tree to an optimized JS function at runtime. Requires 'new Function' (won't run under a strict CSP). ### Returns Returns a `CompiledParser` exposing `.parse()`, `.parseWithContext()`, `.parseWithErrors()`, plus the generated `.source` and `.inlineExpression` strings. ``` -------------------------------- ### analyzeGating(entry, opts?) Source: https://matthew-dean.github.io/parseman/reference/api Performs a static first-char gating diagnostic over a combinator tree. ```APIDOC ## analyzeGating(entry, opts?) ### Description Static first-char gating diagnostic over a combinator tree. Returns a `GatingReport` containing findings on gating status, anti-patterns, and deferred choices. ### Parameters - **entry** (object) - Required - The combinator tree to analyze. - **opts** (object) - Optional - Configuration options including `accept` (a snapshot allowlist for choice IDs). ``` -------------------------------- ### Composing Grammars Across Packages Source: https://matthew-dean.github.io/parseman/guide/extending Demonstrates importing a compiled grammar from a base package and extending it within a dialect package. ```typescript // @scope/base → ships a compiled grammar import { rules, regex, choice } from 'parseman' with { type: 'macro' } export const base = rules(g => ({ Value: choice(g.Num, g.Word), Num: regex(/[0-9]+/), Word: regex(/[a-z]+/) })) // @scope/dialect → extends it, importing the COMPILED base import { rules, regex, compose } from 'parseman' with { type: 'macro' } import { base } from '@scope/base' export const parser = compose([base, rules(() => ({ Num: regex(/[0-9]+!/) }))]) ``` -------------------------------- ### parse(c, input, opts?) Source: https://matthew-dean.github.io/parseman/guide/combinators Runs a combinator once against the provided input string. ```APIDOC ## parse(c, input, opts?) ### Description Executes a combinator against an input string. Returns an object containing the result status, the parsed value, and the span of the match. ### Parameters - **c** (Combinator) - Required - The combinator to execute. - **input** (string) - Required - The input string to parse. - **opts** (Object) - Optional - Additional parsing options. ``` -------------------------------- ### choice(...alternatives) Source: https://matthew-dean.github.io/parseman/guide/combinators Provides ordered alternatives with PEG semantics where the first match wins. ```APIDOC ## choice(...alternatives) ### Description Ordered alternatives with PEG semantics: first match wins. Write the longer of two overlapping alternatives first to avoid shadowing. ``` -------------------------------- ### buildTriviaIndex(root, input?, opts?) Source: https://matthew-dean.github.io/parseman/reference/api Walks a CST to generate a lookup table for trivia tokens keyed by node. ```APIDOC ## buildTriviaIndex(root, input?, opts?) ### Description Converts a flat `triviaLog` into a lookup table of `before` and `after` maps for whitespace-sensitive analysis. ### Parameters - **root** (object) - Required - The CST root node. - **input** (string) - Optional - The source input string. - **opts** (object) - Optional - Additional options for the index build. ``` -------------------------------- ### Configure EBNF production ordering Source: https://matthew-dean.github.io/parseman/guide/spec-generation Demonstrates how to toggle between declaration order and reachable order when generating EBNF output. ```typescript // rules declared as [expr, zzz, term], where expr references term: toEBNF(g) // expr, zzz, term (declaration order) toEBNF(g, { sort: 'reachable' }) // expr, term, zzz (term introduced at first use) ``` -------------------------------- ### Performance testing commands Source: https://matthew-dean.github.io/parseman/guide/regex-lowering Commands used to verify performance and ensure lowering optimizations do not regress. ```bash pnpm perf:guard # fast pre-commit check: CSS speed vs a committed baseline pnpm bench # parser-to-parser comparison (JSON/CSV/GraphQL) pnpm bench:parseman # interpreted vs compiled Parseman suite pnpm test:perf # heavier perf assertions ``` -------------------------------- ### Run specific benchmark tasks Source: https://matthew-dean.github.io/parseman/guide/benchmarks Various commands for regression testing, baseline management, and performance guarding. ```bash pnpm bench:parseman ``` ```bash pnpm bench:baseline ``` ```bash pnpm perf:guard ``` -------------------------------- ### createVisitor(handlers) Source: https://matthew-dean.github.io/parseman/guide/ast Creates a visitor function that dispatches based on the node's type. Handlers receive an API object to control recursion. ```APIDOC ## createVisitor(handlers) ### Description Creates a visitor function that dispatches logic based on the node's type. Handlers receive an API object with `visit` and `visitChildren` methods to manage recursion. If a node type has no handler, it falls through to its children. ### Signature `createVisitor(handlers: { [type: string]: (node: N, api: { visit: (n: N) => R, visitChildren: (n: N) => R[] }) => R }): (root: N) => R` ### Example ```typescript import { createVisitor } from 'parseman' const evalExpr = createVisitor({ Num: (n) => Number((n as NumNode).value), Add: (n, api) => api.visitChildren(n).reduce((a, b) => a + b, 0), }) const total = evalExpr(tree) ``` ``` -------------------------------- ### Wire language service into a language server Source: https://matthew-dean.github.io/parseman/guide/editor-integration Demonstrates managing document state, incremental updates, and completion requests within a language server connection. ```typescript const css = languageService({ rules: grammar, root: 'StyleSheet' }, config) const docs = new Map>() connection.onDidOpenTextDocument(({ textDocument: t }) => { docs.set(t.uri, css.openDocument(t.text)) publish(t.uri) }) connection.onDidChangeTextDocument(({ textDocument, contentChanges }) => { let doc = docs.get(textDocument.uri)! for (const c of contentChanges) { const from = doc /* map c.range → offsets */ , to = from // (via your line index) doc = doc.edit(from, to, c.text) } docs.set(textDocument.uri, doc) publish(textDocument.uri) }) connection.onCompletion(({ textDocument, position }) => { const doc = docs.get(textDocument.uri)! return doc.completionsAt(offsetOf(position)).map(c => ({ label: c.label, detail: c.detail })) }) function publish(uri: string) { const diags = docs.get(uri)!.diagnostics().map(d => ({ severity: d.severity === 'error' ? 1 : 2, range: rangeOf(d.span), message: d.message, })) connection.sendDiagnostics({ uri, diagnostics: diags }) } ``` -------------------------------- ### parse(c, input, opts?) Source: https://matthew-dean.github.io/parseman/guide/combinators Executes a combinator against an input string using the interpreter. ```APIDOC ## parse(c, input, opts?) ### Description Runs a combinator once through the interpreter to parse the provided input string. ``` -------------------------------- ### Compare grammar performance approaches Source: https://matthew-dean.github.io/parseman/guide/performance A comparison of different parsing strategies for a repeated 3-shape group, demonstrating the performance benefits of collapsing combinators into a single regex. ```text oneOrMore(sequence(ident, sp, num, sp, hex, sp)) ``` ```text same, with inline regex(…) instead of shared refs ``` ```text one regex(/…ident…num…hex…/) per group ``` -------------------------------- ### Using expect and isParseError Source: https://matthew-dean.github.io/parseman/guide/combinators Demonstrates making a token required and checking for parse errors during recovery. ```typescript // [verify] import { expect, isParseError, sequence, literal, regex, parse } from 'parseman' const decl = sequence(regex(/[a-z]+/), expect(literal(':'), 'colon'), regex(/[a-z]*/)) const r = parse(decl, 'color red', { recover: true }) r.ok // → true isParseError(r.ok && r.value[1]) // → true ``` -------------------------------- ### choice(...args) Source: https://matthew-dean.github.io/parseman/reference/api Ordered PEG alternatives where the first match wins. Arms can be plain combinators or gated arms. ```APIDOC ## choice(...args) ### Description Ordered PEG alternatives where the first match wins. When every arm's first-set is disjoint and non-nullable, the choice compiles to an O(1) first-char dispatch. ``` -------------------------------- ### parser(opts, root) Source: https://matthew-dean.github.io/parseman/reference/api Wraps a root combinator with document-level options and provides a .parse(input) method. ```APIDOC ## parser(opts, root) ### Description Wraps a root combinator with document-level options such as `trivia`, `trackLines`, and `captureTrivia`, and adds a `.parse(input)` convenience method. ``` -------------------------------- ### Define CstBuildHostOptions Source: https://matthew-dean.github.io/parseman/reference/types Configuration for CST construction, including predicates for collapsing transparent wrappers. ```typescript type CstCollapsePredicate = ( type: string, child: unknown, children: readonly unknown[], rawChildren: readonly unknown[], ) => boolean type CstBuildHostOptions = { collapse?: boolean | readonly string[] | CstCollapsePredicate } ``` -------------------------------- ### Execute Grammar Instrumentation Source: https://matthew-dean.github.io/parseman/guide/grammar-observability Initialize the coverage collector and trace sink, then pass the instrumentation context to the run function. ```typescript import { createGrammarCoverageCollector, createGrammarInstrumentationContext, createGrammarTraceSink, compiledGrammarCoverageDefinitions, run, } from 'parseman' const collector = createGrammarCoverageCollector(compiledGrammarCoverageDefinitions(grammar)) const trace = createGrammarTraceSink({ capacity: 200 }) const context = createGrammarInstrumentationContext({ collector, trace }) run(grammar.Entry, 'yes', { instrumentation: context }) ``` -------------------------------- ### Build a visitor with createVisitor Source: https://matthew-dean.github.io/parseman/reference/api Creates a visitor that dispatches based on node type, allowing for recursive evaluation of tree structures. ```typescript const evalExpr = createVisitor({ Num: (n) => Number((n.children[0] as CSTLeaf).value), Add: (n, api) => api.visitChildren(n).reduce((a, b) => a + b, 0), }) const total = evalExpr(tree) ``` -------------------------------- ### Build a CST with a custom host Source: https://matthew-dean.github.io/parseman/guide/incremental Pass a build host to ensure that incremental edits produce the same CST structure as a fresh parse. ```typescript import { parseDoc, cstBuildHost } from 'parseman' let doc = parseDoc(registry, 'Stylesheet', src, { build: cstBuildHost }) doc = doc.edit(from, to, text) // re-parsed subtrees are CST nodes too ``` -------------------------------- ### Define NodeOptions Source: https://matthew-dean.github.io/parseman/reference/types Configuration for AST/CST node construction, including unwrapping, collapsing, and trivia management. ```typescript type NodeOptions = { unwrap?: boolean collapse?: boolean captureTrivia?: boolean trailingTrivia?: boolean // commit one active-trivia run at this node's terminal boundary } ``` -------------------------------- ### Dispatch nodes with createVisitor Source: https://matthew-dean.github.io/parseman/guide/ast Dispatches on node types using handlers. Partial visitors are supported as nodes without handlers fall through to children. ```typescript import { createVisitor } from 'parseman' const evalExpr = createVisitor({ Num: (n) => Number((n as NumNode).value), Add: (n, api) => api.visitChildren(n).reduce((a, b) => a + b, 0), }) const total = evalExpr(tree) ``` -------------------------------- ### compile(c) Source: https://matthew-dean.github.io/parseman/guide/combinators Lowers a combinator to JavaScript for improved performance while maintaining the same semantics. ```APIDOC ## compile(c) ### Description Compiles a combinator into executable JavaScript code. ``` -------------------------------- ### Using the peek combinator Source: https://matthew-dean.github.io/parseman/guide/combinators Demonstrates using peek for positive lookahead to check for patterns without consuming them. ```typescript // [verify] import { peek, sequence, literal, regex, parse } from 'parseman' // "only try this arm when the punctuation is ahead" — then let the real // production consume it. const mixinRef = sequence(peek(regex(/[.#]/)), regex(/[.#][\w-]+/)) parse(mixinRef, '.rounded').value // → [null, '.rounded'] parse(mixinRef, 'rounded').ok // → false // Zero-width, like `not`. parse(peek(literal('@')), '@media').span // → { start: 0, end: 0 } ``` -------------------------------- ### makeWord(boundary, options) Source: https://matthew-dean.github.io/parseman/guide/combinators Creates a factory function for parsing keywords with specific boundary characters and options. ```APIDOC ## makeWord(boundary, options) ### Description A definition-time factory that fixes the boundary class and keyword options, for grammars where every keyword shares them. ### Parameters - **boundary** (string) - Required - A string defining the allowed characters for the word. - **options** (object) - Optional - Configuration object (e.g., { caseInsensitive: boolean }). ``` -------------------------------- ### scanTo(sentinel, opts?) Source: https://matthew-dean.github.io/parseman/guide/combinators Walks forward until the sentinel matches without consuming it, returning the skipped text. ```APIDOC ## scanTo(sentinel, opts?) ### Description Scans input until a sentinel is found. It respects ambient trivia and `scanSkip` configurations. ### Parameters - **sentinel** (Parser) - Required - The parser to stop at. - **opts** (Object) - Optional - Configuration options. - **skip** (Array) - Extra opaque units to skip. - **raw** (boolean) - If true, skips nothing ambiently. - **orEOF** (boolean) - If true, succeeds at EOF if sentinel is not found. ``` -------------------------------- ### Binding Compiled Rules Source: https://matthew-dean.github.io/parseman/guide/macro-mode Demonstrates the two ways to bind compiled rules from a factory. ```typescript const { value } = rules(…) // each rule becomes a top-level function const grammar = rules(…) // an object literal of compiled rules; grammar.value(…) works ``` -------------------------------- ### analyzeDuplicationRules(ruleMap, opts?) Source: https://matthew-dean.github.io/parseman/reference/api Performs a static structural-duplication diagnostic over a rule map. ```APIDOC ## analyzeDuplicationRules(ruleMap, opts?) ### Description Performs a static structural-duplication diagnostic over a rule map. Reports eight families of findings including rewrites, structure loss, and regex fragments. ### Parameters - **ruleMap** (Object) - Required - The rules map to analyze. - **opts** (Object) - Optional - Configuration options. - **accept** (Array) - Optional - Allowlist of finding IDs. ### Response - **DuplicationReport** (Object) - A report containing findings across eight categories. ``` -------------------------------- ### Recognizing keywords with word, literal, and regex Source: https://matthew-dean.github.io/parseman/guide/combinators Demonstrates how word, literal, and regex combinators handle keyword matching and boundary requirements. ```typescript // [verify] import { word, literal, regex, parse } from 'parseman' const all = (input: string) => [parse(word('if'), input).ok, parse(literal('if'), input).ok, parse(regex(/if/), input).ok] // All three match `if` at the start… all('if x') // → [true, true, true] // …but only `word` refuses the keyword inside a longer word. all('ifdef') // → [false, true, true] ``` -------------------------------- ### keywords(words, opts?) Source: https://matthew-dean.github.io/parseman/reference/api Matches one of many keywords, compiled to a single sticky regex. ```APIDOC ## keywords(words, opts?) ### Description Matches one of many keywords, longest-first, compiled to a single sticky regex. ### Parameters - **words** (string[]) - Required - Array of keywords to match. - **opts** (object) - Optional - Configuration options including boundary and caseInsensitive. ``` -------------------------------- ### dispatch(selector, when(...), otherwise(...)) Source: https://matthew-dean.github.io/parseman/reference/api Parses a selector once, uses its string value as a static dispatch key, then parses the selected tail. ```APIDOC ## dispatch(selector, when(...), otherwise(...)) ### Description Parse `selector` once, use its string value as a static dispatch key, then parse the selected tail from the selector end. Use this when one broad selector token is valid generally, and selected selector values have specialized continuation grammars. ``` -------------------------------- ### Create a word parser with makeWord Source: https://matthew-dean.github.io/parseman/guide/combinators Defines a factory for keywords that share specific boundary and case-sensitivity settings. ```typescript // [verify] import { makeWord, parse } from 'parseman' const cssKw = makeWord('A-Za-z0-9_-', { caseInsensitive: true }) parse(cssKw('screen'), 'SCREEN and (x)').value // → 'SCREEN' parse(cssKw('screen'), 'screen-only').ok // → false ``` -------------------------------- ### Compile a grammar at runtime Source: https://matthew-dean.github.io/parseman/guide/modes Use compile() to generate a parser at runtime when a build step is not feasible. Note that this requires 'unsafe-eval' permissions due to the use of new Function. ```typescript import { choice, literal, compile } from 'parseman' const compiled = compile(choice(literal('yes'), literal('no'))) compiled.parse('yes', 0, { trackLines: false }) // { ok: true, value: 'yes', … } compiled.source // the generated JS source string compiled.inlineExpression // self-contained expr (what the plugin inlines) ``` -------------------------------- ### parser(options, root) Source: https://matthew-dean.github.io/parseman/guide/combinators Configures a parser with grammar-wide options such as trivia handling. ```APIDOC ## parser(options, root) ### Description Sets up a parser with specific options. The 'trivia' option defines a combinator to be treated as skippable filler between sequence terms. ``` -------------------------------- ### Committing vs looking with attempt and peek Source: https://matthew-dean.github.io/parseman/guide/combinators Compares attempt, which consumes input on success, with peek, which is zero-width. ```typescript // [verify] import { attempt, peek, literal, parse } from 'parseman' [parse(attempt(literal('ab')), 'abc').span.end, parse(peek(literal('ab')), 'abc').span.end] // → [2, 0] ``` -------------------------------- ### Update benchmark charts Source: https://matthew-dean.github.io/parseman/guide/benchmarks Generates and updates the SVG comparison charts located in the assets directory. ```bash pnpm bench:svg # run chart-only benchmarks, then write assets/bench-*.svg ``` -------------------------------- ### Execute grammar with the Interpreter mode Source: https://matthew-dean.github.io/parseman/guide/modes The default mode requires no build step or configuration, executing directly in any JavaScript environment. ```typescript import { choice, literal, parse } from 'parseman' const yesNo = choice(literal('yes'), literal('no')) parse(yesNo, 'yes') // { ok: true, value: 'yes', … } ``` -------------------------------- ### makeWord(boundary?, opts?) Source: https://matthew-dean.github.io/parseman/reference/api Returns a factory function that creates a Combinator with a fixed boundary class and keyword options. ```APIDOC ## makeWord(boundary?, opts?) ### Description Returns a factory function that creates a Combinator with a fixed boundary class and keyword options. ### Parameters - **boundary** (string) - Optional - Fixed boundary class. - **opts** (object) - Optional - Keyword options. ``` -------------------------------- ### Parse and compile combinators Source: https://matthew-dean.github.io/parseman/guide/combinators Demonstrates using parse() for interpretation and compile() for lowering to JavaScript. ```typescript // [verify] import { compile, parse, choice, literal } from 'parseman' const g = choice(literal('a'), literal('b')) const compiled = compile(g, undefined, { gating: 'off' }) parse(g, 'b').value // → 'b' compiled.parse('b').value // → 'b' ``` -------------------------------- ### Assemble a grammar from reusable parts Source: https://matthew-dean.github.io/parseman/guide/extending Factor reusable rules into standalone grammar objects and compose them into a host grammar. References within the mixin resolve to the host grammar's definitions at runtime. ```typescript // A package exports the mixin machinery as a standalone composable grammar… export const mixins = rules({ trivia }, (g) => ({ MixinCall: sequence(g.Selector, literal('('), g.args, literal(')')), // …references g.Selector / g.args by name — the composing grammar supplies them. })) // …and a consumer composes just that piece in: const parser = compose([css, mixins, myDelta]) ``` -------------------------------- ### Line Indexing Utilities Source: https://matthew-dean.github.io/parseman/reference/api Low-level primitives for mapping byte offsets to line and column information. ```APIDOC ## buildLineIndex(input) Precomputes newline offsets to create a LineIndex for O(log n) lookups. ## offsetToLineCol(index, offset) Maps a byte offset to a { line, col } object (1-based). ## annotateSpan(span, index) Returns a copy of a span with startLine, startColumn, endLine, and endColumn properties filled in. ``` -------------------------------- ### scanTo(sentinel, opts?) Source: https://matthew-dean.github.io/parseman/reference/api Consumes text until the specified sentinel is reached, while respecting ambient skip rules. ```APIDOC ## scanTo(sentinel, opts?) ### Description Consumes text up to the sentinel. By default, it skips ambient trivia and opaque units. ### Parameters - **sentinel** (string) - Required - The text to stop at. - **opts** (object) - Optional - - **skip** (array) - Optional - Extra opaque regions to skip. - **raw** (boolean) - Optional - If true, disables all ambient skipping. - **orEOF** (boolean) - Optional - If true, treats EOF as a success. ``` -------------------------------- ### Implement CI Gating Allowlist Source: https://matthew-dean.github.io/parseman/guide/first-char-gating Use an allowlist to track reviewed ungated choices and fail the build if new ungated choices appear or allowlist entries become stale. ```typescript import { analyzeGating } from 'parseman' const ACCEPTED = ['statement', 'value#1'] // reviewed, intentional (keep a reason each) const report = analyzeGating(grammarEntry, { accept: ACCEPTED }) expect(report.ungated.map(c => c.id)).toEqual([]) // fails when a NEW choice ungates expect(report.acceptedUnused).toEqual([]) // fails when an allowlist entry goes stale ``` -------------------------------- ### Execute a parser with options Source: https://matthew-dean.github.io/parseman/reference/api Run a combinator against an input string with specific parsing options enabled. ```typescript parse(myParser, 'hello world', { trackLines: true, recover: true }) ``` -------------------------------- ### Configure Vitest for grammar coverage Source: https://matthew-dean.github.io/parseman/guide/grammar-observability Enables grammar instrumentation in the Vite configuration for test builds. ```typescript // vitest.config.ts import parseman from 'parseman/plugin' export default { plugins: [parseman.vite({ grammarCoverage: true })], } ``` -------------------------------- ### attempt(combinator) Source: https://matthew-dean.github.io/parseman/reference/api Makes one ordered-choice arm transactional, restoring state if the parser fails after consuming input. ```APIDOC ## attempt(combinator) ### Description Make one ordered-choice arm transactional. If its parser fails after consuming input, Parseman restores its structural capture, trivia, field, and recovery diagnostic sinks before returning a zero-width failure at the attempt entry. ``` -------------------------------- ### analyzeDuplication(entry, opts?) Source: https://matthew-dean.github.io/parseman/reference/api Performs a static structural-duplication diagnostic over a combinator tree entry. ```APIDOC ## analyzeDuplication(entry, opts?) ### Description Performs a static structural-duplication diagnostic over a combinator tree. Reports eight families of findings including rewrites, structure loss, and regex fragments. ### Parameters - **entry** (Object) - Required - The rules map to analyze. - **opts** (Object) - Optional - Configuration options. - **accept** (Array) - Optional - Allowlist of finding IDs. ### Response - **DuplicationReport** (Object) - A report containing findings across eight categories. ``` -------------------------------- ### Build Specification Model Source: https://matthew-dean.github.io/parseman/guide/spec-generation Generate a notation-agnostic model with specific root rules to control output scope. ```typescript buildSpecModel(g, { root: 'expr' }) // only expr, call, list ``` -------------------------------- ### composeLeaf([...recognition, localRules]) Source: https://matthew-dean.github.io/parseman/reference/api A macro that fuses imported recognition-only grammar pieces with a final local rules map. ```APIDOC ## composeLeaf([...recognition, localRules]) ### Description Fuses imported, recognition-only grammar pieces with one final local rules() map. This macro is terminal and cannot be fed into another compose or composeLeaf call. ### Parameters - **recognition** (array) - Required - Array of recognition-only grammar pieces. - **localRules** (object) - Required - The final local rules map. ``` -------------------------------- ### completionsAt(target, input, offset, options?) Source: https://matthew-dean.github.io/parseman/reference/api Returns the set of expected tokens at a specific cursor offset, providing the raw material for autocomplete functionality. ```APIDOC ## completionsAt(target, input, offset, options?) ### Description Returns the set of expected tokens at a cursor offset by probing the grammar at that position via a truncated parse. ### Parameters - **target** (interpreter combinator or compiled grammar) - Required - The grammar or interpreter to probe. - **input** (string) - Required - The input text to parse. - **offset** (number) - Required - The cursor position. - **options.tolerant** (boolean) - Optional - When true, list recovery keeps parsing past a bad element before the cursor. Default: false. ``` -------------------------------- ### Configure Macro build mode Source: https://matthew-dean.github.io/parseman/guide/modes Use import attributes to trigger compile-time evaluation of combinators during the build process. ```typescript import { literal, sequence, choice } from 'parseman' with { type: 'macro' } ```