123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269(****************************************************************************)(* Sail *)(* *)(* Sail and the Sail architecture models here, comprising all files and *)(* directories except the ASL-derived Sail code in the aarch64 directory, *)(* are subject to the BSD two-clause licence below. *)(* *)(* The ASL derived parts of the ARMv8.3 specification in *)(* aarch64/no_vector and aarch64/full are copyright ARM Ltd. *)(* *)(* Copyright (c) 2013-2021 *)(* Kathyrn Gray *)(* Shaked Flur *)(* Stephen Kell *)(* Gabriel Kerneis *)(* Robert Norton-Wright *)(* Christopher Pulte *)(* Peter Sewell *)(* Alasdair Armstrong *)(* Brian Campbell *)(* Thomas Bauereiss *)(* Anthony Fox *)(* Jon French *)(* Dominic Mulligan *)(* Stephen Kell *)(* Mark Wassell *)(* Alastair Reid (Arm Ltd) *)(* *)(* All rights reserved. *)(* *)(* This work was partially supported by EPSRC grant EP/K008528/1 <a *)(* href="http://www.cl.cam.ac.uk/users/pes20/rems">REMS: Rigorous *)(* Engineering for Mainstream Systems</a>, an ARM iCASE award, EPSRC IAA *)(* KTF funding, and donations from Arm. This project has received *)(* funding from the European Research Council (ERC) under the European *)(* Union’s Horizon 2020 research and innovation programme (grant *)(* agreement No 789108, ELVER). *)(* *)(* This software was developed by SRI International and the University of *)(* Cambridge Computer Laboratory (Department of Computer Science and *)(* Technology) under DARPA/AFRL contracts FA8650-18-C-7809 ("CIFV") *)(* and FA8750-10-C-0237 ("CTSRD"). *)(* *)(* Redistribution and use in source and binary forms, with or without *)(* modification, are permitted provided that the following conditions *)(* are met: *)(* 1. Redistributions of source code must retain the above copyright *)(* notice, this list of conditions and the following disclaimer. *)(* 2. Redistributions in binary form must reproduce the above copyright *)(* notice, this list of conditions and the following disclaimer in *)(* the documentation and/or other materials provided with the *)(* distribution. *)(* *)(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)(* SUCH DAMAGE. *)(****************************************************************************)openAstopenAst_defsopenAst_utilopenParser_combinatorsletfind_properties{defs;_}=letrecfind_propacc=function|DEF_aux(DEF_pragma((("property"|"counterexample")asprop_type),command,l),_)::defs->beginmatchUtil.find_next(functionDEF_aux(DEF_val_,_)->true|_->false)defswith|_,Some(DEF_aux(DEF_valvs,_),defs)->find_prop((prop_type,command,l,vs)::acc)defs|_,_->raise(Reporting.err_generall"Property is not attached to any function signature")end|def::defs->find_propaccdefs|[]->accinfind_prop[]defs|>List.map(fun((_,_,_,vs)asprop)->(id_of_val_specvs,prop))|>List.fold_left(funm(id,prop)->Bindings.addidpropm)Bindings.emptyletadd_property_guardspropsast=letopenType_checkinletrecadd_property_guards'acc=function|(DEF_aux(DEF_fundef(FD_aux(FD_function(r_opt,t_opt,funcls),fd_aux)asfdef),def_annot)asdef)::defs->beginmatchBindings.find_opt(id_of_fundeffdef)propswith|Some(_,_,pragma_l,VS_aux(VS_val_spec(TypSchm_aux(TypSchm_ts(quant,_),_),_,_),_))->beginmatchquant_splitquantwith|_,[]->add_property_guards'(def::acc)defs|_,constraints->letadd_constraints_to_funcl(FCL_aux(FCL_funcl(id,Pat_aux(pexp,pexp_aux)),fcl_aux))=letadd_guardexp=(* FIXME: Use an assert *)letexp'=mk_exp(E_block[mk_exp(E_app(mk_id"sail_assume",[mk_exp(E_constraint(List.fold_leftnc_andnc_trueconstraints))]));strip_expexp;])intryType_check.check_exp(env_ofexp)exp'(typ_ofexp)withType_error(_,l,err)->letmsg="\n\
Type error when generating guard for a property.\n\
When generating guards we convert type quantifiers from the function signature\n\
into runtime checks so it must be possible to reconstruct the quantifier from\n\
the function arguments. For example:\n\n\
function f : forall 'n, 'n <= 100. (x: int('n)) -> bool\n\n\
would cause the runtime check x <= 100 to be added to the function body.\n\
To fix this error, ensure that all quantifiers have corresponding function arguments.\n"inraise(Reporting.err_typpragma_l(Type_error.string_of_type_errorerr^msg))inletmk_funclp=FCL_aux(FCL_funcl(id,Pat_aux(p,pexp_aux)),fcl_aux)inmatchpexpwith|Pat_exp(pat,exp)->mk_funcl(Pat_exp(pat,add_guardexp))|Pat_when(pat,guard,exp)->mk_funcl(Pat_when(pat,guard,add_guardexp))inletfuncls=List.mapadd_constraints_to_funclfunclsinletfdef=FD_aux(FD_function(r_opt,t_opt,funcls),fd_aux)inadd_property_guards'(DEF_aux(DEF_fundeffdef,def_annot)::acc)defsend|None->add_property_guards'(def::acc)defsend|def::defs->add_property_guards'(def::acc)defs|[]->List.revaccin{astwithdefs=add_property_guards'[]ast.defs}letrewritedefs=add_property_guards(find_propertiesdefs)defstypeevent=Overflow|Assertion|Assumption|Match|Returntypequery=|Q_allofevent(* All events of type are true *)|Q_existofevent(* Some event of type is true *)|Q_notofquery|Q_andofquerylist|Q_orofquerylistletdefault_query=Q_or[Q_and[Q_not(Q_existAssertion);Q_allReturn;Q_not(Q_existMatch)];Q_existOverflow;Q_not(Q_allAssumption)]moduleEvent=structtypet=eventletcomparee1e2=match(e1,e2)with|Overflow,Overflow->0|Assertion,Assertion->0|Assumption,Assumption->0|Match,Match->0|Return,Return->0|Overflow,_->1|_,Overflow->-1|Assertion,_->1|_,Assertion->-1|Assumption,_->1|_,Assumption->-1|Match,_->1|_,Match->-1endletstring_of_event=function|Overflow->"overflow"|Assertion->"assertion"|Assumption->"assumption"|Match->"match_failure"|Return->"return"letrec_string_of_query=function|Q_allev->"A "^string_of_eventev|Q_existev->"E "^string_of_eventev|Q_notq->"~("^_string_of_queryq^")"|Q_andqs->"("^Util.string_of_list" & "_string_of_queryqs^")"|Q_orqs->"("^Util.string_of_list" | "_string_of_queryqs^")"letparse_query=letamp=token(functionStr.Delim"&"->Some()|_->None)inletbar=token(functionStr.Delim"|"->Some()|_->None)inletlparen=token(functionStr.Delim"("->Some()|_->None)inletrparen=token(functionStr.Delim")"->Some()|_->None)inletquant=token(function|Str.Text("A"|"all")->Some(funx->Q_allx)|Str.Text("E"|"exist")->Some(funx->Q_existx)|_->None)inletevent=token(function|Str.Text"overflow"->SomeOverflow|Str.Text"assertion"->SomeAssertion|Str.Text"assumption"->SomeAssumption|Str.Text"match_failure"->SomeMatch|Str.Text"return"->SomeReturn|_->None)inlettilde=token(functionStr.Delim"~"->Some()|_->None)inletrecexp0()=pchoose(exp1()>>=funx->bar>>=fun_->exp0()>>=funy->preturn(Q_or[x;y]))(exp1())andexp1()=pchoose(exp2()>>=funx->amp>>=fun_->exp1()>>=funy->preturn(Q_and[x;y]))(exp2())andexp2()=pchoose(tilde>>=fun_->exp3()>>=funx->preturn(Q_notx))(exp3())andexp3()=pchoose(lparen>>=fun_->exp0()>>=funx->rparen>>=fun_->preturnx)(quant>>=funf->event>>=funev->preturn(fev))inparse(exp0())"[ \n\t]+\\|(\\|)\\|&\\||\\|~"typepragma={query:query;litmus:stringlist}letdefault_pragma={query=default_query;litmus=[]}letparse_pragmalinput=letkey=Str.regexp":[a-z]+"inlettokens=Str.full_splitkeyinputinletrecprocess_tokspragma=function|Str.Delim":query"::Str.Textquery::rest->beginmatchparse_queryquerywith|Someq->process_toks{pragmawithquery=q}rest|None->raise(Reporting.err_generall("Could not parse query "^String.trimquery))end|Str.Delim":litmus"::rest->letargs,rest=Util.take_drop(functionStr.Text_->true|_->false)restinprocess_toks{pragmawithlitmus=List.map(functionStr.Textt->t|_->assertfalse)args}rest|[]->pragma|_->raise(Reporting.err_generall"Could not parse pragma")inprocess_toksdefault_pragmatokens