export class JSONNumber { constructor ( public val ) { if ( ! isFinite ( Number ( val ) ) ) { error ( "Bad number" ) ; } } } const escapee = { "\"" : "\"" , "\\" : "\\" , "/" : "/" , b : "\b" , f : "\f" , n : "\n" , r : "\r" , t : "\t" } ; let at ; let ch ; let text ; function error ( m ) { throw new SyntaxError ( `${ m } at position ${ at }` ) ; } function next ( c ? ) { if ( c && c !== ch ) { error ( "Expected '" + c + "' instead of '" + ch + "'" ) ; } return ch = text . charAt ( at ++ ) ; } function number ( ) { let string = "" ; if ( ch === "-" ) { string = "-" ; next ( "-" ) ; } while ( ch >= "0" && ch <= "9" ) { string += ch ; next ( ) ; } if ( ch === "." ) { string += "." ; while ( next ( ) && ch >= "0" && ch <= "9" ) { string += ch ; } } if ( ch === "e" || ch === "E" ) { string += ch ; next ( ) ; if ( ch === "-" || ch === "+" ) { string += ch ; next ( ) ; } while ( ch >= "0" && ch <= "9" ) { string += ch ; next ( ) ; } } return new JSONNumber ( string ) ; } function string ( ) { let value = "" ; if ( ch === "\"" ) { while ( next ( ) ) { if ( ch === "\"" ) { next ( ) ; return value ; } if ( ch === "\\" ) { next ( ) ; if ( ch === "u" ) { let uffff = 0 ; for ( let i = 0 ; i < 4 ; i += 1 ) { const hex = parseInt ( next ( ) , 16 ) ; if ( ! isFinite ( hex ) ) { break ; } uffff = uffff * 16 + hex ; } value += String . fromCharCode ( uffff ) ; } else if ( escapee [ ch ] !== undefined ) { value += escapee [ ch ] ; } else { break ; } } else { value += ch ; } } } error ( "Bad string" ) ; } function white ( ) { while ( ch && ch <= " " ) { next ( ) ; } } function word ( ) { switch ( ch ) { case "t" : next ( "t" ) ; next ( "r" ) ; next ( "u" ) ; next ( "e" ) ; return true ; case "f" : next ( "f" ) ; next ( "a" ) ; next ( "l" ) ; next ( "s" ) ; next ( "e" ) ; return false ; case "n" : next ( "n" ) ; next ( "u" ) ; next ( "l" ) ; next ( "l" ) ; return null ; } error ( "Unexpected '" + ch + "'" ) ; } function array ( ) { const arr = [ ] ; if ( ch === "[" ) { next ( "[" ) ; white ( ) ; if ( ch === "]" ) { next ( "]" ) ; return arr ; } while ( ch ) { arr . push ( value ( ) ) ; white ( ) ; if ( ch === "]" ) { next ( "]" ) ; return arr ; } next ( "," ) ; white ( ) ; } } error ( "Bad array" ) ; } function object ( ) { const obj = { } ; if ( ch === "{" ) { next ( "{" ) ; white ( ) ; if ( ch === "}" ) { next ( "}" ) ; return obj ; } while ( ch ) { const key = string ( ) ; white ( ) ; next ( ":" ) ; if ( obj . hasOwnProperty ( key ) ) { error ( "Duplicate key '" + key + "'" ) ; } obj [ key ] = value ( ) ; white ( ) ; if ( ch === "}" ) { next ( "}" ) ; return obj ; } next ( "," ) ; white ( ) ; } } error ( "Bad object" ) ; } function value ( ) { white ( ) ; switch ( ch ) { case "{" : return object ( ) ; case "[" : return array ( ) ; case "\"" : return string ( ) ; case "-" : return number ( ) ; default : return ( ch >= "0" && ch <= "9" ) ? number ( ) : word ( ) ; } } export function JSONParse ( source , reviver ? ) { text = source ; at = 0 ; ch = " " ; const result = value ( ) ; white ( ) ; if ( ch ) { error ( "Syntax error" ) ; } return ( typeof reviver === "function" ) ? ( function walk ( holder , key ) { const val = holder [ key ] ; if ( val && typeof val === "object" && ! ( val instanceof JSONNumber ) ) { for ( let k in val ) { if ( val . hasOwnProperty ( k ) ) { const v = walk ( val , k ) ; if ( v !== undefined ) { val [ k ] = v ; } else { delete val [ k ] ; } } } } return reviver . call ( holder , key , val ) ; } ( { "" : result } , "" ) ) : result ; }