123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117openPpxlibmoduleIf_sat=structmoduleBranch_names=structletthen_name="lname"letelse_name="rname"letbranch_name="name"letattribute_expr(attr:attribute)=matchattr.attr_payloadwith|PStr[{pstr_desc=Pstr_eval(expr,_);_}]->expr|_->Location.raise_errorf~loc:attr.attr_name.loc"Invalid branch name attribute payload"endmoduleExtension_name=structtypet=Sat|Sat1|Sureletto_string=functionSat->"sat"|Sat1->"sat1"|Sure->"sure"endletget_attr~nameexpr=List.find_opt(funattr->attr.attr_name.txt=name)expr.pexp_attributesletoverride_attr_opt~nameexpr(new_attr:attributeoption)=matchnew_attrwith|None->expr|Somenew_attr->(letexisting_attr=get_attr~nameexprinmatchexisting_attrwith|Some_->Location.raise_errorf~loc:new_attr.attr_name.loc"Branch name attribute specified multiple times"|None->letnew_attr={new_attrwithattr_name={new_attr.attr_namewithtxt=name};}in{exprwithpexp_attributes=new_attr::expr.pexp_attributes})letassociated_fn~loc=function|Extension_name.Sat->[%exprSymex_syntax.branch_on]|Sat1->[%exprSymex_syntax.branch_on_take_one]|Sure->[%exprSymex_syntax.if_sure](* Build the location-suffixed branch name as a compile-time string constant
instead of a runtime [String.cat ... __LOC__] call.
Our previous implementation allocated a fresh string on every [if%sat] hit
even when logs are disabled — millions of allocations per symex run. *)letloc_string(loc:Location.t)=Printf.sprintf"File %S, line %d, characters %d-%d"loc.loc_start.pos_fnameloc.loc_start.pos_lnum(loc.loc_start.pos_cnum-loc.loc_start.pos_bol)(loc.loc_end.pos_cnum-loc.loc_start.pos_bol)letexpand_if~loc~extguardthen_else_=letassociated_fn=associated_fn~locextinlethere=loc_stringlocinletlname_attr=get_attr~name:Branch_names.branch_namethen_inletrname_attr=get_attr~name:Branch_names.branch_nameelse_inletlname_expr=matchlname_attrwith|Someattr->Branch_names.attribute_exprattr|None->Ast_builder.Default.estring~loc("Left branch at "^here)inletrname_expr=matchrname_attrwith|Someattr->Branch_names.attribute_exprattr|None->Ast_builder.Default.estring~loc("Right branch at "^here)in[%expr[%eassociated_fn][%eguard]~left_branch_name:[%elname_expr]~right_branch_name:[%ername_expr]~then_:(fun()->[%ethen_])~else_:(fun()->[%eelse_])]letexpand~extexpr=letloc={expr.pexp_locwithloc_ghost=true}inletexpansion=matchexprwith|[%exprif[%e?guard]then[%e?then_]else[%e?else_]]aswhole_expr->letthen_=get_attr~name:Branch_names.then_namewhole_expr|>override_attr_opt~name:Branch_names.branch_namethen_inletelse_=get_attr~name:Branch_names.else_namewhole_expr|>override_attr_opt~name:Branch_names.branch_nameelse_inexpand_if~loc~extguardthen_else_|[%exprif[%e?_]then[%e?_]]->Location.raise_errorf~loc"'if%%%s' must include an else branch"(Extension_name.to_stringext)|_->Location.raise_errorf~loc"%%sat can only be used with 'if'"in{expansionwithpexp_attributes=expr.pexp_attributes@expansion.pexp_attributes;}endmoduleSym_constants=structletrewriterlocs=leti=int_of_stringsinletei=Ast_builder.Default.eint~lociinifi=0then[%exprSym_int_syntax.zero()]elseifi=1then[%exprSym_int_syntax.one()]else[%exprSym_int_syntax.mk_nonzero[%eei]]letsuffix='s'end