UNPKG

parjs

Version:

A parser-combinator library for JavaScript.

80 lines (79 loc) 3.12 kB
"use strict"; /** * @module parjs/combinators */ /** */ Object.defineProperty(exports, "__esModule", { value: true }); const issues_1 = require("../issues"); const result_1 = require("../result"); const combinator_1 = require("./combinator"); const parser_1 = require("../parser"); const scalar_converter_1 = require("../scalar-converter"); const then_1 = require("./then"); const defaultProjection = (sourceMatches, tillMatch, userState) => sourceMatches; function manyTill(till, pProject) { let tillResolved = scalar_converter_1.ScalarConverter.convert(till); let project = pProject || defaultProjection; return combinator_1.defineCombinator(source => { return new class ManyTill extends parser_1.ParjserBase { constructor() { super(...arguments); this.type = "manyTill"; this.expecting = `${source.expecting} or ${tillResolved.expecting}`; } _apply(ps) { let { position } = ps; let arr = []; let successes = 0; while (true) { tillResolved.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; 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 = project(arr, ps.value, ps.userState); ps.kind = result_1.ResultKind.Ok; } }(); }); } exports.manyTill = manyTill; /** * Applies `start` and then repeatedly applies the source parser until * `pTill` succeeds. Similar to a mix of `between` and `manyTill`. * @param start The initial parser to apply. * @param pTill The terminator. * @param projection Optionally, a projection to apply on the captured results. */ function manyBetween(start, pTill, projection) { let till = pTill || start; return combinator_1.defineCombinator(source => { return combinator_1.pipe(start, then_1.qthen(source.pipe(manyTill(till, projection)))); }); } exports.manyBetween = manyBetween; //# sourceMappingURL=many-till.js.map