123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-2023 The MOPSA Project. *)(* *)(* This program is free software: you can redistribute it and/or modify *)(* it under the terms of the GNU Lesser General Public License as published *)(* by the Free Software Foundation, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)openCore.AllopenMopsa_utilsopenLocationopenFormattypeaction=|Execofstmt*route|Evalofexpr*route*semanticletaction_range=function|Exec(stmt,_)->stmt.srange|Eval(expr,_,_)->expr.erangeletaction_vars=function|Exec(stmt,_)->stmt_varsstmt|Eval(expr,_,_)->expr_varsexprletaction_line_optaction=letrange=action_rangeactioninifnot(Location.is_orig_rangerange)thenNoneelseletfile=Location.get_range_filerangeinletline=Location.get_range_linerangeinSome(file,line)(** Get the variables appearing in the line of an action *)letaction_line_varsaction=matchaction_line_optactionwith|None->[]|Some(_,line)->letvisit_expracce=ifnot(Location.is_orig_rangee.erange)thenVisitPartsaccelseletline'=Location.get_range_linee.erangeinifline=line'thenKeep(acc@expr_varse)elseVisitPartsaccinletvisit_stmtaccs=VisitPartsaccinmatchactionwith|Exec(stmt,_)->fold_stmtvisit_exprvisit_stmt[]stmt|Eval(expr,_,_)->fold_exprvisit_exprvisit_stmt[]expr(* Get the number of digits of an integer *)letnb_digitsn=int_of_float(log10(float_of_intn))+1(* Right align an integer *)letpp_right_align_intwidthfmti=letdigits=nb_digitsiinfprintffmt"%s%d"(String.init(width-digits)(fun_->' '))iletpp_right_alignwidthppfmtx=lets=asprintf"%a"ppxinletlen=String.lengthsinfprintffmt"%s%s"(String.init(width-len)(fun_->' '))s(* Format has issues when identing in presence of unicode characters. So we
do it manually. *)letfix_string_indentationindents=letlines=String.split_on_char'\n'sinmatchlineswith|[]->""|[_]->s|hd::tl->letlines'=hd::List.map(funl->(String.makeindent' ')^" "^l)tlinString.concat"\n"lines'lettruncate_strings=letlines=String.split_on_char'\n'sinmatchlineswith|[]|[_]->s|hd::tl->hd^" ..."letpp_exec~truncate~indentfmtstmt=lets=asprintf"@[<v>%a@]"pp_stmtstmtinfprintffmt"%a %a %s %a"Debug.(color45pp_print_string)"𝕊"Debug.(color45pp_print_string)"⟦"(iftruncatethentruncate_stringselsefix_string_indentationindents)Debug.(color45pp_print_string)"⟧"letpp_eval~truncate~indentfmtexp=lets=asprintf"@[<v>%a@]"pp_exprexpinfprintffmt"%a %a %s : %a %a"Debug.(color209pp_print_string)"𝔼"Debug.(color209pp_print_string)"⟦"(iftruncatethentruncate_stringselsefix_string_indentationindents)pp_typexp.etypDebug.(color209pp_print_string)"⟧"letpp_action?(truncate=false)?(indent=0)fmtaction=matchactionwith|Exec(stmt,_)->pp_exec~truncate~indentfmtstmt|Eval(exp,_,_)->pp_eval~truncate~indentfmtexp(** Print source code of an action *)letpp_action_source_codefmtaction=(* Entry point *)letrecdoit()=letrange=action_rangeactioninifnot(is_orig_range(untag_rangerange))then()elseletstart=get_range_startrangeinletfile=start.pos_fileinletline=start.pos_lineinifnot(Sys.file_existsfile)then()elseletch=open_infileinletbefore,at,after=read_lines_aroundchlineinletmax_line=line+List.lengthafterinletmax_digits=nb_digitsmax_lineinList.iter(pp_surrounding_linemax_digitsstd_formatter)before;pp_target_linemax_digitsstd_formatterat;List.iter(pp_surrounding_linemax_digitsstd_formatter)after;close_inch(* Read lines before and after a target line *)andread_lines_aroundchline=letreciterbeforeatafteri=letlo=trySome(input_linech)withEnd_of_file->Noneinmatchlowith|Somel->ifi<line-5theniterbeforeatafter(i+1)elseifi>line+5then(before,at,after)elseifi<linetheniter((i,l)::before)atafter(i+1)elseifi=linetheniterbefore(i,l)after(i+1)elseiterbeforeat((i,l)::after)(i+1)|None->(before,at,after)inletbefore,at,after=iter[](0,"")[]1inList.revbefore,at,List.revafter(* Print a surrounding line *)andpp_surrounding_linemax_linefmt(i,l)=fprintffmt" %a %s@."(pp_right_align_intmax_line)il(* Print the target line *)andpp_target_linemax_linefmt(i,l)=fprintffmt" %a %a %a@."Debug.(color118pp_print_string)"►"Debug.(color118(pp_right_align_intmax_line))iDebug.(color118pp_print_string)lindoit()