123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359(* 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. *)openTypesmoduleB=Yaml_ffi.MmoduleT=Yaml_types.Mtypetag_directive={handle:string;prefix:string}[@@derivingsexp]leterror_to_msge=matchewith|`None->"No error"|`Memory->"Reader error"|`Scanner->"Scanner error"|`Parser->"Parser error"|`Composer->"Compose error"|`Writer->"Writer error"|`Emitter->"Emitter error"|`Ei->"Unknown error code "^Int64.to_stringiletscalar_style_of_ffis:scalar_style=matchswith|`Any->`Any|`Plain->`Plain|`Single_quoted->`Single_quoted|`Double_quoted->`Double_quoted|`Literal->`Literal|`Folded->`Folded|`Eerr->raise(Invalid_argument("invalid scalar style"^Int64.to_stringerr))letlayout_style_of_ffis:layout_style=matchswith|`Any->`Any|`Block->`Block|`Flow->`Flow|`Eerr->raise(Invalid_argument("invalid mapping style"^Int64.to_stringerr))letlayout_style_of_ffis:layout_style=matchswith|`Any->`Any|`Block->`Block|`Flow->`Flow|`Eerr->raise(Invalid_argument("invalid sequence style"^Int64.to_stringerr))letencoding_of_ffie:encoding=matchewith|`Any->`Any|`Utf16be->`Utf16be|`Utf16le->`Utf16le|`Utf8->`Utf8|`Eerr->raise(Invalid_argument("invalid encoding "^Int64.to_stringerr))lettag_directive_of_ffie=letopenCtypesinlethandle=!@(e|->T.Tag_directive.handle)inletprefix=!@(e|->T.Tag_directive.prefix)in{handle;prefix}letlist_of_tag_directivestds=letopenCtypesinletmoduleTEDT=T.Event.Document_start.Tag_directivesinlethd=!@(tds|->TEDT.start)in(* TODO not clear how to parse this as not a linked list *)letacc=[hd]inList.maptag_directive_of_ffiaccletversion_of_directive~major~minor=match(major,minor)with|1,1->`V1_1|1,2->`V1_2|_->raise(Invalid_argument(Printf.sprintf"Unsupported Yaml version %d.%d"majorminor))letdirective_of_version=function`V1_1->(1,1)|`V1_2->(1,2)moduleMark=structtypet={index:int;line:int;column:int}[@@derivingsexp]letof_ffim=letopenCtypesinletint_fieldf=getfmf|>Unsigned.Size_t.to_intinletindex=int_fieldT.Mark.indexinletline=int_fieldT.Mark.lineinletcolumn=int_fieldT.Mark.columnin{index;line;column}endmoduleEvent=structtypepos={start_mark:Mark.t;end_mark:Mark.t}typet=|Stream_startof{encoding:encoding}|Document_startof{version:versionoption;implicit:bool}|Document_endof{implicit:bool}|Mapping_startof{anchor:stringoption;tag:stringoption;implicit:bool;style:layout_style;}|Mapping_end|Stream_end|Scalarofscalar|Sequence_startof{anchor:stringoption;tag:stringoption;implicit:bool;style:layout_style;}|Sequence_end|Aliasof{anchor:string}|Nothingletof_ffie:t*pos=letopenT.EventinletopenCtypesinletty=getfe_typeinletdata=getfedatainletstart_mark=getfestart_mark|>Mark.of_ffiinletend_mark=getfeend_mark|>Mark.of_ffiinletpos={start_mark;end_mark}inletr=matchtywith|`Stream_start->letstart=getfdataData.stream_startinletencoding=getfstartStream_start.encoding|>encoding_of_ffiinStream_start{encoding}|`Document_start->letds=getfdataData.document_startinletversion=letvd=getfdsDocument_start.version_directiveinmatchvdwith|None->None|Somevd->letvd=!@vdinletmajor=getfvdT.Version_directive.majorinletminor=getfvdT.Version_directive.minorinSome(version_of_directive~major~minor)inletimplicit=getfdsDocument_start.implicit<>0inDocument_start{version;implicit}|`Mapping_start->letms=getfdataData.mapping_startinletanchor=getfmsMapping_start.anchorinlettag=getfmsMapping_start.taginletimplicit=getfmsMapping_start.implicit<>0inletstyle=getfmsMapping_start.style|>layout_style_of_ffiinMapping_start{anchor;tag;implicit;style}|`Scalar->lets=getfdataData.scalarinletanchor=getfsScalar.anchorinlettag=getfsScalar.taginletvalue=getfsScalar.valueinletplain_implicit=getfsScalar.plain_implicit<>0inletquoted_implicit=getfsScalar.quoted_implicit<>0inletstyle=getfsScalar.style|>scalar_style_of_ffiinScalar{anchor;tag;value;plain_implicit;quoted_implicit;style}|`Document_end->letde=getfdataData.document_endinletimplicit=getfdeDocument_end.implicit<>0inDocument_end{implicit}|`Sequence_start->letss=getfdataData.sequence_startinletanchor=getfssSequence_start.anchorinlettag=getfssSequence_start.taginletimplicit=getfssSequence_start.implicit<>0inletstyle=getfssSequence_start.style|>layout_style_of_ffiinSequence_start{anchor;tag;implicit;style}|`Sequence_end->Sequence_end|`Mapping_end->Mapping_end|`Stream_end->Stream_end|`Alias->leta=getfdataData.aliasinletanchor=matchgetfaAlias.anchorwith|None->raise(Invalid_argument"empty anchor alias")|Somea->ainAlias{anchor}|`None->Nothing|`Ei->raise(Invalid_argument("Unexpected event, internal library error "^Int64.to_stringi))in(r,pos)endletversion=B.versionletget_version()=letmajor=Ctypes.(allocateint0)inletminor=Ctypes.(allocateint0)inletpatch=Ctypes.(allocateint0)inB.get_versionmajorminorpatch;letmajor=Ctypes.(!@major)inletminor=Ctypes.(!@minor)inletpatch=Ctypes.(!@patch)in(major,minor,patch)typeparser={p:T.Parser.tCtypes.structureCtypes.ptr;event:T.Event.tCtypes.structureCtypes.ptr;buf:charCtypes_static.carray;}letparserstr=letp=Ctypes.(allocate_nT.Parser.t~count:1)inletevent=Ctypes.(allocate_nT.Event.t~count:1)inletr=B.parser_initpinletbuf=Ctypes.CArray.of_stringstrinletbuf_ptr=Ctypes.CArray.startbufinletlen=String.lengthstr|>Unsigned.Size_t.of_intinB.parser_set_input_stringpbuf_ptrlen;matchrwith|1->Ok{buf;p;event}|n->Error(`Msg("error initialising parser: "^string_of_intn))letdo_parse{p;event}=letopenCtypesinletr=B.parser_parsepeventinletdescribe_problem()=matchCtypes.(getf!@pT.Parser.problem)with|None->"(no problem description)"|Somes->letpv=Ctypes.(getf!@pT.Parser.problem_value)inletpo=Ctypes.(getf!@pT.Parser.problem_offset)ins^" character "^string_of_intpv^" position "^Unsigned.Size_t.to_stringpoinmatchrwith|1->Event.of_ffi!@event|>Result.ok|n->Error(`Msg("error calling parser: "^describe_problem()^" returned: "^string_of_intn))typeemitter={e:T.Emitter.tCtypes.structureCtypes.ptr;event:T.Event.tCtypes.structureCtypes.ptr;buf:charCtypes.ptr;written:Unsigned.size_tCtypes.ptr;}letemitter_written{written;_}=Ctypes.(!@written)|>Unsigned.Size_t.to_intletemitter?(len=65535*4)()=lete=Ctypes.(allocate_nT.Emitter.t~count:1)inletevent=Ctypes.(allocate_nT.Event.t~count:1)inletwritten=Ctypes.allocate_nCtypes.size_t~count:1inletr=B.emitter_initeinletbuf=Ctypes.(allocate_nCtypes.char~count:len)inletlen=Unsigned.Size_t.of_intleninB.emitter_set_output_stringebuflenwritten;matchrwith|1->Ok{e;event;written;buf}|n->Error(`Msg("error initialising emitter: "^string_of_intn))letemitter_buf{buf;written}=letlength=Ctypes.(!@written)|>Unsigned.Size_t.to_intinCtypes.string_from_ptrbuf~lengthletcheckla=matchawith|0->Error(`Msg(l^" failed"))|1->Ok()|n->Error(`Msg("unexpected return value: "^string_of_intn))letcheck_emitl{e;event}a=Result.bind(checkla)@@fun()->checkl@@B.emitter_emiteeventletstream_starttencoding=check_emit"stream_start"t@@B.stream_start_event_initt.event(encoding:>T.Encoding.t)letstream_endt=check_emit"stream_end"t@@B.stream_end_event_initt.eventletdocument_start?version?(implicit=true)t=letopenCtypesinletver=matchversionwith|None->from_voidpT.Version_directive.tnull|Somev->letmajor,minor=directive_of_versionvinletv=makeT.Version_directive.tinsetfvT.Version_directive.majormajor;setfvT.Version_directive.minorminor;allocateT.Version_directive.t@@vinlettag=from_voidpT.Tag_directive.tnullincheck_emit"doc_start"t@@B.document_start_event_initt.eventvertagtagimplicitletdocument_end?(implicit=true)t=check_emit"doc_end"t@@B.document_end_event_initt.eventimplicitletscalar{plain_implicit;quoted_implicit;anchor;tag;style;value}t=check_emit"scalar"t@@B.scalar_event_initt.eventanchortagvalue(String.lengthvalue)plain_implicitquoted_implicit(style:>T.Scalar_style.t)letsequence_start?anchor?tag?(implicit=true)?(style=`Block)t=check_emit"seq_start"t@@B.sequence_start_event_initt.eventanchortagimplicit(style:>T.Sequence_style.t)letsequence_endt=check_emit"seq_end"t@@B.sequence_end_event_initt.eventletmapping_start?anchor?tag?(implicit=true)?(style=`Block)t=check_emit"mapping_start"t@@B.mapping_start_event_initt.eventanchortagimplicit(style:>T.Mapping_style.t)letmapping_endt=check_emit"mapping_end"t@@B.mapping_end_event_initt.eventletaliastvalue=check_emit"alias"t@@B.alias_event_initt.eventvalueletemitt=letopenEventinfunction|Stream_start{encoding}->stream_starttencoding|Document_start{version;implicit}->document_start?version~implicitt|Document_end{implicit}->document_end~implicitt|Mapping_start{anchor;tag;implicit;style}->mapping_start?anchor?tag~implicit~stylet|Mapping_end->mapping_endt|Stream_end->stream_endt|Scalars->scalarst|Sequence_start{anchor;tag;implicit;style}->sequence_start?anchor?tag~implicit~stylet|Sequence_end->sequence_endt|Alias{anchor}->aliastanchor|Nothing->Ok()