123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381openStdLabelsopenMoreLabelsincludeConv_intftypet=Type.texternalstring_length:string@local->int@@portable="%string_length"externalstring_get:string@local->int->char@@portable="%string_safe_get"externalint_of_string:string@local->int@@portable="caml_int_of_string"externalfloat_of_string:string@local->float@@portable="caml_float_of_string"externalint32_of_string:string@local->(int32[@unboxed])@@portable="caml_int32_of_string""caml_int32_of_string_unboxed"externalint64_of_string:string@local->(int64[@unboxed])@@portable="caml_int64_of_string""caml_int64_of_string_unboxed"externalnativeint_of_string:string@local->(nativeint[@unboxed])@@portable="caml_nativeint_of_string""caml_nativeint_of_string_unboxed"externalcreate_local_bytes:int->bytes@local@@portable="caml_create_local_bytes"externalunsafe_blit_string:src:string@local->src_pos:int->dst:bytes@local->dst_pos:int->len:int->unit@@portable="caml_blit_string"[@@noalloc][%%templatelet[@modeglobal]bytes_of_stringstr=Bytes.of_stringstrlet[@modelocal]bytes_of_string(str@local)=exclave_letlen=string_lengthstrinletbytes=create_local_bytesleninunsafe_blit_string~src:str~src_pos:0~dst:bytes~dst_pos:0~len;bytes;;]letjsonaf_of_unit():t=`Nullletjsonaf_of_boolb:t=matchbwith|true->`True|false->`False;;letjsonaf_of_stringstr:t=`Stringstrletjsonaf_of_bytesbytes:t=`String(Bytes.to_stringbytes)letjsonaf_of_charc:t=`String(String.make1c)letjsonaf_of_intn:t=`Number(string_of_intn)letjsonaf_of_floatn:t=(* JSON cannot represent [nan], [infinity], or [neg_infinity] *)ifnot(Float.is_finiten)thenfailwith(Printf.sprintf"Cannot represent non-finite float as JSON: %f"n);(* The logic below was stolen from the js_of_ocaml compiler. It ensure roundtripability
of floats while keeping small string representation *)letf12=Printf.sprintf"%.12g"ninifFloat.equaln(float_of_stringf12)then`Numberf12else(letf15=Printf.sprintf"%.15g"ninifFloat.equaln(float_of_stringf15)then`Numberf15else(letf18=Printf.sprintf"%.18g"nin`Numberf18));;letjsonaf_of_int32(n:Int32.t):t=`Number(Int32.to_stringn)letjsonaf_of_int64(n:Int64.t):t=`Number(Int64.to_stringn)letjsonaf_of_nativeintn:t=`Number(Nativeint.to_stringn)letjsonaf_of_refjsonaf_of__arf=jsonaf_of__a!rfletjsonaf_of_lazy_tjsonaf_of__alv=jsonaf_of__a(Lazy.forcelv)letjsonaf_of_optionjsonaf_of__a=function|Somex->jsonaf_of__ax|None->`Null;;letjsonaf_of_or_nulljsonaf_of__a=function|Basement.Or_null_shim.Thisx->jsonaf_of__ax|Null->`Null;;letjsonaf_of_pairjsonaf_of__ajsonaf_of__b(a,b)=`Array[jsonaf_of__aa;jsonaf_of__bb];;letjsonaf_of_triplejsonaf_of__ajsonaf_of__bjsonaf_of__c(a,b,c)=`Array[jsonaf_of__aa;jsonaf_of__bb;jsonaf_of__cc];;(* List.rev (List.rev_map ...) is tail recursive, the OCaml standard library List.map is
NOT. *)letjsonaf_of_listjsonaf_of__alst=`Array(List.rev(List.rev_map~f:jsonaf_of__alst))letjsonaf_of_iarrayjsonaf_of__aar=letlst_ref=ref[]infori=Basement.Stdlib_iarray_labels.lengthar-1downto0dolst_ref:=jsonaf_of__a(Basement.Stdlib_iarray_labels.getari)::!lst_refdone;`Array!lst_ref;;letjsonaf_of_arrayjsonaf_of__aar=jsonaf_of_iarrayjsonaf_of__a(Basement.Stdlib_iarray_labels.unsafe_of_arrayar);;letjsonaf_of_hashtbljsonaf_of_keyjsonaf_of_valhtbl=letcoll~key:k~data:vacc=`Array[jsonaf_of_keyk;jsonaf_of_valv]::accin`Array(Hashtbl.foldhtbl~init:[]~f:coll);;letjsonaf_of_opaque_=`String"<opaque>"letjsonaf_of_fun_=`String"<fun>"exceptionOf_jsonaf_errorofexn*t@@contendedportableletrecord_check_extra_fields=reftrue[%%templatelet[@modeglobal]maybe_globalizet=tlet[@modelocal]maybe_globalizet=Type.globalizet[@@@mode.defaultm=(local,global)]letof_jsonaf_error_exnexcjsonaf=raise(Of_jsonaf_error(exc,Type.mode_cross((maybe_globalize[@modem])jsonaf)));;letof_jsonaf_errorwhat(jsonaf@m)=raise(Of_jsonaf_error(Failurewhat,Type.mode_cross((maybe_globalize[@modem])jsonaf)));;]letlook_like_int(s@local)=letr=reftrueinfori=0tostring_lengths-1domatchstring_getsiwith|'+'|'-'|'0'..'9'->()|_->r:=falsedone;!r;;[%%templateletrecmap_list(f:(Type.t@m->'a@m)@local)(xs:Type.tlist@m)=match[@exclave_if_stacka]xswith|[]->[]|x::xs->(* Some tests are sensitive to evaluation order so always map first. This isn’t
tail-recursive but I think not allocating the list twice on the local stack is a
reasonable advantage here. *)letfx=fxinfx::(map_list[@alloca])fxs[@@alloca@m=stack_local];;letmap_listfxs=List.map~fxs[@@allocheap][@@@alloc.defaulta@m=(heap_global,stack_local)]letunit_of_jsonaf(jsonaf@m)=matchjsonafwith|`Null->()|_->(of_jsonaf_error[@modem])"unit_of_jsonaf: `Null needed"jsonaf;;letbool_of_jsonaf(jsonaf@m)=matchjsonafwith|`True->true|`False->false|_->(of_jsonaf_error[@modem])"bool_of_jsonaf: true/false needed"jsonaf;;letstring_of_jsonaf(jsonaf@m)=matchjsonafwith|`Stringstr->str|_->(of_jsonaf_error[@modem])"string_of_jsonaf: string needed"jsonaf;;letbytes_of_jsonaf(jsonaf@m)=matchjsonafwith|`Stringstr->(bytes_of_string[@modem])str[@exclave_if_stacka]|_->(of_jsonaf_error[@modem])"bytes_of_jsonaf: string needed"jsonaf;;letchar_of_jsonaf(jsonaf@m)=matchjsonafwith|`Stringstr->ifString.lengthstr<>1then(of_jsonaf_error[@modem])"char_of_jsonaf: string must contain one character only"jsonaf;str.[0]|_->(of_jsonaf_error[@modem])"char_of_jsonaf: string of size one needed"jsonaf;;letint_of_jsonaf(jsonaf@m)=matchjsonafwith|`Numbervwhenlook_like_intv->int_of_stringv|_->(of_jsonaf_error[@modem])"int_of_jsonaf: integer needed"jsonaf;;letfloat_of_jsonaf(jsonaf@m)=matchjsonafwith|`Numberstr->float_of_stringstr|_->(of_jsonaf_error[@modem])"float_of_jsonaf: float needed"jsonaf;;letint32_of_jsonaf(jsonaf@m)=matchjsonafwith|`Numberstrwhenlook_like_intstr->int32_of_stringstr|_->(of_jsonaf_error[@modem])"int32_of_jsonaf: integer needed"jsonaf;;letint64_of_jsonaf(jsonaf@m)=matchjsonafwith|`Numberstrwhenlook_like_intstr->int64_of_stringstr|_->(of_jsonaf_error[@modem])"int64_of_jsonaf: integer needed"jsonaf;;letnativeint_of_jsonaf(jsonaf@m)=matchjsonafwith|`Numberstrwhenlook_like_intstr->nativeint_of_stringstr|_->(of_jsonaf_error[@modem])"nativeint_of_jsonaf: integer needed"jsonaf;;letref_of_jsonaf(a__of_jsonaf:(Type.t@m->'a)@m)(jsonaf@m)=ref(a__of_jsonafjsonaf)[@exclave_if_stacka];;letoption_of_jsonaf(a__of_jsonaf:(Type.t@m->'a@m)@m)(jsonaf@m)=match[@exclave_if_stacka]jsonafwith|`Null->None|el->Some(a__of_jsonafel);;letor_null_of_jsonafa__of_jsonaf(jsonaf:Type.t@m)=match[@exclave_if_stacka]jsonafwith|`Null->Basement.Or_null_shim.Null|el->This(a__of_jsonafel);;letpair_of_jsonaf(a__of_jsonaf:(Type.t@m->'a@m)@m)(b__of_jsonaf:(Type.t@m->'b@m)@m)(jsonaf@m)=matchjsonafwith|`Array[a_jsonaf;b_jsonaf]->(leta=a__of_jsonafa_jsonafinletb=b__of_jsonafb_jsonafina,b)[@exclave_if_stacka]|_->(of_jsonaf_error[@modem])"pair_of_jsonaf: invalid format"jsonaf;;lettriple_of_jsonaf(a__of_jsonaf:(Type.t@m->'a@m)@m)(b__of_jsonaf:(Type.t@m->'b@m)@m)(c__of_jsonaf:(Type.t@m->'c@m)@m)(jsonaf@m)=matchjsonafwith|`Array[a_jsonaf;b_jsonaf;c_jsonaf]->(leta=a__of_jsonafa_jsonafinletb=b__of_jsonafb_jsonafinletc=c__of_jsonafc_jsonafina,b,c)[@exclave_if_stacka]|_->(of_jsonaf_error[@modem])"triple_of_jsonaf: invalid format"jsonaf;;letlist_of_jsonaf(a__of_jsonaf:(Type.t@m->'a@m)@m)(jsonaf@m)=matchjsonafwith|`Arraylst->(map_list[@alloca])a__of_jsonaflst[@exclave_if_stacka]|_->(of_jsonaf_error[@modem])"list_of_jsonaf: list needed"jsonaf;;]letlazy_t_of_jsonafa__of_jsonafjsonaf=Lazy.from_val(a__of_jsonafjsonaf)letarray_of_jsonafa__of_jsonafjsonaf=matchjsonafwith|`Array[]->[||]|`Array(h::t)->letlen=List.lengtht+1inletres=Array.makelen(a__of_jsonafh)inletrecloopi=function|[]->res|h::t->res.(i)<-a__of_jsonafh;loop(i+1)tinloop1t|_->of_jsonaf_error"array_of_jsonaf: list needed"jsonaf;;letiarray_of_jsonafa__of_jsonafjsonaf=Basement.Stdlib_iarray_labels.unsafe_of_array(array_of_jsonafa__of_jsonafjsonaf);;lethashtbl_of_jsonafkey_of_jsonafval_of_jsonafjsonaf=matchjsonafwith|`Arraylst->lethtbl=Hashtbl.create0inletact=function|`Array[k_jsonaf;v_jsonaf]->Hashtbl.addhtbl~key:(key_of_jsonafk_jsonaf)~data:(val_of_jsonafv_jsonaf)|_->of_jsonaf_error"hashtbl_of_jsonaf: tuple list needed"jsonafinList.iterlst~f:act;htbl|_->of_jsonaf_error"hashtbl_of_jsonaf: list needed"jsonaf;;[%%template[@@@alloc.defaulta@m=(heap_global,stack_local)]letopaque_of_jsonafjsonaf=(of_jsonaf_error[@modem])"opaque_of_jsonaf: cannot convert opaque values"jsonaf;;letfun_of_jsonafjsonaf=(of_jsonaf_error[@modem])"fun_of_jsonaf: cannot convert function values"jsonaf;;]modulePrimitives=structletjsonaf_of_array=jsonaf_of_arrayletarray_of_jsonaf=array_of_jsonafletjsonaf_of_iarray=jsonaf_of_iarrayletiarray_of_jsonaf=iarray_of_jsonafletjsonaf_of_bool=jsonaf_of_boolletbool_of_jsonaf=bool_of_jsonafletjsonaf_of_char=jsonaf_of_charletchar_of_jsonaf=char_of_jsonafletjsonaf_of_float=jsonaf_of_floatletfloat_of_jsonaf=float_of_jsonafletjsonaf_of_int=jsonaf_of_intletint_of_jsonaf=int_of_jsonafletjsonaf_of_int32=jsonaf_of_int32letint32_of_jsonaf=int32_of_jsonafletjsonaf_of_int64=jsonaf_of_int64letint64_of_jsonaf=int64_of_jsonafletjsonaf_of_list=jsonaf_of_listletlist_of_jsonaf=list_of_jsonafletjsonaf_of_nativeint=jsonaf_of_nativeintletnativeint_of_jsonaf=nativeint_of_jsonafletjsonaf_of_option=jsonaf_of_optionletoption_of_jsonaf=option_of_jsonafletjsonaf_of_or_null=jsonaf_of_or_nullletor_null_of_jsonaf=or_null_of_jsonafletjsonaf_of_ref=jsonaf_of_refletref_of_jsonaf=ref_of_jsonafletjsonaf_of_string=jsonaf_of_stringletstring_of_jsonaf=string_of_jsonafletjsonaf_of_bytes=jsonaf_of_bytesletbytes_of_jsonaf=bytes_of_jsonafletjsonaf_of_unit=jsonaf_of_unitletunit_of_jsonaf=unit_of_jsonafletjsonaf_of_lazy_t=jsonaf_of_lazy_tletlazy_t_of_jsonaf=lazy_t_of_jsonafletjsonaf_of_hashtbl=jsonaf_of_hashtbllethashtbl_of_jsonaf=hashtbl_of_jsonafend