import { just , nothing , Maybe } from './maybe' ; import { pair , Pair } from './pair' ; const cons = < T > ( x , xs ) : T [ ] => [ x ] . concat ( xs ) ; /**
 * Function that matches on some input, driving the parser.
 */ export interface ParseFunction < T > { ( s ) : Maybe < Pair < T , string > > ; } /**
 * Basic parser combinator.
 */ export class Parser < T > { parse : ParseFunction < T > ; constructor ( parse ) { this . parse = parse ; } prefix < R > ( parser ) { return parser . flatMap ( ( _o ) => this ) ; } suffix ( parser ) { return this . flatMap ( ( t ) => parser . map ( ( _o ) => t ) ) ; } map < R > ( f ) { return new Parser < R > ( ( s ) => this . parse ( s ) . map ( ( p ) => pair ( f ( p . _1 ) , p . _2 ) ) ) ; } flatMap < R > ( f ) { return new Parser < R > ( ( s ) => this . parse ( s ) . flatMap ( ( p ) => f ( p . _1 ) . parse ( p . _2 ) ) ) ; } zeroOrMore ( ) { return this . oneOrMore ( ) . orDefault ( [ ] ) ; } oneOrMore ( ) { return this . flatMap ( ( x ) => this . zeroOrMore ( ) . map ( ( xs ) => cons ( x , xs ) ) ) ; } or < R > ( alt ) { return new Parser < T | R > ( ( s ) => this . parse ( s ) . orElse ( ( ) => alt . parse ( s ) ) ) ; } orDefault < R > ( value ) { return new Parser < T | R > ( ( s ) => this . parse ( s ) . orElse ( ( ) => just ( pair ( value , s ) ) ) ) ; } separatedBy < R > ( delimiter ) { const skipped = this . prefix ( delimiter ) ; return this . flatMap ( ( t ) => skipped . zeroOrMore ( ) . map ( ( ts ) => cons ( t , ts ) ) ) ; } } export const matcher = ( pattern ) => new Parser < string > ( ( s ) => { const m = s . match ( pattern ) ; return m === null ? nothing : just ( pair ( m [ 0 ] , s . slice ( m [ 0 ] . length ) ) ) ; } ) ;