[camlp4] Add the MetaGenerator that will replace the dirty script

git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@7680 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
master
Nicolas Pouillard 2006-10-04 16:19:01 +00:00
parent ebd5102f96
commit 736355d144
1 changed files with 194 additions and 0 deletions

View File

@ -0,0 +1,194 @@
open Camlp4.PreCast;
module MapTy = Map.Make String;
type t =
{ name : Ast.ident;
type_decls : MapTy.t Ast.ctyp;
acc : Ast.expr;
app : Ast.expr;
id : Ast.expr;
tup : Ast.expr;
com : Ast.expr;
str : Ast.expr;
int : Ast.expr;
flo : Ast.expr;
chr : Ast.expr;
ant : Ast.ident;
};
value _loc = Loc.ghost;
value x i = <:ident< $lid:"x"^string_of_int i$ >>;
value meta_ s = <:ident< $lid:"meta_"^s$ >>;
value mf_ s = "mf_" ^ s;
value rec string_of_ident =
fun
[ <:ident< $lid:s$ >> -> s
| <:ident< $uid:s$ >> -> s
| <:ident< $i1$.$i2$ >> -> "acc_" ^ (string_of_ident i1) ^ "_" ^ (string_of_ident i2)
| <:ident< $i1$ $i2$ >> -> "app_" ^ (string_of_ident i1) ^ "_" ^ (string_of_ident i2)
| <:ident< $anti:_$ >> -> assert False ];
value fold_args ty f init =
let (_, res) =
List.fold_left (fun (i, acc) ty -> (succ i, f ty i acc)
) (0, init) ty
in res;
value fold_data_ctors ty f init =
let rec loop acc t =
match t with
[ <:ctyp< $uid:cons$ of $ty$ >> -> f cons (Ast.list_of_ctyp ty []) acc
| <:ctyp< $uid:cons$ >> -> f cons [] acc
| <:ctyp< $t1$ | $t2$ >> -> loop (loop acc t1) t2
| <:ctyp<>> -> acc
| _ -> assert False ] in
loop init ty;
value fold_type_decls m f init =
MapTy.fold f m.type_decls init;
value patt_of_data_ctor_decl cons tyargs =
fold_args tyargs (fun _ i acc ->
<:patt< $acc$ $id:x i$ >>
) <:patt< $id:cons$ >>;
value expr_of_data_ctor_decl cons tyargs =
fold_args tyargs (fun _ i acc ->
<:expr< $acc$ $id:x i$ >>
) <:expr< $id:cons$ >>;
value is_antiquot_data_ctor s =
let ls = String.length s in
ls > 3 && String.sub s (ls - 3) 3 = "Ant";
value rec meta_ident m =
fun
[ <:ident< $i1$.$i2$ >> -> <:expr< Ast.IdAcc _loc $meta_ident m i1$ $meta_ident m i2$ >>
| <:ident< $i1$ $i2$ >> -> <:expr< Ast.IdApp _loc $meta_ident m i1$ $meta_ident m i2$ >>
| <:ident< $anti:s$ >> -> <:expr< $anti:s$ >>
| <:ident< $lid:s$ >> -> <:expr< Ast.IdLid _loc $str:s$ >>
| <:ident< $uid:s$ >> -> <:expr< Ast.IdUid _loc $str:s$ >> ];
value m_app m x y = <:expr< $m.app$ _loc $x$ $y$ >>;
value m_id m i = <:expr< $m.id$ _loc $i$ >>;
value m_uid m s = m_id m (meta_ident m <:ident< $uid:s$ >>);
value failure = <:expr< raise (Failure "MetaGenerator: cannot handle that kind of types") >>;
value mk_meta m =
let m_name_uid x = <:ident< $m.name$.$uid:x$ >> in
fold_type_decls m (fun tyname tydcl acc ->
let funct =
match tydcl with
[ Ast.TyDcl _ _ tyvars <:ctyp< [$ty$] >> _ ->
let match_case =
fold_data_ctors ty (fun cons tyargs acc ->
let m_name_cons = m_name_uid cons in
let init = m_id m (meta_ident m m_name_cons) in
let p = patt_of_data_ctor_decl m_name_cons tyargs in
let e =
if cons = "BAnt" || cons = "OAnt" then
<:expr< $id:m.ant$ _loc x0 >>
else if is_antiquot_data_ctor cons then
expr_of_data_ctor_decl m.ant tyargs
else
fold_args tyargs (fun ty i acc ->
let rec fcall_of_ctyp ty =
match ty with
[ <:ctyp< $id:id$ >> ->
<:expr< $id:meta_ (string_of_ident id)$ >>
| <:ctyp< ($t1$ * $t2$) >> ->
<:expr< (fun _loc (x1, x2) ->
$m.tup$ _loc
($m.com$ _loc
($fcall_of_ctyp t1$ _loc x1)
($fcall_of_ctyp t2$ _loc x2))) >>
| <:ctyp< $t1$ $t2$ >> ->
<:expr< $fcall_of_ctyp t1$ $fcall_of_ctyp t2$ >>
| <:ctyp< '$s$ >> -> <:expr< $lid:mf_ s$ >>
| _ -> failure ]
in m_app m acc <:expr< $fcall_of_ctyp ty$ _loc $id:x i$ >>
) init
in <:match_case< $p$ -> $e$ | $acc$ >>
) <:match_case<>> in
List.fold_right (fun tyvar acc ->
match tyvar with
[ <:ctyp< +'$s$ >> | <:ctyp< -'$s$ >> | <:ctyp< '$s$ >> ->
<:expr< fun $lid:mf_ s$ -> $acc$ >>
| _ -> assert False ])
tyvars <:expr< fun _loc -> fun [ $match_case$ ] >>
| Ast.TyDcl _ _ _ _ _ -> <:expr< fun _ -> $failure$ >>
| _ -> assert False ]
in <:binding< $acc$ and $lid:"meta_"^tyname$ = $funct$ >>) <:binding<>>;
value find_type_decls = object
inherit Ast.fold as super;
value accu = MapTy.empty;
method get = accu;
method ctyp =
fun
[ Ast.TyDcl _ name _ _ _ as t -> {< accu = MapTy.add name t accu >}
| t -> super#ctyp t ];
end;
value filter st =
let type_decls = lazy (find_type_decls#str_item st)#get in
object
inherit Ast.map as super;
method module_expr me =
let mk_meta_module m =
let bi = mk_meta m in
<:module_expr<
struct
value meta_string _loc s = $m.str$ _loc s;
value meta_int _loc s = $m.int$ _loc s;
value meta_float _loc s = $m.flo$ _loc s;
value meta_char _loc s = $m.chr$ _loc s;
value meta_bool _loc =
fun
[ False -> $m_uid m "False"$
| True -> $m_uid m "True"$ ];
value rec meta_list mf_a _loc =
fun
[ [] -> $m_uid m "[]"$
| [x :: xs] -> $m_app m (m_app m (m_uid m "::") <:expr< mf_a _loc x >>) <:expr< meta_list mf_a _loc xs >>$ ];
value rec $bi$;
end >> in
match super#module_expr me with
[ <:module_expr< Camlp4Filters.MetaGeneratorExpr $id:i$ >> ->
mk_meta_module
{ name = i;
type_decls = Lazy.force type_decls;
app = <:expr< Ast.ExApp >>;
acc = <:expr< Ast.ExAcc >>;
id = <:expr< Ast.ExId >>;
tup = <:expr< Ast.ExTup >>;
com = <:expr< Ast.ExCom >>;
str = <:expr< Ast.ExStr >>;
int = <:expr< Ast.ExInt >>;
flo = <:expr< Ast.ExFlo >>;
chr = <:expr< Ast.ExChr >>;
ant = <:ident< Ast.ExAnt >>
}
| <:module_expr< Camlp4Filters.MetaGeneratorPatt $id:i$ >> ->
mk_meta_module
{ name = i;
type_decls = Lazy.force type_decls;
app = <:expr< Ast.PaApp >>;
acc = <:expr< Ast.PaAcc >>;
id = <:expr< Ast.PaId >>;
tup = <:expr< Ast.PaTup >>;
com = <:expr< Ast.PaCom >>;
str = <:expr< Ast.PaStr >>;
int = <:expr< Ast.PaInt >>;
flo = <:expr< Ast.PaFlo >>;
chr = <:expr< Ast.PaChr >>;
ant = <:ident< Ast.PaAnt >>
}
| me -> me ];
end#str_item st;
AstFilters.register_str_item_filter filter;