UNPKG

parjs

Version:

Library for building parsers using combinators.

60 lines (55 loc) 1.83 kB
import { Combinated } from "../combinated"; import { Issues } from "../issues"; import type { ParjsCombinator } from "../parjser"; import type { ParjserBase } from "../parser"; import { ResultKind } from "../result"; import type { ParsingState } from "../state"; import { wrapImplicit } from "../wrap-implicit"; class Many1<T> extends Combinated<T, [T, ...T[]]> { type = "many1"; expecting = this.source.expecting; constructor( source: ParjserBase<T>, private _maxIterations: number ) { super(source); } _apply(ps: ParsingState): void { let { position } = ps; const arr = [] as unknown[]; let i = 0; for (;;) { this.source.apply(ps); if (!ps.isOk) break; if (i >= this._maxIterations) break; if (this._maxIterations === Infinity && ps.position === position) { Issues.guardAgainstInfiniteLoop(this.type); } position = ps.position; arr.push(ps.value); i++; } if (ps.atLeast(ResultKind.HardFail)) { return; } if (i === 0) { ps.kind = ResultKind.SoftFail; ps.reason = "expected at least one match"; return; } ps.value = arr; // recover from the last failure. ps.position = position; ps.kind = ResultKind.Ok; } } /** * Applies the source parser 1 or more times until it fails softly. Yields all of its results in an * array. * * @param maxIterations Optionally, the maximum number of times to apply the source parser. Defaults * to `Infinity`. */ export function many1<T>(maxIterations = Infinity): ParjsCombinator<T, [T, ...T[]]> { return source => new Many1<T>(wrapImplicit(source), maxIterations); }