Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file sexp_conv.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415(* Utility Module for S-expression Conversions *)openStdLabelsopenMoreLabelsopenPrintfopenSexp(* Conversion of OCaml-values to S-expressions *)externalformat_float:string->float->string="caml_format_float"(* '%.17g' is guaranteed to be round-trippable.
'%.15g' will be round-trippable and not have noise at the last digit or two for a float
which was converted from a decimal (string) with <= 15 significant digits. So it's
worth trying first to avoid things like "3.1400000000000001".
See comment above [to_string_round_trippable] in {!Core.Float} for
detailed explanation and examples. *)letdefault_string_of_float=ref(funx->lety=format_float"%.15G"xiniffloat_of_stringy=xthenyelseformat_float"%.17G"x);;letread_old_option_format=reftrueletwrite_old_option_format=reftrueletlist_mapfl=List.rev(List.rev_mapl~f)letsexp_of_unit()=List[]letsexp_of_boolb=Atom(string_of_boolb)letsexp_of_stringstr=Atomstrletsexp_of_bytesbytes=Atom(Bytes.to_stringbytes)letsexp_of_charc=Atom(String.make1c)letsexp_of_intn=Atom(string_of_intn)letsexp_of_floatn=Atom(!default_string_of_floatn)letsexp_of_int32n=Atom(Int32.to_stringn)letsexp_of_int64n=Atom(Int64.to_stringn)letsexp_of_nativeintn=Atom(Nativeint.to_stringn)letsexp_of_refsexp_of__arf=sexp_of__a!rfletsexp_of_lazy_tsexp_of__alv=sexp_of__a(Lazy.forcelv)letsexp_of_optionsexp_of__a=function|Somexwhen!write_old_option_format->List[sexp_of__ax]|Somex->List[Atom"some";sexp_of__ax]|Nonewhen!write_old_option_format->List[]|None->Atom"none";;letsexp_of_pairsexp_of__asexp_of__b(a,b)=List[sexp_of__aa;sexp_of__bb]letsexp_of_triplesexp_of__asexp_of__bsexp_of__c(a,b,c)=List[sexp_of__aa;sexp_of__bb;sexp_of__cc];;(* List.rev (List.rev_map ...) is tail recursive, the OCaml standard
library List.map is NOT. *)letsexp_of_listsexp_of__alst=List(List.rev(List.rev_maplst~f:sexp_of__a))letsexp_of_arraysexp_of__aar=letlst_ref=ref[]infori=Array.lengthar-1downto0dolst_ref:=sexp_of__aar.(i)::!lst_refdone;List!lst_ref;;letsexp_of_hashtblsexp_of_keysexp_of_valhtbl=letcoll~key:k~data:vacc=List[sexp_of_keyk;sexp_of_valv]::accinList(Hashtbl.foldhtbl~init:[]~f:coll);;letsexp_of_opaque_=Atom"<opaque>"letsexp_of_fun_=Atom"<fun>"(* Exception converter registration and lookup *)moduleExn_converter=struct(* These exception registration functions assume that context-switches
cannot happen unless there is an allocation. It is reasonable to expect
that this will remain true for the foreseeable future. That way we
avoid using mutexes and thus a dependency on the threads library. *)(* Fast and automatic exception registration *)moduleRegistration=structtypet={sexp_of_exn:exn->Sexp.t;(* If [printexc = true] then this sexp converter is used for Printexc.to_string *)printexc:bool}endmoduleExn_table=Ephemeron.K1.Make(structtypet=extension_constructorletequal=(==)lethash=Obj.Extension_constructor.idend)letthe_exn_table:Registration.tExn_table.t=Exn_table.create17(* Ephemerons are used so that [sexp_of_exn] closure don't keep the
extension_constructor live. *)letadd?(printexc=true)?finalise:_extension_constructorsexp_of_exn=Exn_table.addthe_exn_tableextension_constructor{sexp_of_exn;printexc};;letfind_auto~for_printexcexn=letextension_constructor=Obj.Extension_constructor.of_valexninmatchExn_table.find_optthe_exn_tableextension_constructorwith|None->None|Some{sexp_of_exn;printexc}->(matchfor_printexc,printexcwith|false,_|_,true->Some(sexp_of_exnexn)|true,false->None);;moduleFor_unit_tests_only=structletsize()=(Exn_table.stats_alivethe_exn_table).num_bindingsendendletsexp_of_exn_opt_for_printexcexn=Exn_converter.find_auto~for_printexc:trueexnletsexp_of_exn_optexn=Exn_converter.find_auto~for_printexc:falseexnletsexp_of_exnexn=matchsexp_of_exn_optexnwith|None->List[Atom(Printexc.to_stringexn)]|Somesexp->sexp;;letexn_to_stringe=Sexp.to_string_hum(sexp_of_exne)(* {[exception Blah [@@deriving sexp]]} generates a call to the function
[Exn_converter.add] defined in this file. So we are guaranted that as soon as we
mark an exception as sexpable, this module will be linked in and this printer will be
registered, which is what we want. *)let()=Printexc.register_printer(funexn->matchsexp_of_exn_opt_for_printexcexnwith|None->None|Somesexp->Some(Sexp.to_string_hum~indent:2sexp));;letprintexc_prefer_sexpexn=matchsexp_of_exn_optexnwith|None->Printexc.to_stringexn|Somesexp->Sexp.to_string_hum~indent:2sexp;;(* Conversion of S-expressions to OCaml-values *)exceptionOf_sexp_error=Sexp.Of_sexp_errorletrecord_check_extra_fields=reftrueletof_sexp_error_exnexcsexp=raise(Of_sexp_error(exc,sexp))letof_sexp_errorwhatsexp=raise(Of_sexp_error(Failurewhat,sexp))letunit_of_sexpsexp=matchsexpwith|List[]->()|Atom_|List_->of_sexp_error"unit_of_sexp: empty list needed"sexp;;letbool_of_sexpsexp=matchsexpwith|Atom("true"|"True")->true|Atom("false"|"False")->false|Atom_->of_sexp_error"bool_of_sexp: unknown string"sexp|List_->of_sexp_error"bool_of_sexp: atom needed"sexp;;letstring_of_sexpsexp=matchsexpwith|Atomstr->str|List_->of_sexp_error"string_of_sexp: atom needed"sexp;;letbytes_of_sexpsexp=matchsexpwith|Atomstr->Bytes.of_stringstr|List_->of_sexp_error"bytes_of_sexp: atom needed"sexp;;letchar_of_sexpsexp=matchsexpwith|Atomstr->ifString.lengthstr<>1thenof_sexp_error"char_of_sexp: atom string must contain one character only"sexp;str.[0]|List_->of_sexp_error"char_of_sexp: atom needed"sexp;;letint_of_sexpsexp=matchsexpwith|Atomstr->(tryint_of_stringstrwith|exc->of_sexp_error("int_of_sexp: "^exn_to_stringexc)sexp)|List_->of_sexp_error"int_of_sexp: atom needed"sexp;;letfloat_of_sexpsexp=matchsexpwith|Atomstr->(tryfloat_of_stringstrwith|exc->of_sexp_error("float_of_sexp: "^exn_to_stringexc)sexp)|List_->of_sexp_error"float_of_sexp: atom needed"sexp;;letint32_of_sexpsexp=matchsexpwith|Atomstr->(tryInt32.of_stringstrwith|exc->of_sexp_error("int32_of_sexp: "^exn_to_stringexc)sexp)|List_->of_sexp_error"int32_of_sexp: atom needed"sexp;;letint64_of_sexpsexp=matchsexpwith|Atomstr->(tryInt64.of_stringstrwith|exc->of_sexp_error("int64_of_sexp: "^exn_to_stringexc)sexp)|List_->of_sexp_error"int64_of_sexp: atom needed"sexp;;letnativeint_of_sexpsexp=matchsexpwith|Atomstr->(tryNativeint.of_stringstrwith|exc->of_sexp_error("nativeint_of_sexp: "^exn_to_stringexc)sexp)|List_->of_sexp_error"nativeint_of_sexp: atom needed"sexp;;letref_of_sexpa__of_sexpsexp=ref(a__of_sexpsexp)letlazy_t_of_sexpa__of_sexpsexp=Lazy.from_val(a__of_sexpsexp)letoption_of_sexpa__of_sexpsexp=if!read_old_option_formatthen(matchsexpwith|List[]|Atom("none"|"None")->None|List[el]|List[Atom("some"|"Some");el]->Some(a__of_sexpel)|List_->of_sexp_error"option_of_sexp: list must represent optional value"sexp|Atom_->of_sexp_error"option_of_sexp: only none can be atom"sexp)else(matchsexpwith|Atom("none"|"None")->None|List[Atom("some"|"Some");el]->Some(a__of_sexpel)|Atom_->of_sexp_error"option_of_sexp: only none can be atom"sexp|List_->of_sexp_error"option_of_sexp: list must be (some el)"sexp);;letpair_of_sexpa__of_sexpb__of_sexpsexp=matchsexpwith|List[a_sexp;b_sexp]->leta=a__of_sexpa_sexpinletb=b__of_sexpb_sexpina,b|List_->of_sexp_error"pair_of_sexp: list must contain exactly two elements only"sexp|Atom_->of_sexp_error"pair_of_sexp: list needed"sexp;;lettriple_of_sexpa__of_sexpb__of_sexpc__of_sexpsexp=matchsexpwith|List[a_sexp;b_sexp;c_sexp]->leta=a__of_sexpa_sexpinletb=b__of_sexpb_sexpinletc=c__of_sexpc_sexpina,b,c|List_->of_sexp_error"triple_of_sexp: list must contain exactly three elements only"sexp|Atom_->of_sexp_error"triple_of_sexp: list needed"sexp;;letlist_of_sexpa__of_sexpsexp=matchsexpwith|Listlst->letrev_lst=List.rev_maplst~f:a__of_sexpinList.revrev_lst|Atom_->of_sexp_error"list_of_sexp: list needed"sexp;;letarray_of_sexpa__of_sexpsexp=matchsexpwith|List[]->[||]|List(h::t)->letlen=List.lengtht+1inletres=Array.makelen(a__of_sexph)inletrecloopi=function|[]->res|h::t->res.(i)<-a__of_sexph;loop(i+1)tinloop1t|Atom_->of_sexp_error"array_of_sexp: list needed"sexp;;lethashtbl_of_sexpkey_of_sexpval_of_sexpsexp=matchsexpwith|Listlst->lethtbl=Hashtbl.create0inletact=function|List[k_sexp;v_sexp]->Hashtbl.addhtbl~key:(key_of_sexpk_sexp)~data:(val_of_sexpv_sexp)|List_|Atom_->of_sexp_error"hashtbl_of_sexp: tuple list needed"sexpinList.iterlst~f:act;htbl|Atom_->of_sexp_error"hashtbl_of_sexp: list needed"sexp;;letopaque_of_sexpsexp=of_sexp_error"opaque_of_sexp: cannot convert opaque values"sexp;;letfun_of_sexpsexp=of_sexp_error"fun_of_sexp: cannot convert function values"sexp(* Sexp Grammars *)includeSexp_conv_grammar(* Registering default exception printers *)letget_flc_errorname(file,line,chr)=Atom(sprintf"%s %s:%d:%d"namefilelinechr)let()=List.iter~f:(fun(extension_constructor,handler)->Exn_converter.add~printexc:false~finalise:falseextension_constructorhandler)[([%extension_constructorAssert_failure],function|Assert_failurearg->get_flc_error"Assert_failure"arg|_->assertfalse);([%extension_constructorExit],function|Exit->Atom"Exit"|_->assertfalse);([%extension_constructorEnd_of_file],function|End_of_file->Atom"End_of_file"|_->assertfalse);([%extension_constructorFailure],function|Failurearg->List[Atom"Failure";Atomarg]|_->assertfalse);([%extension_constructorNot_found],function|Not_found->Atom"Not_found"|_->assertfalse);([%extension_constructorInvalid_argument],function|Invalid_argumentarg->List[Atom"Invalid_argument";Atomarg]|_->assertfalse);([%extension_constructorMatch_failure],function|Match_failurearg->get_flc_error"Match_failure"arg|_->assertfalse);([%extension_constructorNot_found_s],function|Not_found_sarg->List[Atom"Not_found_s";arg]|_->assertfalse);([%extension_constructorSys_error],function|Sys_errorarg->List[Atom"Sys_error";Atomarg]|_->assertfalse);([%extension_constructorArg.Help],function|Arg.Helparg->List[Atom"Arg.Help";Atomarg]|_->assertfalse);([%extension_constructorArg.Bad],function|Arg.Badarg->List[Atom"Arg.Bad";Atomarg]|_->assertfalse);([%extension_constructorLazy.Undefined],function|Lazy.Undefined->Atom"Lazy.Undefined"|_->assertfalse);([%extension_constructorParsing.Parse_error],function|Parsing.Parse_error->Atom"Parsing.Parse_error"|_->assertfalse);([%extension_constructorQueue.Empty],function|Queue.Empty->Atom"Queue.Empty"|_->assertfalse);([%extension_constructorScanf.Scan_failure],function|Scanf.Scan_failurearg->List[Atom"Scanf.Scan_failure";Atomarg]|_->assertfalse);([%extension_constructorStack.Empty],function|Stack.Empty->Atom"Stack.Empty"|_->assertfalse);([%extension_constructorSys.Break],function|Sys.Break->Atom"Sys.Break"|_->assertfalse)];;let()=List.iter~f:(fun(extension_constructor,handler)->Exn_converter.add~printexc:true~finalise:falseextension_constructorhandler)[([%extension_constructorOf_sexp_error],function|Of_sexp_error(exc,sexp)->List[Atom"Sexplib.Conv.Of_sexp_error";sexp_of_exnexc;sexp]|_->assertfalse)];;externalignore:_->unit="%ignore"external(=):'a->'a->bool="%equal"