Select Git revision
monadic-parser.ts
-
David Sehnal authoredDavid Sehnal authored
monadic-parser.ts 18.85 KiB
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
/**
* Adapted from Parsimmon (https://github.com/jneen/parsimmon)
* Copyright (c) 2011-present J. Adkisson (http://jneen.net).
*/
export class MonadicParser<A> {
constructor(public _: MonadicParser.Action<A>) { }
parse(input: string): MonadicParser.ParseResult<A> {
const result = this.skip(MonadicParser.eof)._(input, 0);
if (result.status) {
return { success: true, value: result.value };
}
return { success: false, index: makeLineColumnIndex(input, result.furthest), expected: result.expected };
};
tryParse(str: string) {
const result = this.parse(str);
if (result.success) {
return result.value;
} else {
const msg = formatError(str, result);
const err = new Error(msg);
throw err;
}
}
or<B>(alternative: MonadicParser<B>): MonadicParser<A | B> {
return MonadicParser.alt(this, alternative);
}
trim<B>(parser: MonadicParser<B> | string): MonadicParser<A> {
return this.wrap(parser, parser);
}
wrap<L, R>(leftParser: MonadicParser<L> | string, rightParser: MonadicParser<R> | string): MonadicParser<A> {
return seqPick(1,
typeof leftParser === 'string' ? MonadicParser.string(leftParser) : leftParser,
this,
typeof rightParser === 'string' ? MonadicParser.string(rightParser) : rightParser);
}
thru<B>(wrapper: (p: MonadicParser<A>) => MonadicParser<B>) {
return wrapper(this);
}
then<B>(next: MonadicParser<B>): MonadicParser<B> {
return seqPick(1, this, next);
}
many() {
return new MonadicParser((input, i) => {
const accum: A[] = [];
let result: MonadicParser.Result<A> | undefined = void 0;
while (true) {
result = mergeReplies(this._(input, i), result);
if (result.status) {
if (i === result.index) {
throw new Error('infinite loop detected in .many() parser --- calling .many() on a parser which can accept zero characters is usually the cause');
}
i = result.index;
accum.push(result.value);
} else {