Summary: The debugger in the middle of the evaluation makes working on that file difficult. Separating modules a bit, so that we can change the code easier. This is in preparation to trying to add aliases and witnesses to formulas in a next diff. Reviewed By: jvillard Differential Revision: D18708542 fbshipit-source-id: 523f30fc9master
parent
c3e16dbdbc
commit
75794301dc
@ -0,0 +1,340 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
open! IStd
|
||||
module L = Logging
|
||||
|
||||
let pp_ast ~ast_node_to_highlight ?(prettifier = Fn.id) fmt root =
|
||||
let open Ctl_parser_types in
|
||||
let pp_node_info fmt an =
|
||||
let name = Ctl_parser_types.ast_node_name an in
|
||||
let typ = Ctl_parser_types.ast_node_type an in
|
||||
let cast_kind = Ctl_parser_types.ast_node_cast_kind an in
|
||||
Format.fprintf fmt " %s %s %s" name typ cast_kind
|
||||
in
|
||||
let rec pp_children pp_node wrapper fmt level nodes =
|
||||
match nodes with
|
||||
| [] ->
|
||||
()
|
||||
| node :: nodes ->
|
||||
pp_node fmt (wrapper node) level "|-" ;
|
||||
pp_children pp_node wrapper fmt level nodes
|
||||
in
|
||||
let rec pp_ast_aux fmt root level prefix =
|
||||
let get_node_name (an : ast_node) =
|
||||
match an with
|
||||
| Stmt stmt ->
|
||||
Clang_ast_proj.get_stmt_kind_string stmt
|
||||
| Decl decl ->
|
||||
Clang_ast_proj.get_decl_kind_string decl
|
||||
in
|
||||
let should_highlight =
|
||||
match (root, ast_node_to_highlight) with
|
||||
| Stmt r, Stmt n ->
|
||||
phys_equal r n
|
||||
| Decl r, Decl n ->
|
||||
phys_equal r n
|
||||
| _ ->
|
||||
false
|
||||
in
|
||||
let node_name =
|
||||
let node_name = get_node_name root in
|
||||
if should_highlight then prettifier node_name else node_name
|
||||
in
|
||||
let spaces = String.make (level * String.length prefix) ' ' in
|
||||
let next_level = level + 1 in
|
||||
Format.fprintf fmt "%s%s%s %a@\n" spaces prefix node_name pp_node_info root ;
|
||||
match root with
|
||||
| Stmt (DeclStmt (_, stmts, ([VarDecl _] as var_decl))) ->
|
||||
(* handling special case of DeclStmt with VarDecl: emit the VarDecl node
|
||||
then emit the statements in DeclStmt as children of VarDecl. This is
|
||||
because despite being equal, the statements inside VarDecl and those
|
||||
inside DeclStmt belong to different instances, hence they fail the
|
||||
phys_equal check that should colour them *)
|
||||
pp_children pp_ast_aux (fun n -> Decl n) fmt next_level var_decl ;
|
||||
pp_stmts fmt (next_level + 1) stmts
|
||||
| Stmt stmt ->
|
||||
let _, stmts = Clang_ast_proj.get_stmt_tuple stmt in
|
||||
pp_stmts fmt next_level stmts
|
||||
| Decl decl ->
|
||||
let decls =
|
||||
Clang_ast_proj.get_decl_context_tuple decl
|
||||
|> Option.map ~f:(fun (decls, _) -> decls)
|
||||
|> Option.value ~default:[]
|
||||
in
|
||||
pp_decls fmt next_level decls
|
||||
and pp_stmts fmt level stmts = pp_children pp_ast_aux (fun n -> Stmt n) fmt level stmts
|
||||
and pp_decls fmt level decls = pp_children pp_ast_aux (fun n -> Decl n) fmt level decls in
|
||||
pp_ast_aux fmt root 0 ""
|
||||
|
||||
|
||||
module EvaluationTracker = struct
|
||||
exception Empty_stack of string
|
||||
|
||||
type eval_result = Eval_undefined | Eval_true | Eval_false
|
||||
|
||||
type content =
|
||||
{ ast_node: Ctl_parser_types.ast_node
|
||||
; phi: CTLTypes.t
|
||||
; lcxt: CLintersContext.context
|
||||
; eval_result: eval_result
|
||||
; witness: Ctl_parser_types.ast_node option }
|
||||
|
||||
type eval_node = {id: int; content: content}
|
||||
|
||||
type tree = Tree of eval_node * tree list
|
||||
|
||||
type ast_node_to_display =
|
||||
(* the node can be used to describe further sub calls in the evaluation stack *)
|
||||
| Carry_forward of Ctl_parser_types.ast_node
|
||||
(* the node cannot be further used to describe sub calls in the evaluation stack *)
|
||||
| Last_occurrence of Ctl_parser_types.ast_node
|
||||
|
||||
type t =
|
||||
{ next_id: int
|
||||
; eval_stack: (tree * ast_node_to_display) Stack.t
|
||||
; forest: tree list
|
||||
; breakpoint_line: int option
|
||||
; debugger_active: bool }
|
||||
|
||||
let create_content ast_node phi lcxt =
|
||||
{ast_node; phi; eval_result= Eval_undefined; lcxt; witness= None}
|
||||
|
||||
|
||||
let create source_file =
|
||||
let breakpoint_token = "INFER_BREAKPOINT" in
|
||||
let breakpoint_line =
|
||||
In_channel.read_lines (SourceFile.to_abs_path source_file)
|
||||
|> List.findi ~f:(fun _ line -> String.is_substring line ~substring:breakpoint_token)
|
||||
|> Option.map ~f:(fun (i, _) -> i + 1)
|
||||
in
|
||||
{next_id= 0; eval_stack= Stack.create (); forest= []; breakpoint_line; debugger_active= false}
|
||||
|
||||
|
||||
let explain t ~eval_node ~ast_node_to_display =
|
||||
let open Ctl_parser_types in
|
||||
let line_number an =
|
||||
let line_of_source_range (sr : Clang_ast_t.source_range) =
|
||||
let loc_info, _ = sr in
|
||||
loc_info.sl_line
|
||||
in
|
||||
match an with
|
||||
| Stmt stmt ->
|
||||
let stmt_info, _ = Clang_ast_proj.get_stmt_tuple stmt in
|
||||
line_of_source_range stmt_info.si_source_range
|
||||
| Decl decl ->
|
||||
let decl_info = Clang_ast_proj.get_decl_tuple decl in
|
||||
line_of_source_range decl_info.di_source_range
|
||||
in
|
||||
let stop_and_explain_step () =
|
||||
let highlight_style =
|
||||
match eval_node.content.eval_result with
|
||||
| Eval_undefined ->
|
||||
ANSITerminal.[Bold]
|
||||
| Eval_true ->
|
||||
ANSITerminal.[Bold; green]
|
||||
| Eval_false ->
|
||||
ANSITerminal.[Bold; red]
|
||||
in
|
||||
let ast_node_to_highlight = eval_node.content.ast_node in
|
||||
let ast_root, is_last_occurrence =
|
||||
match ast_node_to_display with
|
||||
| Carry_forward n ->
|
||||
(n, false)
|
||||
| Last_occurrence n ->
|
||||
(n, true)
|
||||
in
|
||||
let witness_str =
|
||||
match eval_node.content.witness with
|
||||
| Some witness ->
|
||||
"\n- witness: "
|
||||
^ Ctl_parser_types.ast_node_kind witness
|
||||
^ " "
|
||||
^ Ctl_parser_types.ast_node_name witness
|
||||
| None ->
|
||||
""
|
||||
in
|
||||
let ast_str =
|
||||
Format.asprintf "%a %s"
|
||||
(pp_ast ~ast_node_to_highlight ~prettifier:(ANSITerminal.sprintf highlight_style "%s"))
|
||||
ast_root witness_str
|
||||
in
|
||||
L.progress "@\nNode ID: %d\tEvaluation stack level: %d\tSource line-number: %s@\n"
|
||||
eval_node.id (Stack.length t.eval_stack)
|
||||
(Option.value_map ~default:"Unknown" ~f:string_of_int (line_number ast_node_to_highlight)) ;
|
||||
let is_eval_result_undefined =
|
||||
match eval_node.content.eval_result with Eval_undefined -> true | _ -> false
|
||||
in
|
||||
if is_last_occurrence && is_eval_result_undefined then
|
||||
L.progress "From this step, a transition to a different part of the AST may follow.@\n" ;
|
||||
let phi_str = Format.asprintf "%a" CTLTypes.pp_formula eval_node.content.phi in
|
||||
L.progress "CTL Formula: %s@\n@\n" phi_str ;
|
||||
L.progress "%s@\n" ast_str ;
|
||||
let quit_token = "q" in
|
||||
L.progress "Press Enter to continue or type %s to quit... @?" quit_token ;
|
||||
match In_channel.input_line_exn In_channel.stdin |> String.lowercase with
|
||||
| s when String.equal s quit_token ->
|
||||
L.exit 0
|
||||
| _ ->
|
||||
(* Remove the line at the bottom of terminal with the debug instructions *)
|
||||
let open ANSITerminal in
|
||||
(* move one line up, as current line is the one generated by pressing enter *)
|
||||
move_cursor 0 (-1) ;
|
||||
move_bol () ;
|
||||
(* move to the beginning of the line *)
|
||||
erase Below
|
||||
(* erase what follows the cursor's position *)
|
||||
in
|
||||
match (t.debugger_active, t.breakpoint_line, line_number eval_node.content.ast_node) with
|
||||
| false, Some break_point_ln, Some ln when ln >= break_point_ln ->
|
||||
L.progress "Attaching debugger at line %d" ln ;
|
||||
stop_and_explain_step () ;
|
||||
{t with debugger_active= true}
|
||||
| true, _, _ ->
|
||||
stop_and_explain_step () ; t
|
||||
| _ ->
|
||||
t
|
||||
|
||||
|
||||
let eval_begin t content =
|
||||
let node = {id= t.next_id; content} in
|
||||
let create_subtree root = Tree (root, []) in
|
||||
let subtree' = create_subtree node in
|
||||
let ast_node_from_previous_call =
|
||||
match Stack.top t.eval_stack with
|
||||
| Some (_, Last_occurrence _) ->
|
||||
content.ast_node
|
||||
| Some (_, Carry_forward an) ->
|
||||
an
|
||||
| None ->
|
||||
content.ast_node
|
||||
in
|
||||
let ast_node_to_display =
|
||||
if CTLTypes.has_transition content.phi then Last_occurrence ast_node_from_previous_call
|
||||
else Carry_forward ast_node_from_previous_call
|
||||
in
|
||||
Stack.push t.eval_stack (subtree', ast_node_to_display) ;
|
||||
let t' = explain t ~eval_node:node ~ast_node_to_display in
|
||||
{t' with next_id= t.next_id + 1}
|
||||
|
||||
|
||||
let eval_end t result =
|
||||
let result_bool = Option.is_some result in
|
||||
let eval_result_of_bool = function true -> Eval_true | false -> Eval_false in
|
||||
if Stack.is_empty t.eval_stack then
|
||||
raise (Empty_stack "Unbalanced number of eval_begin/eval_end invocations") ;
|
||||
let evaluated_tree, eval_node, ast_node_to_display =
|
||||
match Stack.pop_exn t.eval_stack with
|
||||
| Tree (({id= _; content} as eval_node), children), ast_node_to_display ->
|
||||
let content' =
|
||||
{content with eval_result= eval_result_of_bool result_bool; witness= result}
|
||||
in
|
||||
let eval_node' = {eval_node with content= content'} in
|
||||
(Tree (eval_node', children), eval_node', ast_node_to_display)
|
||||
in
|
||||
let t' = explain t ~eval_node ~ast_node_to_display in
|
||||
let forest' =
|
||||
if Stack.is_empty t'.eval_stack then evaluated_tree :: t'.forest
|
||||
else
|
||||
let parent =
|
||||
match Stack.pop_exn t'.eval_stack with
|
||||
| Tree (node, children), ntd ->
|
||||
(Tree (node, evaluated_tree :: children), ntd)
|
||||
in
|
||||
Stack.push t'.eval_stack parent ; t'.forest
|
||||
in
|
||||
{t' with forest= forest'}
|
||||
|
||||
|
||||
let equal_ast_node = Poly.equal
|
||||
|
||||
module DottyPrinter = struct
|
||||
let dotty_of_ctl_evaluation t =
|
||||
let open CTLTypes in
|
||||
let open Ctl_parser_types in
|
||||
let buffer_content buf =
|
||||
let result = Buffer.contents buf in
|
||||
Buffer.reset buf ; result
|
||||
in
|
||||
let dotty_of_tree cluster_id tree =
|
||||
let get_root tree = match tree with Tree (root, _) -> root in
|
||||
let get_children tree = match tree with Tree (_, children) -> List.rev children in
|
||||
(* shallow: emit dotty about root node and edges to its children *)
|
||||
let shallow_dotty_of_tree tree =
|
||||
let root_node = get_root tree in
|
||||
let children = get_children tree in
|
||||
let edge child_node =
|
||||
if equal_ast_node root_node.content.ast_node child_node.content.ast_node then
|
||||
Printf.sprintf "%d -> %d [style=dotted]" root_node.id child_node.id
|
||||
else Printf.sprintf "%d -> %d [style=bold]" root_node.id child_node.id
|
||||
in
|
||||
let color =
|
||||
match root_node.content.eval_result with
|
||||
| Eval_true ->
|
||||
"green"
|
||||
| Eval_false ->
|
||||
"red"
|
||||
| _ ->
|
||||
L.(die InternalError) "Tree is not fully evaluated"
|
||||
in
|
||||
let label =
|
||||
let string_of_lcxt c =
|
||||
match c.CLintersContext.et_evaluation_node with
|
||||
| Some s ->
|
||||
"et_evaluation_node = " ^ s
|
||||
| _ ->
|
||||
"et_evaluation_node = NONE"
|
||||
in
|
||||
let string_of_ast_node an =
|
||||
match an with
|
||||
| Stmt stmt ->
|
||||
Clang_ast_proj.get_stmt_kind_string stmt
|
||||
| Decl decl ->
|
||||
Clang_ast_proj.get_decl_kind_string decl
|
||||
in
|
||||
let smart_string_of_formula phi =
|
||||
let num_children = List.length children in
|
||||
match phi with
|
||||
| And _ when Int.equal num_children 2 ->
|
||||
"(...) AND (...)"
|
||||
| Or _ when Int.equal num_children 2 ->
|
||||
"(...) OR (...)"
|
||||
| Implies _ when Int.equal num_children 2 ->
|
||||
"(...) ==> (...)"
|
||||
| Not _ ->
|
||||
"NOT(...)"
|
||||
| _ ->
|
||||
Format.asprintf "%a" CTLTypes.pp_formula phi
|
||||
in
|
||||
Format.sprintf "(%d)\\n%s\\n%s\\n%s" root_node.id
|
||||
(Escape.escape_dotty (string_of_ast_node root_node.content.ast_node))
|
||||
(Escape.escape_dotty (string_of_lcxt root_node.content.lcxt))
|
||||
(Escape.escape_dotty (smart_string_of_formula root_node.content.phi))
|
||||
in
|
||||
let edges =
|
||||
let buf = Buffer.create 16 in
|
||||
List.iter
|
||||
~f:(fun subtree -> Buffer.add_string buf (edge (get_root subtree) ^ "\n"))
|
||||
children ;
|
||||
buffer_content buf
|
||||
in
|
||||
Printf.sprintf "%d [label=\"%s\" shape=box color=%s]\n%s\n" root_node.id label color edges
|
||||
in
|
||||
let rec traverse buf tree =
|
||||
Buffer.add_string buf (shallow_dotty_of_tree tree) ;
|
||||
List.iter ~f:(traverse buf) (get_children tree)
|
||||
in
|
||||
let buf = Buffer.create 16 in
|
||||
traverse buf tree ;
|
||||
Printf.sprintf "subgraph cluster_%d {\n%s\n}" cluster_id (buffer_content buf)
|
||||
in
|
||||
let buf = Buffer.create 16 in
|
||||
List.iteri
|
||||
~f:(fun cluster_id tree -> Buffer.add_string buf (dotty_of_tree cluster_id tree ^ "\n"))
|
||||
(List.rev t.forest) ;
|
||||
Printf.sprintf "digraph CTL_Evaluation {\n%s\n}\n" (buffer_content buf)
|
||||
end
|
||||
end
|
@ -0,0 +1,48 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
|
||||
module EvaluationTracker : sig
|
||||
type eval_result = Eval_undefined | Eval_true | Eval_false
|
||||
|
||||
type content =
|
||||
{ ast_node: Ctl_parser_types.ast_node
|
||||
; phi: CTLTypes.t
|
||||
; lcxt: CLintersContext.context
|
||||
; eval_result: eval_result
|
||||
; witness: Ctl_parser_types.ast_node option }
|
||||
|
||||
type eval_node = {id: int; content: content}
|
||||
|
||||
type tree = Tree of eval_node * tree list
|
||||
|
||||
type ast_node_to_display =
|
||||
(* the node can be used to describe further sub calls in the evaluation stack *)
|
||||
| Carry_forward of Ctl_parser_types.ast_node
|
||||
(* the node cannot be further used to describe sub calls in the evaluation stack *)
|
||||
| Last_occurrence of Ctl_parser_types.ast_node
|
||||
|
||||
type t =
|
||||
{ next_id: int
|
||||
; eval_stack: (tree * ast_node_to_display) Stack.t
|
||||
; forest: tree list
|
||||
; breakpoint_line: int option
|
||||
; debugger_active: bool }
|
||||
|
||||
val create : SourceFile.t -> t
|
||||
|
||||
val create_content : Ctl_parser_types.ast_node -> CTLTypes.t -> CLintersContext.context -> content
|
||||
|
||||
val eval_begin : t -> content -> t
|
||||
|
||||
val eval_end : t -> Ctl_parser_types.ast_node option -> t
|
||||
|
||||
module DottyPrinter : sig
|
||||
val dotty_of_ctl_evaluation : t -> string
|
||||
end
|
||||
end
|
@ -0,0 +1,62 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
|
||||
(**
|
||||
This module defines a language to define checkers. These checkers are interpreted over the AST of
|
||||
the program. A checker is defined by a CTL formula which expresses a condition saying when the
|
||||
checker should report a problem.
|
||||
*)
|
||||
|
||||
(** "set" clauses are used for defining mandatory variables that will be used
|
||||
by when reporting issues: eg for defining the condition.
|
||||
|
||||
"desc" clauses are used for defining the error message,
|
||||
the suggestion, the severity.
|
||||
|
||||
"let" clauses are used to define temporary formulas which are then
|
||||
used to abbreviate the another formula. For example
|
||||
|
||||
let f = a And B
|
||||
|
||||
set formula = f OR f
|
||||
|
||||
set message = "bla"
|
||||
|
||||
*)
|
||||
|
||||
type clause =
|
||||
| CLet of ALVar.formula_id * ALVar.t list * CTLTypes.t (** Let clause: let id = definifion; *)
|
||||
| CSet of ALVar.keyword * CTLTypes.t (** Set clause: set id = definition *)
|
||||
| CDesc of ALVar.keyword * string (** Description clause eg: set message = "..." *)
|
||||
| CPath of [`WhitelistPath | `BlacklistPath] * ALVar.t list
|
||||
|
||||
type ctl_checker =
|
||||
{id: string (** Checker's id *); definitions: clause list (** A list of let/set definitions *)}
|
||||
|
||||
type al_file =
|
||||
{ import_files: string list
|
||||
; global_macros: clause list
|
||||
; global_paths: (string * ALVar.alexp list) list
|
||||
; checkers: ctl_checker list }
|
||||
|
||||
val print_checker : ctl_checker -> unit
|
||||
|
||||
val eval_formula :
|
||||
CTLTypes.t
|
||||
-> Ctl_parser_types.ast_node
|
||||
-> CLintersContext.context
|
||||
-> Ctl_parser_types.ast_node option
|
||||
(** return the evaluation of the formula and a witness *)
|
||||
|
||||
val save_dotty_when_in_debug_mode : SourceFile.t -> unit
|
||||
|
||||
val next_state_via_transition :
|
||||
Ctl_parser_types.ast_node -> CTLTypes.transitions -> Ctl_parser_types.ast_node list
|
||||
|
||||
val create_ctl_evaluation_tracker : SourceFile.t -> unit
|
@ -0,0 +1,177 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
|
||||
(** Transition labels used for example to switch from decl to stmt *)
|
||||
type transitions =
|
||||
| AccessorForProperty of ALVar.alexp (** decl to decl *)
|
||||
| Body (** decl to stmt *)
|
||||
| FieldName of ALVar.alexp (** stmt to stmt, decl to decl *)
|
||||
| Fields (** stmt to stmt, decl to decl *)
|
||||
| InitExpr (** decl to stmt *)
|
||||
| Super (** decl to decl *)
|
||||
| ParameterName of ALVar.alexp (** stmt to stmt, decl to decl *)
|
||||
| ParameterPos of ALVar.alexp (** stmt to stmt, decl to decl *)
|
||||
| Parameters (** stmt to stmt, decl to decl *)
|
||||
| Cond
|
||||
| PointerToDecl (** stmt to decl *)
|
||||
| Protocol (** decl to decl *)
|
||||
| Sibling (** decl to decl *)
|
||||
| SourceExpr
|
||||
[@@deriving compare]
|
||||
|
||||
let is_transition_to_successor trans =
|
||||
match trans with
|
||||
| Body
|
||||
| InitExpr
|
||||
| FieldName _
|
||||
| Fields
|
||||
| ParameterName _
|
||||
| ParameterPos _
|
||||
| Parameters
|
||||
| Cond
|
||||
| SourceExpr ->
|
||||
true
|
||||
| Super | PointerToDecl | Protocol | AccessorForProperty _ | Sibling ->
|
||||
false
|
||||
|
||||
|
||||
(* In formulas below prefix
|
||||
"E" means "exists a path"
|
||||
"A" means "for all path" *)
|
||||
|
||||
type t =
|
||||
(* A ctl formula *)
|
||||
| True
|
||||
| False
|
||||
(* not really necessary but it makes it evaluation faster *)
|
||||
| Atomic of CPredicates.t
|
||||
| Not of t
|
||||
| And of t * t
|
||||
| Or of t * t
|
||||
| Implies of t * t
|
||||
| InNode of ALVar.alexp list * t
|
||||
| AX of transitions option * t
|
||||
| EX of transitions option * t
|
||||
| AF of transitions option * t
|
||||
| EF of transitions option * t
|
||||
| AG of transitions option * t
|
||||
| EG of transitions option * t
|
||||
| AU of transitions option * t * t
|
||||
| EU of transitions option * t * t
|
||||
| EH of ALVar.alexp list * t
|
||||
| ET of ALVar.alexp list * transitions option * t
|
||||
| InObjCClass of t * t
|
||||
[@@deriving compare]
|
||||
|
||||
let equal = [%compare.equal: t]
|
||||
|
||||
let has_transition phi =
|
||||
match phi with
|
||||
| True | False | Atomic _ | Not _ | And _ | Or _ | Implies _ | InNode _ | EH _ | InObjCClass _ ->
|
||||
false
|
||||
| AX (trans_opt, _)
|
||||
| AF (trans_opt, _)
|
||||
| AG (trans_opt, _)
|
||||
| AU (trans_opt, _, _)
|
||||
| EX (trans_opt, _)
|
||||
| EF (trans_opt, _)
|
||||
| EG (trans_opt, _)
|
||||
| EU (trans_opt, _, _)
|
||||
| ET (_, trans_opt, _) ->
|
||||
Option.is_some trans_opt
|
||||
|
||||
|
||||
let pp_transition fmt trans_opt =
|
||||
let pp_aux fmt trans =
|
||||
match trans with
|
||||
| AccessorForProperty kind ->
|
||||
Format.pp_print_string fmt ("AccessorForProperty " ^ ALVar.alexp_to_string kind)
|
||||
| Body ->
|
||||
Format.pp_print_string fmt "Body"
|
||||
| FieldName name ->
|
||||
Format.pp_print_string fmt ("FieldName " ^ ALVar.alexp_to_string name)
|
||||
| Fields ->
|
||||
Format.pp_print_string fmt "Fields"
|
||||
| InitExpr ->
|
||||
Format.pp_print_string fmt "InitExpr"
|
||||
| Super ->
|
||||
Format.pp_print_string fmt "Super"
|
||||
| ParameterName name ->
|
||||
Format.pp_print_string fmt ("ParameterName " ^ ALVar.alexp_to_string name)
|
||||
| ParameterPos pos ->
|
||||
Format.pp_print_string fmt ("ParameterPos " ^ ALVar.alexp_to_string pos)
|
||||
| Parameters ->
|
||||
Format.pp_print_string fmt "Parameters"
|
||||
| Cond ->
|
||||
Format.pp_print_string fmt "Cond"
|
||||
| Protocol ->
|
||||
Format.pp_print_string fmt "Protocol"
|
||||
| PointerToDecl ->
|
||||
Format.pp_print_string fmt "PointerToDecl"
|
||||
| Sibling ->
|
||||
Format.pp_print_string fmt "Sibling"
|
||||
| SourceExpr ->
|
||||
Format.pp_print_string fmt "SourceExpr"
|
||||
in
|
||||
match trans_opt with Some trans -> pp_aux fmt trans | None -> Format.pp_print_char fmt '_'
|
||||
|
||||
|
||||
(* a flag to print more or less in the dotty graph *)
|
||||
let full_print = true
|
||||
|
||||
let rec pp_formula fmt phi =
|
||||
let nodes_to_string nl = List.map ~f:ALVar.alexp_to_string nl in
|
||||
match phi with
|
||||
| True ->
|
||||
Format.pp_print_string fmt "True"
|
||||
| False ->
|
||||
Format.pp_print_string fmt "False"
|
||||
| Atomic p ->
|
||||
CPredicates.pp_predicate fmt p
|
||||
| Not phi ->
|
||||
if full_print then Format.fprintf fmt "NOT(%a)" pp_formula phi
|
||||
else Format.pp_print_string fmt "NOT(...)"
|
||||
| And (phi1, phi2) ->
|
||||
if full_print then Format.fprintf fmt "(%a AND %a)" pp_formula phi1 pp_formula phi2
|
||||
else Format.pp_print_string fmt "(... AND ...)"
|
||||
| Or (phi1, phi2) ->
|
||||
if full_print then Format.fprintf fmt "(%a OR %a)" pp_formula phi1 pp_formula phi2
|
||||
else Format.pp_print_string fmt "(... OR ...)"
|
||||
| Implies (phi1, phi2) ->
|
||||
Format.fprintf fmt "(%a ==> %a)" pp_formula phi1 pp_formula phi2
|
||||
| InNode (nl, phi) ->
|
||||
Format.fprintf fmt "IN-NODE %a: (%a)"
|
||||
(Pp.comma_seq Format.pp_print_string)
|
||||
(nodes_to_string nl) pp_formula phi
|
||||
| AX (trs, phi) ->
|
||||
Format.fprintf fmt "AX[->%a](%a)" pp_transition trs pp_formula phi
|
||||
| EX (trs, phi) ->
|
||||
Format.fprintf fmt "EX[->%a](%a)" pp_transition trs pp_formula phi
|
||||
| AF (trs, phi) ->
|
||||
Format.fprintf fmt "AF[->%a](%a)" pp_transition trs pp_formula phi
|
||||
| EF (trs, phi) ->
|
||||
Format.fprintf fmt "EF[->%a](%a)" pp_transition trs pp_formula phi
|
||||
| AG (trs, phi) ->
|
||||
Format.fprintf fmt "AG[->%a](%a)" pp_transition trs pp_formula phi
|
||||
| EG (trs, phi) ->
|
||||
Format.fprintf fmt "EG[->%a](%a)" pp_transition trs pp_formula phi
|
||||
| AU (trs, phi1, phi2) ->
|
||||
Format.fprintf fmt "A[->%a][%a UNTIL %a]" pp_transition trs pp_formula phi1 pp_formula phi2
|
||||
| EU (trs, phi1, phi2) ->
|
||||
Format.fprintf fmt "E[->%a][%a UNTIL %a]" pp_transition trs pp_formula phi1 pp_formula phi2
|
||||
| EH (arglist, phi) ->
|
||||
Format.fprintf fmt "EH[%a](%a)"
|
||||
(Pp.comma_seq Format.pp_print_string)
|
||||
(nodes_to_string arglist) pp_formula phi
|
||||
| ET (arglist, trans, phi) ->
|
||||
Format.fprintf fmt "ET[%a][%a](%a)"
|
||||
(Pp.comma_seq Format.pp_print_string)
|
||||
(nodes_to_string arglist) pp_transition trans pp_formula phi
|
||||
| InObjCClass (phi1, phi2) ->
|
||||
if full_print then Format.fprintf fmt "InObjCClass(%a, %a)" pp_formula phi1 pp_formula phi2
|
Loading…
Reference in new issue