UNPKG

parjs

Version:

A parser-combinator library for JavaScript.

115 lines (105 loc) 4.25 kB
/** * @module parjs/combinators */ /** */ import {ParsingState} from "../state"; import {ResultKind} from "../result"; import {ParjsCombinator} from "../.."; import {ImplicitParjser, ScalarConverter} from "../scalar-converter"; import {defineCombinator} from "./combinator"; import {ParjserBase} from "../parser"; /** * Applies the source parser. If it fails softly, will try to apply the * given parsers in sequential order. If all fail, parsing will fail with the * error of the last parser. * This combinator cannot recover from Hard or Fatal failures. If any parser * fails in that way, the returned parser will fail with that info and will not * try other parsers. * * @param alt1 The first alternative parser to apply. */ export function or<T1, T2>( alt1: ImplicitParjser<T2> ): ParjsCombinator<T1, T1 | T2>; /** * Applies the source parser. If it fails softly, will try to apply the * given parsers in sequential order. If all fail, parsing will fail with the * error of the last parser. * This combinator cannot recover from Hard or Fatal failures. If any parser * fails in that way, the returned parser will fail with that info and will not * try other parsers. * * @param alt1 The first alternative parser to apply. * @param alt2 The second alternative parser to apply. */ export function or<T1, T2, T3>( alt1: ImplicitParjser<T2>, alt2: ImplicitParjser<T3> ): ParjsCombinator<T1, T1 | T2 | T3>; /** * Applies the source parser. If it fails softly, will try to apply the * given parsers in sequential order. If all fail, parsing will fail with the * error of the last parser. * This combinator cannot recover from Hard or Fatal failures. If any parser * fails in that way, the returned parser will fail with that info and will not * try other parsers. * * @param alt1 The first alternative parser to apply. * @param alt2 The second alternative parser to apply. * @param alt3 The third alternative parser to apply. */ export function or<T1, T2, T3, T4>( alt1: ImplicitParjser<T2>, alt2: ImplicitParjser<T3>, alt3: ImplicitParjser<T4> ): ParjsCombinator<T1, T1 | T2 | T3 | T4>; /** * Applies the source parser. If it fails softly, will try to apply the * given parsers in sequential order. If all fail, parsing will fail with the * error of the last parser. * This combinator cannot recover from Hard or Fatal failures. If any parser * fails in that way, the returned parser will fail with that info and will not * try other parsers. * * @param alt1 The first alternative parser to apply. * @param alt2 The second alternative parser to apply. * @param alt3 The third alternative parser to apply. * @param alt4 The fourth alternative parser to apply. */ export function or<T1, T2, T3, T4, T5>( alt1: ImplicitParjser<T2>, alt2: ImplicitParjser<T3>, alt3: ImplicitParjser<T4>, alt4: ImplicitParjser<T5> ): ParjsCombinator<T1, T1 | T2 | T3 | T4 | T5>; export function or(...alts: ImplicitParjser<any>[]) { let resolvedAlts = alts.map(x => ScalarConverter.convert(x) as any as ParjserBase); return defineCombinator(source => { resolvedAlts.splice(0, 0, source); let altNames = resolvedAlts.map(x => x.type); return new class Or extends ParjserBase { type = "or"; expecting = `expecting one of: ${altNames.join(", ")}`; _apply(ps: ParsingState): void { let {position} = ps; for (let i = 0; i < resolvedAlts.length; i++) { // go over each alternative. let cur = resolvedAlts[i]; // apply it on the current state. cur.apply(ps); if (ps.isOk) { // if success, return. The PS records the result. return; } else if (ps.isSoft) { // backtrack to the original position and try again. ps.position = position; } else { // if failure, return false, return; } } ps.kind = ResultKind.SoftFail; } }(); }); }