Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file CCSexp.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Simple S-expression parsing/printing} *)type'aor_error=('a,string)resulttype'agen=unit->'aoptionmoduletypeSEXP=CCSexp_intf.SEXPmoduletypeS=CCSexp_intf.Sletequal_string(a:string)b=Stdlib.(=)abletcompare_string(a:string)b=Stdlib.compareablet_with_infilenamef=letic=open_infilenameintryletx=ficinclose_inic;xwithe->close_inic;Error(Printexc.to_stringe)let_with_outfilenamef=letoc=open_outfilenameintryletx=focinclose_outoc;xwithe->close_outoc;raiseemoduleMake(Sexp:SEXP)=structtypet=Sexp.ttypesexp=ttypeloc=Sexp.locletatom=Sexp.atomletlist=Sexp.listletof_intx=Sexp.atom(string_of_intx)letof_floatx=Sexp.atom(string_of_floatx)letof_boolx=Sexp.atom(string_of_boolx)letof_unit=Sexp.list[]letof_listl=Sexp.listlletof_rev_listl=Sexp.list(List.revl)letof_pair(x,y)=Sexp.list[x;y]letof_triple(x,y,z)=Sexp.list[x;y;z]letof_quad(x,y,z,u)=Sexp.list[x;y;z;u]letof_variantnameargs=Sexp.list(Sexp.atomname::args)letof_fieldnamet=Sexp.list[Sexp.atomname;t]letof_recordl=Sexp.list(List.map(fun(n,x)->of_fieldnx)l)(** {3 Printing} *)(* shall we escape the string because of one of its chars? *)let_must_escapes=tryfori=0toString.lengths-1doletc=String.unsafe_getsiinmatchcwith|' '|')'|'('|'"'|';'|'\\'|'\n'|'\t'|'\r'->raiseExit|_whenChar.codec>127->raiseExit(* non-ascii *)|_->()done;falsewithExit->true(* empty atoms must be escaped *)let_must_escapes=String.lengths=0||_must_escapesletrecto_bufbt=Sexp.match_t~atom:(funs->if_must_escapesthenPrintf.bprintfb"\"%s\""(String.escapeds)elseBuffer.add_stringbs)~list:(function|[]->Buffer.add_stringb"()"|[x]->Printf.bprintfb"(%a)"to_bufx|l->Buffer.add_charb'(';List.iteri(funit'->ifi>0thenBuffer.add_charb' ';to_bufbt')l;Buffer.add_charb')')letto_stringt=letb=Buffer.create128into_bufbt;Buffer.contentsbletrecppfmtt=Sexp.match_t~atom:(funs->if_must_escapesthenFormat.fprintffmt"\"%s\""(String.escapeds)elseFormat.pp_print_stringfmts)~list:(function|[]->Format.pp_print_stringfmt"()"|[x]->Format.fprintffmt"@[<hov2>(%a)@]"ppx|l->Format.fprintffmt"@[<hov1>(";List.iteri(funit'->ifi>0thenFormat.fprintffmt"@ ";ppfmtt')l;Format.fprintffmt")@]")letrecpp_noindentfmtt=Sexp.match_t~atom:(funs->if_must_escapesthenFormat.fprintffmt"\"%s\""(String.escapeds)elseFormat.pp_print_stringfmts)~list:(function|[]->Format.pp_print_stringfmt"()"|[x]->Format.fprintffmt"(%a)"pp_noindentx|l->Format.pp_print_charfmt'(';List.iteri(funit'->ifi>0thenFormat.pp_print_charfmt' ';pp_noindentfmtt')l;Format.pp_print_charfmt')')letto_chanoct=letfmt=Format.formatter_of_out_channelocinppfmtt;Format.pp_print_flushfmt()letto_file_iterfilenameseq=_with_outfilename(funoc->seq(funt->to_chanoct;output_charoc'\n'))letto_filefilenamet=to_file_iterfilename(funk->kt)(** {2 Parsing} *)(** A parser of ['a] can return [Yield x] when it parsed a value,
or [Fail e] when a parse error was encountered, or
[End] if the input was empty *)type'aparse_result=|Yieldof'a|Failofstring|EndmoduleDecoder=structmoduleL=CCSexp_lextypet={buf:Lexing.lexbuf;mutablecur_tok:L.tokenoption;(* current token *)}letcur(t:t):L.token=matcht.cur_tokwith|SomeL.EOI->assertfalse|Somet->t|None->(* fetch token *)lettok=L.tokent.bufint.cur_tok<-Sometok;tokletjunkt=t.cur_tok<-Noneletof_lexbufbuf={buf;cur_tok=None}exceptionE_endexceptionE_errorofint*int*stringletpair_of_pos_p=letopenLexinginp.pos_lnum,p.pos_cnum-p.pos_bolletloc_of_buf_with_?startbuff=letopenLexinginletstart=matchstartwith|Somep->p|None->buf.lex_start_pinf(pair_of_pos_start)(pair_of_pos_buf.lex_curr_p)buf.lex_curr_p.pos_fnamelet[@inline]loc_of_buf_(self:t):locoption=matchSexp.make_locwith|None->None|Somef->Some(loc_of_buf_with_self.buff)letlast_loc=loc_of_buf_leterror_lexbufmsg=letstart=Lexing.lexeme_start_plexbufinletline,col=pair_of_pos_startinraise(E_error(line,col,msg))letnext(t:t)=letopenLexinginletrecexpr()=matchcurtwith|L.EOI->raiseE_end|L.SEXP_COMMENT->junkt;let_u=expr()in(* discard next sexp *)expr()|L.ATOMs->junkt;(matchSexp.make_locwith|None->Sexp.atoms|Somef->(* build a position for this token *)letloc=loc_of_buf_with_t.buffinSexp.atom_with_loc~locs)|L.LIST_OPEN->letpos_start=t.buf.lex_curr_pinjunkt;letl=lst[]in(matchcurtwith|L.LIST_CLOSE->junkt;(matchSexp.make_locwith|None->Sexp.listl|Somef->letloc=loc_of_buf_with_~start:pos_startt.buffinSexp.list_with_loc~locl)|_->error_t.buf"expected ')'")|L.LIST_CLOSE->error_t.buf"expected expression"andlstacc=matchcurtwith|L.LIST_CLOSE->List.revacc|L.LIST_OPEN|L.ATOM_|L.SEXP_COMMENT->letsub=expr()inlst(sub::acc)|L.EOI->error_t.buf"unexpected EOI"intryYield(expr())with|E_end->End|E_error(line,col,msg)|CCSexp_lex.Error(line,col,msg)->Fail(Printf.sprintf"parse error at %d:%d: %s"linecolmsg)letto_list(d:t):_or_error=letreciteracc=matchnextdwith|End->Ok(List.revacc)|Yieldx->iter(x::acc)|Faile->Erroreintryiter[]withe->Error(Printexc.to_stringe)endletdec_next_(d:Decoder.t):_or_error=matchDecoder.nextdwith|End->Error"unexpected end of file"|Yieldx->Okx|Fails->Errorsletparse_strings:tor_error=letbuf=Lexing.from_stringsinletd=Decoder.of_lexbufbufindec_next_dletparse_string_lists:tlistor_error=letbuf=Lexing.from_stringsinletd=Decoder.of_lexbufbufinDecoder.to_listdletset_file_?filebuf=letopenLexinginmatchfilewith|Somes->buf.lex_start_p<-{buf.lex_start_pwithpos_fname=s}|None->()letparse_chan_?fileic:sexpor_error=letbuf=Lexing.from_channelicinset_file_?filebuf;letd=Decoder.of_lexbufbufindec_next_dletparse_chan_list_?fileic=letbuf=Lexing.from_channelicinset_file_?filebuf;letd=Decoder.of_lexbufbufinDecoder.to_listdletparse_chanic=parse_chan_icletparse_chan_listic=parse_chan_list_icletparse_chan_genic=letbuf=Lexing.from_channelicinletd=Decoder.of_lexbufbufinfun()->matchDecoder.nextdwith|End->None|Faile->Some(Errore)|Yieldx->Some(Okx)letparse_filefilename=_with_infilename(parse_chan_~file:filename)letparse_file_listfilename=_with_infilename(parse_chan_list_~file:filename)endtypet=[`Atomofstring|`Listoftlist]letrecequalab=matcha,bwith|`Atoms1,`Atoms2->equal_strings1s2|`Listl1,`Listl2->(tryList.for_all2equall1l2withInvalid_argument_->false)|`Atom_,_|`List_,_->falseletreccompare_listab=matcha,bwith|[],[]->0|[],_::_->-1|_::_,[]->1|x::xs,y::ys->(matchcomparexywith|0->compare_listxsys|c->c)andcompareab=matcha,bwith|`Atoms1,`Atoms2->compare_strings1s2|`Listl1,`Listl2->compare_listl1l2|`Atom_,_->-1|`List_,_->1moduleBasic_=structtypenonrect=ttypeloc=unitletmake_loc=Noneletatomx=`Atomxletlistx=`Listxletatom_with_loc~loc:_s=atomsletlist_with_loc~loc:_l=listlletmatch_x~atom~list=matchxwith|`Atomx->atomx|`Listl->listlendinclude(Make(Basic_):Swithtypet:=tandtypeloc=unit)letatoms:t=`Atoms