/**
 * This file is derived from https://github.com/jneen/parsimmon and
 * https://github.com/DefinitelyTyped/DefinitelyTyped.
 */ interface Index { /** zero-based character offset */ offset : number ; /** one-based line offset */ line : number ; /** one-based column offset */ column : number ; } interface Mark < T > { start : Index ; end : Index ; value : T ; } interface Node < Name extends string , T > extends Mark < T > { name : Name ; } type Result < T > = Success < T > | Failure ; interface Success < T > { status : true ; value : T ; } interface Failure { status : false ; expected : string [ ] ; index : Index ; } type TypedRule < TLanguageSpec > = { [ P in keyof TLanguageSpec ] : ( r : TypedLanguage < TLanguageSpec > ) => Parser < TLanguageSpec [ P ] > ; } ; type TypedLanguage < TLanguageSpec > = { [ P in keyof TLanguageSpec ] : Parser < TLanguageSpec [ P ] > ; } ; interface Parser < T > { parse ( input ) : Result < T > ; or < U > ( otherParser ) : Parser < T | U > ; then < U > ( call ) : Parser < U > ; then < U > ( anotherParser ) : Parser < U > ; map < U > ( call ) : Parser < U > ; skip < U > ( otherParser ) : Parser < T > ; many ( ) : Parser < T [ ] > ; mark ( ) : Parser < Mark < T > > ; node < Name extends string > ( name ) : Parser < Node < Name , T > > ; desc ( description ) : Parser < T > ; sepBy < U > ( separator ) : Parser < T [ ] > ; } function Parsimmon ( action ) { if ( ! ( this instanceof Parsimmon ) ) { return new Parsimmon ( action ) ; } this . _ = action ; } const _ = Parsimmon . prototype ; function makeSuccess ( index , value ) { return { expected : [ ] , furthest : - 1 , index , status : true , value , } ; } function makeFailure ( index , expected ) { expected = [ expected ] ; return { expected , furthest : index , index : - 1 , status : false , value : null , } ; } function mergeReplies ( result , last ) { if ( ! last ) { return result ; } if ( result . furthest > last . furthest ) { return result ; } const expected = result . furthest === last . furthest ? union ( result . expected , last . expected ) : last . expected ; return { expected , furthest : last . furthest , index : result . index , status : result . status , value : result . value , } ; } function makeLineColumnIndex ( input , i ) { const lines = input . slice ( 0 , i ) . split ( '\n' ) ; const lineWeAreUpTo = lines . length ; const columnWeAreUpTo = lines [ lines . length - 1 ] . length + 1 ; return { column : columnWeAreUpTo , line : lineWeAreUpTo , offset : i , } ; } function union ( xs , ys ) { const obj = { } ; for ( let i = 0 ; i < xs . length ; i ++ ) { obj [ xs [ i ] ] = true ; } for ( let j = 0 ; j < ys . length ; j ++ ) { obj [ ys [ j ] ] = true ; } const keys = [ ] ; for ( const k in obj ) { keys . push ( k ) ; } keys . sort ( ) ; return keys ; } function flags ( re ) { const s = String ( re ) ; return s . slice ( s . lastIndexOf ( '/' ) + 1 ) ; } function anchoredRegexp ( re ) { return RegExp ( `^(?:${ re . source })` , flags ( re ) ) ; } function seq ( ... params ) { const parsers = [ ] . slice . call ( params ) ; const numParsers = parsers . length ; return Parsimmon ( function ( input , i ) { let result ; const accum = new Array ( numParsers ) ; for ( let j = 0 ; j < numParsers ; j += 1 ) { result = mergeReplies ( parsers [ j ] . _ ( input , i ) , result ) ; if ( ! result . status ) { return result ; } accum [ j ] = result . value ; i = result . index ; } return mergeReplies ( makeSuccess ( i , accum ) , result ) ; } ) ; } function seqMap < T , U > ( p1 , cb ) ; function seqMap < T , U , V > ( p1 , p2 , cb ) ; function seqMap < T , U , V , W > ( p1 , p2 , p3 , cb ) ; function seqMap < T , U , V , W , X > ( p1 , p2 , p3 , p4 , cb ) ; function seqMap < T , U , V , W , X , Y > ( p1 , p2 , p3 , p4 , p5 , cb ) ; function seqMap ( ... params ) { const args = [ ] . slice . call ( params ) ; const mapper = args . pop ( ) ; return seq . apply ( null , args ) . map ( function ( results ) { return mapper . apply ( null , results ) ; } ) ; } function createLanguage < TLanguageSpec > ( parsers ) { const language = { } as TypedLanguage < TLanguageSpec > ; for ( const key in parsers ) { ( function ( rule ) { const func = function ( ) { return parsers [ rule ] ( language ) ; } ; language [ rule ] = lazy ( func ) ; } ) ( key ) ; } return language ; } function alt ( ... params ) { const parsers = [ ] . slice . call ( params ) ; return Parsimmon ( function ( input , i ) { let result ; for ( let j = 0 ; j < parsers . length ; j += 1 ) { result = mergeReplies ( parsers [ j ] . _ ( input , i ) , result ) ; if ( result . status ) { return result ; } } return result ; } ) ; } function sepBy ( parser , separator ) { return sepBy1 ( parser , separator ) . or ( succeed ( [ ] ) ) ; } function sepBy1 ( parser , separator ) { const pairs = separator . then ( parser ) . many ( ) ; return seqMap ( parser , pairs , function ( r , rs ) { return [ r ] . concat ( rs ) ; } ) ; } _ . parse = function ( input ) { const result = this . skip ( eof ) . _ ( input , 0 ) ; if ( result . status ) { return { status : true , value : result . value , } ; } return { expected : result . expected , index : makeLineColumnIndex ( input , result . furthest ) , status : false , } ; } ; _ . or = function ( alternative ) { return alt ( this , alternative ) ; } ; _ . then = function ( next ) { return seq ( this , next ) . map ( function ( results ) { return results [ 1 ] ; } ) ; } ; _ . many = function ( ) { const self = this ; return Parsimmon ( function ( input , i ) { const accum = [ ] ; let result ; for ( ; ; ) { result = mergeReplies ( self . _ ( 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 { return mergeReplies ( makeSuccess ( i , accum ) , result ) ; } } } ) ; } ; _ . map = function ( fn ) { const self = this ; return Parsimmon ( function ( input , i ) { const result = self . _ ( input , i ) ; if ( ! result . status ) { return result ; } return mergeReplies ( makeSuccess ( result . index , fn ( result . value ) ) , result ) ; } ) ; } ; _ . skip = function ( next ) { return seq ( this , next ) . map ( function ( results ) { return results [ 0 ] ; } ) ; } ; _ . node = function ( name ) { return seqMap ( index , this , index , function ( start , value , end ) { return { end , name , start , value , } ; } ) ; } ; _ . sepBy = function ( separator ) { return sepBy ( this , separator ) ; } ; _ . desc = function ( expected ) { expected = [ expected ] ; const self = this ; return Parsimmon ( function ( input , i ) { const reply = self . _ ( input , i ) ; if ( ! reply . status ) { reply . expected = expected ; } return reply ; } ) ; } ; function string ( str ) { const expected = `'${ str }'` ; return Parsimmon ( function ( input , i ) { const j = i + str . length ; const head = input . slice ( i , j ) ; if ( head === str ) { return makeSuccess ( j , head ) ; } return makeFailure ( i , expected ) ; } ) ; } function regexp ( re , group = 0 ) { const anchored = anchoredRegexp ( re ) ; const expected = String ( re ) ; return Parsimmon ( function ( input , i ) { const match = anchored . exec ( input . slice ( i ) ) ; if ( match ) { const fullMatch = match [ 0 ] ; const groupMatch = match [ group ] ; return makeSuccess ( i + fullMatch . length , groupMatch ) ; } return makeFailure ( i , expected ) ; } ) ; } function succeed ( value ) { return Parsimmon ( function ( __ , i ) { return makeSuccess ( i , value ) ; } ) ; } function lazy ( f ) { const parser = Parsimmon ( function ( input , i ) { parser . _ = f ( ) . _ ; return parser . _ ( input , i ) ; } ) ; return parser ; } const index = Parsimmon ( function ( input , i ) { return makeSuccess ( i , makeLineColumnIndex ( input , i ) ) ; } ) ; const eof = Parsimmon ( function ( input , i ) { if ( i < input . length ) { return makeFailure ( i , 'EOF' ) ; } return makeSuccess ( i , null ) ; } ) ; const optWhitespace = regexp ( /\s*/u ) . desc ( 'optional whitespace' ) ; const whitespace = regexp ( /\s+/u ) . desc ( 'whitespace' ) ; export const P = { alt , createLanguage , index , lazy , makeFailure , makeSuccess , of : succeed , optWhitespace , regexp , sepBy , sepBy1 , seq , seqMap , string , succeed , whitespace , } ;