UNPKG

parjs

Version:

Library for building parsers using combinators.

85 lines 3.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.manyBetween = exports.manyTill = void 0; const combinated_1 = require("../combinated"); const issues_1 = require("../issues"); const result_1 = require("../result"); const wrap_implicit_1 = require("../wrap-implicit"); const combinator_1 = require("./combinator"); const then_1 = require("./then"); const defaultProjection = (sourceMatches, till, state) => sourceMatches; class ManyTill extends combinated_1.Combinated { constructor(source, _till, _project) { super(source); this._till = _till; this._project = _project; this.type = "manyTill"; this.expecting = `${this.source.expecting} or ${this._till.expecting}`; } _apply(ps) { let { position } = ps; const arr = []; let successes = 0; for (;;) { this._till.apply(ps); if (ps.isOk) { break; } else if (ps.atLeast(result_1.ResultKind.HardFail)) { // if till failed hard/fatally, we return the fail result. return; } // backtrack to before till failed. ps.position = position; this.source.apply(ps); if (ps.isOk) { arr.push(ps.value); } else if (ps.isSoft) { // many failed softly before till... ps.kind = successes === 0 ? result_1.ResultKind.SoftFail : result_1.ResultKind.HardFail; return; } else { // many failed hard/fatal return; } if (ps.position === position) { issues_1.Issues.guardAgainstInfiniteLoop("manyTill"); } position = ps.position; successes++; } ps.value = this._project(arr, ps.value, ps.userState); ps.kind = result_1.ResultKind.Ok; } } function manyTill(till, pProject) { const tillResolved = (0, wrap_implicit_1.wrapImplicit)(till); const project = pProject || defaultProjection; return (source) => { return new ManyTill((0, wrap_implicit_1.wrapImplicit)(source), tillResolved, // eslint-disable-next-line @typescript-eslint/no-explicit-any project); }; } exports.manyTill = manyTill; /** * Applies `start` and then repeatedly applies the source parser until `pTill` succeeds. Similar to * a mix of `between` and `manyTill`. Yields the results of the source parser in an array. * * @param start The initial parser to apply. * @param pTill Optionally, the terminator. Defaults to `start`. * @param projection Optionally, a projection to apply on the captured results. */ function manyBetween(start, pTill, projection) { const till = pTill || start; return source => { const wrapped = (0, wrap_implicit_1.wrapImplicit)(source); return (0, combinator_1.pipe)(start, // eslint-disable-next-line @typescript-eslint/no-explicit-any (0, then_1.qthen)(wrapped.pipe(manyTill(till, projection)))); }; } exports.manyBetween = manyBetween; //# sourceMappingURL=many-till.js.map