123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244moduletypeSexp=sigtypet=|Atomofstring|ListoftlistendmoduletypeMonad=sigtype'atvalreturn:'a->'atvalbind:'at->('a->'bt)->'btendmoduleMake(Sexp:Sexp)=structopenSexp(* This is to keep compatibility with 4.02 without writing [Result.]
everywhere *)type('a,'b)result=('a,'b)Result.result=|Okof'a|Errorof'bmoduletypeInput=sigtypetmoduleMonad:Monadvalread_string:t->int->(string,string)Result.resultMonad.tvalread_char:t->(char,string)Result.resultMonad.tendletparse_errorf=Format.ksprintf(funmsg->Errormsg)fletinvalid_characterc=parse_error"invalid character %C"cletmissing_left_parenthesis()=parse_error"right parenthesis without matching left parenthesis"moduleMake_parser(Input:Input)=structletint_of_digitc=Char.codec-Char.code'0'let(>>=)=Input.Monad.bindopenInput.Monadletrecparse_atominputlen=Input.read_charinput>>=function|Errore->return@@Errore|Ok('0'..'9'asc)->letlen=(len*10)+int_of_digitciniflen>Sys.max_string_lengththenreturn@@parse_error"atom too big to represent"elseparse_atominputlen|Ok':'->(Input.read_stringinputlen>>=function|Oks->return@@Ok(Atoms)|Errore->return@@Errore)|Okc->return@@invalid_charactercletrecparse_manydepthinputacc=Input.read_charinput>>=function|Ok'('->(parse_many(depth+1)input[]>>=function|Oksexps->parse_manydepthinput@@(Listsexps::acc)|e->returne)|Ok')'->return(ifdepth=0thenmissing_left_parenthesis()elseOk(List.revacc))|Okcwhen'0'<=c&&c<='9'->(parse_atominput(int_of_digitc)>>=function|Oksexp->parse_manydepthinput(sexp::acc)|Errore->return@@Errore)|Okc->return@@invalid_characterc|Errore->return(ifdepth=0thenOk(List.revacc)elseErrore)letparseinput=Input.read_charinput>>=function|Errore->return@@Errore|Ok'('->(parse_many1input[]>>=function|Oksexps->return@@Ok(Listsexps)|Errore->return@@Errore)|Ok')'->return@@missing_left_parenthesis()|Okcwhen'0'<=c&&c<='9'->parse_atominput(int_of_digitc)|Okc->return@@invalid_charactercletparse_manyinput=parse_many0input[]end[@@inlinedalways]letpremature_end="premature end of input"moduleId_monad=structtype'at='aletreturnx=xletbindxf=fxendmoduleString_input=structtypet={buf:string;mutablepos:int}moduleMonad=Id_monadletread_stringtlen=letpos=t.posinifpos+len<=String.lengtht.bufthen(lets=String.subt.bufposlenint.pos<-pos+len;Oks)elseErrorpremature_endletread_chart=ift.pos+1<=String.lengtht.bufthen(letpos=t.posinletc=t.buf.[pos]int.pos<-pos+1;Okc)elseErrorpremature_endendmoduleString_parser=Make_parser(String_input)letparse_strings=letinput:String_input.t={buf=s;pos=0}inmatchString_parser.parseinputwith|Okparsed->ifinput.pos<>String.lengthsthenError(input.pos,"data after canonical S-expression")elseOkparsed|Errormsg->Error(input.pos,msg)letparse_string_manys=letinput:String_input.t={buf=s;pos=0}inmatchString_parser.parse_manyinputwith|Okl->Okl|Errore->Error(input.pos,e)moduleIn_channel_input=structtypet=in_channelmoduleMonad=Id_monadletread_stringsizeinput=tryOk(really_input_stringsizeinput)withEnd_of_file->Errorpremature_endletread_charinput=tryOk(input_charinput)withEnd_of_file->Errorpremature_endendmoduleIn_channel_parser=Make_parser(In_channel_input)letinput_optic=letpos=LargeFile.pos_inicinmatchIn_channel_parser.parseicwith|Okx->Ok(Somex)|Errormsg->Errormsg|exceptionEnd_of_file->ifLargeFile.pos_inic=posthenOkNoneelseErrorpremature_endletinputic=matchinput_opticwith|OkNone->Errorpremature_end|Ok(Somex)->Okx|Errormsg->Errormsgletinput_many=letrecloopicacc=matchinput_opticwith|Error_asres->res|OkNone->Ok(List.revacc)|Ok(Somex)->loopic(x::acc)infunic->loopic[]letserialised_length=letrecloopacct=matchtwith|Atoms->letlen=String.lengthsinletx=refleninletlen_len=ref1inwhile!x>9dox:=!x/10;incrlen_lendone;acc+!len_len+1+len|Listl->List.fold_leftloopacclinfunt->loop0tletto_bufferbufsexp=letrecloop=function|Atomstr->Buffer.add_stringbuf(string_of_int(String.lengthstr));Buffer.add_stringbuf":";Buffer.add_stringbufstr|Liste->Buffer.add_charbuf'(';List.iterloope;Buffer.add_charbuf')'inloopsexpletto_stringsexp=letbuf=Buffer.create(serialised_lengthsexp)into_bufferbufsexp;Buffer.contentsbufletto_channelocsexp=letrecloop=function|Atomstr->output_stringoc(string_of_int(String.lengthstr));output_charoc':';output_stringocstr|Listl->output_charoc'(';List.iterloopl;output_charoc')'inloopsexpend