summaryrefslogblamecommitdiff
path: root/interpret/bad_interpret.ml
blob: 08ccf85a1c02b21842b19ecebfa4abc9aaba50c9 (plain) (tree)
1
2
3
4
5
6
7


         
             
 
                                       
 














































                                                                                         
 
 

 

                           





                      
  
                                                               
  


                                   
                    
                             

                          
                      

                                                               



                                                       



































































                                                               
                                                                                








                                                
                                      
                                          
                  

                                                                

                       


                          
                             

                                                 

                                                                  

                      
                                      
                            
                                                                         


                      
                                                                           


                








                                                                                     
                                                                      












                                                                                  
 
 
                       

                    

                                          


                                     

                                                      






                                                                                              

                                                          


                                           

                                                          







                                                             
                                                           

                                                                         
                                                                       


                                        
                                          



                                                                 


                                        






                                                                                 
                                                   


                                               
                                                                                   
                                                 
                                                                                   







                                                                                       
                                                                       

                                     
                                      
 






                                                           
                                                  






                                                                            

                                                                                            



                      
open Ast
open Data
open Util
open Ast_util

(* Data structures for the interpret *)

type scope = string

type svalue =
  | VInt of int
  | VBool of bool
  | VReal of float
  | VState of id
  | VPrevious of value
  | VBusy   (* intermediate value : calculating ! for detection of cycles *)
and value = svalue list

type state = svalue VarMap.t

(* functions for recursively getting variables *)

type calc_fun = 
  | F of (state -> calc_map -> state)
and calc_map = calc_fun VarMap.t

let get_var (st: state) (c: calc_map) (id: id) : (state * svalue) =
  let st =
    if VarMap.mem id st then st
    else match VarMap.find id c with
    | F f ->
      (* Format.printf "%s[ " id; *)
      let r = f (VarMap.add id VBusy st) c in
      (* Format.printf "]%s " id; *)
      r
  in
    match VarMap.find id st with
    | VBusy -> combinatorial_cycle id
    | v -> st, v

(* pretty-printing *)

let rec str_of_value = function
  | VInt i -> string_of_int i
  | VReal r -> string_of_float r
  | VBool b -> if b then "true" else "false"
  | VState s -> "state " ^ s
  | VPrevious p ->
    "[" ^
      List.fold_left (fun s v -> (if s = "" then "" else s ^ ", ") ^ str_of_value v) "" p
      ^ "]"
  | VBusy -> "#"
let print_state st =
  VarMap.iter (fun id v -> Format.printf "%s = %s@." id (str_of_value v)) st




(* Expression evaluation *)

type eval_env = {
  p: prog;
  c: calc_map;
  scopes: string list;
}

(*
  eval_expr : eval_env -> string -> expr ext -> (state * value)
*)
let rec eval_expr env st exp =
  let sub_eval = eval_expr env in
  let scope = List.hd env.scopes in
  match fst exp with
  | AST_identifier (id, _) ->
    let rec aux = function
      | [] ->
        no_variable id
      | sc::q ->
        try let st, v = get_var st env.c (sc^"/"^id) in st, [v]
        with Not_found -> aux q
    in loc_error (snd exp) aux env.scopes
  | AST_idconst (id, _) ->
    let st, v = get_var st env.c ("cst/"^id) in st, [v]
  (* on numerical values *)
  | AST_int_const (i, _) -> st, [VInt (int_of_string i)]
  | AST_real_const (r, _) -> st, [VReal (float_of_string r)]
  | AST_unary(AST_UPLUS, e) -> sub_eval st e
  | AST_unary(AST_UMINUS, e) ->
    begin match sub_eval st e with
    | st, [VInt x] -> st, [VInt (-x)]
    | st, [VReal x] -> st, [VReal(-. x)]
    | _ -> type_error "Unary on non-numerical."
    end
  | AST_binary(op, e1, e2) ->
    let st, v1 = sub_eval st e1 in
    let st, v2 = sub_eval st e2 in
    let iop, fop = match op with
    | AST_PLUS -> (+), (+.)
    | AST_MINUS -> (-), (-.)
    | AST_MUL -> ( * ), ( *. )
    | AST_DIV -> (/), (/.)
    | AST_MOD -> (mod), mod_float
    in
    begin match v1, v2 with
    | [VInt a], [VInt b] -> st, [VInt (iop a b)]
    | [VReal a], [VReal b] -> st, [VReal(fop a b)]
    | _ -> type_error "Invalid arguments for numerical binary."
    end
  (* on boolean values *)
  | AST_bool_const b -> st, [VBool b]
  | AST_binary_rel(op, e1, e2) ->
    let st, v1 = sub_eval st e1 in
    let st, v2 = sub_eval st e2 in
    let r = match op with
    | AST_EQ -> (=)     | AST_NE -> (<>)
    | AST_LT -> (<)     | AST_LE -> (<=)
    | AST_GT -> (>)     | AST_GE -> (>=)
    in
    begin match v1, v2 with
    | [VInt a], [VInt b] -> st, [VBool (r a b)]
    | [VReal a], [VReal b] -> st, [VBool (r a b)]
    | [VBool a], [VBool b] -> st, [VBool (r a b)]
    | _ -> type_error "Invalid arguments for binary relation."
    end
  | AST_binary_bool(op, e1, e2) ->
    let st, v1 = sub_eval st e1 in
    let st, v2 = sub_eval st e2 in
    let r = match op with
    | AST_AND -> (&&)   | AST_OR -> (||)
    in
    begin match v1, v2 with
    | [VBool a], [VBool b] -> st, [VBool (r a b)]
    | _ -> type_error "Invalid arguments for boolean relation."
    end
  | AST_not(e) ->
    begin match sub_eval st e with
    | st, [VBool b] -> st, [VBool (not b)]
    | _ -> type_error "Invalid arguments for boolean negation."
    end
  (* temporal primitives *)
  | AST_pre(exp, n) ->
    begin try match VarMap.find (scope^"/"^n) st with
      | VPrevious x -> st, x
      | _ -> st, []
    with Not_found -> st, []
    end
  | AST_arrow(before, after) -> 
    begin try match VarMap.find (scope^"/init") st with
    | VBool true -> sub_eval st before
    | VBool false -> sub_eval st after
    | _ -> assert false
    with Not_found -> error ("Internal: could not find init for scope " ^ scope)
    end
  (* other *)
  | AST_if(cond, a, b) ->
    let st, cv = sub_eval st cond in
    begin match cv with
    | [VBool true] -> sub_eval st a
    | [VBool false] -> sub_eval st b
    | _ -> type_error "Invalid condition in if."
    end
  | AST_instance((f, _), args, nid) ->
    let (n, _) = find_node_decl env.p f in
    List.fold_left
      (fun (st, vs) (_, (id,_), _) ->
          let st, v = get_var st env.c (scope^"/"^nid^"/"^id) in
          st, vs @ [v])
      (st, []) n.ret

(* Constant calculation *)

let rec calc_const p d st c =
  let env = { p = p; c = c; scopes = ["cst"] } in
  match eval_expr env st d.value with
  | st, [v] -> VarMap.add ("cst/"^d.c_name) v st
  | _ -> type_error ("Cannot assign tuple to constant" ^ d.c_name)

let program_consts p =
  let cdecl = extract_const_decls p in
  let ccmap = List.fold_left
    (fun c (d, _) -> VarMap.add ("cst/"^d.c_name) (F (calc_const p d)) c)
    VarMap.empty cdecl
  in
  List.fold_left
    (fun st (d, _) -> let st, _ = get_var st ccmap ("cst/"^d.c_name) in st)
    VarMap.empty
    cdecl

(* get initial state for program *)
let program_init_state p root_node =
  let (n, _) = find_node_decl p root_node in
  let rec aux st p scope eqs =
    let st = VarMap.add (scope^"/init") (VBool true) st in
    let add_subscopes =
      List.fold_left (fun st (ss_id, ss_eqs, _) -> aux st p (scope^"/"^ss_id) ss_eqs)
    in
    let add_eq st eq = match fst eq with
        | AST_assign(_, e) -> add_subscopes st (extract_instances p e)
        | AST_assume _ | AST_guarantee _ -> st
        | AST_automaton (aid, astates, ret) ->
          let (initial, _) = List.find (fun (s, _) -> s.initial) astates in
          let st = VarMap.add (scope^":"^aid^".state") (VState initial.name) st in
          let add_astate st ((astate:Ast.state), _) =
            aux st p (scope^":"^aid^"."^astate.name) astate.body
          in
          List.fold_left add_astate st astates
        | AST_activate _ -> not_implemented "program_init_state activate"
    in
    List.fold_left add_eq st eqs
  in
    aux (program_consts p) p "" n.body


(* Program execution *)

(* build calc map *)
let rec build_prog_ccmap p scopes eqs st =
  let scope = List.hd scopes in
  let add_eq c eq = match fst eq with
    | AST_assign(vars, e) ->
      let calc st c =
        let env = { p = p; c = c; scopes = scopes } in
        let st, vals = eval_expr env st e in
        List.fold_left2
          (fun st (id,_) v -> VarMap.add (scope^"/"^id) v st)
          st vars vals
      in
      let c = List.fold_left (fun c (id, _) -> VarMap.add (scope^"/"^id) (F calc) c) c vars in

      let add_subscope c (ss_id, ss_eqs, ss_args) =
        let c = VarMap.merge disjoint_union c
          (build_prog_ccmap p [scope^"/"^ss_id] ss_eqs st)
        in
        let add_v c ((_, (id, _), _), eq) =
          let calc st c =
            let env = { p = p; c = c; scopes = scopes } in
            let st, vals = eval_expr env st eq in
            match vals with
            | [v] -> VarMap.add (scope^"/"^ss_id^"/"^id) v st
            | _ -> type_error "invalid arity"
          in
          VarMap.add (scope^"/"^ss_id^"/"^id) (F calc) c
        in
        List.fold_left add_v c ss_args
      in
      List.fold_left add_subscope c (extract_instances p e)
    | AST_assume _ | AST_guarantee _ -> c
    | AST_automaton _ -> not_implemented "build_prog_ccmap for automaton"
    | AST_activate _ -> not_implemented "build_prog_ccmap for activate"
  in
  List.fold_left add_eq VarMap.empty eqs

let extract_next_state active env eqs st =
  let csts = VarMap.filter
    (fun k _ -> String.length k > 4 && String.sub k 0 4 = "cst/")
    st
  in
  let rec aux active scopes eqs st nst =
    let scope = List.hd env.scopes in

    let r = VarMap.add (scope^"/init")
        (if active then VBool false
          else try VarMap.find (scope^"/init") st with Not_found -> assert false)
        nst
    in
    let add_subscopes active =
      List.fold_left (fun (st, nst) (ss_id, ss_eqs, _) ->
        aux active [scope^"/"^ss_id] ss_eqs st nst)
    in
    let add_eq (st, nst) eq = match fst eq with
      | AST_assign(vars, e) ->
        let st, nst = add_subscopes active (st, nst) (extract_instances env.p e) in
        List.fold_left (fun (st, nst) (pn, pe) ->
            let st, v = if active then eval_expr { env with scopes = scopes } st pe
              else st,
                try match VarMap.find (scope^"/"^pn) st with VPrevious x -> x | _ -> []
                with Not_found -> []
            in
            st, VarMap.add (scope^"/"^pn) (VPrevious v) nst)
          (st, nst) (extract_pre e)
      | AST_assume _ | AST_guarantee _ -> st, nst
      | AST_automaton _ -> not_implemented "extract_next_state automaton"
      | AST_activate _ -> not_implemented "extract_next_state activate"
    in
    List.fold_left add_eq (st, r) eqs
  in aux active env.scopes eqs st csts



let program_step p st inputs root_node =
  let (n, _) = find_node_decl p root_node in
  let st = List.fold_left
    (fun st (n, v) -> VarMap.add ("/"^n) v st) st inputs in

  let ccmap = build_prog_ccmap p [""] n.body st in

  let st = List.fold_left
    (fun st (_, (id, _), _) -> let st, _ = get_var st ccmap ("/"^id) in st)
    st n.ret in
  let outputs = List.map
    (fun (_, (id, _), _) -> let _, v = get_var st ccmap ("/"^id) in (id, v))
    n.ret in

  let st, next_st = extract_next_state true { p = p; scopes = [""]; c = ccmap } n.body st in

  st, outputs, next_st