123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134(* Pa_qualified
-----------------------------------------------------------------------------
Copyright (C) 2015, Max Mouratov
License:
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2.1, as published by the Free Software Foundation.
This library 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 GNU Library General Public License version 2.1 for more details
(enclosed in LICENSE.txt).
Description:
Pa_qualified adds support for fully qualified module references to OCaml.
If a module reference (in any possible context) starts with "Q.", then
the rest of the reference denotes a context-independent globally unique
path (as if the reference was located at the very beginning of the file).
Qualified references can never be shadowed by other definitions
(warranty void if "Q" is defined explicitly somewhere).
See README.rst for more information.
*)openCamlp4moduleStringSet=Set.Make(String)moduleId:Sig.Id=structletname="pa_qualified"letversion="0.5"end(* The predefined prefix that denotes a globally qualified name *)letqualified_prefix="Q"moduleMake(AstFilters:Camlp4.Sig.AstFilters)=structopenAstFilters(* Generating a globally unique name for the helper module *)letgen_helper_nameloc=letfname=Filename.chop_extension(Ast.Loc.file_nameloc)inPrintf.sprintf"_Q_%s_"fname(* Replacing all Qs with the unique name of the helper module,
as well as collecting all the different Xs in Q.X.* references *)letmake_reference_collectorhelper_name=object(self)inheritAst.mapassuper(* A set of globally referenced modules *)valmutablecollected=StringSet.emptymethodget_collected=StringSet.elementscollectedmethodidentid=matchidwith(* Getting the X out of Q.X.*,
replacing Q with a reference to the helper module *)|IdAcc_->(matchAst.list_of_identid[]with|IdUid(head_loc,head)::((IdUid(_,x)::_)asrest)whenhead=qualified_prefix->collected<-StringSet.addxcollected;Ast.idAcc_of_list(IdUid(head_loc,helper_name)::rest)|_->id)|_->super#identidend(* Injecting the helper module into the implementation *)let()=AstFilters.register_str_item_filter(funsi->let_loc=Ast.loc_of_str_itemsiinlethelper_name=gen_helper_name_locinletcollector=make_reference_collectorhelper_nameinletsi=collector#str_itemsiinletqualified=collector#get_collectedinmatchqualifiedwith|[]->si|ids-><:str_item<module$uid:(helper_name)$=struct$list:(ids|>List.map(fun id-><:str_item<module$uid:(id)$=$uid:(id)$>>))$end;$(si)$;>>)(* Injecting the helper module into the interface *)let()=AstFilters.register_sig_item_filter(funsi->let_loc=Ast.loc_of_sig_itemsiinlethelper_name=gen_helper_name_locinletcollector=make_reference_collectorhelper_nameinletsi=collector#sig_itemsiinletqualified=collector#get_collectedinmatchqualifiedwith|[]->si|ids-><:sig_item<module$uid:(helper_name)$:sig$list:(ids|>List.map(fun id-><:sig_item<module$uid:(id)$:moduletypeof$uid:(id)$>>))$end;$(si)$;>>)endmoduleM=Camlp4.Register.AstFilter(Id)(Make)