parjs
Version:
Library for building parsers using combinators.
85 lines • 3.21 kB
JavaScript
;
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