123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275(*----------------------------------------------------------
TYPE/BINDING CHECK
------------------------------------------------------------
Type "sémantique" des idents et des exps
n.b. pour l'instant, on n'a que des types de base,
mais ga pourrait changer ...
Pour les profils, on gère le polymorphisme
avec des pseudos-types "any"
Pour les types any, on peut compléter par une
condition qui restreint le match typiquement
- aux types data (autres que trace)
- aux types numériques seulement
----------------------------------------------------------*)openLutErrorsopenFormatopenSyntaxeletdbg=Verbose.get_flag"CkType"typebasic=Syntaxe.predef_type(** le type "weight" est purement interne *)typet=TEFF_weight|TEFF_except|TEFF_trace|TEFF_dataofbasic|TEFF_listofbasic|TEFF_tupleofbasiclist|TEFF_anyofstring*any_cond|TEFF_refofbasicandany_cond=(t->toption)letlift_ref=functionTEFF_refa->TEFF_dataa|_->(raise(Failure"not a ref"))letis_data=functionTEFF_data_->true|_->falseletget_data_tupletl=(letundata=functionTEFF_datad->d|_->raise(Failure"not a data")inTEFF_tuple(List.mapundatatl))lettuple_to_data_listt=(letredata=functiond->TEFF_datadinmatchtwithTEFF_tuplebl->(List.mapredatabl)|_->raise(Failure"not a tuple"))letis_ref=functionTEFF_ref_->true|_->falseletbasic_to_string=(functionBool->"bool"|Int->"int"|Real->"real")(* pretty-print des types *)letrecto_string=(function|TEFF_datad->(basic_to_stringd)|TEFF_listd->(basic_to_stringd)^" list"|TEFF_tuplel->String.concat"*"(List.mapbasic_to_stringl)|TEFF_refx->(basic_to_stringx)^" ref"|TEFF_trace->"trace"|TEFF_weight->"weight"|TEFF_except->"exception"|TEFF_any(s,_)->s)andprof_to_string=(function(tl,t)->(sprintf"%s->%s"(list_to_stringtl)(list_to_stringt)))andlist_to_string=(function[]->""|t::[]->to_stringt|t::l->sprintf"%s*%s"(to_stringt)(list_to_stringl))letref_of=functionTEFF_datax->TEFF_refx|z->(raise(Internal_error("CkTypeEff:ref_of","unexpected ref flag on type "^(to_stringz))))(* any data :
accepte tout type data ou data ref,
lifte les ref
*)letany_data_cond=(functionTEFF_datax->Some(TEFF_datax)|TEFF_refx->Some(TEFF_datax)|_->None)letany_num_cond=(functionTEFF_dataInt->Some(TEFF_dataInt)|TEFF_dataReal->Some(TEFF_dataReal)|TEFF_refInt->Some(TEFF_dataInt)|TEFF_refReal->Some(TEFF_dataReal)|_->None)(* type "fonctionnel", pour les macros et les opérateurs *)typeprofile=tlist*tlist(* acceptable profile for external func *)letis_data_profile(i,o)=(List.fold_left(funax->a&&(is_datax))true(i@o))letres_of_prof:profile->tlist=sndletparams_of_prof:profile->tlist=fstletsplit_prof=funx->xletget_proftinltout=(tinl,tout)(* TYPE USUELS *)letboolean=TEFF_dataBoolletbooleans=TEFF_listBoolletboolref=TEFF_refBoolletintref=TEFF_refIntletinteger=TEFF_dataIntletreal=TEFF_dataReallettrace=TEFF_traceletweight=TEFF_weightletexcept=TEFF_except(* QQ TYPES ANY ... *)letany_data1=TEFF_any("'a",any_data_cond)let_any_data2=TEFF_any("'b",any_data_cond)letany_num1=TEFF_any("'n",any_num_cond)(* PROFILS USUELS *)(* simples ... *)letprof_t_t=([trace],[trace])letprof_tt_t=([trace;trace],[trace])letprof_tw_t=([trace;weight],[trace])letprof_it_t=([integer;trace],[trace])letprof_ti_t=([trace;integer],[trace])letprof_bt_t=([boolean;trace],[trace])letprof_iit_t=([integer;integer;trace],[trace])letprof_b_b=([boolean],[boolean])letprof_bb_b=([boolean;boolean],[boolean])letprof_bl_b=([booleans],[boolean])letprof_ii_i=([integer;integer],[integer])letprof_iii_i=([integer;integer;integer],[integer])letprof_et_t=([except;trace],[trace])letprof_ett_t=([except;trace;trace],[trace])(* polymorphes data ... *)letprof_bxx_x=([boolean;any_data1;any_data1],[any_data1])letprof_xx_b=([any_data1;any_data1],[boolean])(* surchargés numériques ... *)letprof_nn_b=([any_num1;any_num1],[boolean])letprof_nn_n=([any_num1;any_num1],[any_num1])letprof_n_n=([any_num1],[any_num1])letrecof_texp=(functionTEXP_predefBool->boolean|TEXP_predefInt->integer|TEXP_predefReal->real|TEXP_trace->trace|TEXP_refx->ref_of(of_texp(TEXP_predefx)))(* compatibilité des types :
bool -> trace
int -> weight
int ref -> weight
x ref -> x
*)letlifts_tot1t2=(letres=(t1=t2)||((t1=boolref)&&(t2=boolean))||((t1=boolean)&&(t2=trace))||((t1=boolref)&&(t2=trace))||((t1=integer)&&(t2=weight))||((t1=intref)&&(t2=weight))||(match(t1,t2)with(TEFF_refx,TEFF_datay)->(x=y)|_->false)inres)(* compatibilité d'un profil avec une liste de types de params
Renvoie le type eff du résultat ou lève une exception :
Failure OU Invalid_argument (on fait dans le détail ?)
*)letrecmatch_proftelprof=((* table locale pour les types any *)letanytab=Hashtbl.create2inmatchprofwith|([TEFF_listBool],[TEFF_dataBool])->(* a special case for xor/nor/# *)letdoittc=trymatch_in_typeanytabtc(TEFF_refBool)with_->match_in_typeanytabtcbooleaninlet_tins=List.mapdoittelinlet_tout=List.map(match_out_typeanytab)[TEFF_dataBool]in_tout|(txl,tres)->letdoittctx=match_in_typeanytabtctxinlet_tins=List.map2doitteltxlinlet_tout=List.map(match_out_typeanytab)tresin(* ICI : on a le profil effectif,
est-ce que ca peut etre utile ??? *)Verbose.exe~flag:dbg(fun_->Printf.fprintfstderr"CkTypeEff.match [%s] with (%s) gives %s\n"(list_to_stringtel)(prof_to_stringprof)(list_to_string_tout));_tout)(*
Vérifie la compatibilité :
- d'un type obtenu (tobtd)
- d'un type attendu (texptd)
- dans un table d'assoc. des any (anytab)
*)andmatch_in_typeanytabtobtdtexptd=match(tobtd,texptd)with|(_,TEFF_any(k,cond))->(try(lettprev=Util.hfindanytabkinmatch_in_typeanytabtobtdtprev)withNot_found->(match(condtobtd)with|Somet->(Hashtbl.addanytabkt;t)|None->failwith"uncompatible types"))|_->(if(lifts_totobtdtexptd)thentexptdelsefailwith"uncompatible types")andmatch_out_typeanytabtres=(matchtreswithTEFF_any(k,_)->(try(Util.hfindanytabk)withNot_found->(failwith"uncompatible types"))|_->tres)