123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470(******************************************************************************)(* ASLRef *)(******************************************************************************)(*
* SPDX-FileCopyrightText: Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
* SPDX-License-Identifier: BSD-3-Clause
*)(******************************************************************************)(* Disclaimer: *)(* This material covers both ASLv0 (viz, the existing ASL pseudocode language *)(* which appears in the Arm Architecture Reference Manual) and ASLv1, a new, *)(* experimental, and as yet unreleased version of ASL. *)(* This material is work in progress, more precisely at pre-Alpha quality as *)(* per Arm’s quality standards. *)(* In particular, this means that it would be premature to base any *)(* production tool development on this material. *)(* However, any feedback, question, query and feature request would be most *)(* welcome; those can be sent to Arm’s Architecture Formal Team Lead *)(* Jade Alglave <jade.alglave@arm.com>, or by raising issues or PRs to the *)(* herdtools7 github repository. *)(******************************************************************************)openASTopenASTUtilsletfatal_frompos=Error.fatal_frompos(* A bit more informative than assert false *)let_warn=falselet_dbg=falseletrecsubtypes_namesenvs1s2=ifString.equals1s2thentrueelsematchIMap.find_opts1StaticEnv.(env.global.subtypes)with|None->false|Somes1'->subtypes_namesenvs1's2letsubtypesenvt1t2=match(t1.desc,t2.desc)with|T_Nameds1,T_Nameds2->subtypes_namesenvs1s2|_->falsemoduletypeS=sigmoduleB:Backend.SmoduleIEnv:Env.Swithtypev=B.valueandmoduleScope=B.Scopetypevalue_read_from=B.value*AST.identifier*B.Scope.ttype'amaybe_exception=|Normalof'a|Throwingof(value_read_from*AST.ty)option*IEnv.envvaleval_expr:IEnv.env->AST.expr->(B.value*IEnv.env)maybe_exceptionB.mvalrun_typed_env:(AST.identifier*B.value)list->StaticEnv.global->AST.t->B.valueB.mvalrun_typed:StaticEnv.global->AST.t->B.valueB.mendmoduletypeConfig=sigmoduleInstr:Instrumentation.SEMINSTRvalunroll:intvalerror_handling_time:Error.error_handling_timeendmoduleMake(B:Backend.S)(C:Config)=structmoduleB=BmoduleSemanticsRule=Instrumentation.SemanticsRuletype'am='aB.mmoduleEnvConf=structmoduleScope=B.Scopetypev=B.valueletunroll=C.unrollendmoduleIEnv=Env.RunTime(EnvConf)typeenv=IEnv.envtypevalue_read_from=B.value*identifier*B.Scope.ttype'amaybe_exception=|Normalof'a|Throwingof(value_read_from*ty)option*env(** An intermediate result of a statement. *)typecontrol_flow_state=|ReturningofB.valuelist*IEnv.global(** Control flow interruption: skip to the end of the function. *)|Continuingofenv(** Normal behaviour: pass to next statement. *)typeexpr_eval_type=(B.value*env)maybe_exceptionmtypestmt_eval_type=control_flow_statemaybe_exceptionmtypefunc_eval_type=(value_read_fromlist*IEnv.global)maybe_exceptionmletunsupported_expre=fatal_fromeError.(UnsupportedExpr(C.error_handling_time,e))(*****************************************************************************)(* *)(* Monadic operators *)(* *)(*****************************************************************************)letone=B.v_of_int1lettrue'=E_Literal(L_Booltrue)|>add_dummy_annotationletfalse'=E_Literal(L_Boolfalse)|>add_dummy_annotation(* Return *)(* ------ *)letreturn=B.returnletreturn_normalv=Normalv|>returnletreturn_continueenv:stmt_eval_type=Continuingenv|>return_normalletreturn_returnenvvs:stmt_eval_type=Returning(vs,env.IEnv.global)|>return_normal(* Bind *)(* ---- *)(* Sequential bind *)let(let*|)=B.bind_seq(* Data bind *)let(let*)=B.bind_datalet(>>=)=B.bind_data(* Control bind *)let(let*=)=B.bind_ctrllet(>>*=)=B.bind_ctrl(* Choice *)letchoicemv1v2=B.choicem(returnv1)(returnv2)(*
* Choice with inserted branching (commit) effect/
* [choice_with_branching_effect_msg m_cond msg v1 v2 kont]:
* [m_cond], evaluates to boolean condition,
* [msg], message to decorate the branching event,
* [v1 v2] alternative for choice.
* [kont] contitinuation, takes choosed [v1] or [v2] as
* input .
*)letchoice_with_branch_effect_msgm_condmsgv1v2kont=choicem_condv1v2>>=funv->B.commit(Somemsg)>>*=fun()->kontvletchoice_with_branch_effectm_conde_condv1v2kont=letpp_cond=Format.asprintf"%a@?"PP.pp_expre_condinchoice_with_branch_effect_msgm_condpp_condv1v2kont(* Exceptions *)letbind_exceptionbindermf=binderm(functionNormalv->fv|Throwing_asres->returnres)letbind_exception_seqmf=bind_exceptionB.bind_seqmflet(let**|)=bind_exception_seqletbind_exception_datamf=bind_exceptionB.bind_datamflet(let**)=bind_exception_data(* Continue *)(* [bind_continue m f] executes [f] on [m] only if [m] is [Normal (Continuing _)] *)letbind_continue(m:stmt_eval_type)f:stmt_eval_type=bind_exception_seqm@@function|Continuingenv->fenv|Returning_asres->return_normalreslet(let*>)=bind_continue(* Unroll *)(* [bind_unroll "while" m f] executes [f] on [m] after having ticked the
unrolling stack of [m] only if [m] is [Normal (Continuing _)] *)letbind_unroll(loop_name,loop_pos)(m:stmt_eval_type)f:stmt_eval_type=bind_continuem@@funenv->letstop,env'=IEnv.tick_decrenvinifstopthenletmsg=Printf.sprintf"%s at %s pruned"loop_name(PP.pp_pos_str_no_charloop_pos)inB.cutoffTmsgenv>>=return_continueelsefenv'letbind_maybe_unrollloop_nameundet=ifundetthenbind_unrollloop_nameelsebind_continue(* To give name to rules *)let(|:)=C.Instr.use_with(* Product parallel *)(* ---------------- *)let(and*)=B.prod_par(* Application *)(* ----------- *)let(>=>)mf=B.appl_datamf(*****************************************************************************)(* *)(* Environments *)(* *)(*****************************************************************************)(* Global env *)(* ---------- *)leteval_global_declenv0eval_exprdenv_m=let*|env=env_minmatchd.descwith|D_GlobalStorage{initial_value;name;_}->(letscope=B.Scope.global~init:trueinmatchIMap.find_optnameenv0with|Somev->IEnv.declare_globalnamevenv|>return|None->letinit_expr=matchinitial_valuewith|Somee->e|None->fatal_fromdTypeInferenceNeededinlet*eval_res=eval_exprenvinit_exprinletv,env2=matcheval_reswith|Normal(v,env2)->(v,env2)|Throwing(exc,_env2)->letty=matchexcwith|Some(_,ty)->ty|None->T_Named"implicit"|>add_pos_fromdinfatal_fromd(UnexpectedInitialisationThrow(ty,name))inlet*()=B.on_write_identifiernamescopevinletenv3=IEnv.declare_globalnamevenv2inreturnenv3)|_->returnenv(* Begin EvalBuildGlobalEnv *)(** [build_genv penv static_env ast primitives] is the global environment before
the start of the evaluation of [ast], with predefined values in [penv]. *)letbuild_genvenv0eval_expr(static_env:StaticEnv.global)(ast:AST.t)=let()=if_dbgthenFormat.eprintf"@[<v 2>Executing in env:@ %a@.]"StaticEnv.pp_globalstatic_envinletenv0=IMap.of_listenv0inletglobal_decl_folder=function|TopoSort.ASTFold.Singled->eval_global_declenv0eval_exprd|TopoSort.ASTFold.Recursiveds->List.fold_right(eval_global_declenv0eval_expr)dsinletenv=letopenIEnvinletglobal=global_from_staticstatic_envandlocal=local_empty_scoped(B.Scope.global~init:true)in{global;local}inlet*|env=TopoSort.ASTFold.foldglobal_decl_folderast(returnenv)inreturnenv.global|:SemanticsRule.BuildGlobalEnv(* End *)(* Bind Environment *)(* ---------------- *)letdiscard_exceptionm=B.bind_datam@@function|Normalv->returnv|Throwing_->assertfalseletbind_envmf=B.delaym@@funresm->matchreswith|Normal(_v,env)->f(discard_exceptionm>=>fst,env)|Throwing_asres->(* Do not discard [m], otherwise events are lost *)m>>=fun_->returnreslet(let*^)=bind_env(* Primitives handling *)(* ------------------- *)letprimitive_runtimes=List.to_seqB.primitives|>Seq.mapAST.(fun({name;subprogram_type=_;_},f)->(name,f))|>Hashtbl.of_seqletprimitive_decls=List.map(fun(f,_)->D_Funcf|>add_dummy_annotation)B.primitiveslet()=iffalsethenFormat.eprintf"@[<v 2>Primitives:@ %a@]@."PP.pp_tprimitive_decls(*****************************************************************************)(* *)(* Evaluation functions *)(* *)(*****************************************************************************)(* Utils *)(* ----- *)letv_false=L_Boolfalse|>B.v_of_literalletv_true=L_Booltrue|>B.v_of_literalletm_false=returnv_falseletm_true=returnv_trueletv_to_int~locv=matchB.v_to_zvwith|SomezwhenZ.fits_intz->Z.to_intz|Somez->Printf.eprintf"Overflow in asllib: cannot convert back to 63-bit integer the \
integer %a.\n\
%!"Z.outputz;unsupported_exprloc|None->fatal_fromloc(MismatchType(B.debug_valuev,[integer']))letsync_listms=letfoldermvsm=let*v=mand*vs=vsminreturn(v::vs)inList.fold_rightfolderms(return[])letfold_par2fold1fold2acce1e2=let*^m1,acc=fold1acce1inlet*^m2,acc=fold2acce2inlet*v1=m1and*v2=m2inreturn_normal((v1,v2),acc)letrecfold_par_listfoldacces=matcheswith|[]->return_normal([],acc)|e::es->let**(v,vs),acc=fold_par2fold(fold_par_listfold)acceesinreturn_normal(v::vs,acc)letrecfold_parm_listfoldacces=matcheswith|[]->return_normal([],acc)|e::es->let*^m,acc=foldacceinlet**ms,acc=fold_parm_listfoldaccesinreturn_normal(m::ms,acc)letlexpr_is_varle=matchle.descwithLE_Var_|LE_Discard->true|_->falseletdeclare_local_identifierenvnamev=let*()=B.on_write_identifiername(IEnv.get_scopeenv)vinIEnv.declare_localnamevenv|>returnletdeclare_local_identifier_menvxm=m>>=declare_local_identifierenvxletdeclare_local_identifier_mmenvmxm=let*|env=envmindeclare_local_identifier_menvxmletassign_local_identifierenvxv=let*()=B.on_write_identifierx(IEnv.get_scopeenv)vinIEnv.assign_localxvenv|>returnletreturn_identifieri="return-"^string_of_intiletthrow_identifier()=fresh_var"thrown"(* Begin EvalReadValueFrom *)letread_value_from((v,name,scope):value_read_from)=let*()=B.on_read_identifiernamescopevinreturnv|:SemanticsRule.ReadValueFrom(* End *)letbig_opdefaultop=letfolderm_accm=let*acc=m_accand*v=minopaccvinfunction[]->default|x::li->List.fold_leftfolderxli(** [check_non_overlapping_slices slices value_ranges] checks that the
slice ranges [value_ranges] are non-overlapping.
[value_ranges] are given by a list of couples [(start, length)].
If they are overlapping, an error [OverlappingSlices (slices, Dynamic)]
is thrown. *)letcheck_non_overlapping_slicesslicesvalue_ranges=letcheck_two_ranges_are_non_overlapping(s1,l1)m(s2,l2)=let*()=minletcond=let*s1l1s2=let*s1l1=B.binopPLUSs1l1inB.binopLEQs1l1s2and*s2l2s1=let*s2l2=B.binopPLUSs2l2inB.binopLEQs2l2s1inB.binopBORs1l1s2s2l2s1inlet*b=choicecondtruefalseinifbthenreturn()elseError.(fatal_unknown_pos(OverlappingSlices(slices,C.error_handling_time)))inletcheck_range_does_not_overlap_previous_rangespast_rangesrange=let*past_ranges=past_rangesinlet*()=List.fold_left(check_two_ranges_are_non_overlappingrange)(return())past_rangesinreturn(range::past_ranges)inlet*_=List.fold_leftcheck_range_does_not_overlap_previous_ranges(return[])value_rangesinreturn()(* Evaluation of Expressions *)(* ------------------------- *)(** [eval_expr] specifies how to evaluate an expression [e] in an environment
[env]. More precisely, [eval_expr env e] is the monadic evaluation of
[e] in [env]. *)letreceval_expr(env:env)(e:expr):expr_eval_type=iffalsethenFormat.eprintf"@[<3>Eval@ @[%a@]@]@."PP.pp_expre;matche.descwith(* Begin EvalELit *)|E_Literall->return_normal(B.v_of_literall,env)|:SemanticsRule.ELit(* End *)(* Begin EvalATC *)|E_ATC(e1,t)->let**v,new_env=eval_exprenve1inlet*b=is_val_of_typee1envvtin(ifbthenreturn_normal(v,new_env)elsefatal_frome1(Error.MismatchType(B.debug_valuev,[t.desc])))|:SemanticsRule.ATC(* End *)(* Begin EvalEVar *)|E_Varx->(matchIEnv.findxenvwith|Localv->let*()=B.on_read_identifierx(IEnv.get_scopeenv)vinreturn_normal(v,env)|Globalv->let*()=B.on_read_identifierx(B.Scope.global~init:false)vinreturn_normal(v,env)|NotFound->fatal_frome@@Error.UndefinedIdentifierx)|:SemanticsRule.EVar(* End *)|E_Binop(((BAND|BOR|IMPL)asop),e1,e2)whenis_simple_expre1&&is_simple_expre2->let*=v1=eval_expr_sefenve1inifB.is_undeterminedv1thenlet*v2=eval_expr_sefenve2inlet*v=B.binopopv1v2inreturn_normal(v,env)else(* This is equivalent to the non-optimised case, but we can't use the
syntactic sugar trick used in the following cases as we can't
reconstruct an expression from a value. *)leteval_e2()=eval_expr_sefenve2inletret_true()=m_trueandret_false()=m_falseinleton_true,on_false=matchopwith|BAND->(eval_e2,ret_false)|BOR->(ret_true,eval_e2)|IMPL->(eval_e2,ret_true)|_->assertfalseinlet*v=B.ternaryv1on_trueon_falseinreturn_normal(v,env)(* Begin EvalBinopAnd *)|E_Binop(BAND,e1,e2)->(* if e1 then e2 else false *)E_Cond(e1,e2,false')|>add_pos_frome|>eval_exprenv|:SemanticsRule.BinopAnd(* End *)(* Begin EvalBinopOr *)|E_Binop(BOR,e1,e2)->(* if e1 then true else e2 *)E_Cond(e1,true',e2)|>add_pos_frome|>eval_exprenv|:SemanticsRule.BinopOr(* End *)(* Begin EvalBinopImpl *)|E_Binop(IMPL,e1,e2)->(* if e1 then e2 else true *)E_Cond(e1,e2,true')|>add_pos_frome|>eval_exprenv|:SemanticsRule.BinopImpl(* End *)(* Begin EvalBinop *)|E_Binop(op,e1,e2)->let*^m1,env1=eval_exprenve1inlet*^m2,new_env=eval_exprenv1e2inlet*v1=m1and*v2=m2inlet*v=B.binopopv1v2inreturn_normal(v,new_env)|:SemanticsRule.Binop(* End *)(* Begin EvalUnop *)|E_Unop(op,e1)->let**v1,env1=eval_exprenve1inlet*v=B.unopopv1inreturn_normal(v,env1)|:SemanticsRule.Unop(* End *)(* Begin EvalECond *)|E_Cond(e_cond,e1,e2)->let*^m_cond,env1=eval_exprenve_condinifis_simple_expre1&&is_simple_expre2thenlet*=v_cond=m_condinlet*v=(* The calls to [eval_expr_sef] are safe because [is_simple_expr]
implies [is_pure]. *)B.ternaryv_cond(fun()->eval_expr_sefenv1e1)(fun()->eval_expr_sefenv1e2)inreturn_normal(v,env)|:SemanticsRule.ECondSimpleelsechoice_with_branch_effectm_conde_conde1e2(eval_exprenv1)|:SemanticsRule.ECond(* End *)(* Begin EvalESlice *)|E_Slice(e_bv,slices)->let*^m_bv,env1=eval_exprenve_bvinlet*^m_positions,new_env=eval_slicesenv1slicesinlet*v_bv=m_bvand*positions=m_positionsinlet*v=B.read_from_bitvectorpositionsv_bvinreturn_normal(v,new_env)|:SemanticsRule.ESlice(* End *)(* Begin EvalECall *)|E_Call{name;params;args}->(* pass [params] and [args] as labelled arguments to avoid confusion *)let**|ms,new_env=eval_call(to_pose)nameenv~params~argsinlet*v=matchmswith|[m]->m|_->let*vs=sync_listmsinB.create_vectorvsinreturn_normal(v,new_env)|:SemanticsRule.ECall(* End *)(* Begin EvalEGetArray *)|E_GetArray(e_array,e_index)->let*^m_array,env1=eval_exprenve_arrayinlet*^m_index,new_env=eval_exprenv1e_indexinlet*v_array=m_arrayand*v_index=m_indexinleti_index=v_to_int~loc:ev_indexinlet*v=B.get_indexi_indexv_arrayinreturn_normal(v,new_env)|:SemanticsRule.EGetArray(* End *)(* Begin EvalEGetEnumArray *)|E_GetEnumArray(e_array,e_index)->let*^m_array,env1=eval_exprenve_arrayinlet*^m_index,new_env=eval_exprenv1e_indexinlet*v_array=m_arrayand*v_index=m_indexin(* an enumerated array is represented by a record value. *)letlabel=B.v_to_labelv_indexinlet*v=B.get_fieldlabelv_arrayinreturn_normal(v,new_env)|:SemanticsRule.EGetEnumArray(* End *)(* Begin EvalEGetTupleItem *)|E_GetItem(e_tuple,index)->let**v_tuple,new_env=eval_exprenve_tupleinlet*v=B.get_indexindexv_tupleinreturn_normal(v,new_env)|:SemanticsRule.EGetTupleItem(* End *)(* Begin EvalERecord *)|E_Record(_,e_fields)->letnames,fields=List.splite_fieldsinlet**v_fields,new_env=eval_expr_listenvfieldsinlet*v=B.create_record(List.combinenamesv_fields)inreturn_normal(v,new_env)|:SemanticsRule.ERecord(* End *)(* Begin EvalEGetField *)|E_GetField(e_record,field_name)->let**v_record,new_env=eval_exprenve_recordinlet*v=B.get_fieldfield_namev_recordinreturn_normal(v,new_env)|:SemanticsRule.EGetBitField(* End *)(* Begin EvalEGetFields *)|E_GetFields(e_record,field_names)->let**v_record,new_env=eval_exprenve_recordinlet*v_list=List.map(funfield_name->B.get_fieldfield_namev_record)field_names|>sync_listinlet*v=B.concat_bitvectorsv_listinreturn_normal(v,new_env)(* End *)(* Begin EvalETuple *)|E_Tuplee_list->let**v_list,new_env=eval_expr_listenve_listinlet*v=B.create_vectorv_listinreturn_normal(v,new_env)|:SemanticsRule.ETuple(* End *)(* Begin EvalEArray *)|E_Array{length=e_length;value=e_value}->let**v_value,new_env=eval_exprenve_valuein(* The call to [eval_expr_sef] is safe because Typing.annotate_type
checks that all expressions on which a type depends are statically
evaluable, i.e. side-effect-free. *)let*v_length=eval_expr_sefenve_lengthinletn_length=v_to_int~loc:ev_lengthinlet*v=B.create_vector(List.initn_length(Fun.constv_value))inreturn_normal(v,new_env)|:SemanticsRule.EArray(* End *)(* Begin EvalEEnumArray *)|E_EnumArray{labels;value=e_value}->let**v_value,new_env=eval_exprenve_valueinletfield_inits=List.map(funl->(l,v_value))labelsinlet*v=B.create_recordfield_initsinreturn_normal(v,new_env)|:SemanticsRule.EEnumArray(* End *)(* Begin EvalEArbitrary *)|E_Arbitraryt->(* The call to [eval_expr_sef] is safe because Typing.annotate_type
checks that all expressions on which a type depends are statically
evaluable, i.e. side-effect-free. *)let*v=B.v_unknown_of_type~eval_expr_sef:(eval_expr_sefenv)tinreturn_normal(v,env)|:SemanticsRule.EArbitrary(* End *)(* Begin EvalEPattern *)|E_Pattern(e,p)->let**v1,new_env=eval_exprenveinlet*v=eval_patternenvev1pinreturn_normal(v,new_env)|:SemanticsRule.EPattern(* End *)(* Evaluation of Side-Effect-Free Expressions *)(* ------------------------------------------ *)(** [eval_expr_sef] specifies how to evaluate a side-effect-free expression
[e] in an environment [env]. More precisely, [eval_expr_sef env e] is the
[eval_expr env e], if e is side-effect-free. *)(* Begin EvalESideEffectFreeExpr *)andeval_expr_sefenve:B.valuem=eval_exprenve>>=function|Normal(v,_env)->returnv|Throwing(None,_)->letmsg=Format.asprintf"@[<hov 2>An exception was@ thrown@ when@ evaluating@ %a@]@."PP.pp_expreinfatal_frome(Error.UnexpectedSideEffectmsg)|Throwing(Some(_,ty),_)->letmsg=Format.asprintf"@[<hov 2>An exception of type @[<hv>%a@]@ was@ thrown@ when@ \
evaluating@ %a@]@."PP.pp_tytyPP.pp_expreinfatal_frome(Error.UnexpectedSideEffectmsg)(* End *)(* Runtime checks *)(* -------------- *)(* Begin EvalValOfType *)andis_val_of_typelocenvvty:boolB.m=letbig_or=big_opm_false(B.binopBOR)inletrecin_valuesvty=matchty.descwith|T_IntUnConstrained->m_true|T_Int(Parameterized_)->(* This cannot happen, because:
1. Forgetting now about named types, or any kind of compound types,
you cannot ask: [expr as ty] if ty is the unconstrained integer
because there is no syntax for it.
2. You cannot construct a type that is an alias for the
parameterized integer type.
3. You cannot put the parameterized integer type in a compound
type.
*)fatal_fromlocError.UnrespectedParserInvariant|T_Bits(e,_)->(* The call to [eval_expr_sef] is justified since annotate_type
checks that all expressions on which a type depends are statically
evaluable, i.e. side-effect-free. *)let*v'=eval_expr_sefenveand*v_length=B.bitvector_lengthvinB.binopEQ_OPv_lengthv'|T_Int(WellConstrainedconstraints)->(* The calls to [eval_expr_sef] are justified since annotate_type
checks that all expressions on which a type depends are statically
evaluable, i.e., side-effect-free. *)letis_constraint_sat=function|Constraint_Exacte->let*v'=eval_expr_sefenveinB.binopEQ_OPvv'|:SemanticsRule.IsConstraintSat|Constraint_Range(e1,e2)->let*v1=eval_expr_sefenve1and*v2=eval_expr_sefenve2inlet*c1=B.binopLEQv1vand*c2=B.binopLEQvv2inB.binopBANDc1c2|:SemanticsRule.IsConstraintSatinList.mapis_constraint_satconstraints|>big_or|T_Tupletys->letfold(i,prev)ty'=letm=let*v'=B.get_indexivinlet*here=in_valuesv'ty'inprev>>=B.binopBANDherein(i+1,m)inList.fold_leftfold(0,m_true)tys|>snd|_->fatal_fromlocTypeInferenceNeededinchoice(in_valuesvty)truefalse(* End *)(* Evaluation of Left-Hand-Side Expressions *)(* ---------------------------------------- *)(** [eval_lexpr version env le m] is [env[le --> m]]. *)andeval_lexprverleenvm:envmaybe_exceptionB.m=matchle.descwith(* Begin EvalLEDiscard *)|LE_Discard->return_normalenv|:SemanticsRule.LEDiscard(* End *)|LE_Varx->(let*v=minmatchIEnv.assignxvenvwith(* Begin EvalLEVar *)|Localenv->let*()=B.on_write_identifierx(IEnv.get_scopeenv)vinreturn_normalenv|:SemanticsRule.LEVar|Globalenv->let*()=B.on_write_identifierx(B.Scope.global~init:false)vinreturn_normalenv|:SemanticsRule.LEVar(* End *)|NotFound->(matchverwith(* Begin EvalLEUndefIdentOne *)|V1->fatal_fromle@@Error.UndefinedIdentifierx|:SemanticsRule.LEUndefIdentV1(* End *)(* Begin EvalLEUndefIdentZero *)|V0->(* V0 first assignments promoted to local declarations *)declare_local_identifierenvxv>>=return_normal|:SemanticsRule.LEUndefIdentV0))(* End *)(* Begin EvalLESlice *)|LE_Slice(e_bv,slices)->let*^m_bv,env1=expr_of_lexpre_bv|>eval_exprenvinlet*^m_slice_ranges,env2=eval_slicesenv1slicesinletnew_m_bv=let*v=mand*slice_ranges=m_slice_rangesand*v_bv=m_bvinlet*()=check_non_overlapping_slicesslicesslice_rangesinB.write_to_bitvectorslice_rangesvv_bvineval_lexprvere_bvenv2new_m_bv|:SemanticsRule.LESlice(* End *)(* Begin EvalLESetArray *)|LE_SetArray(re_array,e_index)->let*^rm_array,env1=expr_of_lexprre_array|>eval_exprenvinlet*^m_index,env2=eval_exprenv1e_indexinletm1=let*v=mand*v_index=m_indexand*rv_array=rm_arrayinB.set_index(v_to_int~loc:e_indexv_index)vrv_arrayineval_lexprverre_arrayenv2m1|:SemanticsRule.LESetArray(* End *)(* Begin EvalLESetEnumArray *)|LE_SetEnumArray(re_array,e_index)->let*^rm_array,env1=expr_of_lexprre_array|>eval_exprenvinlet*^m_index,env2=eval_exprenv1e_indexinletm1=let*v=mand*v_index=m_indexand*rv_array=rm_arrayin(* an enumerated array is represented by a record value. *)letlabel=B.v_to_labelv_indexinB.set_fieldlabelvrv_arrayineval_lexprverre_arrayenv2m1|:SemanticsRule.LESetEnumArray(* End *)(* Begin EvalLESetField *)|LE_SetField(re_record,field_name)->let*^rm_record,env1=expr_of_lexprre_record|>eval_exprenvinletm1=let*v=mand*rv_record=rm_recordinB.set_fieldfield_namevrv_recordineval_lexprverre_recordenv1m1|:SemanticsRule.LESetField(* End *)(* Begin EvalLEDestructuring *)|LE_Destructuringle_list->(* The index-out-of-bound on the vector are done either in typing,
either in [B.get_index]. *)letn=List.lengthle_listinletnmonads=List.initn(funi->m>>=B.get_indexi)inmulti_assignverenvle_listnmonads|:SemanticsRule.LEDestructuring(* End *)(* Begin EvalLESetFields *)|LE_SetFields(le_record,fields,slices)->let()=ifList.compare_lengthsfieldsslices!=0thenfatal_fromleError.TypeInferenceNeededinlet*^rm_record,env1=expr_of_lexprle_record|>eval_exprenvin(* AssignBitvectorFields( *)letm2=List.fold_left2(funm1field_name(i1,i2)->letslice=[(B.v_of_inti1,B.v_of_inti2)]inlet*v_record_slices=m>>=B.read_from_bitvectorsliceand*rv_record=m1inB.set_fieldfield_namev_record_slicesrv_record)rm_recordfieldsslices(* AssignBitvectorFields) *)ineval_lexprverle_recordenv1m2|:SemanticsRule.LESetFields(* End *)(* Evaluation of Expression Lists *)(* ------------------------------ *)(* Begin EvalEExprListM *)andeval_expr_list_menves=fold_parm_listeval_exprenves|:SemanticsRule.EExprListM(* End *)(* Begin EvalEExprList *)andeval_expr_listenves=fold_par_listeval_exprenves|:SemanticsRule.EExprList(* End *)(* Evaluation of Slices *)(* -------------------- *)(** [eval_slices env slices] is the list of pair [(i_n, l_n)] that
corresponds to the start (included) and the length of each slice in
[slices]. *)andeval_slicesenv:slicelist->(B.value_rangelist*env)maybe_exceptionm=(* Begin EvalSlice *)leteval_sliceenv=function|Slice_Singlee->let**v_start,new_env=eval_exprenveinreturn_normal((v_start,one),new_env)|:SemanticsRule.Slice|Slice_Length(e_start,e_length)->let*^m_start,env1=eval_exprenve_startinlet*^m_length,new_env=eval_exprenv1e_lengthinlet*v_start=m_startand*v_length=m_lengthinreturn_normal((v_start,v_length),new_env)|:SemanticsRule.Slice|Slice_Range(e_top,e_start)->let*^m_top,env1=eval_exprenve_topinlet*^m_start,new_env=eval_exprenv1e_startinlet*v_top=m_topand*v_start=m_startinlet*v_length=B.binopMINUSv_topv_start>>=B.binopPLUSoneinreturn_normal((v_start,v_length),new_env)|:SemanticsRule.Slice|Slice_Star(e_factor,e_length)->let*^m_factor,env1=eval_exprenve_factorinlet*^m_length,new_env=eval_exprenv1e_lengthinlet*v_factor=m_factorand*v_length=m_lengthinlet*v_start=B.binopMULv_factorv_lengthinreturn_normal((v_start,v_length),new_env)|:SemanticsRule.Slice(* End *)in(* Begin EvalSlices *)fold_par_listeval_sliceenv|:SemanticsRule.Slices(* End *)(* Evaluation of Patterns *)(* ---------------------- *)(** [eval_pattern env pos v p] determines if [v] matches the pattern [p]. *)andeval_patternenvposv:pattern->B.valuem=lettrue_=B.v_of_literal(L_Booltrue)|>returninletfalse_=B.v_of_literal(L_Boolfalse)|>returninletdisjunction=big_opfalse_(B.binopBOR)andconjunction=big_optrue_(B.binopBAND)in(* The calls to [eval_expr_sef] are justified since annotate_pattern
checks that all expressions on which a type depends are statically
evaluable, i.e. side-effect-free. *)funp->matchp.descwith(* Begin EvalPAll *)|Pattern_All->true_|:SemanticsRule.PAll(* End *)(* Begin EvalPAny *)|Pattern_Anyps->letbs=List.map(eval_patternenvposv)psindisjunctionbs|:SemanticsRule.PAny(* End *)(* Begin EvalPGeq *)|Pattern_Geqe->let*v1=eval_expr_sefenveinB.binopGEQvv1|:SemanticsRule.PGeq(* End *)(* Begin EvalPLeq *)|Pattern_Leqe->let*v1=eval_expr_sefenveinB.binopLEQvv1|:SemanticsRule.PLeq(* End *)(* Begin EvalPNot *)|Pattern_Notp1->let*b1=eval_patternenvposvp1inB.unopBNOTb1|:SemanticsRule.PNot(* End *)(* Begin EvalPRange *)|Pattern_Range(e1,e2)->let*b1=let*v1=eval_expr_sefenve1inB.binopGEQvv1and*b2=let*v2=eval_expr_sefenve2inB.binopLEQvv2inB.binopBANDb1b2|:SemanticsRule.PRange(* End *)(* Begin EvalPSingle *)|Pattern_Singlee->let*v1=eval_expr_sefenveinB.binopEQ_OPvv1|:SemanticsRule.PSingle(* End *)(* Begin EvalPMask *)|Pattern_Maskm->letbvbv=L_BitVectorbv|>B.v_of_literalinletm_set=Bitvector.mask_setmandm_unset=Bitvector.mask_unsetminletm_specified=Bitvector.logorm_setm_unsetinlet*nv=B.unopNOTvinlet*v_set=B.binopAND(bvm_set)vand*v_unset=B.binopAND(bvm_unset)nvinlet*v_set_or_unset=B.binopORv_setv_unsetinB.binopEQ_OPv_set_or_unset(bvm_specified)|:SemanticsRule.PMask(* End *)(* Begin EvalPTuple *)|Pattern_Tupleps->letn=List.lengthpsinlet*vs=List.initn(funi->B.get_indexiv)|>sync_listinletbs=List.map2(eval_patternenvpos)vspsinconjunctionbs|:SemanticsRule.PTuple(* End *)(* Evaluation of Local Declarations *)(* -------------------------------- *)andeval_local_declldienvm_init:envmaybe_exceptionm=let()=iffalsethenFormat.eprintf"Evaluating %a.@."PP.pp_local_decl_itemldiinmatchldiwith(* Begin EvalLDVar *)|LDI_Varx->m_init>>=declare_local_identifierenvx>>=return_normal|:SemanticsRule.LDVar(* End *)(* Begin EvalLDTuple *)|LDI_Tupleldis->letn=List.lengthldisinlet*vm=m_initinletliv=List.initn(funi->B.returnvm>>=B.get_indexi)inletfolderenvmxvm=let**|env=envminvm>>=declare_local_identifierenvx>>=return_normalinList.fold_left2folder(return_normalenv)ldisliv|:SemanticsRule.LDTuple(* End *)(* Evaluation of Statements *)(* ------------------------ *)(** [eval_stmt env s] evaluates [s] in [env]. This is either an interruption
[Returning vs] or a continuation [env], see [eval_res]. *)andeval_stmt(env:env)s:stmt_eval_type=(iffalsethenmatchs.descwith|S_Seq_->()|_->Format.eprintf"@[<3>Eval@ @[%a@]@]@."PP.pp_stmts);matchs.descwith(* Begin EvalSPass *)|S_Pass->return_continueenv|:SemanticsRule.SPass(* End *)(* Begin EvalSAssignCall *)|S_Assign({desc=LE_Destructuringles;_},{desc=E_Call{name;params;args};_})whenList.for_alllexpr_is_varles->(* pass [params] and [args] as labelled arguments to avoid confusion *)let**|vms,env1=eval_call(to_poss)nameenv~params~argsinlet**|new_env=protected_multi_assigns.versionenv1slesvmsinreturn_continuenew_env|:SemanticsRule.SAssignCall(* End *)(* Begin EvalSAssign *)|S_Assign(le,re)->let*^m,env1=eval_exprenvreinlet**|new_env=eval_lexprs.versionleenv1minreturn_continuenew_env|:SemanticsRule.SAssign(* End *)(* Begin EvalSReturn *)|S_Return(Some{desc=E_Tuplees;_})->let**|ms,new_env=eval_expr_list_menvesinletscope=IEnv.get_scopenew_envinletfolderaccm=let*|i,vs=accinlet*v=minlet*()=B.on_write_identifier(return_identifieri)scopevinreturn(i+1,v::vs)inlet*|_i,vs=List.fold_leftfolder(return(0,[]))msinreturn_returnnew_env(List.revvs)|:SemanticsRule.SReturn|S_Return(Somee)->let**v,env1=eval_exprenveinlet*()=B.on_write_identifier(return_identifier0)(IEnv.get_scopeenv1)vinreturn_returnenv1[v]|:SemanticsRule.SReturn|S_ReturnNone->return_returnenv[]|:SemanticsRule.SReturn(* End *)(* Begin EvalSSeq *)|S_Seq(s1,s2)->let*>env1=eval_stmtenvs1ineval_stmtenv1s2|:SemanticsRule.SSeq(* End *)(* Begin EvalSCall *)|S_Call{name;params;args}->(* pass [params] and [args] as labelled arguments to avoid confusion *)let**|returned,env'=eval_call(to_poss)nameenv~params~argsinlet()=assert(returned=[])inreturn_continueenv'|:SemanticsRule.SCall(* End *)(* Begin EvalSCond *)|S_Cond(e,s1,s2)->let*^v,env'=eval_exprenveinchoice_with_branch_effectves1s2(eval_blockenv')|:SemanticsRule.SCond(* Begin EvalSAssert *)|S_Asserte->let*^v,env1=eval_exprenveinlet*=b=choicevtruefalseinifbthenreturn_continueenv1elsefatal_frome@@Error.AssertionFailede|:SemanticsRule.SAssert(* End *)(* Begin EvalSWhile *)|S_While(e,e_limit_opt,body)->let*limit_opt=eval_limitenve_limit_optinletenv=IEnv.tick_pushenvineval_loopstrueenvlimit_optebody|:SemanticsRule.SWhile(* End *)(* Begin EvalSRepeat *)|S_Repeat(body,e,e_limit_opt)->let*limit_opt1=eval_limitenve_limit_optinlet*limit_opt2=tick_loop_limitslimit_opt1inlet*>env1=eval_blockenvbodyinletenv2=IEnv.tick_push_bisenv1ineval_loopsfalseenv2limit_opt2ebody|:SemanticsRule.SRepeat(* End *)(* Begin EvalSFor *)|S_For{index_name;start_e;dir;end_e;body;limit=e_limit_opt}->(* The calls to [eval_expr_sef] are safe because Typing.annotate_stmt,
S_For case, checks that the bounds are side-effect-free. *)let*start_v=eval_expr_sefenvstart_eand*end_v=eval_expr_sefenvend_eand*limit_opt=eval_limitenve_limit_optin(* By typing *)letundet=B.is_undeterminedstart_v||B.is_undeterminedend_vinlet*|env1=declare_local_identifierenvindex_namestart_vinletenv2=ifundetthenIEnv.tick_push_bisenv1elseenv1inletloop_msg=ifundetthenPrintf.sprintf"for %s"index_nameelsePrintf.sprintf"for %s = %s %s %s"index_name(B.debug_valuestart_v)(PP.pp_for_directiondir)(B.debug_valueend_v)inlet*>env3=eval_forloop_msgundetenv2index_namelimit_optstart_vdirend_vbodyinletenv4=ifundetthenIEnv.tick_popenv3elseenv3inIEnv.remove_localindex_nameenv4|>return_continue|:SemanticsRule.SFor(* End *)(* Begin EvalSThrow *)|S_ThrowNone->return(Throwing(None,env))|:SemanticsRule.SThrow|S_Throw(Some(e,Somet))->let**v,new_env=eval_exprenveinletname=throw_identifier()andscope=B.Scope.global~init:falseinlet*()=B.on_write_identifiernamescopevinreturn(Throwing(Some((v,name,scope),t),new_env))|:SemanticsRule.SThrow|S_Throw(Some(_e,None))->fatal_fromsError.TypeInferenceNeeded(* End *)(* Begin EvalSTry *)|S_Try(s1,catchers,otherwise_opt)->lets_m=eval_blockenvs1ineval_catchersenvcatchersotherwise_opts_m|:SemanticsRule.STry(* End *)(* Begin EvalSDecl *)|S_Decl(_ldk,ldi,_ty_opt,Somee_init)->let*^m_init,env1=eval_exprenve_initinlet**|new_env=eval_local_declldienv1m_initinreturn_continuenew_env|:SemanticsRule.SDecl|S_Decl(_ldk,_ldi,_ty_opt,None)->fatal_fromsTypeInferenceNeeded(* End *)(* Begin EvalSPrint *)|S_Print{args=e_list;newline;debug}->let**v_list,new_env=eval_expr_listenve_listinlet()=ifdebugthenletopenFormatinletpp_valuefmtv=B.debug_valuev|>pp_print_stringfmtineprintf"@[@<2>%a:@ @[%a@]@ ->@ %a@]@."PP.pp_poss(pp_print_list~pp_sep:pp_print_spacePP.pp_expr)e_list(pp_print_list~pp_sep:pp_print_spacepp_value)v_listelse(List.mapB.debug_valuev_list|>String.concat""|>print_string;ifnewlinethenprint_newline()else())inreturn_continuenew_env|:SemanticsRule.SPrint(* End *)|S_Pragma_->assertfalse|S_Unreachable->fatal_fromsError.UnreachableReached(* Evaluation of Blocks *)(* -------------------- *)(* Begin EvalBlock *)andeval_blockenvstm=letblock_env=IEnv.push_scopeenvinlet*>block_env1=eval_stmtblock_envstminIEnv.pop_scopeenvblock_env1|>return_continue|:SemanticsRule.Block(* End *)(* Evaluation of while and repeat loops *)(* ------------------------------------ *)(* Evaluation of loop limits *)andeval_limitenve_limit_opt=matche_limit_optwith|None->returnNone|Somee_limit->((* The call to [eval_expr_sef] is safe because
[Typing.annotate_limit_expr] checks that the limit is statically
evaluable. *)let*v_limit=eval_expr_sefenve_limitinmatchB.v_to_zv_limitwith|Somelimit->return(Somelimit)|None->fatal_frome_limit(Error.MismatchType(B.debug_valuev_limit,[integer'])))andcheck_recurse_limitposnameenve_limit_opt=let*limit_opt=eval_limitenve_limit_optinmatchlimit_optwith|None->return()|Somelimit->letstack_size=IEnv.get_stack_sizenameenviniflimit<stack_sizethenfatal_fromposError.RecursionLimitReachedelsereturn()andtick_loop_limitloclimit_opt=matchlimit_optwith|None->returnNone|Somelimit->letnew_limit=Z.predlimitinifZ.signnew_limit>=0thenreturn(Somenew_limit)elsefatal_fromlocError.LoopLimitReached(* Begin EvalLoop *)andeval_looplocis_whileenvlimit_opte_condbody:stmt_eval_type=(* Name for warn messages. *)letloop_name=ifis_whilethen"while loop"else"repeat loop"inletloop_desc=(loop_name,loc)in(* Continuation in the positive case. *)letloopenv=let*limit_opt'=tick_loop_limitloclimit_optinlet*>env1=eval_blockenvbodyineval_looplocis_whileenv1limit_opt'e_condbodyin(* First we evaluate the condition *)let*^cond_m,env=eval_exprenve_condin(* Depending if we are in a while or a repeat,
we invert that condition. *)letcond_m=ifis_whilethencond_melsecond_m>>=B.unopBNOTin(* If needs be, we tick the unrolling stack before looping. *)B.delaycond_m@@funcondcond_m->letbinder=bind_maybe_unrollloop_desc(B.is_undeterminedcond)in(* Real logic: if condition is validated, we loop,
otherwise we continue to the next statement. *)choice_with_branch_effectcond_me_condloopreturn_continue(binder(return_continueenv))|:SemanticsRule.Loop(* End *)(* Evaluation of for loops *)(* ----------------------- *)(* Begin EvalFor *)andeval_forloop_msgundetenvindex_namelimit_optv_startdirv_endbody:stmt_eval_type=(* Evaluate the condition: "has the for loop terminated?" *)let*next_limit_opt=tick_loop_limitbodylimit_optinletcond_m=letcomp_for_dir=matchdirwithUp->LT|Down->GTinlet*()=B.on_read_identifierindex_name(IEnv.get_scopeenv)v_startinB.binopcomp_for_dirv_endv_startin(* Increase the loop counter *)letstepenvindex_namev_startdir=letop_for_dir=matchdirwithUp->PLUS|Down->MINUSinlet*()=B.on_read_identifierindex_name(IEnv.get_scopeenv)v_startinlet*v_step=B.binopop_for_dirv_startoneinlet*new_env=assign_local_identifierenvindex_namev_stepinreturn(v_step,new_env)in(* Continuation in the positive case. *)letloopenv=letloop_desc=("for loop",body)inbind_maybe_unrollloop_descundet(eval_blockenvbody)@@funenv1->let*|v_step,env2=stepenv1index_namev_startdirineval_forloop_msgundetenv2index_namenext_limit_optv_stepdirv_endbodyin(* Real logic: if the condition holds, we continue to the next
loop iteration, otherwise we loop. *)choice_with_branch_effect_msgcond_mloop_msgreturn_continueloop(funkont->kontenv)|:SemanticsRule.For(* End *)(* Evaluation of Catchers *)(* ---------------------- *)andeval_catchersenvcatchersotherwise_opts_m:stmt_eval_type=(* rethrow_implicit handles the implicit throwing logic, that is for
statement like:
try throw_my_exception ()
catch
when MyException => throw;
end
It edits the thrown value only in the case of an implicit throw and
we have a explicitely thrown exception in the context. More formally:
[rethrow_implicit to_throw m] is:
- [m] if [m] is [Normal _]
- [m] if [m] is [Throwing (Some _, _)]
- [Throwing (Some to_throw, g)] if [m] is [Throwing (None, g)] *)(* Begin EvalRethrowImplicit *)letrethrow_implicit(v,v_ty)s_m=B.bind_seqs_m@@function|Throwing(None,env_throw1)->Throwing(Some(v,v_ty),env_throw1)|>return|(Normal_|Throwing(Some_,_))asres->returnres|:SemanticsRule.RethrowImplicit(* End *)in(* [catcher_matches t c] returns true if the catcher [c] match the raised
exception type [t]. *)(* Begin EvalFindCatcher *)letcatcher_matches=letstatic_env={StaticEnv.emptywithglobal=env.global.static}infunv_ty(_e_name,e_ty,_stmt)->subtypesstatic_envv_tye_ty|:SemanticsRule.FindCatcher(* End *)in(* Main logic: *)(* If an explicit throw has been made in the [try] block: *)B.bind_seqs_m@@function(* Begin CatchNoThrow *)|(Normal_|Throwing(None,_))asres->returnres|:SemanticsRule.CatchNoThrow(* End *)|Throwing(Some(v,v_ty),env_throw)->((* We compute the environment in which to compute the catch statements. *)matchList.find_opt(catcher_matchesv_ty)catcherswith(* If any catcher matches the exception type: *)|Somecatcher->((* Begin EvalCatch *)matchcatcherwith|None,_e_ty,s->eval_blockenv_throws|>rethrow_implicit(v,v_ty)|:SemanticsRule.Catch(* Begin EvalCatchNamed *)|Somename,_e_ty,s->(* If the exception is declared to be used in the
catcher, we update the environment before executing [s]. *)let*|env2=read_value_fromv|>declare_local_identifier_menv_thrownamein(let*>env3=eval_blockenv2sinIEnv.remove_localnameenv3|>return_continue)|>rethrow_implicit(v,v_ty)|:SemanticsRule.CatchNamed(* End *))|None->((* Otherwise we try to execute the otherwise statement, or we
return the exception. *)matchotherwise_optwith(* Begin EvalCatchOtherwise *)|Somes->eval_blockenv_throws|>rethrow_implicit(v,v_ty)|:SemanticsRule.CatchOtherwise(* Begin EvalCatchNone *)|None->s_m|:SemanticsRule.CatchNone))(* End *)(* Evaluation of Function Calls *)(* ---------------------------- *)(** [eval_call pos name env ~params ~args] evaluates the call to function
[name] with arguments [args] and parameters [params].
The arguments/parameters are labelled to avoid confusion. *)(* Begin EvalCall *)andeval_callposnameenv~params~args=let*^vargs,env1=eval_expr_list_menvargsinlet*^vparams,env2=eval_expr_list_menv1paramsinlet*vargs=vargsand*vparams=vparamsinletgenv=IEnv.incr_stack_sizenameenv2.globalinletres=eval_subprogramgenvnamepos~params:vparams~args:vargsinB.bind_seqres@@function|Throwing(v,env_throw)->letgenv2=IEnv.decr_stack_sizenameenv_throw.globalinletnew_env=IEnv.{local=env2.local;global=genv2}inreturn(Throwing(v,new_env))|:SemanticsRule.Call|Normal(ms,global)->letms2=List.mapread_value_frommsinletgenv2=IEnv.decr_stack_sizenameglobalinletnew_env=IEnv.{local=env2.local;global=genv2}inreturn_normal(ms2,new_env)|:SemanticsRule.Call(* End *)(* Evaluation of Subprograms *)(* ----------------------- *)(** [eval_subprogram genv name pos ~params ~args] evaluates the function named [name]
in the global environment [genv], with [args] the actual arguments, and
[params] the positional parameters.
The arguments/parmeters are labelled to avoid confusion. *)andeval_subprogram(genv:IEnv.global)namepos~params~(args:B.valuemlist):func_eval_type=matchIMap.find_optnamegenv.static.subprogramswith(* Begin EvalFUndefIdent *)|None->fatal_frompos@@Error.UndefinedIdentifiername|:SemanticsRule.FUndefIdent(* End *)(* Begin EvalFPrimitive *)|Some({body=SB_Primitive_;_},_)->letscope=B.Scope.new_localnameinletbody=Hashtbl.findprimitive_runtimesnameinlet*ms=bodyparamsargsinlet_,vsm=List.fold_right(funm(i,acc)->letx=return_identifieriinletm'=let*|v=let*v=minlet*()=B.on_write_identifierxscopevinreturn(v,x,scope)and*vs=accinreturn(v::vs)in(i+1,m'))ms(0,return[])inlet*|vs=vsminreturn_normal(vs,genv)|:SemanticsRule.FPrimitive(* End *)(* Begin EvalFBadArity *)|Some({args=arg_decls;_},_)whenList.compare_lengthsargsarg_decls<>0->fatal_frompos@@Error.BadArity(Dynamic,name,List.lengtharg_decls,List.lengthargs)|:SemanticsRule.FBadArity|Some({parameters=parameter_decls;_},_)whenList.compare_lengthsparamsparameter_decls<>0->fatal_frompos@@Error.BadParameterArity(Dynamic,V1,name,List.lengthparameter_decls,List.lengthparams)|:SemanticsRule.FBadArity(* End *)(* Begin EvalFCall *)|Some({body=SB_ASLbody;args=arg_decls;parameters=param_decls;recurse_limit;_;},_)->(let()=iffalsethenFormat.eprintf"Evaluating %s.@."nameinletscope=B.Scope.new_localnameinletenv1=IEnv.{global=genv;local=local_empty_scopedscope}inlet*()=check_recurse_limitposnameenv1recurse_limitinletdeclare_argenvmxm=declare_local_identifier_mmenvmxminletarg_names=List.mapfstarg_declsinletenv2=List.fold_left2declare_arg(returnenv1)arg_namesargs|:SemanticsRule.AssignArgsinletparam_names=List.mapfstparam_declsinlet*|env3=List.fold_left2declare_argenv2param_namesparamsinlet**|res=eval_stmtenv3bodyinlet()=iffalsethenFormat.eprintf"Finished evaluating %s.@."nameinmatchreswith|Continuingenv4->return_normal([],env4.global)|Returning(xs,ret_genv)->letvs=List.mapi(funiv->(v,return_identifieri,scope))xsinreturn_normal(vs,ret_genv))|:SemanticsRule.FCall(* End *)(** [multi_assign env [le_1; ... ; le_n] [m_1; ... ; m_n]] is
[env[le_1 --> m_1] ... [le_n --> m_n]]. *)(* Begin EvalLEMultiAssign *)andmulti_assignverenvlesmonads:envmaybe_exceptionm=letfolderenvmlevm=let**|env=envmineval_lexprverleenvvminList.fold_left2folder(return_normalenv)lesmonads|:SemanticsRule.LEMultiAssign(* End *)(** As [multi_assign], but checks that [les] and [monads] have the same
length. *)andprotected_multi_assignverenvposlesmonads:envmaybe_exceptionm=ifList.compare_lengthslesmonads!=0thenfatal_frompos@@Error.BadArity(Dynamic,"tuple construction",List.lengthles,List.lengthmonads)elsemulti_assignverenvlesmonads(* Begin EvalSpec *)letrun_typed_envenv(static_env:StaticEnv.global)(ast:AST.t):B.valuem=let*|env=build_genvenveval_exprstatic_envastinlet*|res=eval_subprogramenv"main"dummy_annotated~params:[]~args:[]in(matchreswith|Normal([v],_genv)->read_value_fromv|Normal_->Error.(fatal_unknown_pos(MismatchedReturnValue"main"))|Throwing(v_opt,_genv)->letmsg=matchv_optwith|None->"implicitely thrown out of a try-catch."|Some((v,_,_scope),ty)->Format.asprintf"%a %s"PP.pp_tyty(B.debug_valuev)inError.fatal_unknown_pos(Error.UncaughtExceptionmsg))|:SemanticsRule.Specletrun_typedenvast=run_typed_env[]envast(* End *)end