123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294(**************************************************************************)(* *)(* Copyright 2013 OCamlPro *)(* *)(* All rights reserved. This file is distributed under the terms of *)(* the Lesser GNU Public License version 3.0. *)(* *)(* This software is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* Lesser GNU General Public License for more details. *)(* *)(**************************************************************************)(* - Input stream handling - *)openApprox_lexermoduleStream=structtypestream={nstream:Nstream.t;last:token;before_last:token;region:Pos.Region.t;stop:Lexing.position ->bool}letof_nstream ?(stop=fun_->false)nstream={nstream;last =COMMENT;before_last=COMMENT;region=Pos.Region.zero;stop;}letnext stream=letshiftstreamtokregion={stream withregion;last=tok;before_last=match stream.lastwith|COMMENT ->stream.before_last|tok->tok;}inmatchNstream.nextstream.nstreamwith|Some({Nstream.token;region},nstream)->ifstream.stop(Pos.Region.sndregion)thenEOF,shiftstreamEOFregionelsetoken,shift {streamwithnstream}token region|_->EOF,shiftstreamEOFstream.regionletequalsst1st2=st1.nstream==st2.nstreamletnext_twostream=lettok1,stream =nextstreaminlettok2,stream=nextstreamintok1,tok2,streamletnext_three stream=lettok1,stream=nextstreaminlettok2,stream=nextstreaminlettok3,stream=nextstreamintok1,tok2,tok3,streamletprevious stream=stream.before_lastlettokenstream=stream.lastletposstream=letpos1=Pos.Region.fststream.regioninletpos2=Pos.Region.sndstream.regioninLexing.(pos1.pos_lnum,pos1.pos_cnum-pos1.pos_bol,pos2.pos_cnum-pos1.pos_cnum)endletclose_defstream=matchStream.previous streamwith|AMPERSAND|AMPERAMPER |BARBAR|BEGIN|COLONCOLON|COLONEQUAL|COMMA|DO|DOWNTO|ELSE|EQUAL|GREATER|IF|IN|INFIXOP0_|INFIXOP1_|INFIXOP2_|INFIXOP3_|INFIXOP4_|LBRACE|LBRACELESS|LBRACKET|LBRACKETBAR|LBRACKETLESS|LBRACKETGREATER|LESS|LESSMINUS|LPAREN|MATCH|MINUS|MINUSDOT|MINUSGREATER|OR|PLUS|PLUSDOT|QUESTION|QUESTIONQUESTION|SEMI|STAR|THEN|TO|TRY|WHEN|WHILE|TILDE->false|_->trueletparse_pathstream=letrecauxacc stream =matchStream.next_two streamwith|DOT,UIDENTi,stream->aux(i::acc)stream|_->List.revacc,streaminmatchStream.nextstreamwith|UIDENTi,stream ->letpath,stream =aux[]streamini::path,stream|_->[],streamletrecskip_to_next_parenstream=lettok,stream =Stream.nextstream inmatchtokwith|RPAREN|EOF->stream|_->skip_to_next_parenstream(* - Now for the interesting stuff - *)typescope=Def|Block|Paren|Bracetypeenv=Aliasofstring *stringlist|Openofstringlisttype t=(scope*envlist)listletempty=[]let recclosetscope =matchtwith|[]->[]|(scope1,_)::rwhenscope1=scope ->r|_::r->closerscopeletmaybe_closetscope=matchtwith|(scope1,_)::rwhenscope1=scope ->r|t->tletpushtinfo=matchtwith|(scope,infos)::r->(scope,info::infos)::r|[]->[Block,[info]](* print error ? *)(* [ (X : S) ]* *)letparse_functor_argsstream=letrecauxstream =letparse_error=[],streaminmatch Stream.next_threestreamwith|LPAREN,UIDENT x,COLON,stream->beginmatchparse_pathstreamwith|[],_->parse_error|s,stream->(* XXX: convert module constraints into module aliases ?*)letstream=skip_to_next_parenstreaminletargs,stream=auxstreaminAlias(x,s)::args,streamend|_->parse_error inauxstream(* functor (X: S) -> *)letparse_functorstream=letrecauxstream =letparse_error=[],streaminmatch Stream.nextstreamwith|FUNCTOR,stream ->letargs,stream=parse_functor_argsstreaminbeginmatchStream.nextstreamwith|MINUSGREATER,stream->letrest,stream=auxstreaminargs@rest,stream|_->parse_errorend|_->parse_error inauxstreamletparsetstream0=lettok,stream=Stream.nextstream0 inmatchtokwith|STRUCT|SIG|BEGIN|OBJECT->(Block,[])::t,stream|END->closetBlock,stream|LPAREN->(Paren,[])::t,stream|RPAREN->closetParen,stream|LBRACE->ifstream0.last=INFIXOP3"%"thent,streamelse(* for mlyheaders *)(matchparse_pathstreamwith|[],stream->(Brace,[])::t,stream|path,stream->(Brace,[Openpath])::t,stream)|RBRACE->ifstream0.last=INFIXOP3"%"thent,streamelse(* for mlyheaders *)closetBrace,stream|OPEN->lett=ifStream.previousstream=LETthentelsemaybe_closetDefinletpath,stream=parse_pathstream inpusht(Openpath),stream|INCLUDE->letpath,stream=parse_pathstream inpusht(Openpath),stream|LETwhenclose_defstream->(Def,[])::maybe_closetDef,stream|MODULE->lett=ifclose_defstreamthenmaybe_closetDefelse tinletident,stream=matchStream.nextstreamwith|UIDENTu,stream->u,stream|TYPE,stream1->(matchStream.nextstream1 with|UIDENT u,stream->u,stream|_->"",stream)|_->"",stream inletfunctor_pre_args,stream=parse_functor_args stream inlettop_def,stream=matchStream.next streamwith|EQUAL,stream1->beginmatchparse_pathstream1with|[],_->[],stream|path,stream->path,streamend|_->[],stream(* todo *)inletfunctor_post_args,stream=matchStream.next streamwith|EQUAL,stream->parse_functorstream|_->[],stream inletaliases=functor_pre_args@functor_post_argsinlett=iftop_def <>[]thenpusht(Alias(ident,top_def))elsetin(Def,Open[ident]::aliases)::t,stream|UIDENT_->(* Module.( ... ) or Module.{ ... } *)letpath,stream=parse_pathstream0 in(matchStream.next_twostreamwith|DOT,LPAREN,stream->(Paren,[Openpath])::t,stream|DOT,LBRACE,stream->(matchparse_pathstreamwith|[],stream ->(Brace,[Openpath])::t,stream|path2,stream->(Brace,[Openpath;Openpath2])::t,stream)|_->t,stream)|_->t,streamletpos_afterlinecolpos=letopenLexing inpos.pos_lnum>line||pos.pos_lnum=line&&pos.pos_cnum-pos.pos_bol>=colletread_nstream?line ?columnnstream=letrecparse_all(t,stream)=ifStream.previousstream=EOFthentelseparse_all(parsetstream)inletstop=matchline,columnwith|Somel,Somec->Some(pos_afterlc)|Somel,None->Some(pos_afterl0)|_->Noneinparse_all([Block,[]],Stream.of_nstream?stopnstream)letread?line?columnchan=read_nstream ?line ?column(Nstream.of_channelchan)letread_stringstring=read_nstream(Nstream.of_stringstring)letto_list=letaux acct=List.fold_left(funacc->function|Brace,_->acc(* brace opens don't propagate down *)|_,ctx->List.rev_appendctxacc)acctinfunction|(Brace,ctx)::t->aux(List.revctx)t|t-> aux[]tlet fold_nstreamfacc?(init=[])?stopnstream=let recauxacctstream=ifStream.previousstream=EOFthenaccelselett1,stream1=parsetstreaminletreccatch_upaccstream=lettok,stream =Stream.nextstream inifStream.equalsstreamstream1thenaccelsecatch_up(faccttok(Stream.posstream))streaminletacc=catch_upaccstreaminletacc=facct1(Stream.tokenstream1)(Stream.posstream1)inauxacct1stream1inletstream=Stream.of_nstream?stopnstreaminauxacc[Block,init]streamletfoldfacc?init?stopchan=fold_nstreamfacc?init?stop(Nstream.of_channelchan)letfold_stringfacc?init?stopchan=fold_nstreamfacc?init?stop(Nstream.of_stringchan)letfrom_dot_merlin dir =tryletic=open_in(Filename.concatdir".merlin")intryletrecscanic=matchIndexMisc.string_split' '(input_lineic)with|"FLG"::flags->letrecaux =function|"-open"::modname::r->Open(IndexMisc.string_split'.'modname)::auxr|_::r->auxr|[]->[]inauxflags@scanic|_->scanic|exceptionEnd_of_file->[]inletr=scanicinclose_inic;rwithe->close_in ic;raiseewith_->[]