module /** */ import { Issues } from "../issues" ; import { ParsingState , UserState } from "../state" ; import { ResultKind } from "../result" ; import { ImplicitParjser , ParjsCombinator } from "../../index" ; import { defineCombinator , pipe } from "./combinator" ; import { ParjserBase } from "../parser" ; import { ScalarConverter } from "../scalar-converter" ; import { qthen } from "./then" ; const defaultProjection = ( sourceMatches , tillMatch , userState ) => sourceMatches ; param till param project export function manyTill < TSource , TTill = any , TResult = TSource [ ] > ( till , project ? ) ; export function manyTill ( till , pProject ? ) { let tillResolved = ScalarConverter . convert ( till ) as any as ParjserBase ; let project = pProject || defaultProjection ; return defineCombinator ( source => { return new class ManyTill extends ParjserBase { type = "manyTill" ; expecting = `${ source . expecting } or ${ tillResolved . expecting }` ; _apply ( ps ) { let { position } = ps ; let arr = [ ] as any [ ] ; let successes = 0 ; while ( true ) { tillResolved . apply ( ps ) ; if ( ps . isOk ) { break ; } else if ( ps . atLeast ( ResultKind . HardFail ) ) { return ; } ps . position = position ; source . apply ( ps ) ; if ( ps . isOk ) { arr . push ( ps . value ) ; } else if ( ps . isSoft ) { ps . kind = successes === 0 ? ResultKind . SoftFail : ResultKind . HardFail ; return ; } else { return ; } if ( ps . position === position ) { Issues . guardAgainstInfiniteLoop ( "manyTill" ) ; } position = ps . position ; successes ++ ; } ps . value = project ( arr , ps . value , ps . userState ) ; ps . kind = ResultKind . Ok ; } } ( ) ; } ) ; } param start param pTill param projection export function manyBetween < TSource , TTill = any , TResult = TSource [ ] > ( start , pTill ? , projection ? ) { let till = pTill || start ; return defineCombinator ( source => { return pipe ( start , qthen ( source . pipe ( manyTill ( till , projection ) ) ) ) ; } ) ; }