parjs
Version:
A parser-combinator library for JavaScript.
80 lines (79 loc) • 3.12 kB
JavaScript
;
/**
* @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