summaryrefslogblamecommitdiff
path: root/abstract/transform.ml
blob: e6886b8d4c48f54840cfa843bc7ff590f287cc32 (plain) (tree)
































































































































































































                                                                                  
              
                                         





                                    
open Ast
open Util
open Ast_util
open Formula

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 = {
    p           : Ast.prog;
    consts      : I.value VarMap.t;
    root_scope  : scope;
    (* future : the automata state *)
}

let f_and a b =
  if a = BConst true then b
    else if b = BConst true then a
      else BAnd(a, b)


(* 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(_, id) -> where [NIdent id]
  | AST_arrow(a, b) ->
      BOr(
        BAnd(BRel(AST_EQ, NIdent(node^"/"^prefix^"time"), NIntConst 0),
          sub where a),
        BAnd(BRel(AST_GE, NIdent(node^"/"^prefix^"time"), NIntConst 1),
          sub where b))
  (* other *)
  | AST_if(c, a, b) ->
    BOr(
      BAnd(f_of_bexpr td (node, prefix) c, sub where a),
      BAnd(BNot(f_of_bexpr td (node, prefix) c), sub where b))
  | AST_instance ((f, _), args, nid) ->
    let (n, _) = find_node_decl td.p f in
    where (List.map (fun (_, (id, _), _) -> NIdent (node^"/"^nid^"/"^id)) n.ret)
    
  (* boolean values treated as integers *)
  | _ ->
    BOr(
      BAnd ((f_of_bexpr td (node, prefix) expr), where [NIntConst 1]),
      BAnd (BNot(f_of_bexpr td (node, prefix) expr), where [NIntConst 0])
    )

(* f_of_expr :
    transform_data -> (string, string) -> expr -> bool_expr
*)
and f_of_bexpr td (node, prefix) expr =
  let sub = f_of_bexpr td (node, prefix) in
  match fst expr with
  | AST_bool_const b -> BConst b
  | AST_binary_bool(AST_AND, a, b) -> BAnd(sub a, sub b)
  | AST_binary_bool(AST_OR, a, b) -> BOr(sub a, sub b)
  | AST_not(a) -> BNot(sub a)
  | AST_binary_rel(rel, a, b) ->
    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
  | _ -> loc_error (snd expr) error "Invalid type : expected boolean value"
  
  

and f_of_scope active td (node, prefix, eqs) =
  let expr_eq e eq =
    let instance_eq (id, eqs, args) =
      let eq = f_of_scope active td (node^"/"^id, "", eqs) 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.p e)
    in
    let pre_expr (id, expr) =
      if active then
        f_of_nexpr td (node, prefix) (function
            | [v] -> BRel(AST_EQ, NIdent("N"^id), v)
            | _ -> invalid_arity "pre on complex data not supported")
          expr
      else
        BRel(AST_EQ, NIdent("N"^id), NIdent id)
    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) ->
      if active then
        f_of_bexpr td (node, prefix) e
      else
        BConst true
    | AST_guarantee _ -> BConst true
    | 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)
        | AST_activate_if(c, a, b) ->
          BOr(
            f_and (f_of_bexpr td (node, prefix) c)
              (f_and (do_tree_act a) (do_tree_inact b)),
            f_and (BNot(f_of_bexpr 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)
        | 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 p root =
    let td = {
      root_scope = get_root_scope p root;
      p = p;
      consts = I.consts p root;
    } in

    f_of_scope true td td.root_scope