123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)openLogic_typingopenLogic_ptreeopenCil_typeslet()=letcallpure={bl_name="\\callpure";bl_labels=[];bl_params=[];bl_type=None;bl_profile=[]}andcallset={bl_name="\\callset";bl_labels=[];bl_params=[];bl_type=None;bl_profile=[]}andcall={bl_name="\\call";bl_labels=[];bl_params=[];bl_type=None;bl_profile=[]}andcallresult={bl_name="\\callresult";bl_labels=[];bl_params=[];bl_type=None;bl_profile=[]}inLogic_builtin.addcallpure;Logic_builtin.addcallset;Logic_builtin.addcall;Logic_builtin.addcallresultletid_hash=Hashtbl.create3lettype_relationaltyping_contextlocl=letfunction_parameter_checkctxtxtpred=matchx.term_typewith|Ctype(ty)->ifCil_datatype.Typ.equalttythen()elselettest=newPrinter.extensible_printer()inctxt.errorloc"Cast are not supported:@. @[%a and %a are not compatible@] \
for term @. @[%a@] in call of %s @."(test#logic_typeNone)x.term_type(Printer.pp_typ)tPrinter.pp_termx(pred.vname)|Linteger->ifnot(Ast_types.is_integralt)thenctxt.errorloc"Cast are not supported:@. @[%a and %a are not compatible@] \
for term @[%a@] in call of %s @."(Printer.pp_logic_type)x.term_type(Printer.pp_typ)tPrinter.pp_termx(pred.vname)|Lreal->ifnot(Ast_types.is_floatt)thenctxt.errorloc"Cast are not supported:@. @[%a and %a are not compatible@] \
for term @[%a@] in call of %s @."(Printer.pp_logic_type)x.term_type(Printer.pp_typ)tPrinter.pp_termx(pred.vname)|_->ctxt.errorloc"@[<v 2>Function %s is called with a parameter with \
an unsupported type:@;@[%a@]"pred.vnamePrinter.pp_termxinletis_funcvarctxt=ifAst_types.is_funvar.vtypethenvarelsectxt.errorloc"Expected a C function: @ @[%a@] @."Printer.pp_varinfovarinlettest_originctxtfound=matchfound.lv_originwith|Somevar->is_funcvarctxt|None->ctxt.errorloc"No origin information for: @ @[%a@] @."Printer.pp_logic_varfoundinletcheck_is_function_namectxtp=matchp.lexpr_nodewith|PLvarx->lettest=tryctxt.find_varxwith|_->ctxt.errorloc"Unknown function: @ @[%s@] @."xintest_originctxttest|_->ctxt.errorloc"Expected a function name for call but get:@ @[%a@] @."Logic_print.print_lexprpinletcheck_inline_optionp=matchp.lexpr_nodewith|PLconstant(c)->(matchcwith|IntConstant(s)->Some(int_of_strings)|_->None)|_->Noneinletcheck_call_paramctxtenvpf=matchp.lexpr_nodewith|PLapp("\\callpure",[],_)->ctxt.type_termctxtenvp|PLvar_->typing_context.type_termctxtenvp|PLarrow_->typing_context.type_termctxtenvp|PLconstant_->ctxt.type_termctxtenvp|PLbinop_->ctxt.type_termctxtenvp|PLdot_->ctxt.type_termctxtenvp|PLarrget_->ctxt.type_termctxtenvp|PLunop_->ctxt.type_termctxtenvp|_->ctxt.errorloc"Unsupported terme@. @[%a@] @.in parameter for function %s @."Logic_print.print_lexprpfinlettype_termctxtenvp=matchp.lexpr_nodewith|PLapp("\\callpure",[],param)->let(inline,param)=(matchcheck_inline_option(List.hdparam)with|None->(1,param)|Somex->(x,(List.tlparam)))inletpred=check_is_function_namectxt(List.hdparam)inlet(rt,args,_,_)=Cil.splitFunctionTypepred.vtypeinifOption.is_noneargsthenctxt.errorloc"Function %a does not have a prototype"Printer.pp_varinfopred;letargs=Option.getargsinletlength_pre=List.length(List.tlparam)andlength_f=List.lengthargsiniflength_pre<>length_fthenctxt.errorloc"Expected %d parameter for the call of the pure function %s @."length_fpred.vname;letpredn=List.map(funp->check_call_paramctxtenvp(pred.vname))(List.tlparam)inList.iter2(funx(_,t,_)->function_parameter_checkctxtxtpred)prednargs;letli=List.hd(Logic_env.find_all_logic_functions"\\callpure")inli.l_type<-Some(Cil_types.Ctypert);letinline=Logic_const.tinteger~loc:pred.vdeclinlineinletlv_funct=Cil.cvar_to_lvarpredinletfunct={term_node=TLval(TVar(lv_funct),TNoOffset);term_loc=inline.term_loc;term_type=Cil_types.Ctype(pred.vtype);term_name=[]}inLogic_const.term~loc:p.lexpr_loc(Tapp(li,[],(inline::[funct])@predn))(Cil_types.Ctypert)|PLapp("\\callresult",[],param)->ifList.lengthparam<>1thenctxt.errorloc"Expected one parameter for \\callresult built-in (identifier):@. @[%a@] @."Logic_print.print_lexprpelsebeginletid=List.hdparaminletid=matchid.lexpr_nodewith|PLvarn->n|_->ctxt.errorloc"Expect an identifier as parameter for built-in \\callresult: @. @[%a@] @."Logic_print.print_lexprpinletf=(try(Hashtbl.findid_hashid)with|Not_found->ctxt.errorloc"Unknown identifier %s for @. @[%a@] @."idLogic_print.print_lexprp|_->assertfalse)inletli=List.hd(Logic_env.find_all_logic_functions"\\callresult")inlet(rt,_,_,_)=Cil.splitFunctionTypef.vtypeinli.l_type<-Some(Cil_types.Ctypert);letti=Logic_const.tstring~loc:p.lexpr_locidinLogic_const.term~loc:p.lexpr_loc(Tapp(li,[],[ti]))(Cil_types.Ctypert)end|PLapp("\\callpure",_,_)->ctxt.errorloc"Expect no label for built-in \\callpure: @. @[%a@] @."Logic_print.print_lexprp|PLapp("\\callresult",_,_)->ctxt.errorloc"Expect no label for built-in \\callresult: @. [%a@] @."Logic_print.print_lexprp|_->typing_context.type_termctxtenvpinletcheck_identifierctxtlpred=letrecauxliacc=matchliwith|h1::q1->auxq1(h1::acc)|[]->accinifList.lengthl==0thenctxt.errorloc"Expect an identifier for the \\call to function %s @."pred.vnameelse(letreverse=auxl[]in(List.tlreverse,List.hdreverse))inletcheck_callset_paramctxtenvp=matchp.lexpr_nodewith|PLapp("\\call",[],param)->let(inline,param)=(matchcheck_inline_option(List.hdparam)with|None->(1,param)|Somex->(x,(List.tlparam)))inletpred=check_is_function_namectxt(List.hdparam)inlet(rt,args,_,_)=Cil.splitFunctionTypepred.vtypeinifOption.is_noneargsthenctxt.errorloc"Function %a does not have a prototype"Printer.pp_varinfopred;letargs=Option.getargsinlet(funct_param,id)=check_identifierctxt(List.tlparam)predinletlength_pre=(List.lengthfunct_param)andlength_f=List.lengthargsiniflength_pre<>length_fthen(ctxt.errorloc"Expected %d parameter for the \\call of the function %s: @. @[%a@] @."length_fpred.vnameLogic_print.print_lexprp)else(letid=(matchid.lexpr_nodewith|PLvarn->n|_->ctxt.errorloc"Expect an identifier as last parameter \
for function %s: @. [%a@] @."pred.vnameLogic_print.print_lexprp)inmatch(Hashtbl.findid_hashid)with|exceptionNot_found->Hashtbl.addid_hashidpred;letpredn=List.map(funp->check_call_paramctxtenvp(pred.vname))(List.revfunct_param)inList.iter2(funx(_,t,_)->function_parameter_checkctxtxtpred)prednargs;letli=List.hd(Logic_env.find_all_logic_functions"\\call")inletinline=Logic_const.tinteger~loc:pred.vdeclinlineinlettid=Logic_const.tstring~loc:pred.vdeclidinli.l_type<-Some(Cil_types.Ctypert);letlv_funct=Cil.cvar_to_lvarpredinletfunct={term_node=TLval(TVar(lv_funct),TNoOffset);term_loc=inline.term_loc;term_type=Cil_types.Ctype(pred.vtype);term_name=[]}inletres=Logic_const.term~loc:p.lexpr_loc(Tapp(li,[],tid::inline::[funct]@predn))(Cil_types.Ctypert)inletlabel_pre="Pre_"^idinletlabel_post="Post_"^idinletnew_env=Logic_typing.Lenv.add_logic_labellabel_pre(FormalLabellabel_pre)envinletnew_env=Logic_typing.Lenv.add_logic_labellabel_post(FormalLabellabel_post)new_envinnew_env,res|_->ctxt.errorloc"Multiple use of identifier %s @."id)|PLapp("\\call",_,_)->ctxt.errorloc"Expect no label for built-in \\call: @. @[%a@] @."Logic_print.print_lexprp|_->ctxt.errorloc"Unsupported terme type in \\callset built-in: @. @[%a@] @."Logic_print.print_lexprpinletcheck_call_setctxtenvp=matchp.lexpr_nodewith|PLapp("\\callset",[],param)->letenv,calls=List.fold_right(funp(env,calls)->let(env,call)=check_callset_paramctxtenvpin(env,call::calls))param(env,[])inletli=List.hd(Logic_env.find_all_logic_functions"\\callset")inletnamed_pred={pred_name=[];pred_loc=p.lexpr_loc;pred_content=(Papp(li,[],calls))}inenv,Logic_const.pred_of_id_pred(Logic_const.new_predicatenamed_pred)|PLapp("\\callset",_,_)->ctxt.errorloc"Expect no label for built-in \\callset @."|_->ctxt.errorloc"Unsupported term type in \\rela built-in @."inlettype_predicatectxtenvp=matchp.lexpr_nodewith|PLnamed(name,exp)->letpred=ctxt.type_predicatectxtenvexpin{pred_name=[name];pred_loc=pred.pred_loc;pred_content=pred.pred_content}|PLapp("\\callpure",_,_)->ctxt.errorloc"A \\callpure is equivalent to a term"|PLapp("\\rela",[],param)->ifnot(Rpp_options.Is_buildin_rela_first.get())thenctxt.errorloc"@[<v 2>Expected \\rela built-in to be the first element \
in predicate or in \\forall:@;%a@]"Logic_print.print_lexprpelse((ifList.lengthparam!=2then(ctxt.errorloc"Expected 2 parameter for the \\rela built-in: @. @[%a@] @."Logic_print.print_lexprp)else(letenv,callset=check_call_setctxtenv(List.hdparam)inletpred=typing_context.type_predicatectxtenv(List.hd(List.tlparam))inLogic_const.pimplies~loc:p.lexpr_loc(callset,pred))))|PLimplies(({lexpr_node=PLapp("\\callset",_,_)}asset),pred)->ifnot(Rpp_options.Is_buildin_rela_first.get())thenctxt.errorloc"Expected \\callset built-in to be the first element in predicat \
or in \\forall:@. @[%a@] @."Logic_print.print_lexprpelse(letenv,callset=check_call_setctxtenvsetinletpred=typing_context.type_predicatectxtenvpredinLogic_const.pimplies~loc:p.lexpr_loc(callset,pred))|PLapp("\\callset",_,_)->ctxt.errorloc"Built-in \\callset must be the first element in an implication: @. @[%a@] @."Logic_print.print_lexprp|PLforall(_)->typing_context.type_predicatectxtenvp|PLapp("\\rela",_,_)->ctxt.errorloc"Expect no label for built-in \\rela: @. @[%a@] @."Logic_print.print_lexprp|_->Rpp_options.Is_buildin_rela_first.set(false);typing_context.type_predicatectxtenvpinletctxt={typing_contextwithtype_term;type_predicate}inmatchlwith|p::[]->Rpp_options.Is_buildin_rela_first.set(true);letacsl_pred=Ext_preds[ctxt.type_predicatectxtctxt.pre_statep]inHashtbl.clearid_hash;acsl_pred|_->typing_context.errorloc"expecting one predicate in relational clause @."let()=Acsl_extension.register_global~plugin:"rpp""relational"type_relationaltrue(* Acsl_extension.register_behavior "relational" type_relational true *)