123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644(*---------------------------------------------------------------------------
Copyright (c) 2012 The jsonm programmers. All rights reserved.
Distributed under the ISC license, see terms at the end of the file.
---------------------------------------------------------------------------*)(* Braced non-terminals in comments refer to RFC 4627 non-terminals. *)letio_buffer_size=65536(* IO_BUFFER_SIZE 4.0.0 *)letpp=Format.fprintf(* Unsafe string and bytes manipulations. If you don't believe the authors's
invariants, replacing with safe versions makes everything safe in the
module. He won't be upset. *)letunsafe_bytesj=Char.code(String.unsafe_getsj)letunsafe_blitssoffddoff=Bytes.unsafe_blit(Bytes.unsafe_of_strings)soffddoffletunsafe_set_bytesjbyte=Bytes.unsafe_setsj(Char.unsafe_chrbyte)(* Characters and their classes *)letux_eoi=max_int(* End of input, outside unicode range. *)letux_soi=max_int-1(* Start of input, outside unicode range. *)letu_nl=0x0A(* \n *)letu_sp=0x20(* *)letu_quot=0x22(* '' *)letu_lbrack=0x5B(* [ *)letu_rbrack=0x5D(* ] *)letu_lbrace=0x7B(* { *)letu_rbrace=0x7D(* } *)letu_colon=0x3A(* : *)letu_dot=0x2E(* . *)letu_comma=0x2C(* , *)letu_minus=0x2D(* - *)letu_slash=0x2F(* / *)letu_bslash=0x5C(* \ *)letu_times=0x2A(* * *)letu_rep=Uchar.to_intUutf.u_repletmust_escapeu=u<=0x1F||u=0x22||u=0x5Cletis_digitu=0x30<=u&&u<=0x39letis_hex_digitu=0x30<=u&&u<=0x39||0x41<=u&&u<=0x46||0x61<=u&&u<=0x66letis_white=function(* N.B. Uutf normalizes U+000D to U+000A. *)|0x20|0x09|0x0A->true|_->falseletis_val_sep=function(* N.B. Uutf normalizes U+000D to U+000A. *)|0x20|0x09|0x0A|0x2C|0x5D|0x7D->true|_->false(* Data model *)typelexeme=[|`Null|`Boolofbool|`Stringofstring|`Floatoffloat|`Nameofstring|`As|`Ae|`Os|`Oe]letpp_lexemeppf=function|`Null->ppppf"`Null"|`Boolb->ppppf"@[`Bool %b@]"b|`Strings->ppppf"@[`String %S@]"s|`Names->ppppf"@[`Name %S@]"s|`Floatf->ppppf"@[`Float %s@]"(string_of_floatf)|`As->ppppf"`As"|`Ae->ppppf"`Ae"|`Os->ppppf"`Os"|`Oe->ppppf"`Oe"(* Decode *)typeerror=[|`Illegal_BOM|`Illegal_escapeof[`Not_hex_ucharofUchar.t|`Not_esc_ucharofUchar.t|`Not_lo_surrogateofint|`Lone_lo_surrogateofint|`Lone_hi_surrogateofint]|`Illegal_string_ucharofUchar.t|`Illegal_bytesofstring|`Illegal_literalofstring|`Illegal_numberofstring|`Unclosedof[`As|`Os|`String|`Comment]|`Expectedof[`Comment|`Value|`Name|`Name_sep|`Json|`Eoi|`Avalofbool(* [true] if first array value *)|`Omemofbool(* [true] if first object member *)]]leterr_bom=`Error(`Illegal_BOM)leterr_not_hexu=`Error(`Illegal_escape(`Not_hex_uchar(Uchar.of_intu)))leterr_not_escu=`Error(`Illegal_escape(`Not_esc_uchar(Uchar.of_intu)))leterr_not_lop=`Error(`Illegal_escape(`Not_lo_surrogatep))leterr_lone_lop=`Error(`Illegal_escape(`Lone_lo_surrogatep))leterr_lone_hip=`Error(`Illegal_escape(`Lone_hi_surrogatep))leterr_str_charu=`Error(`Illegal_string_uchar(Uchar.of_intu))leterr_bytesbs=`Error(`Illegal_bytesbs)leterr_unclosed_comment=`Error(`Unclosed`Comment)leterr_unclosed_string=`Error(`Unclosed`String)leterr_unclosed_arr=`Error(`Unclosed`As)leterr_unclosed_obj=`Error(`Unclosed`Os)leterr_numbers=`Error(`Illegal_numbers)leterr_literals=`Error(`Illegal_literals)leterr_exp_comment=`Error(`Expected`Comment)leterr_exp_value=`Error(`Expected`Value)leterr_exp_name=`Error(`Expected`Name)leterr_exp_nsep=`Error(`Expected`Name_sep)leterr_exp_arr_fst=`Error(`Expected(`Avaltrue))leterr_exp_arr_nxt=`Error(`Expected(`Avalfalse))leterr_exp_obj_fst=`Error(`Expected(`Omemtrue))leterr_exp_obj_nxt=`Error(`Expected(`Omemfalse))leterr_exp_json=`Error(`Expected`Json)leterr_exp_eoi=`Error(`Expected`Eoi)letpp_cpppfu=ppppf"U+%04X"uletpp_ucharppfu=ifUchar.to_intu<=0x1F(* most control chars *)thenpp_cpppf(Uchar.to_intu)elseletb=Buffer.create4inUutf.Buffer.add_utf_8bu;ppppf"'%s' (%a)"(Buffer.contentsb)pp_cp(Uchar.to_intu)letpp_errorppf=function|`Illegal_BOM->ppppf"@[illegal@ initial@ BOM@ in@ character@ stream@]"|`Illegal_escaper->ppppf"@[illegal@ escape,@ ";beginmatchrwith|`Not_hex_ucharu->ppppf"%a@ not@ a@ hex@ digit@]"pp_ucharu|`Not_esc_ucharu->ppppf"%a@ not@ an@ escaped@ character@]"pp_ucharu|`Lone_lo_surrogatep->ppppf"%a@ lone@ low@ surrogate@]"pp_cpp|`Lone_hi_surrogatep->ppppf"%a@ lone@ high@ surrogate@]"pp_cpp|`Not_lo_surrogatep->ppppf"%a@ not@ a@ low@ surrogate@]"pp_cppend|`Illegal_string_ucharu->ppppf"@[illegal@ character@ in@ JSON@ string@ (%a)@]"pp_ucharu|`Illegal_bytesbs->letl=String.lengthbsinppppf"@[illegal@ bytes@ in@ character@ stream@ (";ifl>0thenppppf"%02X"(Char.code(bs.[0]));fori=1tol-1doppppf" %02X"(Char.code(bs.[i]))done;ppppf")@]"|`Illegal_numbern->ppppf"@[illegal@ number@ (%s)@]"n|`Illegal_literall->ppppf"@[illegal@ literal@ (%s)@]"l|`Unclosedr->ppppf"@[unclosed@ ";beginmatchrwith|`As->ppppf"array@]";|`Os->ppppf"object@]";|`String->ppppf"string@]";|`Comment->ppppf"comment@]"end|`Expectedr->ppppf"@[expected@ ";beginmatchrwith|`Comment->ppppf"JavaScript@ comment@]"|`Value->ppppf"JSON@ value@]"|`Name->ppppf"member@ name@]"|`Name_sep->ppppf"name@ separator@ (':')@]"|`Avaltrue->ppppf"value@ or@ array@ end@ (value@ or@ ']')@]"|`Avalfalse->ppppf"value@ separator@ or@ array@ end@ (','@ or@ ']')@]"|`Omemtrue->ppppf"member@ name@ or@ object@ end@ ('\"'@ or@ '}')@]"|`Omemfalse->ppppf"value@ separator@ or@ object@ end@ (','@ or@ '}')@]"|`Json->ppppf"JSON@ text (JSON value)@]"|`Eoi->ppppf"end@ of@ input@]"endtypepos=int*inttypeencoding=[`UTF_8|`UTF_16|`UTF_16BE|`UTF_16LE]typesrc=[`Channelofin_channel|`Stringofstring|`Manual]typedecode=[`Await|`End|`Lexemeoflexeme|`Erroroferror]typeuncut=[`Commentof[`M|`S]*string|`Whiteofstring]letpp_decodeppf=function|`Lexemel->ppppf"@[`Lexeme @[(%a)@]@]"pp_lexemel|`Await->ppppf"`Await"|`End->ppppf"`End"|`Errore->ppppf"@[`Error @[(%a)@]@]"pp_errore|`Whites->ppppf"@[`White @[%S@]@]"s|`Comment(style,s)->letpr_styleppf=function`M->ppppf"`M"|`S->ppppf"`S"inppppf"@[`Comment @[(%a, %S)@]@]"pr_stylestylestypedecoder={u:Uutf.decoder;(* Unicode character decoder. *)buf:Buffer.t;(* string accumulation buffer. *)mutableuncut:bool;(* [true] to bufferize comments and white space. *)mutables_line:int;(* last saved start line. *)mutables_col:int;(* last saved start column. *)mutablee_line:int;(* last saved end line. *)mutablee_col:int;(* last saved end column. *)mutablec:int;(* character lookahead. *)mutablestack:(* stack of open arrays and objects. *)[`Asofpos|`Osofpos]list;mutablenext_name:bool;(* [true] if next decode should be [`Name]. *)mutablelast_start:bool;(* [true] if last lexeme was `As or `Os. *)mutablek:(* decoder continuation. *)decoder->[decode|uncut]}letbaddcdc=Uutf.Buffer.add_utf_8d.buf(Uchar.unsafe_of_intc)letbaddd=Uutf.Buffer.add_utf_8d.buf(Uchar.unsafe_of_intd.c)letbufd=lett=Buffer.contentsd.bufin(Buffer.cleard.buf;t)letdposd=Uutf.decoder_lined.u,Uutf.decoder_cold.uletsposd=d.s_line<-Uutf.decoder_lined.u;d.s_col<-Uutf.decoder_cold.uleteposd=d.e_line<-Uutf.decoder_lined.u;d.e_col<-Uutf.decoder_cold.uletstack_ranged=matchd.stackwith[]->assertfalse|`As(l,c)::_|`Os(l,c)::_->d.s_line<-l;d.s_col<-c;eposdletdpopd=match(sposd;eposd;d.stack)with|_::(`Os_::_asss)->d.next_name<-true;d.stack<-ss|_::(`As_::_asss)->d.next_name<-false;d.stack<-ss|_::[]->d.next_name<-false;d.stack<-[]|[]->assertfalseletret_eoid=`Endletret(v:[<decode|uncut])kd=d.k<-k;vletrecreadckd=matchUutf.decoded.uwith|`Ucharu->d.c<-(Uchar.to_intu);kd|`End->d.c<-ux_eoi;kd|`Await->ret`Await(readck)d|`Malformedbs->d.c<-u_rep;eposd;ret(err_bytesbs)kdletrecr_scommentkd=(* single line comment. // was eaten. *)if(d.c<>u_nl&&d.c<>ux_eoi)then(baddd;readc(r_scommentk)d)else(eposd;ret(`Comment(`S,bufd))(readck)d)letrecr_mcommentclosingkd=(* multiline comment. /* was eaten. *)if(d.c=ux_eoi)then(eposd;reterr_unclosed_commentret_eoid)elseifclosingthenbeginif(d.c=u_slash)then(eposd;ret(`Comment(`M,bufd))(readck)d)elseif(d.c=u_times)then(baddd;readc(r_mcommenttruek)d)else(baddcdu_times;baddd;readc(r_mcommentfalsek)d)endelsebeginif(d.c=u_times)thenreadc(r_mcommenttruek)delse(baddd;readc(r_mcommentfalsek)d)endletr_commentkd=(* comment, / was eaten. *)ifd.c=u_slashthenreadc(r_scommentk)delseifd.c=u_timesthenreadc(r_mcommentfalsek)delse(eposd;reterr_exp_commentkd)letrecr_ws_uncutkd=if(is_whited.c)then(eposd;baddd;readc(r_ws_uncutk)d)elseret(`White(bufd))kdletrecr_white_uncutkd=(* {ws} / comment *)if(is_whited.c)then(sposd;r_ws_uncut(r_white_uncutk)d)elseif(d.c=u_slash)then(sposd;readc(r_comment(r_white_uncutk))d)elsekdletrecr_wskd=if(is_whited.c)thenreadc(r_wsk)delsekd(* {ws} *)letr_whitekd=ifd.uncutthenr_white_uncutkdelser_wskdletrecr_u_escapehiucountkd=(* unicode escapes. *)leterrorerrkd=baddcdu_rep;reterrkdinifcount>0thenifnot(is_hex_digitd.c)then(eposd;error(err_not_hexd.c)(readck)d)elseletu=u*16+(ifd.c<=0x39(* 9 *)thend.c-0x30elseifd.c<=0x46(* F *)thend.c-0x37elsed.c-0x57)in(eposd;readc(r_u_escapehiu(count-1)k)d)elsematchhiwith|Somehi->(* combine high and low surrogate into scalar value. *)ifu<0xDC00||u>0xDFFFthenerror(err_not_lou)kdelseletu=((((hiland0x3FF)lsl10)lor(uland0x3FF))+0x10000)in(baddcdu;kd)|None->ifu<0xD800||u>0xDFFFthen(baddcdu;kd)elseifu>0xDBFFthenerror(err_lone_lou)kdelseifd.c<>u_bslashthenerror(err_lone_hiu)kdelsereadc(fund->ifd.c<>0x75(* u *)thenerror(err_lone_hiu)(r_escapek)delsereadc(r_u_escape(Someu)04k)d)dandr_escapekd=matchd.cwith|0x22(* '' *)->baddcdu_quot;readckd|0x5C(* \ *)->baddcdu_bslash;readckd|0x2F(* / *)->baddcdu_slash;readckd|0x62(* b *)->baddcd0x08;readckd|0x66(* f *)->baddcd0x0C;readckd|0x6E(* n *)->baddcdu_nl;readckd|0x72(* r *)->baddcd0x0D;readckd|0x74(* t *)->baddcd0x09;readckd|0x75(* u *)->readc(r_u_escapeNone04k)d|c->eposd;baddcdu_rep;ret(err_not_escc)(readck)dletrecr_stringkd=(* {string}, '' eaten. *)ifd.c=ux_eoithen(eposd;reterr_unclosed_stringret_eoid)elseifnot(must_escaped.c)then(baddd;readc(r_stringk)d)elseifd.c=u_quotthen(eposd;readckd)elseifd.c=u_bslashthenreadc(r_escape(r_stringk))delse(eposd;baddcdu_rep;ret(err_str_chard.c)(readc(r_stringk))d)letrecr_floatkd=(* {number} *)ifnot(is_val_sepd.c)&&d.c<>ux_eoithen(eposd;baddd;readc(r_floatk)d)elselets=bufdintryret(`Lexeme(`Float(float_of_strings)))kdwith|Failure_->ret(err_numbers)kdletrecr_literalkd=(* {true} / {false} / {null} *)ifnot(is_val_sepd.c)&&d.c<>ux_eoithen(eposd;baddd;readc(r_literalk)d)elsematchbufdwith|"true"->ret(`Lexeme(`Booltrue))kd|"false"->ret(`Lexeme(`Boolfalse))kd|"null"->ret(`Lexeme`Null)kd|s->ret(err_literals)kdletrecr_valueerrkd=matchd.cwith(* {value} *)|0x5B(* [ *)->(* {begin-array} *)sposd;eposd;d.last_start<-true;d.stack<-`As(dposd)::d.stack;ret(`Lexeme`As)(readck)d|0x7B(* { *)->(* {begin-object} *)sposd;eposd;d.last_start<-true;d.next_name<-true;d.stack<-`Os(dposd)::d.stack;ret(`Lexeme`Os)(readck)d|0x22(* '' *)->letlstringkd=ret(`Lexeme(`String(bufd)))kdinsposd;readc(r_string(lstringk))d|0x66(* f *)|0x6E(* n *)|0x74(* t *)->sposd;r_literalkd|uwhenis_digitu||u=u_minus->sposd;r_floatkd|u->errkdletrecdiscard_toc1c2errkd=ifd.c=c1||d.c=c2||d.c=ux_eoithenreterrkdelse(eposd;readc(discard_toc1c2errk)d)letr_arr_valkd=(* [{value-separator}] {value} / {end-array} *)letnxvalerrkd=sposd;discard_tou_commau_rbrackerrkdinletlast_start=d.last_startind.last_start<-false;ifd.c=ux_eoithen(stack_ranged;reterr_unclosed_arrret_eoid)elseifd.c=u_rbrackthen(dpopd;ret(`Lexeme`Ae)(readck)d)elseiflast_startthenr_value(nxvalerr_exp_arr_fst)kdelseifd.c=u_commathenreadc(r_white(r_value(nxvalerr_exp_value)k))delsenxvalerr_exp_arr_nxtkdletnxmemerrkd=sposd;d.next_name<-true;discard_tou_commau_rbraceerrkdletr_obj_valuekd=(* {name-separator} {value} *)d.next_name<-true;ifd.c=u_colonthenreadc(r_white(r_value(nxmemerr_exp_value)k))delsenxmemerr_exp_nsepkdletr_obj_namekd=(* [{value-separator}] string / end-object *)letr_nameerrkd=letlnkd=ret(`Lexeme(`Name(bufd)))kdinifd.c<>u_quotthennxmemerrkdelse(sposd;readc(r_string(lnk))d)inletlast_start=d.last_startind.last_start<-false;d.next_name<-false;ifd.c=ux_eoithen(stack_ranged;reterr_unclosed_objret_eoid)elseifd.c=u_rbracethen(dpopd;ret(`Lexeme`Oe)(readck)d)elseiflast_startthenr_nameerr_exp_obj_fstkdelseifd.c=u_commathenreadc(r_white(r_nameerr_exp_namek))delsenxmemerr_exp_obj_nxtkdletr_endkd=(* end of input *)ifd.c=ux_eoithenret`Endret_eoidelseletdrainkd=sposd;discard_toux_eoiux_eoierr_exp_eoikdindrainret_eoidletrecr_lexemed=matchd.stackwith|`As_::_->r_white(r_arr_valr_lexeme)d|`Os_::_->ifd.next_namethenr_white(r_obj_namer_lexeme)delser_white(r_obj_valuer_lexeme)d|[]->r_white(r_endr_lexeme)dletrecdiscard_to_whiteerrkd=ifis_whited.c||d.c=ux_eoithenreterrkdelse(eposd;readc(discard_to_whiteerrk)d)letrecr_jsonkd=(* {value} *)leterrkd=sposd;discard_to_whiteerr_exp_json(r_white(r_jsonk))dinifd.c<>ux_eoithenr_valueerrkdelsereterr_exp_jsonkdletr_startd=(* start of input *)letbomkd=ifUutf.decoder_removed_bomd.uthenreterr_bomkdelsekdinreadc(bom(r_white(r_jsonr_lexeme)))dletnln=`ASCII(Uchar.unsafe_of_int0x000A)letdecoder?encodingsrc=letu=Uutf.decoder?encoding~nlnsrcin{u;buf=Buffer.create1024;uncut=false;s_line=1;s_col=0;e_line=1;e_col=0;c=ux_soi;next_name=false;last_start=false;stack=[];k=r_start}letdecode_uncutd=d.uncut<-true;d.kdletrecdecoded=match(d.uncut<-false;d.kd)with|#decodeasv->(v:>[>decode])|`Comment_|`White_->assertfalseletdecoder_srcd=Uutf.decoder_srcd.uletdecoded_ranged=(d.s_line,d.s_col),(d.e_line,d.e_col)letdecoder_encodingd=matchUutf.decoder_encodingd.uwith|#encodingasenc->enc|`US_ASCII|`ISO_8859_1->assertfalse(* Encode *)letinvalid_argfmt=letb=Buffer.create20in(* for thread safety. *)letppf=Format.formatter_of_bufferbinletkppf=Format.pp_print_flushppf();invalid_arg(Buffer.contentsb)inFormat.kfprintfkppffmtletinvalid_boundsjl=invalid_arg"invalid bounds (index %d, length %d)"jlletexpectev=invalid_arg"%a encoded but expected %s"pp_decodeveletexpect_awaitv=expect"`Await"vletexpect_endl=expect"`End"(`Lexemel)letexpect_mem_valuel=expect"any `Lexeme but `Name, `Oe or `Ae"(`Lexemel)letexpect_arr_value_ael=expect"any `Lexeme but `Name or `Oe"(`Lexemel)letexpect_name_or_oel=expect"`Lexeme (`Name _ | `Oe)"(`Lexemel)letexpect_jsonv=expect"`Lexeme (`Null | `Bool _ | `Float _ | `String _ | `As | `Os)"vletexpect_lendlstartv=expect(iflstart=`Asthen"`Lexeme `Ae"else"`Lexeme `Oe")vtypedst=[`Channelofout_channel|`BufferofBuffer.t|`Manual]typeencode=[`Await|`End|`Lexemeoflexeme]typeencoder={dst:dst;(* output destination. *)minify:bool;(* [true] for compact output. *)mutableo:Bytes.t;(* current output chunk. *)mutableo_pos:int;(* next output position to write. *)mutableo_max:int;(* maximal output position to write. *)buf:Buffer.t;(* buffer to format floats. *)mutablestack:[`As|`Os]list;(* stack of open arrays and objects. *)mutablenest:int;(* nesting level (String.length stack). *)mutablenext_name:bool;(* [true] if next encode should `Name. *)mutablelast_start:bool;(* [true] if last encode was [`As | `Os]. *)mutablek:(* decoder continuation. *)encoder->[encode|uncut]->[`Ok|`Partial]}leto_reme=e.o_max-e.o_pos+1(* remaining bytes to write in [e.o]. *)letdstesjl=(* set [e.o] with [s]. *)if(j<0||l<0||j+l>Bytes.lengths)theninvalid_boundsjl;e.o<-s;e.o_pos<-j;e.o_max<-j+l-1letpartialke=function`Await->ke|v->expect_awaitvletflushke=matche.dstwith(* get free space in [d.o] and [k]ontinue. *)|`Manual->e.k<-partialk;`Partial|`Channeloc->outputoce.o0e.o_pos;e.o_pos<-0;ke|`Bufferb->leto=Bytes.unsafe_to_stringe.oinBuffer.add_substringbo0e.o_pos;e.o_pos<-0;keletrecwritebbke=(* write byte [b] and [k]ontinue. *)ife.o_pos>e.o_maxthenflush(writebbk)eelse(unsafe_set_bytee.oe.o_posb;e.o_pos<-e.o_pos+1;ke)letrecwritessjlke=(* write [l] bytes from [s] starting at [j]. *)letrem=o_remeinifrem>=lthen(unsafe_blitsje.oe.o_posl;e.o_pos<-e.o_pos+l;ke)elsebeginunsafe_blitsje.oe.o_posrem;e.o_pos<-e.o_pos+rem;flush(writess(j+rem)(l-rem)k)eendletrecwritebufjlke=(* write [l] bytes from [e.buf] starting at [j]. *)letrem=o_remeinifrem>=lthen(Buffer.blite.bufje.oe.o_posl;e.o_pos<-e.o_pos+l;ke)elsebeginBuffer.blite.bufje.oe.o_posrem;e.o_pos<-e.o_pos+rem;flush(writebuf(j+rem)(l-rem)k)eendletw_indentke=letrecloopindentke=letspaceseindent=letmax=e.o_pos+indent-1inforj=e.o_postomaxdounsafe_set_bytee.oju_spdone;e.o_pos<-max+1inletrem=o_remeinifrem<indentthen(spaceserem;flush(loop(indent-rem)k)e)else(spaceseindent;ke)inloop(e.nest*2)keletrecw_json_stringske=(* escapes as mandated by the standard. *)letrecloopsjposmaxke=ifpos>maxthen(ifj>maxthenkeelsewritessj(pos-j)ke)elseletnext=pos+1inletescapeesc=(* assert (String.length esc = 2 ). *)writessj(pos-j)(writesesc02(loopsnextnextmaxk))einmatchunsafe_bytesposwith|0x22->escape"\\\""|0x5C->escape"\\\\"|0x0A->escape"\\n"|cwhenc<=0x1F->lethexd=(ifd<10then0x30+delse0x41+(d-10))inwritessj(pos-j)(writes"\\u00"04(writeb(hex(clsr4))(writeb(hex(cland0xF))(loopsnextnextmaxk))))e|c->loopsjnextmaxkeinwritebu_quot(loops00(String.lengths-1)(writebu_quotk))eletw_namenke=e.last_start<-false;e.next_name<-false;w_json_stringn(writebu_colonk)eletw_value~in_objlke=matchlwith|`Strings->e.last_start<-false;e.next_name<-in_obj;w_json_stringske|`Boolb->e.last_start<-false;e.next_name<-in_obj;ifbthenwrites"true"04keelsewrites"false"05ke|`Floatf->e.last_start<-false;e.next_name<-in_obj;Buffer.cleare.buf;Printf.bprintfe.buf"%.16g"f;writebuf0(Buffer.lengthe.buf)ke|`Os->e.last_start<-true;e.next_name<-true;e.nest<-e.nest+1;e.stack<-`Os::e.stack;writebu_lbraceke|`As->e.last_start<-true;e.next_name<-false;e.nest<-e.nest+1;e.stack<-`As::e.stack;writebu_lbrackke|`Null->e.last_start<-false;e.next_name<-in_obj;writes"null"04ke|`Oe|`Ae|`Name_asl->ifin_objthenexpect_mem_valuelelseexpect_arr_value_aelletw_lexemekel=letepope=e.last_start<-false;e.nest<-e.nest-1;e.stack<-List.tle.stack;matche.stackwith|`Os::_->e.next_name<-true;|_->e.next_name<-falseinmatchList.hde.stackwith|`Os->(* inside object. *)ifnote.next_namethenw_value~in_obj:truelkeelsebeginmatchlwith|`Namen->letnamenke=ife.minifythenw_namenkeelsewritebu_nl(w_indent(w_namen(writebu_spk)))einife.last_startthennamenkeelsewritebu_comma(namenk)e|`Oe->ife.minify||e.last_startthen(epope;writebu_rbraceke)else(epope;writebu_nl(w_indent(writebu_rbracek))e)|v->expect_name_or_oelend|`As->(* inside array. *)beginmatchlwith|`Ae->ife.minify||e.last_startthen(epope;writebu_rbrackke)else(epope;writebu_nl(w_indent(writebu_rbrackk))e)|l->letvaluelke=ife.minifythenw_value~in_obj:falselkeelsewritebu_nl(w_indent(w_value~in_obj:falselk))einife.last_startthenvaluelkeelsewritebu_comma(valuelk)eendletrecencode_ke=function|`Lexemel->ife.stack=[]thenexpect_endlelsew_lexemekel|`Endasv->ife.stack=[]thenflushkeelseexpect_lend(List.hde.stack)v|`Whitew->writesw0(String.lengthw)ke|`Comment(`S,c)->writes"//"02(writesc0(String.lengthc)(writebu_nlk))e|`Comment(`M,c)->writes"/*"02(writesc0(String.lengthc)(writes"*/"02k))e|`Await->`Okletrecencode_loope=e.k<-encode_encode_loop;`Okletrecencode_jsone=function(* first [k] to start with [`Os] or [`As]. *)|`Lexeme(`Null|`Bool_|`Float_|`String_|`As|`Osasl)->w_value~in_obj:falselencode_loope|`End|`Lexeme_asv->expect_jsonv|`White_|`Comment_asv->encode_(fune->e.k<-encode_json;`Ok)ev|`Await->`Okletencoder?(minify=true)dst=leto,o_pos,o_max=matchdstwith|`Manual->Bytes.empty,1,0(* implies [o_rem e = 0]. *)|`Buffer_|`Channel_->Bytes.createio_buffer_size,0,io_buffer_size-1in{dst=(dst:>dst);minify;o;o_pos;o_max;buf=Buffer.create30;stack=[];nest=0;next_name=false;last_start=false;k=encode_json}letencodeev=e.ke(v:>[encode|uncut])letencoder_dste=e.dstletencoder_minifye=e.minify(* Manual *)moduleManual=structletsrcd=Uutf.Manual.srcd.uletdst=dstletdst_rem=o_remend(* Uncut *)moduleUncut=structletdecode=decode_uncutletpp_decode=pp_decodeletencodeev=e.ke(v:>[encode|uncut])end(*---------------------------------------------------------------------------
Copyright (c) 2012 The jsonm programmers
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
---------------------------------------------------------------------------*)