123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212(* Copyright (c) 2017 Anil Madhavapeddy <anil@recoil.org>
*
* Permission to use, copy, modify, and 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. *)includeTypesmoduleUtil=UtilmoduleStream=StreamopenStreamlet(>>=)=Result.bindletscalar?anchor?tag?(plain_implicit=true)?(quoted_implicit=false)?(style=`Plain)value={anchor;tag;plain_implicit;quoted_implicit;style;value}letyaml_scalar_to_jsont=matchtwith|"null"|"NULL"|""|"Null"|"~"->`Null|"y"|"Y"|"yes"|"Yes"|"YES"|"true"|"True"|"TRUE"|"on"|"On"|"ON"->`Booltrue|"n"|"N"|"no"|"No"|"NO"|"false"|"False"|"FALSE"|"off"|"Off"|"OFF"->`Boolfalse|"-.inf"->`Floatneg_infinity|".inf"->`Floatinfinity|".nan"|".NaN"|".NAN"->`Floatnan|s->(try`Float(float_of_strings)with_->`Strings)letto_jsonv=letrecfn=function(* Quoted implicts are represented as strings in Json. *)|`Scalar{value;quoted_implicit=true}->`Stringvalue|`Scalar{value}->yaml_scalar_to_jsonvalue|`Alias_->failwith"Anchors are not supported when serialising to JSON"|`A{s_members}->`A(List.mapfns_members)|`O{m_members}->letsimple_key_to_string=function|`Scalar{anchor;value}->value|k->failwith"non-string key is not supported"in`O(List.map(fun(k,v)->simple_key_to_stringk,fnv)m_members)inmatchfnvwith|r->Okr|exception(Failuremsg)->Error(`Msgmsg)letof_json(v:value)=letrecfn=function|`Null->`Scalar(scalar"")|`Boolb->`Scalar(scalar(string_of_boolb))|`Floatf->`Scalar(scalar(string_of_floatf))|`Stringvalue->`Scalar(scalarvalue)|`Al->`A{s_anchor=None;s_tag=None;s_implicit=true;s_members=List.mapfnl}|`Ol->`O{m_anchor=None;m_tag=None;m_implicit=true;m_members=List.map(fun(k,v)->`Scalar(scalark),(fnv))l}inmatchfnvwith|r->Okr|exception(Failuremsg)->Error(`Msgmsg)letto_string?len?(encoding=`Utf8)?scalar_style?layout_style(v:value)=emitter?len()>>=funt->stream_starttencoding>>=fun()->document_startt>>=fun()->letreciter=function|`Null->Stream.scalar(scalar"")t|`Strings->letstyle=matchyaml_scalar_to_jsonswith|`Strings->scalar_style|_->Some`Double_quotedinStream.scalar(scalar?style~quoted_implicit:trues)t|`Floats->Stream.scalar(scalar(Printf.sprintf"%.16g"s))t(* NOTE: Printf format on the line above taken from the jsonm library *)|`Bools->Stream.scalar(scalar(string_of_bools))t|`Al->sequence_start?style:layout_stylet>>=fun()->letrecfn=function|[]->sequence_endt|hd::tl->iterhd>>=fun()->fntlinfnl|`Ol->mapping_start?style:layout_stylet>>=fun()->letrecfn=function|[]->mapping_endt|(k,v)::tl->iter(`Stringk)>>=fun()->iterv>>=fun()->fntlinfnliniterv>>=fun()->document_endt>>=fun()->stream_endt>>=fun()->letr=Stream.emitter_buftinOk(Bytes.to_stringr)letto_string_exn?len?encoding?scalar_style?layout_styles=matchto_string?len?encoding?scalar_style?layout_styleswith|Oks->s|Error(`Msgm)->raise(Invalid_argumentm)letyaml_to_string?(encoding=`Utf8)?scalar_style?layout_stylev=emitter()>>=funt->stream_starttencoding>>=fun()->document_startt>>=fun()->letreciter=function|`Scalars->Stream.scalarst|`Aliasanchor->aliastanchor|`A{s_anchor=anchor;s_tag=tag;s_implicit=implicit;s_members}->sequence_start?anchor?tag~implicit?style:layout_stylet>>=fun()->letrecfn=function|[]->sequence_endt|hd::tl->iterhd>>=fun()->fntlinfns_members|`O{m_anchor=anchor;m_tag=tag;m_implicit=implicit;m_members}->mapping_start?anchor?tag~implicit?style:layout_stylet>>=fun()->letrecfn=function|[]->mapping_endt|(k,v)::tl->iterk>>=fun()->iterv>>=fun()->fntlinfnm_membersiniterv>>=fun()->document_endt>>=fun()->stream_endt>>=fun()->letr=Stream.emitter_buftinOk(Bytes.to_stringr)letyaml_of_strings=letopenEventinparsers>>=funt->letnext()=do_parset>>=fun(e,pos)->Ok(e,pos)innext()>>=fun(e,pos)->matchewith|Stream_start_->beginnext()>>=fun(e,pos)->matchewith|Document_start_->beginletrecparse_v(e,pos)=matchewith|Sequence_start{anchor;tag;implicit;style=_}->next()>>=parse_seq[]>>=funs->Ok(`A{s_anchor=anchor;s_tag=tag;s_implicit=implicit;s_members=s})|Scalarscalar->Ok(`Scalarscalar)|Alias{anchor}->Ok(`Aliasanchor)|Mapping_start{anchor;tag;implicit;style=_}->next()>>=parse_map[]>>=funs->Ok(`O{m_anchor=anchor;m_tag=anchor;m_implicit=implicit;m_members=s})|e->Error(`Msg"todo")andparse_seqacc(e,pos)=matchewith|Sequence_end->Ok(List.revacc)|e->parse_v(e,pos)>>=funv->next()>>=parse_seq(v::acc)andparse_mapacc(e,pos)=matchewith|Mapping_end->Ok(List.revacc)|e->beginparse_v(e,pos)>>=funk->next()>>=parse_v>>=funv->next()>>=parse_map((k,v)::acc)endinnext()>>=parse_vend|Stream_end->Ok(`Scalar(scalar""))|e->Error(`Msg"Not document start")end|_->Error(`Msg"Not stream start")letof_strings=yaml_of_strings>>=to_jsonletof_string_exns=matchof_stringswith|Oks->s|Error(`Msgm)->raise(Invalid_argumentm)letppppfs=matchto_stringswith|Oks->Format.pp_print_stringppfs|Error(`Msgm)->Format.pp_print_stringppf(Printf.sprintf"(error (%s))"m)letrecequalv1v2=matchv1,v2with|`Null,`Null->true|`Boolx1,`Boolx2->((=):bool->bool->bool)x1x2|`Floatx1,`Floatx2->((=):float->float->bool)x1x2|`Stringx1,`Stringx2->String.equalx1x2|`Axs1,`Axs2->List.for_all2equalxs1xs2|`Oxs1,`Oxs2->List.for_all2(fun(k1,v1)(k2,v2)->String.equalk1k2&&equalv1v2)xs1xs2|_->false