open Ast open Util open Ast_util open Formula open Typing open Interpret (* used for constant evaluation ! *) (* Transform SCADE program to logical formula. *) (* node * prefix * equations *) type scope = id * id * eqn ext list type transform_data = { rp : rooted_prog; consts : I.value VarMap.t; (* future : the automata state *) } (* f_of_nexpr : transform_data -> (string, string) -> (num_expr list -> 'a) -> expr -> 'a *) let rec f_of_nexpr td (node, prefix) where expr = let sub = f_of_nexpr td (node, prefix) in match fst expr with (* ident *) | AST_identifier(id, _) -> where [NIdent (node^"/"^id)] | AST_idconst(id, _) -> begin let x = VarMap.find ("cst/"^id) td.consts in try where [NIntConst (I.as_int x)] with _ -> try where [NRealConst (I.as_real x)] with _ -> error "Invalid data for supposedly numerical constant." end (* numerical *) | AST_int_const(i, _) -> where [NIntConst(int_of_string i)] | AST_real_const(r, _) -> where [NRealConst(float_of_string r)] | AST_unary(op, e) -> sub (function | [x] -> where [NUnary(op, x)] | _ -> invalid_arity "Unary operator") e | AST_binary(op, a, b) -> sub (function | [x] -> sub (function | [y] -> where [NBinary(op, x, y)] | _ -> invalid_arity "binary_operator") b | _ -> invalid_arity "binary operator") a (* temporal *) | AST_pre(expr, id) -> let typ = type_expr td.rp node expr in where (List.mapi (fun i _ -> NIdent (id^"."^(string_of_int i))) typ) | AST_arrow(a, b) -> f_or (f_and (BRel(AST_EQ, NIdent(node^"/"^prefix^"time"), NIntConst 0)) (sub where a)) (f_and (BRel(AST_GE, NIdent(node^"/"^prefix^"time"), NIntConst 1)) (sub where b)) (* other *) | AST_if(c, a, b) -> f_or (f_and (f_of_expr td (node, prefix) c) (sub where a)) (f_and (BNot(f_of_expr td (node, prefix) c)) (sub where b)) | AST_instance ((f, _), args, nid) -> let (n, _) = find_node_decl td.rp.p f in where (List.map (fun (_, id, _) -> NIdent (node^"/"^nid^"/"^id)) n.ret) (* boolean values treated as integers *) | _ -> f_or (f_and ((f_of_expr td (node, prefix) expr)) (where [NIntConst 1])) (f_and (BNot(f_of_expr td (node, prefix) expr)) (where [NIntConst 0])) (* f_of_expr : transform_data -> (string, string) -> expr -> bool_expr f_of_bexpr : transform_data -> (string, string) -> (bool_expr -> 'a) -> expr -> 'a *) and f_of_bexpr td (node, prefix) where expr = let sub = f_of_bexpr td (node, prefix) in match fst expr with | AST_bool_const b -> where (BConst b) | AST_binary_bool(AST_AND, a, b) -> f_and (sub where a) (sub where b) | AST_binary_bool(AST_OR, a, b) -> f_or (sub where a) (sub where b) | AST_not(a) -> BNot(sub where a) | AST_binary_rel(rel, a, b) -> where (f_of_nexpr td (node, prefix) (function | [x] -> f_of_nexpr td (node, prefix) (function | [y] -> BRel(rel, x, y) | _ -> invalid_arity "boolean relation") b | _ -> invalid_arity "boolean relation") a) | AST_identifier (id, _) -> let id = node^"/"^id in f_or (f_and (BBoolEq(id, true)) (where (BConst true))) (f_and (BBoolEq(id, false)) (where (BConst false))) (* temporal *) | AST_pre(_, id) -> f_or (f_and (BBoolEq(id, true)) (where (BConst true))) (f_and (BBoolEq(id, false)) (where (BConst false))) | AST_arrow(a, b) -> f_or (f_and (BRel(AST_EQ, NIdent(node^"/"^prefix^"time"), NIntConst 0)) (sub where a)) (f_and (BRel(AST_GE, NIdent(node^"/"^prefix^"time"), NIntConst 1)) (sub where b)) (* other *) | AST_if(c, a, b) -> f_or (f_and (f_of_expr td (node, prefix) c) (sub where a)) (f_and (BNot(f_of_expr td (node, prefix) c)) (sub where b)) | _ -> loc_error (snd expr) error "Expected boolean value." and f_of_expr td (node, prefix) expr = f_of_bexpr td (node, prefix) (fun x -> x) expr (* Translate program into one big formula *) let rec f_of_scope active td (node, prefix, eqs) assume_guarantees = let expr_eq e eq = let instance_eq (_, id, eqs, args) = let eq = f_of_scope active td (node^"/"^id, "", eqs) assume_guarantees in if active then List.fold_left (fun eq ((_,argname,_), expr) -> let eq_arg = f_of_nexpr td (node, prefix) (function | [v] -> BRel(AST_EQ, NIdent(node^"/"^id^"/"^argname), v) | _ -> invalid_arity "in argument") expr in f_and eq eq_arg) eq args else eq in let eq = List.fold_left (fun x i -> f_and (instance_eq i) x) eq (extract_instances td.rp.p e) in let pre_expr (id, expr) = if active then f_of_nexpr td (node, prefix) (fun elist -> list_fold_op f_and (List.mapi (fun i v -> BRel(AST_EQ, NIdent("N"^id^"."^(string_of_int i)), v)) elist)) expr else let typ = type_expr td.rp node expr in list_fold_op f_and (List.mapi (fun i _ -> let x = string_of_int i in BRel(AST_EQ, NIdent("N"^id^"."^x), NIdent (id^"."^x))) typ) in List.fold_left (fun x i -> f_and (pre_expr i) x) eq (extract_pre e) in let do_eq eq = match fst eq with | AST_assign(ids, e) -> let assign_eq = if active then f_of_nexpr td (node, prefix) (fun vs -> let rels = List.map2 (fun (id, _) v -> BRel(AST_EQ, NIdent (node^"/"^id), v)) ids vs in list_fold_op f_and rels) e else BConst true in expr_eq e assign_eq | AST_assume (_, e) -> let assume_eq = if active then f_of_expr td (node, prefix) e else BConst true in expr_eq e assume_eq | AST_guarantee (_, e) -> let guarantee_eq = if active && assume_guarantees then f_of_expr td (node, prefix) e else BConst true in expr_eq e guarantee_eq | AST_activate (b, _) -> let rec cond_eq = function | AST_activate_body b -> BConst true | AST_activate_if(c, a, b) -> f_and (expr_eq c (BConst true)) (f_and (cond_eq a) (cond_eq b)) in let rec do_tree_act = function | AST_activate_body b -> f_of_scope true td (node, b.act_id^".", b.body) assume_guarantees | AST_activate_if(c, a, b) -> f_or (f_and (f_of_expr td (node, prefix) c) (f_and (do_tree_act a) (do_tree_inact b))) (f_and (BNot(f_of_expr td (node, prefix) c)) (f_and (do_tree_act b) (do_tree_inact a))) and do_tree_inact = function | AST_activate_body b -> f_of_scope false td (node, b.act_id^".", b.body) assume_guarantees | AST_activate_if(_, a, b) -> f_and (do_tree_inact a) (do_tree_inact b) in f_and (cond_eq b) (if active then do_tree_act b else do_tree_inact b) | AST_automaton _ -> not_implemented "f_of_scope do_eq automaton" in let time_incr_eq = if active then BRel(AST_EQ, NIdent("N"^node^"/"^prefix^"time"), NBinary(AST_PLUS, NIntConst 1, NIdent(node^"/"^prefix^"time"))) else BRel(AST_EQ, NIdent("N"^node^"/"^prefix^"time"), NIdent(node^"/"^prefix^"time")) in List.fold_left f_and time_incr_eq (List.map do_eq eqs) and f_of_prog rp assume_guarantees = let td = { rp = rp; consts = I.consts rp; } in f_of_scope true td td.rp.root_scope assume_guarantees (* Translate init state into a formula *) let rec init_f_of_scope rp (node, prefix, eqs) = let expr_eq e = let instance_eq (_, id, eqs, args) = init_f_of_scope rp (node^"/"^id, "", eqs) in List.fold_left (fun x i -> f_and (instance_eq i) x) (BConst true) (extract_instances rp.p e) in let do_eq eq = match fst eq with | AST_assign(_, e) | AST_assume(_, e) | AST_guarantee(_, e) -> expr_eq e | AST_activate (b, _) -> let rec cond_eq = function | AST_activate_body b -> init_f_of_scope rp (node, b.act_id^".", b.body) | AST_activate_if(c, a, b) -> f_and (expr_eq c) (f_and (cond_eq a) (cond_eq b)) in cond_eq b | AST_automaton _ -> not_implemented "f_of_scope do_eq automaton" in let time_eq = BRel(AST_EQ, NIdent(node^"/"^prefix^"time"), NIntConst 0) in List.fold_left f_and time_eq (List.map do_eq eqs) and init_f_of_prog rp = init_f_of_scope rp rp.root_scope (* Get expressions for guarantee violation *) let rec g_of_scope td (node, prefix, eqs) cond = let expr_g e = let instance_g (_, id, eqs, args) = g_of_scope td (node^"/"^id, "", eqs) cond in List.fold_left (fun x i -> (instance_g i) @ x) [] (extract_instances td.rp.p e) in let do_eq eq = match fst eq with | AST_assign(_, e) | AST_assume(_, e) -> expr_g e | AST_guarantee((id, _), e) -> (id, f_and cond (f_of_expr td (node, prefix) (AST_not(e), snd e))) :: (expr_g e) | AST_activate (b, _) -> let rec cond_g cond = function | AST_activate_body b -> g_of_scope td (node, b.act_id^".", b.body) cond | AST_activate_if(c, a, b) -> (cond_g (f_and cond (f_of_expr td (node, prefix) c)) a) @ (cond_g (f_and cond (f_of_expr td (node, prefix) (AST_not(c), snd c))) b) @ (expr_g c) in cond_g cond b | AST_automaton _ -> not_implemented "g_of_scope automaton" in List.fold_left (@) [] (List.map do_eq eqs) and guarantees_of_prog rp = let td = { rp = rp; consts = I.consts rp; } in g_of_scope td rp.root_scope (BConst true)