123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752(*
* uTop_main.ml
* ------------
* Copyright : (c) 2011, Jeremie Dimino <jeremie@dimino.org>
* Licence : BSD3
*
* This file is a part of utop.
*)[@@@warning"-7-9-27-32-33"]openCamomileLibraryDefault.CamomileopenLwt_reactopenLTerm_dlistopenLTerm_textopenLTerm_geomopenUTopopenUTop_tokenopenUTop_stylesopenUTop_privateletget_desc x=#ifOCAML_VERSION >=(4,14,0)Types.get_descx#elsex.Types.desc#endiflettoploop_use_silentlyfmtname=#ifOCAML_VERSION>=(4,14,0)Toploop.use_silentlyfmt(Filename)#elseToploop.use_silentlyfmtname#endifletreturn,(>>=)=Lwt.return,Lwt.(>>=)moduleString_set=Set.Make(String)exception Termofint(* +-----------------------------------------------------------------+
| History |
+-----------------------------------------------------------------+ *)letsave_history()=match!UTop.history_file_namewith|None->return()|Somefn->Lwt.catch(fun()->LTerm_history.saveUTop.history?max_size:!UTop.history_file_max_size?max_entries:!UTop.history_file_max_entriesfn)(function|Unix.Unix_error(error,func,arg)->Lwt_log.error_f"cannot save history to %S: %s: %s" fnfunc(Unix.error_message error)|exn->Lwt.failexn)let init_history ()=(* Save history on exit. *)Lwt_main.at_exitsave_history;(* Load history. *)match!UTop.history_file_namewith|None->return()|Somefn->Lwt.catch(fun()->LTerm_history.loadUTop.historyfn)(function|Unix.Unix_error(error,func,arg)->Lwt_log.error_f"cannot load history from %S: %s: %s"fnfunc(Unix.error_message error)|exn->Lwt.failexn)(* +-----------------------------------------------------------------+
| offset --> index |
+-----------------------------------------------------------------+ *)(* Return the index (in unicode characters) of the character starting
a offset (in bytes) [ofs] in [str]. *)letindex_of_offsetsrcofs=letrecauxidxofs'=if ofs'=ofsthenidxelseifofs'>ofsthenidx-1elseifofs'=String.lengthsrcthen-1elseaux(idx+1)(Zed_utf8.unsafe_nextsrcofs')inaux00let convert_locstr(a,b)=(index_of_offsetstra,index_of_offsetstrb)letconvert_locsstrlocs=List.map(fun(a,b)->convert_locstr(a,b))locsletget_linesrcline=letrecauxline'ofsskipped=if ofs>=String.lengthsrcthen("",0)elseifline'=linethen(String.subsrcofs(String.lengthsrc-ofs),skipped)elseletch,next_ofs=Zed_utf8.unsafe_extract_nextsrcofsinifZed_utf8.escaped_charch="\\n"thenaux(line'+1)next_ofs(skipped +1)elseauxline'next_ofs(skipped +1)inaux100letconvert_one_linestrlineofs=letselected,skipped =get_line strlineinindex_of_offset selectedofs+skippedletconvert_line str(start_ofs,end_ofs)lines=(convert_one_line strlines.startstart_ofs,convert_one_linestrlines.stopend_ofs)letconvert_loc_line inputlocs lines =List.map2(funlocline->matchlinewith|None->convert_locinputloc|Some line->convert_lineinputlocline)locs lines(* +-----------------------------------------------------------------+
| The read-line class |
+-----------------------------------------------------------------+ *)#ifOCAML_VERSION>=(4,04,0)letast_impl_kind=Pparse.Structure#elseletast_impl_kind=Config.ast_impl_magic_number#endifletpreprocess input=matchinputwith|Parsetree.Ptop_defpstr->Parsetree.Ptop_def(Pparse.apply_rewriters~tool_name:"ocaml"ast_impl_kindpstr)|_->inputletparse_input_multiinput=letbuf=Buffer.create32inletresult=UTop.collect_formattersbuf[Format.err_formatter](fun()->match !UTop.parse_use_fileinputfalsewith|UTop.Error(locs,msg)->UTop.Error (convert_locsinputlocs,"Error: "^msg^"\n")|UTop.Valuephrases->tryUTop.Value(List.mappreprocessphrases)withPparse.Errorerror->Pparse.report_error Format.str_formattererror;UTop.Error([],"Error: "^Format.flush_str_formatter()^"\n"))in(result,Buffer.contents buf)letparse_and_checkinputeos_is_error=letbuf=Buffer.create32inletresult=UTop.collect_formattersbuf[Format.err_formatter](fun()->match!UTop.parse_toplevel_phraseinputeos_is_errorwith|UTop.Error(locs,msg)->UTop.Error (convert_locsinputlocs,"Error: "^msg^"\n")|UTop.Valuephrase->trylet phrase=preprocessphraseinmatch UTop.check_phrasephrasewith|None->UTop.Valuephrase|Some(locs,msg,lines)->UTop.Error(convert_loc_lineinputlocslines,msg)withPparse.Errorerror->Pparse.report_error Format.str_formattererror;UTop.Error([],"Error: "^Format.flush_str_formatter()^"\n"))in(result,Buffer.contents buf)letadd_terminators=letterminator=UTop.get_phrase_terminator()|>Zed_string.unsafe_of_utf8inifZed_string.ends_withs~suffix:terminatorthenselseZed_string.appendsterminatorletis_accept :LTerm_read_line.action->bool=function|Accept->true|action->action==UTop.end_and_accept_current_phrase(* Read a phrase. If the result is a value, it is guaranteed to be a
valid phrase (i.e. typable and compilable). It also returns
warnings printed parsing. *)classread_phrase ~term=object(self)inherit[Parsetree.toplevel_phraseUTop.result*string]LTerm_read_line.engine~history:(LTerm_history.contentsUTop.history)()assuperinherit[Parsetree.toplevel_phraseUTop.result*string]LTerm_read_line.termtermassuper_termmethodcreate_temporary_file_for_external_editor=Filename.temp_file"utop"".ml"methodexternal_editor =UTop.get_external_editor()valmutablereturn_value=Nonemethodeval=matchreturn_valuewith|Somex->x|None->assertfalsemethod!send_actionaction=letaction:LTerm_read_line.action=ifis_acceptaction&&S.valueself#mode<>LTerm_read_line.EditionthenAcceptelseactioninsuper#send_actionactionmethod!exec?(keys=[])=function|action ::actionswhenS.valueself#mode=LTerm_read_line.Edition&&is_acceptaction->beginZed_macro.addself#macroaction;let input=Zed_rope.to_string(Zed_edit.textself#edit)inletinput=ifaction==UTop.end_and_accept_current_phrasethenadd_terminatorinputelseinputinletinput_utf8=Zed_string.to_utf8inputin(* Toploop does that: *)Location.reset();leteos_is_error =not!UTop.smart_acceptintryletresult=parse_and_check input_utf8eos_is_errorinreturn_value<-Someresult;LTerm_history.addUTop.historyinput;letout,warnings=resultinbeginmatchoutwith|UTop.Value_->UTop_history.add_inputUTop.stashable_session_history input_utf8;UTop_history.add_warningsUTop.stashable_session_history warnings;|(UTop.Error(_,msg))->UTop_history.add_bad_inputUTop.stashable_session_history input_utf8;UTop_history.add_warningsUTop.stashable_session_history warnings;UTop_history.add_errorUTop.stashable_session_history msg;end;return(LTerm_read_line.Resultresult)withUTop.Need_more->(* Input not finished, continue. *)self#insert(UChar.of_char'\n');self#exec~keysactionsend|actions->super_term#execactionsmethod!styliselast=letstyled,position=super#styliselastin(* Syntax highlighting *)letstyliseloctoken_style=fori=loc.idx1toloc.idx2-1doletch,style=styled.(i)instyled.(i)<-(ch,LTerm_style.mergetoken_stylestyle)doneinUTop_styles.stylisestylise(UTop_lexer.lex_string(Zed_string.to_utf8(LTerm_text.to_stringstyled)));ifnotlastthen(* Parenthesis matching. *)LTerm_text.stylise_parenthesis styledpositionstyles.style_parenelsebeginmatchreturn_valuewith|Some(UTop.Error(locs,_),_)->(* Highlight error locations. *)List.iter(fun(start,stop)->fori=max0starttomin(Array.lengthstyled)stop-1doletch,style=styled.(i)instyled.(i)<-(ch,{stylewithLTerm_style.underline=Sometrue})done)locs|_->()end;(styled,position)method!completion =letpos,words=UTop_complete.complete~phrase_terminator:(UTop.get_phrase_terminator())~input:(Zed_string.to_utf8(Zed_rope.to_stringself#input_prev))inletwords=words|>List.map(fun(k,v)->(Zed_string.unsafe_of_utf8k,Zed_string.unsafe_of_utf8v))inself#set_completionposwordsmethod!show_box=S.valueself#mode<>LTerm_read_line.Edition||UTop.get_show_box()initializer(* Set the source signal for the size of the terminal. *)UTop_private.set_sizeself#size;(* Set the source signal for the key sequence. *)UTop_private.set_key_sequenceself#key_sequence;(* Set the prompt. *)self#set_prompt!UTop.promptend(* +-----------------------------------------------------------------+
| Out phrase printing |
+-----------------------------------------------------------------+ *)let fix_stringstr=letlen=String.lengthstrinletofs,_,_=Zed_utf8.next_errorstr0inifofs=lenthenstrelsebeginletbuf=Buffer.create(len+128)inifofs>0then Buffer.add_substringbufstr0ofs;letrecloop ofs=Zed_utf8.addbuf(UChar.of_charstr.[ofs]);letofs1=ofs+1inletofs2,_,_=Zed_utf8.next_errorstrofs1inifofs1<ofs2thenBuffer.add_substringbufstrofs1(ofs2-ofs1);ifofs2<lenthenloopofs2elseBuffer.contentsbufinloopofsendletrender_out_phrase termstring=ifString.lengthstring>=100*1024thenLTerm.fprinttermstringelsebeginlet string=fix_stringstringinletstyled=LTerm_text.of_utf8stringinletstyliseloctoken_style=fori=loc.idx1toloc.idx2-1doletch,style=styled.(i)instyled.(i)<-(ch,LTerm_style.mergetoken_stylestyle)doneinUTop_styles.stylisestylise(UTop_lexer.lex_stringstring);LTerm.fprintstermstyledendletorig_print_out_signature=!Toploop.print_out_signatureletorig_print_out_phrase=!Toploop.print_out_phraseletis_implicit_namename=name<>""&&name.[0]='_'&&trylet_=int_of_string@@String.subname1(String.lengthname-1)intruewithFailure _->falseletmap_itemsunwrapwrap items=letrecauxacc=function|[]->acc|item::items->let sig_item,_=unwrap iteminletname,rec_status=matchsig_itemwith|Outcometree.Osig_class (_,name,_,_,rs)|Outcometree.Osig_class_type(_,name,_,_,rs)|Outcometree.Osig_module(name,_,rs)|Outcometree.Osig_type({Outcometree.otype_name=name},rs)->(name,rs)|Outcometree.Osig_typext({Outcometree.oext_name=name},_)|Outcometree.Osig_modtype(name,_)#ifOCAML_VERSION<(4,03,0)|Outcometree.Osig_value(name,_,_)->(name,Outcometree.Orec_not)#else|Outcometree.Osig_value{oval_name=name;_}->(name,Outcometree.Orec_not)|Outcometree.Osig_ellipsis->("",Outcometree.Orec_not)#endifinlet keep=name=""||name.[0]<>'_'||(UTop.get_create_implicits()&& is_implicit_namename)inifkeepthenaux(item::acc)itemselse(* Replace the [Orec_next] at the head of items by [Orec_first] *)letitems=matchitemswith|[]->[]|item::items'->letsig_item,extra=unwrapiteminmatchsig_itemwith|Outcometree.Osig_class(a,name,b,c,rs)->ifrs =Outcometree.Orec_nextthenwrap(Outcometree.Osig_class(a,name,b,c,Outcometree.Orec_first))extra::items'elseitems|Outcometree.Osig_class_type(a,name,b,c,rs)->ifrs=Outcometree.Orec_nextthenwrap (Outcometree.Osig_class_type(a,name,b,c,Outcometree.Orec_first))extra::items'elseitems|Outcometree.Osig_module(name,a,rs)->ifrs=Outcometree.Orec_nextthenwrap(Outcometree.Osig_module(name,a,Outcometree.Orec_first))extra::items'elseitems|Outcometree.Osig_type(oty,rs)->ifrs=Outcometree.Orec_nextthenwrap(Outcometree.Osig_type(oty,Outcometree.Orec_first))extra::items'elseitems|Outcometree.Osig_typext_#ifOCAML_VERSION>=(4,03,0)|Outcometree.Osig_ellipsis#endif|Outcometree.Osig_modtype_|Outcometree.Osig_value_->itemsinauxacc itemsinList.rev(aux[]items)letprint_out_signatureppitems=ifUTop.get_hide_reserved()thenorig_print_out_signaturepp(map_items(funx->(x,()))(funx()->x)items)elseorig_print_out_signatureppitemsletprint_out_phrasepp phrase=ifUTop.get_hide_reserved()thenletphrase=matchphrasewith|Outcometree.Ophr_eval_|Outcometree.Ophr_exception_->phrase|Outcometree.Ophr_signatureitems->Outcometree.Ophr_signature(map_items(funx->x)(funxy->(x,y))items)inorig_print_out_phraseppphraseelseorig_print_out_phraseppphraselet()=Toploop.print_out_signature:=print_out_signature;Toploop.print_out_phrase:=print_out_phrase(* +-----------------------------------------------------------------+
| Toplevel expression rewriting |
+-----------------------------------------------------------------+ *)letwith_loclocstr={Location.txt=str;Location.loc=loc;}(* A rule for rewriting a toplevel expression. *)typerewrite_rule ={type_to_rewrite:Longident.t;mutablepath_to_rewrite:Path.toption;required_values:Longident.tlist;(* Values that must exist and be persistent for the rule to apply. *)rewrite:Location.t->Parsetree.expression->Parsetree.expression;(* The rewrite function. *)enabled:boolReact.signal;(* Whether the rule is enabled or not. *)}#ifOCAML_VERSION<(4,11,0)letlongident_parse=Longident.parse#elseletlongident_parse str=letlexbuf=Lexing.from_stringstrinParse.longidentlexbuf#endifletlongident_lwt_main_run=Longident.Ldot(Longident.Lident"Lwt_main","run")letlongident_async_thread_safe_block_on_async_exn=Longident.(Ldot(Ldot(Lident"Async","Thread_safe"),"block_on_async_exn"))letlongident_unit=Longident.Lident"()"#ifOCAML_VERSION>=(4,03,0)letnolabel=Asttypes.Nolabel#elseletnolabel=""#endifletrewrite_rules=[(* Rewrite Lwt.t expressions to Lwt_main.run <expr> *){type_to_rewrite=Longident.(Ldot(Lident"Lwt","t"));path_to_rewrite=None;required_values =[longident_lwt_main_run];rewrite=(funloce->letopenAst_helper inwith_default_locloc(fun()->Exp.apply(Exp.ident(with_locloclongident_lwt_main_run))[(nolabel,e)]));enabled=UTop.auto_run_lwt;};(* Rewrite Async.Defered.t expressions to
Async.Thread_safe.block_on_async_exn (fun () -> <expr>). *){type_to_rewrite=Longident.(Ldot(Ldot(Lident"Async","Deferred"),"t"));path_to_rewrite=None;required_values=[longident_async_thread_safe_block_on_async_exn];rewrite =(funloce->letopenAst_helperinletpunit=Pat.construct(with_locloc(Longident.Lident"()"))Noneinwith_default_locloc (fun()->Exp.apply(Exp.ident(with_locloclongident_async_thread_safe_block_on_async_exn))[(nolabel,Exp.fun_nolabelNonepunite)]));enabled=UTop.auto_run_async;}]#ifOCAML_VERSION>=(4,10,0)let lookup_typelongidentenv=Env.find_type_by_namelongidentenv#elifOCAML_VERSION>=(4,04,0)letlookup_typelongidentenv=letpath=Env.lookup_typelongidentenvin(path,Env.find_typepathenv)#elseletlookup_type=Env.lookup_type#endifletrule_pathrule=matchrule.path_to_rewritewith|Some_asx->x|None->tryletenv=!Toploop.toplevel_envinletpath=matchlookup_typerule.type_to_rewriteenvwith|path,{Types.type_kind=Types.Type_abstract;Types.type_private=Asttypes.Public;Types.type_manifest=Somety}->beginmatchget_desc(Ctype.expand_headenvty)with|Types.Tconstr(path,_,_)->path|_->pathend|path,_->pathinletopt=Somepathinrule.path_to_rewrite<-opt;optwith_->None(* Returns whether the given path is persistent. *)letrecis_persistent_path=function|Path.Pidentid->Ident.persistentid#ifOCAML_VERSION>=(4,08,0)|Path.Pdot(p,_)->is_persistent_pathp#else|Path.Pdot(p,_,_)->is_persistent_pathp#endif|Path.Papply(_,p)->is_persistent_pathp(* Check that the given long identifier is present in the environment
and is persistent. *)letis_persistent_in_envlongident=letlookup_value=#ifOCAML_VERSION>=(4,10,0)Env.find_value_by_name#elseEnv.lookup_value#endifintryis_persistent_path (fst(lookup_valuelongident!Toploop.toplevel_env))withNot_found->falseletrule_matchesrulepath =React.S.valuerule.enabled&&(matchrule_pathrulewith|None->false|Somepath'->Path.samepathpath')&&List.for_allis_persistent_in_envrule.required_values(* Returns whether the argument is a toplevel expression. *)letis_eval=function|{Parsetree.pstr_desc=Parsetree.Pstr_eval_}->true|_->false(* Returns the rewrite rule associated to a type, if any. *)letrule_of_typetyp=matchget_desc (Ctype.expand_head !Toploop.toplevel_envtyp)with|Types.Tconstr(path,_,_)->begintrySome(List.find(funrule->rule_matchesrulepath)rewrite_rules)with_->Noneend|_->Noneletrewrite_str_itempstr_itemtstr_item=matchpstr_item,tstr_item.Typedtree.str_descwith|({Parsetree.pstr_desc=Parsetree.Pstr_eval(e,_);Parsetree.pstr_loc =loc},Typedtree.Tstr_eval({Typedtree.exp_type=typ},_))->beginmatch rule_of_typetypwith|Somerule->{Parsetree.pstr_desc=Parsetree.Pstr_eval (rule.rewriteloce,[]);Parsetree.pstr_loc =loc}|None ->pstr_itemend|_->pstr_itemlettype_structure envpstr=#ifOCAML_VERSION >=(4,14,0)lettstr,_,_,_,_=Typemod.type_structureenvpstrin#elifOCAML_VERSION >=(4,12,0)lettstr,_,_,_=Typemod.type_structureenvpstrin#elifOCAML_VERSION>=(4,08,0)let tstr,_,_,_=Typemod.type_structureenvpstrLocation.nonein#elselettstr,_,_=Typemod.type_structureenvpstrLocation.nonein#endiftstrletrewritephrase=matchphrasewith|Parsetree.Ptop_defpstr->if(UTop.get_auto_run_lwt()||UTop.get_auto_run_async())&&List.existsis_evalpstrthenlettstr=type_structure!Toploop.toplevel_envpstrinParsetree.Ptop_def(List.map2rewrite_str_itempstrtstr.Typedtree.str_items)elsephrase|Parsetree.Ptop_dir_->phraseletadd_letbinding_namedef=letopenParsetreeinmatch defwith|{pstr_desc=Pstr_eval(expr,attr);pstr_loc}->{pstr_loc;pstr_desc =Pstr_value(Asttypes.Nonrecursive,[{pvb_pat={ppat_desc =Ppat_var{txt=binding_name;loc=pstr_loc;};#ifOCAML_VERSION>=(4,08,0)ppat_loc_stack=[];#endifppat_loc=pstr_loc;ppat_attributes=[];};pvb_expr=expr;pvb_attributes=attr;pvb_loc=pstr_loc;}]);}|_->defletbind_expressionsnamephrase=matchphrase with|Parsetree.Ptop_defpstr->Parsetree.Ptop_def (List.map(add_letname)pstr)|Parsetree.Ptop_dir_->phrase(* +-----------------------------------------------------------------+
| Handling of [@@toplevel_printer] attributes |
+-----------------------------------------------------------------+ *)#ifOCAML_VERSION >=(4,04,0)#ifOCAML_VERSION>=(4,09,0)modulePersistent_signature =Persistent_env.Persistent_signature#elsemodulePersistent_signature=Env.Persistent_signature#endifletexecute_phrase=letnew_cmis=ref[]inletdefault_load =!Persistent_signature.loadinletload~unit_name=letres=default_load~unit_namein(matchreswithNone->()|Somex->new_cmis:=x.cmi::!new_cmis);resinPersistent_signature.load:=load;let reccollect_printerspathsignatureacc=List.fold_left(funaccitem->match(item:Types.signature_item)with#ifOCAML_VERSION>=(4,08,0)|Sig_module(id,_,{md_type=Mty_signatures;_},_,_)->#else|Sig_module(id,{md_type =Mty_signatures;_},_)->#endifcollect_printers(Longident.Ldot(path,Ident.nameid))sacc#ifOCAML_VERSION>=(4,08,0)|Sig_value(id,vd,_)->#else|Sig_value(id,vd)->#endif#ifOCAML_VERSION>=(4,08,0)ifList.exists(fun attr->letopenParsetreeinmatchattr.attr_namewith|{Asttypes.txt="toplevel_printer"|"ocaml.toplevel_printer";_}->#elseif List.exists(function|{Asttypes.txt="toplevel_printer"|"ocaml.toplevel_printer";_},_->#endiftrue|_->false)vd.val_attributesthenLongident.Ldot(path,Ident.nameid)::accelseacc|_->acc)accsignatureinletacknowledge_new_cmis()=letl=!new_cmisinnew_cmis:=[];letprinters=List.fold_left(funacc(cmi:Cmi_format.cmi_infos)->collect_printers(Longident.Lidentcmi.cmi_name)cmi.cmi_signacc)[]linList.iter(Topdirs.dir_install_printerFormat.err_formatter)printersinfunbppphrase->acknowledge_new_cmis();letres=Toploop.execute_phrasebppphraseinacknowledge_new_cmis();res#elseletexecute_phrase=Toploop.execute_phrase#endif(* +-----------------------------------------------------------------+
| Main loop |
+-----------------------------------------------------------------+ *)letregisters=refLTerm_vi.Vi.Interpret.RegisterMap.emptyletrecread_phrase term=Lwt.catch(fun()->letread_line=newread_phrase~termin(match!UTop.edit_modewith|LTerm_editor.Default->()|LTerm_editor.Viasmode->read_line#set_editor_modemode);letvi_state=read_line#vi_stateinvi_state#set_registers!registers;read_line#run>>=funresult->registers:=vi_state#get_registers;returnresult)(function|Sys.Break->LTerm.fprintlterm"Interrupted.">>=fun()->read_phraseterm|exn->Lwt.failexn)letprint_errortermmsg=LTerm.set_styletermstyles.style_error>>=fun()->Lwt_io.printmsg>>=fun()->LTerm.set_styletermLTerm_style.none>>=fun()->LTerm.flushtermletrecloopterm=(* Reset completion. *)UTop_complete.reset();(* increment the command counter. *)UTop_private.set_count(S.valueUTop_private.count +1);(* Call hooks. *)LTerm_dlist.iter_l(funf->f())UTop.new_command_hooks;(* Read interactively user input. *)letphrase_opt=Lwt_main.run(Lwt.finalize(fun ()->read_phraseterm>>=fun(result,warnings)->(* Print warnings before errors. *)Lwt_io.printwarnings>>=fun()->matchresultwith|UTop.Valuephrase->return(Somephrase)|UTop.Error(locs,msg)->print_errortermmsg>>=fun()->return None)(fun()->LTerm.flushterm))inmatchphrase_opt with|Somephrase->(* Rewrite toplevel expressions. *)letcount=S.valueUTop_private.countinletphrase=rewritephraseinletphrase=ifUTop.get_create_implicits()thenletbinding_name =Printf.sprintf"_%d"countinbind_expressions binding_namephraseelsephrasein(* Set the margin of standard formatters. *)UTop_private.set_marginFormat.std_formatter;UTop_private.set_marginFormat.err_formatter;(* Formatter to get the output phrase. *)letbuffer=Buffer.create1024inletpp=Format.formatter_of_bufferbufferinUTop_private.set_marginpp;(tryEnv.reset_cache_toplevel();if!Clflags.dump_parsetreethenPrintast.top_phraseppphrase;if!Clflags.dump_sourcethenPprintast.top_phraseppphrase;ignore(execute_phrasetrueppphrase);(* Flush everything. *)Format.pp_print_flushFormat.std_formatter();Format.pp_print_flushFormat.err_formatter();flushstdout;flushstderr;(* Get the string printed. *)Format.pp_print_flushpp();let string=Buffer.contentsbufferinUTop_history.add_outputUTop.stashable_session_historystring;matchphrasewith|Parsetree.Ptop_def_->(* The string is an output phrase, colorize it. *)Lwt_main.run(render_out_phrasetermstring)|Parsetree.Ptop_dir_->(* The string is an error message. *)Lwt_main.run(print_errortermstring)with exn->(* The only possible errors are directive errors. *)let msg=UTop.get_messageErrors.report_errorexnin(* Skip the dumb location. *)let msg=tryletidx=String.indexmsg'\n'+1inString.submsgidx(String.lengthmsg-idx)withNot_found->msginLwt_main.run(print_error term msg));loopterm|None->loopterm(* +-----------------------------------------------------------------+
| Welcome message |
+-----------------------------------------------------------------+ *)letwelcometerm=(* Create a context to render the welcome message. *)letsize=LTerm.sizeterminletsize={rows=3;cols=size.cols}inletmatrix=LTerm_draw.make_matrixsizeinletctx=LTerm_draw.contextmatrixsizein(* Draw the message in a box. *)letmessage =Printf.sprintf"Welcome to utop version %s (using OCaml version %s)!"UTop.versionSys.ocaml_versioninLTerm_draw.fill_stylectxLTerm_style.({nonewithforeground=Somelcyan});LTerm_draw.draw_hlinectx00size.colsLTerm_draw.Light;LTerm_draw.draw_framectx{row1=0;row2=3;col1=(size.cols-(String.lengthmessage+4))/2;col2=(size.cols+(String.lengthmessage+4))/2;}LTerm_draw.Light;LTerm_draw.draw_styledctx1((size.cols-String.lengthmessage)/2)(eval[B_fgLTerm_style.yellow;Smessage]);(* Render to the screen. *)LTerm.print_boxtermmatrix>>=fun ()->(*Move to after the box. *)LTerm.fprintterm"\n">>=fun()->LTerm.flushterm(* +-----------------------------------------------------------------+
| Classic mode |
+-----------------------------------------------------------------+ *)letread_input_classicpromptbufferlen=letrecloopi=ifi=lenthenreturn (i,false)elseLwt_io.read_char_optLwt_io.stdin >>=function|Somec->Bytes.setbufferic;ifc='\n'thenreturn(i+1,false)elseloop(i+1)|None->return(i,true)inLwt_main.run(Lwt_io.writeLwt_io.stdoutprompt>>=fun()->loop0)(* +-----------------------------------------------------------------+
| Emacs mode |
+-----------------------------------------------------------------+ *)moduleEmacs(M:sigend)=struct(* Copy standard output, which will be used to send commands. *)letcommand_oc=Unix.out_channel_of_descr (Unix.dup Unix.stdout)letsplit_at?(trim=false)chstr=letrecaux accij=ifj=String.length strtheniftrim&&i=jthenaccelse(String.substri(j-i))::accelseifstr.[j]=chthenaux(String.substri(j-i)::acc)(j+1)(j+1)elseauxacci(j+1)inList.rev(aux[]00)(* +---------------------------------------------------------------+
| Sending commands to Emacs |
+---------------------------------------------------------------+ *)(* Mutex used to send commands to Emacs. *)letcommand_mutex=Mutex.create()letsendcommandargument=Mutex.lockcommand_mutex;output_stringcommand_occommand;output_charcommand_oc ':';output_stringcommand_ocargument;output_charcommand_oc'\n';flushcommand_oc;Mutex.unlockcommand_mutex(* Keep the [utop-phrase-terminator] variable of the emacs part in sync. *)let()=S.keep(S.map (send"phrase-terminator")UTop.phrase_terminator)(* +---------------------------------------------------------------+
| Standard outputs redirection |
+---------------------------------------------------------------+ *)(* The output of ocaml (stdout and stderr) is redirected so the
emacs parts of utop can recognize it. *)(* Continuously copy the output of ocaml to Emacs. *)letreccopy_outputwhichic=letline=input_lineicinsendwhichline;copy_outputwhichic(* Create a thread which redirect the given output: *)let redirectwhichfd=letfdr,fdw=Unix.pipe()inUnix.dup2fdwfd;Unix.closefdw;Thread.create(copy_outputwhich)(Unix.in_channel_of_descrfdr)(* Redirects stdout and stderr: *)let _=redirect"stdout"Unix.stdoutlet_=redirect"stderr"Unix.stderr(* +---------------------------------------------------------------+
| Loop | +---------------------------------------------------------------+ *)letread_line ()=letbehavior=Sys.signalSys.sigintSys.Signal_ignoreintryletline=Lwt_main.run(Lwt_io.read_line_optLwt_io.stdin)inSys.set_signalSys.sigintbehavior;linewith exn ->Sys.set_signalSys.sigintbehavior;raiseexnletread_command()=matchread_line()with|None->None|Someline->match trySome (String.indexline':')withNot_found->Nonewith|None->send"stderr" "':' missing!";exit1|Someidx->Some(String.subline0idx,String.subline(idx+1)(String.lengthline-(idx+1)))letread_data()=letbuf=Buffer.create1024inletrecloopfirst=matchread_command()with|None->send"stderr""'end' command missing!";exit1|Some("data",data)->ifnotfirstthenBuffer.add_charbuf'\n';Buffer.add_stringbufdata;loopfalse|Some ("end",_)->Buffer.contentsbuf|Some(command,argument)->Printf.ksprintf(send"stderr")"'data' or 'end' command expected, got %S!"command;exit1inlooptrueletprocess_checked_phrasephrase=(* Rewrite toplevel expressions. *)letphrase=rewritephraseintryEnv.reset_cache_toplevel();ignore(execute_phrasetrueFormat.std_formatterphrase);truewithexn->(* The only possible errors are directive errors. *)letmsg=UTop.get_messageErrors.report_errorexnin(* Skip the dumb location. *)letmsg=tryletidx=String.indexmsg'\n'+1inString.submsgidx(String.lengthmsg-idx)withNot_found->msginList.iter(send"stderr")(split_at~trim:true'\n'msg);falseletprocess_input add_to_history eos_is_error=letinput=read_data()inletinput_zed=Zed_string.unsafe_of_utf8inputinletresult,warnings=parse_and_checkinputeos_is_errorinmatchresult with|UTop.Valuephrase->send"accept""";List.iter(send"stderr")(split_at~trim:true'\n'warnings);ifadd_to_historythenLTerm_history.addUTop.historyinput_zed;ignore(process_checked_phrase phrase)|UTop.Error(locs,msg)->send"accept"(String.concat","(List.map(fun(a,b)->Printf.sprintf"%d,%d"ab)locs));List.iter(send"stderr")(split_at~trim:true'\n'warnings);ifadd_to_historythenLTerm_history.addUTop.history input_zed;List.iter(send"stderr")(split_at~trim:true'\n'msg)letsend_errorlocsmsgwarnings=send"accept" (String.concat","(List.map(fun(a,b)->Printf.sprintf"%d,%d"ab)locs));matchwarningswith|Somewarnings->List.iter(send"stderr")(split_at~trim:true'\n'warnings)|None->();List.iter(send"stderr")(split_at~trim:true'\n'msg)letprocess_input_multi()=letinput=read_data()inletresult,warnings=parse_input_multiinputinlettypecheckphrase=matchUTop.check_phrasephrasewith|None->None|Some(locs,msg,lines)->Some(convert_loc_lineinputlocslines,msg)inmatchresultwith|UTop.Valuephrases->send"accept""";List.iter(send"stderr")(split_at~trim:true'\n'warnings);letrecloop=function|(phrase::more_phrases)->beginmatchtypecheckphrasewith|Some(locs,msg)->send_errorlocsmsgNone|None->letsuccess =process_checked_phrase phraseinifsuccessthenloopmore_phraseselse()end|[]->()inloopphrases|UTop.Error(locs,msg)->send_errorlocsmsg(Somewarnings)letrecloop()=(* Reset completion. *)UTop_complete.reset();(* Increment the command counter. *)UTop_private.set_count(S.valueUTop_private.count+1);(* Call hooks. *)LTerm_dlist.iter_l(funf->f())UTop.new_command_hooks;(* Tell emacs we are ready. *)send"prompt""";loop_commands(LTerm_history.contentsUTop.history)[]andloop_commandshistory_prevhistory_next=matchread_command()with|None->()|Some("input",arg)->letargs=split_at','arginletallow_incomplete=List.mem"allow-incomplete" argsandadd_to_history=List.mem"add-to-history"argsinletcontinue=tryprocess_input add_to_history(notallow_incomplete);falsewithUTop.Need_more ->send"continue""";trueinifcontinuethenloop_commandshistory_prevhistory_nextelseloop()|Some("input-multi",_)->letcontinue=tryprocess_input_multi();falsewithUTop.Need_more ->send"continue""";trueinifcontinuethenloop_commands history_prevhistory_nextelseloop()|Some ("complete-company",_)->letinput=read_data ()inlet_,words=UTop_complete.complete~phrase_terminator:(UTop.get_phrase_terminator ())~inputinsend"completion-start""";List.iter(fun(w,_)->send"completion"w)words;send"completion-stop""";loop_commands history_prevhistory_next|Some("complete",_)->letinput=read_data()inletstart,words=UTop_complete.complete~phrase_terminator:(UTop.get_phrase_terminator())~inputinletwords =List.mapfstwordsinletprefix=LTerm_read_line.common_prefixwordsinletindex=String.length input-startinletsuffix =ifindex>0&&index<=String.lengthprefixthenString.subprefixindex(String.lengthprefix-index)else""inifsuffix=""thenbeginsend"completion-start""";List.iter(send"completion")words;send"completion-stop""";endelsesend"completion-word"suffix;loop_commands history_prev history_next|Some("history-prev",_)->beginletinput=read_data()inmatchhistory_prevwith|[]->send"history-bound""";loop_commands history_prev history_next|entry::history_prev->List.iter(send "history-data")(split_at'\n'(Zed_string.to_utf8entry));send"history-end""";loop_commands history_prev (input::history_next)end|Some("history-next",_)->beginletinput=read_data()inmatchhistory_nextwith|[]->send"history-bound""";loop_commands history_prev history_next|entry::history_next->List.iter(send"history-data")(split_at'\n'entry);send"history-end""";loop_commands((Zed_string.unsafe_of_utf8input)::history_prev)history_nextend|Some("exit",code)->exit(int_of_stringcode)|Some ("save-history",code)->Lwt_main.run(save_history());loop_commandshistory_prevhistory_next|Some("require",package)->begintryTopfind.load_deeply [package]withFl_package_base.No_such_package(pkg,reason)->send"no-such-package"pkgend;loop_commandshistory_prevhistory_next|Some(command,_)->Printf.ksprintf(send"stderr")"unrecognized command %S!"command;exit1end(* +-----------------------------------------------------------------+
| Extra macros |
+-----------------------------------------------------------------+ *)lettypeofsid=letid=longident_parsesidinletenv=!Toploop.toplevel_envin#ifOCAML_VERSION>=(4,10,0)letlookup_value=Env.find_value_by_nameandlookup_label=Env.find_label_by_nameandlookup_modtype=Env.find_modtype_by_nameandlookup_module idenv=letpath,decl=Env.find_module_by_nameidenvin(path,decl.md_type)#elseletlookup_value=Env.lookup_valueandlookup_label=Env.lookup_labelandlookup_modtype=Env.lookup_modtypeandlookup_moduleidenv=letpath=Env.lookup_moduleidenv~load:truein(path,(Env.find_modulepathenv).md_type)#endifinlet from_type_desc=function|Types.Tconstr(path,_,_)->lettyp_decl=Env.find_typepathenvinpath,typ_decl|_->assertfalseinletout_sig_item =trylet(path,ty_decl)=lookup_typeidenvin#ifOCAML_VERSION>=(4,08,0)letid=Ident.create_local(Path.namepath)in#elseletid=Ident.create(Path.namepath)in#endifSome(Printtyp.tree_of_type_declarationidty_decl Types.Trec_not)with Not_found->trylet(path,val_descr)=lookup_valueidenvin#ifOCAML_VERSION >=(4,08,0)letid=Ident.create_local(Path.namepath)in#elseletid=Ident.create (Path.namepath)in#endifSome(Printtyp.tree_of_value_descriptionidval_descr)withNot_found->tryletlbl_desc=lookup_labelidenvinlet(path,ty_decl)=from_type_desc(get_desclbl_desc.Types.lbl_res)in#ifOCAML_VERSION>=(4,08,0)let id=Ident.create_local(Path.namepath)in#elseletid=Ident.create(Path.namepath)in#endifSome(Printtyp.tree_of_type_declarationidty_declTypes.Trec_not)withNot_found->tryletpath,mod_typ=lookup_moduleidenvin#ifOCAML_VERSION>=(4,08,0)letid=Ident.create_local(Path.namepath)in#elseletid=Ident.create(Path.namepath)in#endifSome(Printtyp.tree_of_moduleidmod_typTypes.Trec_not)withNot_found->trylet(path,mty_decl)=lookup_modtypeidenvin#ifOCAML_VERSION>=(4,08,0)letid=Ident.create_local(Path.namepath)in#elseletid=Ident.create (Path.namepath)in#endifSome(Printtyp.tree_of_modtype_declaration idmty_decl)withNot_found->try#ifOCAML_VERSION>=(4,10,0)letcstr_desc=Env.find_constructor_by_nameidenvin#elseletcstr_desc=Env.lookup_constructoridenvin#endifmatchcstr_desc.Types.cstr_tagwith|_->let(path,ty_decl)=from_type_desc(get_desccstr_desc.Types.cstr_res)in#ifOCAML_VERSION>=(4,08,0)letid=Ident.create_local(Path.namepath)in#elseletid=Ident.create(Path.namepath)in#endifSome(Printtyp.tree_of_type_declarationidty_declTypes.Trec_not)withNot_found->Noneinmatchout_sig_itemwith|None->Lwt_main.run(Lazy.forceLTerm.stdout>>= funterm->print_errorterm"Unknowntype\n")|Someosig->letbuf=Buffer.create128inletpp=Format.formatter_of_bufferbufin!Toploop.print_out_signaturepp[osig];Format.pp_print_newlinepp();letstr =Buffer.contentsbufinLwt_main.run(Lazy.forceLTerm.stdout>>=funterm->render_out_phrasetermstr)letdefault_info={Toploop.section ="UTop";doc="";(* TODO: have some kind of documentation *)}let()=Toploop.add_directive"typeof"(Toploop.Directive_string typeof)default_info(* +-----------------------------------------------------------------+
| Entry point |
+-----------------------------------------------------------------+ *)letemacs_mode=reffalseletpreload=ref[]letprepare()=Toploop.set_paths();tryletok=List.for_all(function|`Packagesl->UTop.requirel;true|`Objectfn->#ifOCAML_VERSION >=(4,13,0)Toploop.load_fileFormat.err_formatterfn)#elseTopdirs.load_fileFormat.err_formatterfn)#endif(List.rev!preload)inifokthen!Toploop.toplevel_startup_hook();okwithexn->tryErrors.report_error Format.err_formatter exn;falsewithexn->Format.eprintf"Uncaught exception: %s\n"(Printexc.to_stringexn);false#ifOCAML_VERSION>=(4,09,0)externalcaml_sys_modify_argv:stringarray->unit="caml_sys_modify_argv"letoverride_argv()=letlen=Array.lengthSys.argv-!Arg.currentinletcopy=Array.init len(funi->Sys.argv.(i+!Arg.current))incaml_sys_modify_argvcopy;Arg.current:=0#elseletoverride_argv()=letlen=Array.lengthSys.argv-!Arg.currentinArray.blitSys.argv!Arg.currentSys.argv0len;Obj.truncate(Obj.reprSys.argv)len;Arg.current:=0#endifletrun_scriptname=(* To prevent message from camlp4 *)Sys.interactive:=false;ifnot(prepare())thenexit2;override_argv();Toploop.initialize_toplevel_env();Location.input_name:=UTop.input_name;iftoploop_use_silentlyFormat.err_formattername thenexit0elseexit2letfile_argumentname=ifFilename.check_suffixname".cmo"||Filename.check_suffix name".cma"thenpreload:=`Objectname::!preloadelserun_scriptnameletprint_version()=Printf.printf"The universal toplevel for OCaml, version %s, compiled for OCaml version %s\n"UTop.versionSys.ocaml_version;exit0letprint_version_num ()=Printf.printf"%s\n"UTop.version;exit0(* Config from command line *)letautoload=reftrueletargs=Arg.align[#ifOCAML_VERSION>=(4,08,0)"-absname",Arg.SetClflags.absname," Show absolute filenames in error message";#else"-absname",Arg.SetLocation.absname," Show absolute filenames in error message";#endif"-I",Arg.String(fundir->Clflags.include_dirs:=dir::!Clflags.include_dirs),"<dir> Add <dir> to the list of include directories";"-init",Arg.String(funs->Clflags.init_file:=Somes),"<file> Load <file> instead of default init file";"-labels",Arg.ClearClflags.classic," Use commuting label mode";"-no-app-funct",Arg.ClearClflags.applicative_functors," Deactivate applicative functors";"-noassert",Arg.SetClflags.noassert," Do not compile assertion checks";"-nolabels",Arg.SetClflags.classic," Ignore non-optional labels in types";"-nostdlib",Arg.SetClflags.no_std_include," Do not add default directory to the list of include directories";"-ppx",Arg.String(funppx->Clflags.all_ppx:=ppx::!Clflags.all_ppx),"<command> Pipe abstract syntax trees through preprocessor <command>";"-principal",Arg.SetClflags.principal," Check principality of type inference";#ifOCAML_VERSION<(5,0,0)"-safe-string",Arg.ClearClflags.unsafe_string," Make strings immutable";#endif"-short-paths",Arg.ClearClflags.real_paths," Shorten paths in types (the default)";"-no-short-paths",Arg.SetClflags.real_paths," Do not shorten paths in types";"-rectypes",Arg.SetClflags.recursive_types," Allow arbitrary recursive types";"-stdin",Arg.Unit(fun()->run_script"")," Read script from standard input";"-strict-sequence",Arg.SetClflags.strict_sequence," Left-hand part of a sequence must have type unit";#ifOCAML_VERSION>=(4,08,0)"-unsafe",Arg.SetClflags.unsafe," Do not compile bounds checking on array and string access";#else"-unsafe",Arg.SetClflags.fast," Do not compile bounds checking on array and string access";#endif"-version",Arg.Unitprint_version," Print version and exit";"-vnum",Arg.Unitprint_version_num," Print version number and exit";"-w",Arg.String(funopt->ignore(Warnings.parse_optionsfalseopt)),Printf.sprintf"<list> Enable or disable warnings according to <list>:\n\
\ +<spec> enable warnings in <spec>\n\
\ -<spec> disable warnings in <spec>\n\
\ @<spec> enable warnings in <spec> and treat them as errors\n\
\ <spec> can be:\n\
\ <num> a single warning number\n\
\ <num1>..<num2> a range of consecutive warning numbers\n\
\ <letter> a predefined set\n\
\ default setting is %S"Warnings.defaults_w;"-warn-error",Arg.String(funopt->ignore(Warnings.parse_options trueopt)),Printf.sprintf"<list> Enable or disable error status for warnings according to <list>\n\
\ See option -w forthe syntax of <list>.\n\
\ Default setting is %S"Warnings.defaults_warn_error;"-warn-help",Arg.UnitWarnings.help_warnings," Show description of warning numbers";"-emacs",Arg.Setemacs_mode," Run in emacs mode";"-hide-reserved",Arg.Unit(fun()->UTop.set_hide_reservedtrue)," Hide identifiers starting with a '_' (the default)";"-show-reserved",Arg.Unit(fun()->UTop.set_hide_reserved false)," Show identifiers starting with a '_'";"-no-implicit-bindings",Arg.Unit(fun()->UTop.set_create_implicitsfalse)," Don't add implicit bindings for expressions (the default)";"-implicit-bindings",Arg.Unit(fun()->UTop.set_create_implicitstrue)," Add implicit bindings: <expr>;; -> let _0 = <expr>;;";"-no-autoload",Arg.Clearautoload," Disable autoloadingof files in$OCAML_TOPLEVEL_PATH/autoload";"-require",Arg.String(funs->preload:=`Packages(UTop.split_wordss)::!preload),"<package> Load this package";"-dparsetree",Arg.SetClflags.dump_parsetree," Dump OCaml AST after rewriting";"-dsource",Arg.SetClflags.dump_source," Dump OCaml source after rewriting";]let()=Clflags.real_paths:=falseletapp_name=Filename.basenameSys.executable_nameletusage=Printf.sprintf"Usage: %s <options> <object-files> [script-file [arguments]]\noptions are:"app_nameletload_init_filesdir=letfiles=Sys.readdirdirinArray.sortString.comparefiles;Array.iter(funfn->ifFilename.check_suffixfn".ml"thenignore(toploop_use_silentlyFormat.err_formatter(Filename.concatdirfn):bool))files;;letcommon_init~initial_env=(* Initializes toplevel environment. *)(matchinitial_envwith|None->Toploop.initialize_toplevel_env()|Someenv->Toploop.toplevel_env:=env);(* Set the global input name. *)Location.input_name:=UTop.input_name;(* Make sure SIGINT is catched while executing OCaml code. *)Sys.catch_breaktrue;(* Load system init files. *)(matchtrySome(Sys.getenv"OCAML_TOPLEVEL_PATH")withNot_found->Nonewith|Somedir->Topdirs.dir_directorydir;letautoload_dir=Filename.concatdir"autoload"inif!autoload&&!UTop_private.autoload&&Sys.file_existsautoload_dirthenload_init_files autoload_dir|None->());(* Load user's init file. *)letinit_fn=match!Clflags.init_filewith|Somefn->ifSys.file_existsfnthenSomefnelse(Printf.eprintf"Init file not found: \"%s\".\n"fn;None)|None->ifSys.file_exists".ocamlinit"&&Sys.getcwd()<>LTerm_resources.homethenSome".ocamlinit"elseletxdg_fn=LTerm_resources.xdgbd_file~loc:LTerm_resources.Config"utop/init.ml"inifSys.file_existsxdg_fnthenSomexdg_fnelseletfn=Filename.concatLTerm_resources.home".ocamlinit"inifSys.file_existsfnthenSomefnelseNonein(matchinit_fnwith|None->()|Somefn->ignore(toploop_use_silentlyFormat.err_formatter fn:bool));(* Load history after the initialization fileso the user can change
the history file name. *)Lwt_main.run(init_history ());(* Install signal handlers. *)letbehavior=Sys.Signal_handle(funsigno->raise(Termsigno))inletcatchsigno=trySys.set_signal signo behaviorwith_->(* All signals may not be supported on some OS. *)()in(* We lost the terminal. *)catchSys.sighup;(* Termination request. *)catchSys.sigtermletload_inputrc()=Lwt.catchLTerm_inputrc.load(function|Unix.Unix_error(error,func,arg)->Lwt_log.error_f"cannot load key bindings from %S: %s: %s"LTerm_inputrc.defaultfunc(Unix.error_messageerror)|LTerm_inputrc.Parse_error(fname,line,msg)->Lwt_log.error_f"error in key bindings file %S, line %d: %s"fnamelinemsg|exn->Lwt.failexn)letprotocol_version=1letmain_aux~initial_env=Arg.parseargsfile_argumentusage;ifnot(prepare())thenexit2;if!emacs_modethenbeginPrintf.printf"protocol-version:%d\n%!"protocol_version;UTop_private.set_uiUTop_private.Emacs;letmoduleEmacs=Emacs(structend)inPrintf.printf"Welcome to utop version %s (using OCaml version %s)!\n\n%!"UTop.versionSys.ocaml_version;common_init~initial_env;Emacs.loop()endelsebeginUTop_private.set_uiUTop_private.Console;letterm=Lwt_main.run(Lazy.forceLTerm.stdout)inifLTerm.incoming_is_a_ttyterm&<erm.outgoing_is_a_ttytermthenbegin(* Set the initial size. *)UTop_private.set_size(S.const (LTerm.sizeterm));(* Load user data. *)Lwt_main.run(Lwt.join[UTop_styles.load();load_inputrc()]);(* Display a welcome message. *)Lwt_main.run(welcometerm);(* Common initialization. *)common_init~initial_env;(* Print help message. *)print_string"\nType #utop_help for help about using utop.\n\n";flushstdout;(* Main loop. *)trylooptermwithLTerm_read_line.Interrupt->()endelsebegin(* Use the standard toplevel. Just make sure that Lwt threads can
run while reading phrases. *)Toploop.read_interactive_input:=read_input_classic;Toploop.loopFormat.std_formatterendend;(* Don't let the standard toplevel run... *)exit0letmain_internal~initial_env=letexit_status =ref2intrymain_aux ~initial_envwithexn->(match exnwith|Unix.Unix_error(error,func,"")->Printf.eprintf"%s: %s: %s\n"app_namefunc(Unix.error_message error)|Unix.Unix_error(error,func,arg)->Printf.eprintf"%s: %s(%S): %s\n"app_namefuncarg(Unix.error_messageerror)#ifOCAML_VERSION>=(4,12,0)|Compenv.Exit_with_status e->exit_status:=e#endif|exn->Printf.eprintf"Fatal error: exception %s\n"(Printexc.to_stringexn));Printexc.print_backtracestderr;flushstderr;exit!exit_statusletmain()=main_internal~initial_env:Nonetypevalue=V:string*_->valueexceptionFoundofEnv.t#ifOCAML_VERSION>=(4,03,0)letget_required_labelnameargs=matchList.find(fun (lab,_)->lab =Asttypes.Labelledname)argswith|_,x->x|exception Not_found->None#elseletget_required_labelnameargs=matchList.find(fun(lab,_,k)->lab="loc"&&k=Typedtree.Required)argswith|_,x,_->x|_->None|exceptionNot_found->None#endifletwalkdir~init~f=letrecloopdiracc=let acc=fdiraccinArrayLabels.fold_left(Sys.readdirdir)~init:acc~f:(funaccfn->letfn=Filename.concatdirfninmatchUnix.lstatfnwith|{st_kind=S_DIR;_}->loopfnacc|_->acc)inmatchUnix.lstatdirwith|exceptionUnix.Unix_error(ENOENT,_,_)->init|_->loopdirinitletinteract?(search_path=[])?(build_dir="_build")~unit~loc:(fname,lnum,cnum,_)~values=letsearch_path=walkbuild_dir~init:search_path~f:(fundiracc->dir::acc)inletcmt_fname=tryMisc.find_in_path_uncapsearch_path(unit^".cmt")withNot_found->Printf.ksprintffailwith"%s.cmt not found in search path!"unitinletcmt_infos=Cmt_format.read_cmtcmt_fnameinletexprnext(e:Typedtree.expression)=matche.exp_descwith|Texp_apply(_,args)->begintrymatchget_required_label"loc"args,get_required_label"values"argswith|Somel,Somev->letpos=l.exp_loc.loc_startinifpos.pos_fname=fname&&pos.pos_lnum=lnum&&pos.pos_cnum-pos.pos_bol=cnumthenraise(Foundv.exp_env)|_->nextewithNot_found->nexteend|_->nextein#ifOCAML_VERSION>=(4,09,0)letnextiteratore=Tast_iterator.default_iterator.expriteratoreinletexpriterator=expr(nextiterator)inletiter={Tast_iterator.default_iteratorwithexpr}inletsearch=iter.structureiterin#elseletmoduleSearch=TypedtreeIter.MakeIterator(structincludeTypedtreeIter.DefaultIteratorArgumentletenter_expression=exprignoreend)inletsearch=Search.iter_structurein#endiftrybeginmatchcmt_infos.cmt_annotswith|Implementationst->searchst|_->()end;failwith"Couldn't find location in cmt file"withFoundenv->tryList.iterTopdirs.dir_directory(search_path@cmt_infos.cmt_loadpath);letenv=Envaux.env_of_only_summaryenvinList.iter(fun(V(name,v))->Toploop.setvaluename(Obj.reprv))values;main_internal~initial_env:(Someenv)withexn->Location.report_exceptionFormat.err_formatterexn;exit2let()=Location.register_error_of_exn(function|Envaux.Errorerr->Some(Location.error_of_printer_fileEnvaux.report_errorerr)|_->None)