summaryrefslogtreecommitdiff
path: root/src/lem_interp/0.11/interp.lem
diff options
context:
space:
mode:
Diffstat (limited to 'src/lem_interp/0.11/interp.lem')
-rw-r--r--src/lem_interp/0.11/interp.lem3407
1 files changed, 3407 insertions, 0 deletions
diff --git a/src/lem_interp/0.11/interp.lem b/src/lem_interp/0.11/interp.lem
new file mode 100644
index 00000000..431c1a08
--- /dev/null
+++ b/src/lem_interp/0.11/interp.lem
@@ -0,0 +1,3407 @@
+(*========================================================================*)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(*========================================================================*)
+
+open import Pervasives
+import Map
+import Map_extra (* For 'find' instead of using lookup and maybe types, as we know it cannot fail *)
+import Set_extra (* For 'to_list' because map only goes to set *)
+import List_extra (* For 'nth' and 'head' where we know that they cannot fail *)
+open import Show
+open import Show_extra (* for 'show' to convert nat to string) *)
+open import String_extra (* for chr *)
+import Assert_extra (*For failwith when partiality is known to be unreachable*)
+
+open import Sail_impl_base
+open import Interp_ast
+open import Interp_utilities
+open import Instruction_extractor
+
+(* TODO: upstream into Lem *)
+val stringFromTriple : forall 'a 'b 'c. ('a -> string) -> ('b -> string) -> ('c -> string) -> ('a * 'b * 'c) -> string
+let stringFromTriple showX showY showZ (x,y,z) =
+ "(" ^ showX x ^ ", " ^ showY y ^ ", " ^ showZ z ^ ")"
+
+instance forall 'a 'b 'c. Show 'a, Show 'b, Show 'c => (Show ('a * 'b * 'c))
+ let show = stringFromTriple show show show
+end
+
+val debug_print : string -> unit
+declare ocaml target_rep function debug_print s = `Printf.eprintf` "%s" s
+
+val intern_annot : tannot -> tannot
+let intern_annot annot =
+ match annot with
+ | Just (t,_,ncs,effect,rec_effect) ->
+ Just (t,Tag_empty,ncs,pure,rec_effect)
+ | Nothing -> Nothing
+ end
+
+let val_annot typ = Just(typ,Tag_empty,[],pure,pure)
+
+let ctor_annot typ = Just(typ,Tag_ctor,[],pure,pure)
+
+let enum_annot typ max = Just(typ,Tag_enum max,[],pure,pure)
+
+let non_det_annot annot maybe_id = match annot with
+ | Just(t,_,cs,ef,efr) -> Just(t,Tag_unknown maybe_id,cs,ef,efr)
+ | _ -> Nothing
+end
+
+let is_inc = function | IInc -> true | _ -> false end
+
+let id_of_string s = (Id_aux (Id s) Unknown)
+
+
+let rec {ocaml} string_of_reg_form r = match r with
+ | Form_Reg id _ _ -> get_id id
+ | Form_SubReg id reg_form _ -> (string_of_reg_form reg_form) ^ "." ^ (get_id id)
+end
+
+let rec {ocaml} string_of_value v = match v with
+ | V_boxref nat t -> "$#" ^ (show nat) ^ "$"
+ | V_lit (L_aux lit _) ->
+ (match lit with
+ | L_unit -> "()"
+ | L_zero -> "0"
+ | L_one -> "1"
+ | L_true -> "true"
+ | L_false -> "false"
+ | L_num num -> show num
+ | L_hex hex -> "0x" ^ hex
+ | L_bin bin -> "0b" ^ bin
+ | L_undef -> "undefined"
+ | L_string str-> "\"" ^ str ^ "\"" end)
+ | V_tuple vals -> "(" ^ (list_to_string string_of_value "," vals) ^ ")"
+ | V_list vals -> "[||" ^ (list_to_string string_of_value "," vals) ^ "||]"
+ | V_vector i inc vals ->
+ let default_format _ = "[" ^ (list_to_string string_of_value "," vals) ^ "]" in
+ let to_bin () = (*"("^show i ^") "^ *)"0b" ^
+ (List.foldr
+ (fun v rst ->
+ (match v with
+ | V_lit (L_aux l _) ->
+ (match l with | L_one -> "1" | L_zero -> "0" | L_undef -> "u"
+ | _ -> Assert_extra.failwith "to_bin called with non-bin lits" end)
+ | V_unknown -> "?"
+ | _ -> Assert_extra.failwith "to_bin called with non-bin values" end) ^rst) "" vals) in
+ match vals with
+ | [] -> default_format ()
+ | v::vs ->
+ match v with
+ | V_lit (L_aux L_zero _) -> to_bin()
+ | V_lit (L_aux L_one _) -> to_bin()
+ | _ -> default_format() end end
+ | V_vector_sparse start stop inc vals default ->
+ "[" ^ (list_to_string (fun (i,v) -> (show i) ^ " = " ^ (string_of_value v)) "," vals) ^ "]:" ^
+ show start ^ "-" ^show stop ^ "(default of " ^ (string_of_value default) ^ ")"
+ | V_record t vals ->
+ "{" ^ (list_to_string (fun (id,v) -> (get_id id) ^ "=" ^ (string_of_value v)) ";" vals) ^ "}"
+ | V_ctor id t _ value -> (get_id id) ^ " " ^ string_of_value value
+ | V_unknown -> "Unknown"
+ | V_register r -> string_of_reg_form r
+ | V_register_alias _ _ -> "register_as_alias"
+ | V_track v rs -> "tainted by {" ^ (list_to_string string_of_reg_form "," []) ^ "} --" ^ (string_of_value v)
+end
+let ~{ocaml} string_of_value _ = ""
+
+val debug_print_value_list : list string -> string
+let rec debug_print_value_list vs = match vs with
+ | [] -> ""
+ | [v] -> v
+ | v :: vs -> v ^ ";" ^ debug_print_value_list vs
+end
+val debug_print_value : value -> string
+let rec debug_print_value v = match v with
+ | V_boxref n t -> "V_boxref " ^ (show n) ^ " t"
+ | V_lit (L_aux lit _) ->
+ "V_lit " ^
+ (match lit with
+ | L_unit -> "L_unit"
+ | L_zero -> "L_zero"
+ | L_one -> "L_one"
+ | L_true -> "L_true"
+ | L_false -> "L_false"
+ | L_num num -> "(Lnum " ^ (show num) ^ ")"
+ | L_hex hex -> "(L_hex " ^ hex ^ ")"
+ | L_bin bin -> "(L_bin " ^ bin ^ ")"
+ | L_undef -> "L_undef"
+ | L_string str-> "(L_string " ^ str ^ ")" end)
+ | V_tuple vals ->
+ "V_tuple [" ^ debug_print_value_list (List.map debug_print_value vals) ^ "]"
+ | V_list vals ->
+ "V_list [" ^ debug_print_value_list (List.map debug_print_value vals) ^ "]"
+ | V_vector i inc vals ->
+ "V_vector " ^ (show i) ^
+ " " ^ (if inc = IInc then "IInc" else "IDec") ^
+ " [" ^ debug_print_value_list (List.map debug_print_value vals) ^ "]"
+ | V_vector_sparse start stop inc vals default ->
+ let ppindexval (i,v) = (show i) ^ " = " ^ (debug_print_value v) in
+ let valspp = debug_print_value_list (List.map ppindexval vals) in
+ "V_vector " ^ (show start) ^ " " ^ (show stop) ^ " " ^
+ (if inc = IInc then "IInc" else "IDec") ^
+ " [" ^ valspp ^ "] (" ^ debug_print_value default ^ ")"
+ | V_record t vals ->
+ let ppidval (id,v) = "(" ^ (get_id id) ^ "," ^ debug_print_value v ^ ")" in
+ "V_record t [" ^ debug_print_value_list (List.map ppidval vals) ^ "]"
+ | V_ctor id t k v' ->
+ "V_ctor " ^ (get_id id) ^ " t " ^
+ (match k with | C_Enum n -> "(C_Enum " ^ show n ^ ")"
+ | C_Union -> "C_Union" end) ^
+ "(" ^ debug_print_value v' ^ ")"
+ | V_unknown -> "V_unknown"
+ | V_register r -> "V_register (" ^ string_of_reg_form r ^ ")"
+ | V_register_alias _ _ -> "V_register_alias _ _"
+ | V_track v rs -> "V_track (" ^ debug_print_value v ^ ") _"
+ end
+
+instance (Show value)
+ let show v = debug_print_value v
+end
+
+let rec {coq;ocaml} id_value_eq strict (i, v) (i', v') = i = i' && value_eq strict v v'
+and value_eq strict left right =
+ match (left, right) with
+ | (V_lit l, V_lit l') -> lit_eq l l'
+ | (V_boxref n t, V_boxref m t') -> n = m && t = t'
+ | (V_tuple l, V_tuple l') -> listEqualBy (value_eq strict) l l'
+ | (V_list l, V_list l') -> listEqualBy (value_eq strict) l l'
+ | (V_vector n b l, V_vector m b' l') -> b = b' && listEqualBy (value_eq strict) l l'
+ | (V_vector_sparse n o b l v, V_vector_sparse m p b' l' v') ->
+ n=m && o=p && b=b' &&
+ listEqualBy (fun (i,v) (i',v') -> i=i' && (value_eq strict v v')) l l' && value_eq strict v v'
+ | (V_record t l, V_record t' l') ->
+ t = t' &&
+ listEqualBy (id_value_eq strict) l l'
+ | (V_ctor i t ckind v, V_ctor i' t' ckind' v') -> t = t' && ckind=ckind' && id_value_eq strict (i, v) (i', v')
+ | (V_ctor _ _ (C_Enum i) _,V_lit (L_aux (L_num j) _)) -> i = (natFromInteger j)
+ | (V_lit (L_aux (L_num j) _), V_ctor _ _ (C_Enum i) _) -> i = (natFromInteger j)
+ | (V_unknown,V_unknown) -> true
+ | (V_unknown,_) -> if strict then false else true
+ | (_,V_unknown) -> if strict then false else true
+ | (V_track v1 ts1, V_track v2 ts2) ->
+ if strict
+ then value_eq strict v1 v2 && ts1 = ts2
+ else value_eq strict v1 v2
+ | (V_track v _, v2) -> if strict then false else value_eq strict v v2
+ | (v,V_track v2 _) -> if strict then false else value_eq strict v v2
+ | (_, _) -> false
+ end
+let {isabelle;hol} id_value_eq _ x y = unsafe_structural_equality x y
+let {isabelle;hol} value_eq _ x y = unsafe_structural_equality x y
+
+let {coq;ocaml} value_ineq n1 n2 = not (value_eq false n1 n2)
+let {isabelle;hol} value_ineq = unsafe_structural_inequality
+
+instance (Eq value)
+ let (=) = value_eq false
+ let (<>) = value_ineq
+end
+
+let reg_start_pos reg =
+ match reg with
+ | Form_Reg _ (Just(typ,_,_,_,_)) _ ->
+ let start_from_vec targs = match targs with
+ | [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant s) _)) _;_;_;_] -> natFromInteger s
+ | [Typ_arg_aux (Typ_arg_nexp _) _; Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant s) _)) _; Typ_arg_aux (Typ_arg_order Odec) _; _] -> (natFromInteger s) - 1
+ | [_; _; Typ_arg_aux (Typ_arg_order Oinc) _; _] -> 0
+ | _ -> Assert_extra.failwith "vector type not well formed"
+ end in
+ let start_from_reg targs = match targs with
+ | [Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_app (Id_aux (Id "vector") _) targs) _)) _] -> start_from_vec targs
+ | _ -> Assert_extra.failwith "register not of type vector"
+ end in
+ match typ with
+ | Typ_aux (Typ_app id targs) _ ->
+ if get_id id = "vector" then start_from_vec targs
+ else if get_id id = "register" then start_from_reg targs
+ else Assert_extra.failwith "register abbrev not register or vector"
+ | _ -> Assert_extra.failwith "register abbrev not register or vector"
+ end
+ | _ -> Assert_extra.failwith "reg_start_pos found unexpected sub reg, or reg without a type"
+end
+
+let reg_size reg =
+ match reg with
+ | Form_Reg _ (Just(typ,_,_,_,_)) _ ->
+ let end_from_vec targs = match targs with
+ | [_;Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant s) _)) _;_;_] -> natFromInteger s
+ | _ -> Assert_extra.failwith "register vector type not well formed"
+ end in
+ let end_from_reg targs = match targs with
+ | [Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_app (Id_aux (Id "vector") _) targs) _)) _] -> end_from_vec targs
+ | _ -> Assert_extra.failwith "register does not contain vector"
+ end in
+ match typ with
+ | Typ_aux (Typ_app id targs) _ ->
+ if get_id id = "vector" then end_from_vec targs
+ else if get_id id = "register" then end_from_reg targs
+ else Assert_extra.failwith "register type is none of vector, register, or abbrev"
+ | _ -> Assert_extra.failwith "register type is none of vector, register, or abbrev"
+ end
+ | _ -> Assert_extra.failwith "reg_size given unexpected sub reg or reg without a type"
+end
+
+(*Constant unit value, for use in interpreter *)
+let unit_ty = Typ_aux (Typ_id (Id_aux (Id "unit") Unknown)) Unknown
+let unitv = V_lit (L_aux L_unit Unknown)
+let unit_e = E_aux (E_lit (L_aux L_unit Unknown)) (Unknown, val_annot unit_ty)
+
+(* Store for local memory of ref cells, string stores the name of the function the memory is being created for*)
+type lmem = LMem of string * nat * map nat value * set nat
+
+(* Environment for bindings *)
+type env = map string value
+(* Environment for lexical bindings, nat is a counter to build new unique variables when necessary *)
+type lenv = LEnv of nat * env
+
+let emem name = LMem name 1 Map.empty Set.empty
+let eenv = LEnv 1 Map.empty
+
+let rec list_to_string sep format = function
+ | [] -> ""
+ | [i] -> format i
+ | i::ls -> (format i) ^ sep ^ list_to_string sep format ls
+end
+
+let env_to_string (LEnv c env) =
+ "(LEnv " ^ show c ^ " [" ^
+ (list_to_string ", " (fun (k,v) -> k ^ " -> " ^ (string_of_value v)) (Map_extra.toList env)) ^
+ "])"
+
+instance (Show lenv)
+ let show env = env_to_string env
+end
+
+let mem_to_string (LMem f c mem _) =
+ "(LMem " ^ f ^ " " ^ show c ^
+ " [" ^ (list_to_string ", " (fun (k,v) -> show k ^ " -> " ^ (string_of_value v)) (Map_extra.toList mem)) ^ "])"
+
+instance (Show lmem)
+ let show mem = mem_to_string mem
+end
+
+type sub_reg_map = map string index_range
+
+(*top_level is a tuple of
+ (function definitions environment,
+ all extracted instructions (where possible),
+ default direction
+ letbound and enum values,
+ register values,
+ Typedef union constructors,
+ sub register mappings, and register aliases) *)
+type top_level =
+ | Env of map string (list (funcl tannot)) (*function definitions environment*)
+ * list instruction_form (* extracted instructions (where extractable) *)
+ * i_direction (*default direction*)
+ * env (*letbound and enum values*)
+ * env (*register values*)
+ * map string typ (*typedef union constructors *)
+ * map string sub_reg_map (*sub register mappings*)
+ * map string (alias_spec tannot) (*register aliases*)
+ * bool (* debug? *)
+
+type action =
+ | Read_reg of reg_form * maybe (nat * nat)
+ | Write_reg of reg_form * maybe (nat * nat) * value
+ | Read_mem of id * value * maybe (nat * nat)
+ | Read_mem_tagged of id * value * maybe (nat * nat)
+ | Write_mem of id * value * maybe (nat * nat) * value
+ | Write_ea of id * value
+ | Write_memv of id * value * value
+ | Excl_res of id
+ | Write_memv_tagged of id * value * value * value
+ | Barrier of id * value
+ | Footprint of id * value
+ | Nondet of list (exp tannot) * tag
+ | Call_extern of string * value
+ | Return of value
+ | Exit of (exp tannot)
+ (* For the error case of a failed assert, carries up an optional error message*)
+ | Fail of value
+ (* For stepper, no action needed. String is function called, value is parameter where applicable *)
+ | Step of l * maybe string * maybe value
+
+(* Inverted call stack, where the frame with a Top stack waits for an action to resolve and
+ all other frames for their inner stack *)
+type stack =
+ | Top
+ | Hole_frame of id * exp tannot * top_level * lenv * lmem * stack (* Stack frame waiting for a value *)
+ | Thunk_frame of exp tannot * top_level * lenv * lmem * stack (* Paused stack frame *)
+
+(*Internal representation of outcomes from running the interpreter.
+ Actions request an external party to resolve a request *)
+type outcome =
+ | Value of value
+ | Action of action * stack
+ | Error of l * string
+
+let string_of_id id' =
+ (match id' with
+ | Id_aux id _ ->
+ (match id with
+ | Id s -> s
+ | DeIid s -> s
+ end)
+ end)
+
+instance (Show id)
+ let show = string_of_id
+end
+
+let string_of_kid kid' =
+ (match kid' with
+ | Kid_aux kid _ ->
+ (match kid with
+ | Var s -> s
+ end)
+ end)
+
+instance (Show kid)
+ let show = string_of_kid
+end
+
+let string_of_reg_id (RI_aux (RI_id id ) _) = string_of_id id
+
+instance forall 'a. (Show reg_id 'a)
+ let show = string_of_reg_id
+end
+
+let rec string_of_typ typ' =
+ (match typ' with
+ | Typ_aux typ _ ->
+ (match typ with
+ | Typ_wild -> "(Typ_wild)"
+ | Typ_id id -> "(Typ_id " ^ (string_of_id id) ^ ")"
+ | Typ_var kid -> "(Typ_var " ^ (string_of_kid kid) ^ ")"
+ | Typ_fn typ1 typ2 eff -> "(Typ_fn _ _ _)"
+ | Typ_tup typs -> "(Typ_tup [" ^ String.concat "; " (List.map string_of_typ typs) ^ "])"
+ | Typ_app id args -> "(Typ_app " ^ string_of_id id ^ " _)"
+ end)
+ end)
+
+instance (Show typ)
+ let show = string_of_typ
+end
+
+let rec string_of_lexp l' =
+ (match l' with
+ | LEXP_aux l _ ->
+ (match l with
+ | LEXP_id id -> "(LEXP_id " ^ string_of_id id ^ ")"
+ | LEXP_memory id exps -> "(LEXP_memory " ^ string_of_id id ^ " _)"
+ | LEXP_cast typ id -> "(LEXP_cast " ^ string_of_typ typ ^ " " ^ string_of_id id ^ ")"
+ | LEXP_tup lexps -> "(LEXP_tup [" ^ String.concat "; " (List.map string_of_lexp lexps) ^ "])"
+ | LEXP_vector lexps exps -> "(LEXP_vector _ _)"
+ | LEXP_vector_range lexp exp1 exp2 -> "(LEXP_vector_range _ _ _)"
+ | LEXP_field lexp id -> "(LEXP_field " ^ string_of_lexp lexp ^ "." ^ string_of_id id ^ ")"
+ end)
+ end)
+
+instance forall 'a. (Show lexp 'a)
+ let show = string_of_lexp
+end
+
+let string_of_lit l' =
+ (match l' with
+ | L_aux l _ ->
+ (match l with
+ | L_unit -> "()"
+ | L_zero -> "0"
+ | L_one -> "1"
+ | L_true -> "true"
+ | L_false -> "false"
+ | L_num n -> "0d" ^ (show n)
+ | L_hex s -> "0x" ^ s
+ | L_bin s -> "0b" ^ s
+ | L_undef -> "undef"
+ | L_string s -> "\"" ^ s ^ "\""
+ end)
+ end)
+
+instance (Show lit)
+ let show = string_of_lit
+end
+
+let string_of_order o' =
+ (match o' with
+ | Ord_aux o _ ->
+ (match o with
+ | Ord_var kid -> string_of_kid kid
+ | Ord_inc -> "inc"
+ | Ord_dec -> "dec"
+ end)
+ end)
+
+instance (Show order)
+ let show = string_of_order
+end
+
+let rec string_of_exp e' =
+ (match e' with
+ | E_aux e _ ->
+ (match e with
+ | E_block exps -> "(E_block [" ^ String.concat "; " (List.map string_of_exp exps) ^ "])"
+ | E_nondet exps -> "(E_nondet [" ^ String.concat "; " (List.map string_of_exp exps) ^ "])"
+ | E_id id -> "(E_id \"" ^ string_of_id id ^ "\")"
+ | E_lit lit -> "(E_lit " ^ string_of_lit lit ^ ")"
+ | E_cast typ exp -> "(E_cast " ^ string_of_typ typ ^ " " ^ string_of_exp exp ^ ")"
+ | E_app id exps -> "(E_app " ^ string_of_id id ^ " [" ^ String.concat "; " (List.map string_of_exp exps) ^ "])"
+ | E_app_infix exp1 id exp2 -> "(E_app_infix " ^ string_of_exp exp1 ^ " " ^ string_of_id id ^ " " ^ string_of_exp exp2 ^ ")"
+ | E_tuple exps -> "(E_tuple [" ^ String.concat "; " (List.map string_of_exp exps) ^ "])"
+ | E_if cond thn els -> "(E_if " ^ (string_of_exp cond) ^ " ? " ^ (string_of_exp thn) ^ " : " ^ (string_of_exp els) ^ ")"
+ | E_for id from to_ by order exp -> "(E_for " ^ string_of_id id ^ " " ^ string_of_exp from ^ " " ^ string_of_exp to_ ^ " " ^ string_of_exp by ^ " " ^ string_of_order order ^ " " ^ string_of_exp exp ^ ")"
+ | E_vector exps -> "(E_vector [" ^ String.concat "; " (List.map string_of_exp exps) ^ "])"
+ | E_vector_access exp1 exp2 -> "(E_vector_access " ^ string_of_exp exp1 ^ " " ^ string_of_exp exp2 ^ ")"
+ | E_vector_subrange exp1 exp2 exp3 -> "(E_vector_subrange " ^ string_of_exp exp1 ^ " " ^ string_of_exp exp2 ^ " " ^ string_of_exp exp3 ^ ")"
+ | E_vector_update _ _ _ -> "(E_vector_update)"
+ | E_vector_update_subrange _ _ _ _ -> "(E_vector_update_subrange)"
+ | E_vector_append exp1 exp2 -> "(E_vector_append " ^ string_of_exp exp1 ^ " " ^ string_of_exp exp2 ^ ")"
+ | E_list exps -> "(E_list [" ^ String.concat "; " (List.map string_of_exp exps) ^ "])"
+ | E_cons exp1 exp2 -> "(E_cons " ^ string_of_exp exp1 ^ " :: " ^ string_of_exp exp2 ^ ")"
+ | E_record _ -> "(E_record)"
+ | E_record_update _ _ -> "(E_record_update)"
+ | E_field _ _ -> "(E_field)"
+ | E_case _ _ -> "(E_case)"
+ | E_let _ _ -> "(E_let)"
+ | E_assign lexp exp -> "(E_assign " ^ string_of_lexp lexp ^ " := " ^ string_of_exp exp ^ ")"
+ | E_sizeof _ -> "(E_sizeof _)"
+ | E_exit exp -> "(E_exit " ^ string_of_exp exp ^ ")"
+ | E_return exp -> "(E_return " ^ string_of_exp exp ^ ")"
+ | E_assert cond msg -> "(E_assert " ^ string_of_exp cond ^ " " ^ string_of_exp msg ^ ")"
+ | E_internal_cast _ _ -> "(E_internal_cast _ _)"
+ | E_internal_exp _ -> "(E_internal_exp _)"
+ | E_sizeof_internal _ -> "(E_size _)"
+ | E_internal_exp_user _ _ -> "(E_internal_exp_user _ _)"
+ | E_comment _ -> "(E_comment _)"
+ | E_comment_struc _ -> "(E_comment_struc _)"
+ | E_internal_let _ _ _ -> "(E_internal_let _ _ _)"
+ | E_internal_plet _ _ _ -> "(E_internal_plet _ _ _)"
+ | E_internal_return _ -> "(E_internal_return _)"
+ | E_internal_value value -> "(E_internal_value " ^ debug_print_value value ^ ")"
+ end)
+ end)
+
+instance forall 'a. (Show (exp 'a))
+ let show = string_of_exp
+end
+
+let string_of_alias_spec (AL_aux _as _) =
+ (match _as with
+ | AL_subreg reg_id id -> "(AL_subreg " ^ (show reg_id) ^ " " ^ (show id) ^ ")"
+ | AL_bit reg_id exp -> "(AL_bit " ^ (show reg_id) ^ " " ^ (show exp) ^ ")"
+ | AL_slice reg_id exp1 exp2 -> "(AL_slice " ^ (show reg_id) ^ " " ^ (show exp1) ^ " " ^ (show exp2) ^ ")"
+ | AL_concat reg_id1 reg_id2 -> "(AL_concat " ^ (show reg_id1) ^ " " ^ (show reg_id2) ^ ")"
+ end)
+
+instance forall 'a. (Show alias_spec 'a)
+ let show = string_of_alias_spec
+end
+
+let string_of_quant_item (QI_aux qi _) =
+ (match qi with
+ | QI_id kinded_id -> "(QI_id _)"
+ | QI_const nc -> "(QI_const _)"
+ end)
+
+instance (Show quant_item)
+ let show = string_of_quant_item
+end
+
+let string_of_typquant (TypQ_aux tq _) =
+ (match tq with
+ | TypQ_tq qis -> "(TypQ_tq [" ^ (String.concat "; " (List.map show qis)) ^ "]"
+ | TypQ_no_forall -> "TypQ_no_forall"
+ end)
+
+instance (Show typquant)
+ let show = string_of_typquant
+end
+
+let string_of_typschm (TypSchm_aux (TypSchm_ts typquant typ) _) =
+ "(TypSchm " ^ (show typquant) ^ " " ^ (show typ) ^ ")"
+
+instance (Show typschm)
+ let show = string_of_typschm
+end
+
+let rec string_of_pat (P_aux pat _) =
+ (match pat with
+ | P_lit lit -> "(P_lit " ^ show lit ^ ")"
+ | P_wild -> "P_wild"
+ | P_as pat' id -> "(P_as " ^ string_of_pat pat' ^ " " ^ show id ^ ")"
+ | P_typ typ pat' -> "(P_typ" ^ show typ ^ " " ^ string_of_pat pat' ^ ")"
+ | P_id id -> "(P_id " ^ show id ^ ")"
+ | P_app id pats -> "(P_app " ^ show id ^ " [" ^ String.concat "; " (List.map string_of_pat pats) ^ "])"
+ | P_record _ _ -> "(P_record _ _)"
+ | P_vector pats -> "(P_vector [" ^ String.concat "; " (List.map string_of_pat pats) ^ "])"
+ | P_vector_concat pats -> "(P_vector_concat [" ^ String.concat "; " (List.map string_of_pat pats) ^ "])"
+ | P_tup pats -> "(P_tup [" ^ String.concat "; " (List.map string_of_pat pats) ^ "])"
+ | P_list pats -> "(P_list [" ^ String.concat "; " (List.map string_of_pat pats) ^ "])"
+ end)
+
+instance forall 'a. (Show pat 'a)
+ let show = string_of_pat
+end
+
+let string_of_letbind (LB_aux lb _) =
+ (match lb with
+ | LB_val pat exp -> "(LB_val " ^ (show pat) ^ " " ^ (show exp) ^ ")"
+ end)
+
+instance forall 'a. (Show letbind 'a)
+ let show = string_of_letbind
+end
+
+type interp_mode = <| eager_eval : bool; track_values : bool; track_lmem : bool; debug : bool; debug_indent : string |>
+
+let indent_mode mode = if mode.debug then <| mode with debug_indent = " " ^ mode.debug_indent |> else mode
+
+val debug_fun_enter : interp_mode -> string -> list string -> unit
+let debug_fun_enter mode name args =
+ if mode.debug then
+ debug_print (mode.debug_indent ^ ":: " ^ name ^ " args: [" ^ (String.concat "; " args) ^ "]\n")
+ else
+ ()
+
+val debug_fun_exit : forall 'a. Show 'a => interp_mode -> string -> 'a -> unit
+let debug_fun_exit mode name retval =
+ if mode.debug then
+ debug_print (mode.debug_indent ^ "=> " ^ name ^ " returns: " ^ (show retval) ^ "\n")
+ else
+ ()
+
+(* Evaluates global let binds and prepares the context for individual expression evaluation in the current model *)
+val to_top_env : bool -> (i_direction -> outcome -> maybe value) -> defs tannot -> (maybe outcome * top_level)
+val get_default_direction : top_level -> i_direction
+
+(* interprets the exp sequentially in the presence of a set of top level definitions and returns a value, a memory request, or other external action *)
+val interp :interp_mode -> (i_direction -> outcome -> maybe value) -> defs tannot -> exp tannot -> (outcome * lmem * lenv)
+
+(* Takes a paused partially evaluated expression, puts the value into the environment, and runs again *)
+val resume : interp_mode -> stack -> maybe value -> (outcome * lmem * lenv)
+
+(* Internal definitions to setup top_level *)
+val to_fdefs : defs tannot -> map string (list (funcl tannot))
+let rec to_fdefs (Defs defs) =
+ match defs with
+ | [] -> Map.empty
+ | def::defs ->
+ match def with
+ | DEF_fundef f -> (match f with
+ | FD_aux (FD_function _ _ _ fcls) _ ->
+ match fcls with
+ | [] -> to_fdefs (Defs defs)
+ | (FCL_aux (FCL_Funcl name _) _)::_ ->
+ Map.insert (get_id name) fcls (to_fdefs (Defs defs)) end end)
+ | _ -> to_fdefs (Defs defs) end end
+
+val to_register_fields : defs tannot -> map string (map string index_range)
+let rec to_register_fields (Defs defs) =
+ match defs with
+ | [ ] -> Map.empty
+ | def::defs ->
+ match def with
+ | DEF_type (TD_aux (TD_register id n1 n2 indexes) l') ->
+ Map.insert (get_id id)
+ (List.foldr (fun (a,b) imap -> Map.insert (get_id b) a imap) Map.empty indexes)
+ (to_register_fields (Defs defs))
+ | _ -> to_register_fields (Defs defs)
+ end
+ end
+
+val to_registers : i_direction -> defs tannot -> env
+let rec to_registers dd (Defs defs) =
+ match defs with
+ | [ ] -> Map.empty
+ | def::defs ->
+ match def with
+ | DEF_reg_dec (DEC_aux (DEC_reg typ id) (l,tannot)) ->
+ let dir = match tannot with
+ | Nothing -> dd
+ | Just(t, _, _, _,_) -> dd (*TODO, lets pull the direction out properly*)
+ end in
+ Map.insert (get_id id) (V_register(Form_Reg id tannot dir)) (to_registers dd (Defs defs))
+ | DEF_reg_dec (DEC_aux (DEC_alias id aspec) (l,tannot)) ->
+ Map.insert (get_id id) (V_register_alias aspec tannot) (to_registers dd (Defs defs))
+ | _ -> to_registers dd (Defs defs)
+ end
+ end
+
+val to_aliases : defs tannot -> map string (alias_spec tannot)
+let rec to_aliases (Defs defs) =
+ match defs with
+ | [] -> Map.empty
+ | def::defs ->
+ match def with
+ | DEF_reg_dec (DEC_aux (DEC_alias id aspec) _) ->
+ Map.insert (get_id id) aspec (to_aliases (Defs defs))
+ | DEF_reg_dec (DEC_aux (DEC_typ_alias typ id aspec) _) ->
+ Map.insert (get_id id) aspec (to_aliases (Defs defs))
+ | _ -> to_aliases (Defs defs)
+ end
+ end
+
+val to_data_constructors : defs tannot -> map string typ
+let rec to_data_constructors (Defs defs) =
+ match defs with
+ | [] ->
+ (*Prime environment with built-in constructors*)
+ Map.insert "Some" (Typ_aux (Typ_var (Kid_aux (Var "a") Unknown)) Unknown)
+ (Map.insert "None" unit_t Map.empty)
+ | def :: defs ->
+ match def with
+ | DEF_type (TD_aux t _)->
+ match t with
+ | TD_variant id _ tq tid_list _ ->
+ (List.foldr
+ (fun (Tu_aux t _) map ->
+ match t with
+ | (Tu_ty_id x y) -> Map.insert (get_id y) x map
+ | Tu_id x -> Map.insert (get_id x) unit_t map end)
+ (to_data_constructors (Defs defs))) tid_list
+ | _ -> to_data_constructors (Defs defs) end
+ | _ -> to_data_constructors (Defs defs) end
+ end
+
+(*Memory and environment helper functions*)
+val env_from_list : list (id * value) -> env
+let env_from_list ls = List.foldr (fun (id,v) env -> Map.insert (get_id id) v env) Map.empty ls
+
+val in_env :forall 'a. map string 'a -> string -> maybe 'a
+let in_env env id = Map.lookup id env
+
+val in_lenv : lenv -> id -> value
+let in_lenv (LEnv _ env) id =
+ match in_env env (get_id id) with
+ | Nothing -> V_unknown
+ | Just v -> v
+end
+
+(*Prefer entries in the first when in conflict*)
+val union_env : lenv -> lenv -> lenv
+let union_env (LEnv i1 env1) (LEnv i2 env2) =
+ let l = if i1 < i2 then i2 else i1 in
+ LEnv l (Map.(union) env2 env1)
+
+val fresh_var : lenv -> (id * lenv)
+let fresh_var (LEnv i env) =
+ let lenv = (LEnv (i+1) env) in
+ ((Id_aux (Id ((show i) ^ "var")) Interp_ast.Unknown), lenv)
+
+val add_to_env : (id * value) -> lenv -> lenv
+let add_to_env (id, entry) (LEnv i env) = (LEnv i (Map.insert (get_id id) entry env))
+
+val in_mem : lmem -> nat -> value
+let in_mem (LMem _ _ m _) n =
+ Map_extra.find n m
+ (* Map.lookup n m *)
+
+val update_mem : bool -> lmem -> nat -> value -> lmem
+let update_mem track (LMem owner c m s) loc value =
+ let m' = Map.delete loc m in
+ let m' = Map.insert loc value m' in
+ let s' = if track then Set.insert loc s else s in
+ LMem owner c m' s'
+
+val clear_updates : lmem -> lmem
+let clear_updates (LMem owner c m _) = LMem owner c m Set.empty
+
+(*Value helper functions*)
+
+val is_lit_vector : lit -> bool
+let is_lit_vector (L_aux l _) =
+ match l with
+ | L_bin _ -> true
+ | L_hex _ -> true
+ | _ -> false
+end
+
+val litV_to_vec : lit -> i_direction -> value
+let litV_to_vec (L_aux lit l) (dir: i_direction) =
+ match lit with
+ | L_hex s ->
+ let to_v b = V_lit (L_aux b l) in
+ let hexes = List.map to_v
+ (List.concat
+ (List.map
+ (fun s -> match s with
+ | #'0' -> [L_zero;L_zero;L_zero;L_zero]
+ | #'1' -> [L_zero;L_zero;L_zero;L_one ]
+ | #'2' -> [L_zero;L_zero;L_one ;L_zero]
+ | #'3' -> [L_zero;L_zero;L_one ;L_one ]
+ | #'4' -> [L_zero;L_one ;L_zero;L_zero]
+ | #'5' -> [L_zero;L_one ;L_zero;L_one ]
+ | #'6' -> [L_zero;L_one ;L_one ;L_zero]
+ | #'7' -> [L_zero;L_one ;L_one ;L_one ]
+ | #'8' -> [L_one ;L_zero;L_zero;L_zero]
+ | #'9' -> [L_one ;L_zero;L_zero;L_one ]
+ | #'A' -> [L_one ;L_zero;L_one ;L_zero]
+ | #'B' -> [L_one ;L_zero;L_one ;L_one ]
+ | #'C' -> [L_one ;L_one ;L_zero;L_zero]
+ | #'D' -> [L_one ;L_one ;L_zero;L_one ]
+ | #'E' -> [L_one ;L_one ;L_one ;L_zero]
+ | #'F' -> [L_one ;L_one ;L_one ;L_one ]
+ | #'a' -> [L_one ;L_zero;L_one ;L_zero]
+ | #'b' -> [L_one ;L_zero;L_one ;L_one ]
+ | #'c' -> [L_one ;L_one ;L_zero;L_zero]
+ | #'d' -> [L_one ;L_one ;L_zero;L_one ]
+ | #'e' -> [L_one ;L_one ;L_one ;L_zero]
+ | #'f' -> [L_one ;L_one ;L_one ;L_one ]
+ | _ -> Assert_extra.failwith "Lexer did not restrict to valid hex" end)
+ (String.toCharList s))) in
+ V_vector (if is_inc(dir) then 0 else ((List.length hexes) - 1)) dir hexes
+ | L_bin s ->
+ let bits = List.map
+ (fun s -> match s with
+ | #'0' -> (V_lit (L_aux L_zero l))
+ | #'1' -> (V_lit (L_aux L_one l))
+ | _ -> Assert_extra.failwith "Lexer did not restrict to valid bin"
+ end) (String.toCharList s) in
+ V_vector (if is_inc(dir) then 0 else ((List.length bits) -1)) dir bits
+ | _ -> Assert_extra.failwith "litV predicate did not restrict to literal vectors"
+end
+
+val list_nth : forall 'a . list 'a -> nat -> 'a
+let list_nth l n = List_extra.nth l n
+
+val list_length : forall 'a . list 'a -> integer
+let list_length l = integerFromNat (List.length l)
+
+val taint: value -> set reg_form -> value
+let rec taint value regs =
+ if Set.null regs
+ then value
+ else match value with
+ | V_track value rs -> taint value (regs union rs)
+ | V_tuple vals -> V_tuple (List.map (fun v -> taint v regs) vals)
+ | _ -> V_track value regs
+end
+
+val retaint: value -> value -> value
+let retaint orig updated =
+ match orig with
+ | V_track _ rs -> taint updated rs
+ | _ -> updated
+end
+
+val detaint: value -> value
+let rec detaint value =
+ match value with
+ | V_track value _ -> detaint value
+ | v -> v
+end
+
+(* the inner lambda is to make Isabelle happier about overlapping patterns *)
+let rec binary_taint thunk = fun vall valr ->
+ match (vall,valr) with
+ | (V_track vl rl,V_track vr rr) -> taint (binary_taint thunk vl vr) (rl union rr)
+ | (V_track vl rl,vr) -> taint (binary_taint thunk vl vr) rl
+ | (vl,V_track vr rr) -> taint (binary_taint thunk vl vr) rr
+ | (vl,vr) -> thunk vl vr
+end
+
+let rec merge_values v1 v2 =
+ if value_eq true v1 v2
+ then v1
+ else match (v1,v2) with
+ | (V_lit l, V_lit l') -> if lit_eq l l' then v1 else V_unknown
+ | (V_boxref n t, V_boxref m t') ->
+ (*Changes to memory handled by merge_mem*)
+ if n = m then v1 else V_unknown
+ | (V_tuple l, V_tuple l') ->
+ V_tuple (map2 merge_values l l')
+ | (V_list l, V_list l') ->
+ if (List.length l = List.length l')
+ then V_list (map2 merge_values l l')
+ else V_unknown
+ | (V_vector n b l, V_vector m b' l') ->
+ if b = b' && (List.length l = List.length l')
+ then V_vector n b (map2 merge_values l l')
+ else V_unknown
+ | (V_vector_sparse n o b l v, V_vector_sparse m p b' l' v') ->
+ if (n=m && o=p && b=b' && listEqualBy (fun (i,_) (i',_) -> i=i') l l')
+ then V_vector_sparse n o b (map2 (fun (i,v1) (i',v2) -> (i, merge_values v1 v2)) l l') (merge_values v v')
+ else V_unknown
+ | (V_record t l, V_record t' l') ->
+ (*assumes canonical order for fields in a record*)
+ if t = t' && List.length l = length l'
+ then V_record t (map2 (fun (i,v1) (_,v2) -> (i, merge_values v1 v2)) l l')
+ else V_unknown
+ | (V_ctor i t (C_Enum j) v, V_ctor i' t' (C_Enum j') v') ->
+ if i = i' then v1 else V_unknown
+ | (V_ctor _ _ (C_Enum i) _,V_lit (L_aux (L_num j) _)) -> if i = (natFromInteger j) then v1 else V_unknown
+ | (V_lit (L_aux (L_num j) _), V_ctor _ _ (C_Enum i) _) -> if i = (natFromInteger j) then v2 else V_unknown
+ | (V_ctor i t ckind v, V_ctor i' t' _ v') ->
+ if t = t' && i = i'
+ then (V_ctor i t ckind (merge_values v v'))
+ else V_unknown
+ | (V_unknown,V_unknown) -> V_unknown
+ | (V_track v1 ts1, V_track v2 ts2) ->
+ taint (merge_values v1 v2) (ts1 union ts2)
+ | (V_track v1 ts, v2) -> taint (merge_values v1 v2) ts
+ | (v1,V_track v2 ts) -> taint (merge_values v1 v2) ts
+ | (_, _) -> V_unknown
+end
+
+val merge_lmems : lmem -> lmem -> lmem
+let merge_lmems ((LMem owner1 c1 mem1 set1) as lmem1) ((LMem owner2 c2 mem2 set2) as lmem2) =
+ let diff1 = Set_extra.toList (set1 \ set2) in
+ let diff2 = Set_extra.toList (set2 \ set1) in
+ let inters = Set_extra.toList (set1 inter set2) in
+ let c = max c1 c2 in
+ let mem = LMem owner1 c (if c1 >= c2 then mem1 else mem2) Set.empty in
+ let diff_mem1 =
+ List.foldr
+ (fun i mem -> update_mem false mem i
+ (match Map.lookup i mem2 with
+ | Nothing -> V_unknown
+ | Just v -> merge_values (in_mem lmem1 i) v end)) mem diff1 in
+ let diff_mem2 =
+ List.foldr
+ (fun i mem -> update_mem false mem i
+ (match Map.lookup i mem1 with
+ | Nothing -> V_unknown
+ | Just v -> merge_values (in_mem lmem2 i) v end)) diff_mem1 diff2 in
+ List.foldr
+ (fun i mem -> update_mem false mem i (merge_values (in_mem lmem1 i) (in_mem lmem2 i)))
+ diff_mem2 inters
+
+let vector_length v = match (detaint v) with
+ | V_vector n inc vals -> List.length vals
+ | V_vector_sparse n m inc vals def -> m
+ | V_lit _ -> 1
+ | _ -> 0
+end
+
+val access_vector : value -> nat -> value
+let access_vector v n =
+ retaint v (match (detaint v) with
+ | V_unknown -> V_unknown
+ | V_lit (L_aux L_undef _) -> v
+ | V_lit (L_aux L_zero _) -> v
+ | V_lit (L_aux L_one _ ) -> v
+ | V_vector m dir vs ->
+ list_nth vs (if is_inc(dir) then (n - m) else (m - n))
+ | V_vector_sparse _ _ _ vs d ->
+ match (List.lookup n vs) with
+ | Nothing -> d
+ | Just v -> v end
+ | _ -> Assert_extra.failwith ("access_vector given unexpected " ^ string_of_value v)
+ end )
+
+val from_n_to_n :forall 'a. nat -> nat -> list 'a -> list 'a
+let from_n_to_n from to_ ls = take (to_ - from + 1) (drop from ls)
+
+val slice_sparse_list : (nat -> nat -> bool) -> (nat -> nat) -> list (nat * value) -> nat -> nat -> ((list (nat * value)) * bool)
+let rec slice_sparse_list compare update_n vals n1 n2 =
+ let sl = slice_sparse_list compare update_n in
+ if (n1 = n2) && (vals = [])
+ then ([],true)
+ else if (n1=n2)
+ then ([],false)
+ else match vals with
+ | [] -> ([],true)
+ | (i,v)::vals ->
+ if n1 = i
+ then let (rest,still_sparse) = (sl vals (update_n n1) n2) in ((i,v)::rest,still_sparse)
+ else if (compare n1 i)
+ then (sl vals (update_n n1) n2)
+ else let (rest,_) = (sl vals (update_n i) n2) in ((i,v)::rest,true)
+ end
+
+val slice_vector : value -> nat -> nat -> value
+let slice_vector v n1 n2 =
+ retaint v (match detaint v with
+ | V_vector m dir vs ->
+ if is_inc(dir)
+ then V_vector n1 dir (from_n_to_n (n1 - m) (n2 - m) vs)
+ else V_vector n1 dir (from_n_to_n (m - n1) (m - n2) vs)
+ | V_vector_sparse m n dir vs d ->
+ let (slice, still_sparse) =
+ if is_inc(dir)
+ then slice_sparse_list (>) (fun i -> i + 1) vs n1 n2
+ else slice_sparse_list (<) (fun i -> i - 1) vs n1 n2 in
+ if still_sparse && is_inc(dir)
+ then V_vector_sparse n1 (n2 - n1) dir slice d
+ else if is_inc(dir) then V_vector 0 dir (List.map snd slice)
+ else if still_sparse then V_vector_sparse n1 (n1 - n2) dir slice d
+ else V_vector n1 dir (List.map snd slice)
+ | _ -> Assert_extra.failwith ("slice_vector given unexpected " ^ string_of_value v)
+ end )
+
+val update_field_list : list (id * value) -> env -> list (id * value)
+let rec update_field_list base updates =
+ match base with
+ | [] -> []
+ | (id,v)::bs -> match in_env updates (get_id id) with
+ | Just v -> (id,v)::(update_field_list bs updates)
+ | Nothing -> (id,v)::(update_field_list bs updates) end
+end
+
+val fupdate_record : value -> value -> value
+let fupdate_record base updates =
+ let fupdate_record_helper base updates =
+ (match (base,updates) with
+ | (V_record t bs,V_record _ us) -> V_record t (update_field_list bs (env_from_list us))
+ | _ ->
+ Assert_extra.failwith ("fupdate_record given unexpected " ^
+ string_of_value base ^ " and " ^ (string_of_value updates))
+ end) in
+ binary_taint fupdate_record_helper base updates
+
+val fupdate_sparse : (nat -> nat -> bool) -> list (nat*value) -> nat -> value -> list (nat*value)
+let rec fupdate_sparse comes_after vs n vexp =
+ match vs with
+ | [] -> [(n,vexp)]
+ | (i,v)::vs ->
+ if i = n then (i,vexp)::vs
+ else if (comes_after i n) then (n,vexp)::(i,v)::vs
+ else (i,v)::(fupdate_sparse comes_after vs n vexp)
+end
+
+val fupdate_vec : value -> nat -> value -> value
+let fupdate_vec v n vexp =
+ let tainted = binary_taint (fun v _ -> v) v vexp in
+ retaint tainted
+ (match detaint v with
+ | V_vector m dir vals ->
+ V_vector m dir (List.update vals (if is_inc(dir) then (n-m) else (m-n)) vexp)
+ | V_vector_sparse m o dir vals d ->
+ V_vector_sparse m o dir (fupdate_sparse (if is_inc(dir) then (>) else (<)) vals n vexp) d
+ | _ -> Assert_extra.failwith ("fupdate_vec given unexpected " ^ string_of_value v)
+ end)
+
+val replace_is : forall 'a. list 'a -> list 'a -> nat -> nat -> nat -> list 'a
+let rec replace_is ls vs base start stop =
+ match (ls,vs) with
+ | ([],_) -> []
+ | (ls,[]) -> ls
+ | (l::ls,v::vs) ->
+ if base >= start then
+ if start >= stop then v::ls
+ else v::(replace_is ls vs (base + 1) (start + 1) stop)
+ else l::(replace_is ls (v::vs) (base+1) start stop)
+ end
+
+val replace_sparse : (nat -> nat -> bool) -> list (nat * value) -> list (nat * value) -> list (nat * value)
+let rec replace_sparse compare vals reps =
+ match (vals,reps) with
+ | ([],rs) -> rs
+ | (vs,[]) -> vs
+ | ((i1,v)::vs,(i2,r)::rs) ->
+ if i1 = i2 then (i2,r)::(replace_sparse compare vs rs)
+ else if (compare i1 i2)
+ then (i1,v)::(replace_sparse compare vs ((i2,r)::rs))
+ else (i2,r)::(replace_sparse compare ((i1,v)::vs) rs)
+end
+
+val fupdate_vector_slice : value -> value -> nat -> nat -> value
+let fupdate_vector_slice vec replace start stop =
+ let fupdate_vec_help vec replace =
+ (match (vec,replace) with
+ | (V_vector m dir vals,V_vector r_m dir' reps) ->
+ V_vector m dir
+ (replace_is vals
+ (if dir=dir' then reps else (List.reverse reps))
+ 0 (if is_inc(dir) then (start-m) else (m-start)) (if is_inc(dir) then (stop-m) else (m-stop)))
+ | (V_vector m dir vals, V_unknown) ->
+ V_vector m dir
+ (replace_is vals
+ (List.replicate (if is_inc(dir) then (stop-start) else (start-stop)) V_unknown)
+ 0 (if is_inc(dir) then (start-m) else (m-start)) (if is_inc(dir) then (stop-m) else (m-stop)))
+ | (V_vector_sparse m n dir vals d,V_vector _ _ reps) ->
+ let (_,repsi) = List.foldl (fun (i,rs) r -> ((if is_inc(dir) then i+1 else i-1), (i,r)::rs)) (start,[]) reps in
+ (V_vector_sparse m n dir (replace_sparse (if is_inc(dir) then (<) else (>)) vals (List.reverse repsi)) d)
+ | (V_vector_sparse m n dir vals d, V_unknown) ->
+ let (_,repsi) = List.foldl (fun (i,rs) r -> ((if is_inc(dir) then i+1 else i-1), (i,r)::rs)) (start,[])
+ (List.replicate (if is_inc(dir) then (stop-start) else (start-stop)) V_unknown) in
+ (V_vector_sparse m n dir (replace_sparse (if is_inc(dir) then (<) else (>)) vals (List.reverse repsi)) d)
+ | (V_unknown,_) -> V_unknown
+ | _ -> Assert_extra.failwith ("fupdate vector slice given " ^ (string_of_value vec)
+ ^ " and " ^ (string_of_value replace))
+ end) in
+ binary_taint fupdate_vec_help vec replace
+
+val update_vector_slice : bool -> value -> value -> nat -> nat -> lmem -> lmem
+let update_vector_slice track vector value start stop mem =
+ match (detaint vector,detaint value) with
+ | ((V_boxref n t), v) ->
+ update_mem track mem n (fupdate_vector_slice (in_mem mem n) (retaint value v) start stop)
+ | ((V_vector m _ vs),(V_vector n _ vals)) ->
+ let (V_vector m' _ vs') = slice_vector vector start stop in
+ foldr2 (fun vbox v mem -> match vbox with
+ | V_boxref n t -> update_mem track mem n v end)
+ mem vs' vals
+ | ((V_vector m dir vs),(V_vector_sparse n o _ vals d)) ->
+ let (m',vs') = match slice_vector vector start stop with
+ | (V_vector m' _ vs') -> (m',vs')
+ | _ -> Assert_extra.failwith "slice_vector did not return vector" end in
+ let (_,mem) = foldr (fun vbox (i,mem) ->
+ match vbox with
+ | V_boxref n t ->
+ (if is_inc(dir) then i+1 else i-1,
+ update_mem track mem n (match List.lookup i vals with
+ | Nothing -> d
+ | Just v -> v end))
+ | _ -> Assert_extra.failwith "Internal error: update_vector_slice not of boxes"
+ end) (m,mem) vs' in
+ mem
+ | ((V_vector m _ vs),v) ->
+ let (m',vs') = match slice_vector vector start stop with
+ | (V_vector m' _ vs') -> (m',vs')
+ | _ -> Assert_extra.failwith "slice vector didn't return vector" end in
+ List.foldr (fun vbox mem -> match vbox with
+ | V_boxref n t -> update_mem track mem n v
+ | _ -> Assert_extra.failwith "update_vector_slice not of boxes" end)
+ mem vs'
+ | _ -> Assert_extra.failwith ("update_vector_slice given unexpected " ^ string_of_value vector
+ ^ " and " ^ string_of_value value)
+end
+
+let update_vector_start default_dir new_start expected_size v =
+ retaint v
+ (match detaint v with
+ | V_lit (L_aux L_zero _) -> V_vector new_start default_dir [v]
+ | V_lit (L_aux L_one _) -> V_vector new_start default_dir [v]
+ | V_vector m inc vs -> V_vector new_start inc vs (*Note, may need to shrink and check if still sparse *)
+ | V_vector_sparse m n dir vals d -> V_vector_sparse new_start n dir vals d
+ | V_unknown -> V_vector new_start default_dir (List.replicate expected_size V_unknown)
+ | V_lit (L_aux L_undef _) -> V_vector new_start default_dir (List.replicate expected_size v)
+ | _ -> Assert_extra.failwith ("update_vector_start given unexpected " ^ string_of_value v)
+ end)
+
+val in_ctors : list (id * typ) -> id -> maybe typ
+let rec in_ctors ctors id =
+ match ctors with
+ | [] -> Nothing
+ | (cid,typ)::ctors -> if (get_id cid) = (get_id id) then Just typ else in_ctors ctors id
+end
+
+(*Stack manipulation functions *)
+(*Extends expression and context of 'top' stack frame *)
+let add_to_top_frame e_builder stack =
+ match stack with
+ | Top -> Top
+ | Hole_frame id e t_level env mem stack ->
+ let (e',env') = (e_builder e env) in Hole_frame id e' t_level env' mem stack
+ | Thunk_frame e t_level env mem stack ->
+ let (e',env') = (e_builder e env) in Thunk_frame e' t_level env' mem stack
+ end
+
+(*Is this the innermost hole*)
+let top_hole stack : bool =
+ match stack with
+ | Hole_frame _ (E_aux (E_id (Id_aux (Id "0") _)) _) _ _ _ Top -> true
+ | _ -> false
+end
+
+let redex_id = id_of_string "0"
+let mk_hole l annot t_level l_env l_mem =
+ Hole_frame redex_id (E_aux (E_id redex_id) (l,(intern_annot annot))) t_level l_env l_mem Top
+let mk_thunk l annot t_level l_env l_mem =
+ Thunk_frame (E_aux (E_lit (L_aux L_unit l)) (l,(intern_annot annot))) t_level l_env l_mem Top
+
+(*Converts a Hole_frame into a Thunk_frame, pushing to the top of the stack to insert the value at the innermost context *)
+val add_answer_to_stack : stack -> value -> stack
+let rec add_answer_to_stack stack v =
+ match stack with
+ | Top -> Top
+ | Hole_frame id e t_level env mem Top -> Thunk_frame e t_level (add_to_env (id,v) env) mem Top
+ | Thunk_frame e t_level env mem Top -> Thunk_frame e t_level env mem Top
+ | Hole_frame id e t_level env mem stack -> Hole_frame id e t_level env mem (add_answer_to_stack stack v)
+ | Thunk_frame e t_level env mem stack -> Thunk_frame e t_level env mem (add_answer_to_stack stack v)
+end
+
+(*Throws away all but the environment and local memory of the top stack frame, putting given expression in this context *)
+val set_in_context : stack -> exp tannot -> stack
+let rec set_in_context stack e =
+ match stack with
+ | Top -> Top
+ | Hole_frame id oe t_level env mem Top -> Thunk_frame e t_level env mem Top
+ | Thunk_frame oe t_level env mem Top -> Thunk_frame e t_level env mem Top
+ | Hole_frame _ _ _ _ _ s -> set_in_context s e
+ | Thunk_frame _ _ _ _ s -> set_in_context s e
+end
+
+let get_stack_state stack =
+ match stack with
+ | Top -> Assert_extra.failwith "Top reached in extracting stack state"
+ | Hole_frame id exp top_level lenv lmem stack -> (lenv,lmem)
+ | Thunk_frame exp top_level lenv lmem stack -> (lenv,lmem)
+end
+
+let rec update_stack_state stack ((LMem name c mem _) as lmem) =
+ match stack with
+ | Top -> Top
+ | Hole_frame id oe t_level env (LMem _ _ _ s) Top ->
+ (match Map.lookup (0 : nat) mem with
+ | Nothing -> Thunk_frame oe t_level (add_to_env (id,V_unknown) env) (LMem name c mem s) Top
+ | Just v -> Thunk_frame oe t_level (add_to_env (id, v) env) (LMem name c (Map.delete (0 : nat) mem) s) Top end)
+ | Thunk_frame e t_level env _ Top -> Thunk_frame e t_level env lmem Top
+ | Hole_frame id e t_level env mem s -> Hole_frame id e t_level env mem (update_stack_state s lmem)
+ | Thunk_frame e t_level env mem s -> Thunk_frame e t_level env mem (update_stack_state s lmem)
+end
+
+let rec clear_stack_state stack =
+ match stack with
+ | Top -> Top
+ | Hole_frame id e t_level env lmem Top -> Hole_frame id e t_level env (clear_updates lmem) Top
+ | Thunk_frame e t_level env lmem Top -> Thunk_frame e t_level env (clear_updates lmem) Top
+ | Hole_frame id e t_level env lmem s -> Hole_frame id e t_level env lmem (clear_stack_state s)
+ | Thunk_frame e t_level env lmem s -> Thunk_frame e t_level env lmem (clear_stack_state s)
+end
+
+let rec remove_top_stack_frame stack =
+ match stack with
+ | Top -> Top
+ | Hole_frame _ _ _ _ _ Top -> Top
+ | Thunk_frame _ _ _ _ Top -> Top
+ | Hole_frame id e t_level env lmem stack -> Hole_frame id e t_level env lmem (remove_top_stack_frame stack)
+ | Thunk_frame e t_level env lmem stack -> Thunk_frame e t_level env lmem (remove_top_stack_frame stack)
+end
+
+(*functions for converting in progress evaluation back into expression for building current continuation*)
+let rec combine_typs ts =
+ match ts with
+ | [] -> mk_typ_var "fresh"
+ | [t] -> t
+ | t::ts ->
+ let t' = combine_typs ts in
+ match (t,t') with
+ | (_,Typ_aux (Typ_var _) _) -> t
+ | ((Typ_aux (Typ_app (Id_aux (Id "range") _)
+ [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant bot1) _)) _; Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant top1) _)) _]) _),
+ (Typ_aux (Typ_app (Id_aux (Id "range") _)
+ [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant bot2) _)) _; Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant top2) _)) _]) _)) ->
+ let (smallest,largest) =
+ if bot1 <= bot2
+ then if top1 <= top2 then (bot1, top2) else (bot1, top1)
+ else if top1 <= top2 then (bot2, top2) else (bot2, top1) in
+ mk_typ_app "range" [Typ_arg_nexp (nconstant smallest); Typ_arg_nexp (nconstant largest)]
+ | ((Typ_aux (Typ_app (Id_aux (Id "atom") _) [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant a1) _)) _]) _),
+ (Typ_aux (Typ_app (Id_aux (Id "atom") _) [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant a2) _)) _]) _)) ->
+ if a1 = a2
+ then t
+ else
+ let (smaller,larger) = if a1 < a2 then (a1,a2) else (a2,a1) in
+ mk_typ_app "range" [Typ_arg_nexp (nconstant smaller); Typ_arg_nexp (nconstant larger)]
+ | (Typ_aux (Typ_app (Id_aux (Id "range") _) [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant bot) _)) _;
+ Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant top) _)) _]) _,
+ Typ_aux (Typ_app (Id_aux (Id "atom") _) [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant a) _)) _]) _) ->
+ if bot <= a && a <= top
+ then t
+ else if bot <= a && top <= a
+ then mk_typ_app "range" [Typ_arg_nexp (nconstant bot); Typ_arg_nexp (nconstant a)]
+ else mk_typ_app "range" [Typ_arg_nexp (nconstant a); Typ_arg_nexp (nconstant top)]
+ | (Typ_aux (Typ_app (Id_aux (Id "atom") _) [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant a) _)) _]) _,
+ Typ_aux (Typ_app (Id_aux (Id "range") _) [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant bot) _)) _;
+ Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant top) _)) _]) _) ->
+ if bot <= a && a <= top
+ then t
+ else if bot <= a && top <= a
+ then mk_typ_app "range" [Typ_arg_nexp (nconstant bot); Typ_arg_nexp (nconstant a)]
+ else mk_typ_app "range" [Typ_arg_nexp (nconstant a); Typ_arg_nexp (nconstant top)]
+ | (Typ_aux (Typ_app (Id_aux (Id "vector") _) [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant b1) _)) _;
+ Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant r1) _)) _;
+ Typ_arg_aux (Typ_arg_order (Ord_aux o1 _)) _;
+ Typ_arg_aux (Typ_arg_typ t1) _]) _,
+ Typ_aux (Typ_app (Id_aux (Id "vector") _) [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant b2) _)) _;
+ Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant r2) _)) _;
+ Typ_arg_aux (Typ_arg_order (Ord_aux o2 _)) _;
+ Typ_arg_aux (Typ_arg_typ t2) _]) _) ->
+ let t = combine_typs [t1;t2] in
+ match (o1,o2) with
+ | (Ord_inc,Ord_inc) ->
+ let larger_start = if b1 < b2 then b2 else b1 in
+ let smaller_rise = if r1 < r2 then r1 else r2 in
+ mk_typ_app "vector" [Typ_arg_nexp (nconstant larger_start); Typ_arg_nexp (nconstant smaller_rise);
+ Typ_arg_order (Ord_aux o1 Unknown); Typ_arg_typ t]
+ | (Ord_dec,Ord_dec) ->
+ let smaller_start = if b1 < b2 then b1 else b2 in
+ let smaller_fall = if r1 < r2 then r2 else r2 in
+ mk_typ_app "vector" [Typ_arg_nexp (nconstant smaller_start); Typ_arg_nexp (nconstant smaller_fall);
+ Typ_arg_order (Ord_aux o1 Unknown); Typ_arg_typ t]
+ | _ -> mk_typ_var "fresh"
+ end
+ | _ -> t'
+ end
+ end
+
+let reg_to_t r =
+ match r with
+ | Form_Reg _ (Just (t,_,_,_,_)) _ -> t
+ | _ -> mk_typ_var "fresh"
+ end
+
+let rec val_typ v =
+ match v with
+ | V_boxref n t -> mk_typ_app "reg" [Typ_arg_typ t]
+ | V_lit (L_aux lit _) ->
+ match lit with
+ | L_unit -> mk_typ_id "unit"
+ | L_true -> mk_typ_id "bit"
+ | L_false -> mk_typ_id "bit"
+ | L_one -> mk_typ_id "bit"
+ | L_zero -> mk_typ_id "bit"
+ | L_string _ -> mk_typ_id "string"
+ | L_num n -> mk_typ_app "atom" [Typ_arg_nexp (nconstant n)]
+ | L_undef -> mk_typ_var "fresh"
+ | L_hex _ -> Assert_extra.failwith "literal hex not removed"
+ | L_bin _ -> Assert_extra.failwith "literal bin not removed"
+ end
+ | V_tuple vals -> mk_typ_tup (List.map val_typ vals)
+ | V_vector n dir vals ->
+ let ts = List.map val_typ vals in
+ let t = combine_typs ts in
+ mk_typ_app "vector" [Typ_arg_nexp (nconstant (integerFromNat n)); Typ_arg_nexp (nconstant (list_length vals));
+ Typ_arg_order (Ord_aux (if is_inc dir then Ord_inc else Ord_dec) Unknown);
+ Typ_arg_typ t]
+ | V_vector_sparse n m dir vals d ->
+ let ts = List.map val_typ (d::(List.map snd vals)) in
+ let t = combine_typs ts in
+ mk_typ_app "vector" [Typ_arg_nexp (nconstant (integerFromNat n)); Typ_arg_nexp (nconstant (integerFromNat m));
+ Typ_arg_order (Ord_aux (if is_inc dir then Ord_inc else Ord_dec) Unknown);
+ Typ_arg_typ t]
+ | V_record t ivals -> t
+ | V_list vals ->
+ let ts = List.map val_typ vals in
+ let t = combine_typs ts in
+ mk_typ_app "list" [Typ_arg_typ t]
+ | V_ctor id t _ vals -> t
+ | V_register reg -> reg_to_t reg
+ | V_track v _ -> val_typ v
+ | V_unknown -> mk_typ_var "fresh"
+ | V_register_alias _ _ -> mk_typ_var "fresh"
+ end
+
+let rec to_exp mode env v : (exp tannot * lenv) =
+ ((E_aux (E_internal_value v) (Interp_ast.Unknown, (val_annot (val_typ v)))), env)
+
+val env_to_let : interp_mode -> lenv -> (exp tannot) -> lenv -> ((exp tannot) * lenv)
+let rec env_to_let_help mode env taint_env = match env with
+ | [] -> ([],taint_env)
+ | (i,v)::env ->
+ let t = (val_typ v) in
+ let tan = (val_annot t) in
+ let (e,taint_env) = to_exp mode taint_env v in
+ let (rest,taint_env) = env_to_let_help mode env taint_env in
+ ((((P_aux (P_id (id_of_string i)) (Unknown,tan)),e),t)::rest, taint_env)
+end
+
+let env_to_let mode (LEnv _ env) (E_aux e annot) taint_env =
+ match env_to_let_help mode (Set_extra.toList (Map.toSet env)) taint_env with
+ | ([],taint_env) -> (E_aux e annot,taint_env)
+ | ([((p,e),t)],tain_env) ->
+ (E_aux (E_let (LB_aux (LB_val p e) (Unknown,(val_annot t))) e) annot,taint_env)
+ | (pts,taint_env) ->
+ let ts = List.map snd pts in
+ let pes = List.map fst pts in
+ let ps = List.map fst pes in
+ let es = List.map snd pes in
+ let t = mk_typ_tup ts in
+ let tan = val_annot t in
+ (E_aux (E_let (LB_aux (LB_val (P_aux (P_tup ps) (Unknown,tan))
+ (E_aux (E_tuple es) (Unknown,tan))) (Unknown,tan))
+ (E_aux e annot))
+ annot, taint_env)
+end
+
+let fix_up_nondet typ branches annot =
+ match typ with
+ | Typ_aux (Typ_id (Id_aux (Id "unit") _)) _ -> (branches, Nothing)
+ | _ -> ((List.map
+ (fun e -> E_aux (E_assign (LEXP_aux (LEXP_id redex_id) annot) e) annot) branches), Just "0")
+end
+
+(* match_pattern returns a tuple of (pattern_matches? , pattern_passed_due_to_unknown?, env_of_pattern *)
+val match_pattern : top_level -> pat tannot -> value -> bool * bool * lenv
+let rec match_pattern t_level (P_aux p (_, annot)) value_whole =
+ let (Env fdefs instrs default_dir lets regs ctors subregs aliases debug) = t_level in
+ let (t,tag,cs) = match annot with
+ | Just(t,tag,cs,e,_) -> (t,tag,cs)
+ | Nothing -> (mk_typ_var "fresh",Tag_empty,[]) end in
+ let value = detaint value_whole in
+ let taint_pat v = binary_taint (fun v _ -> v) v value_whole in
+ match p with
+ | P_lit(lit) ->
+ if is_lit_vector lit then
+ let (n, inc, bits) = match litV_to_vec lit default_dir
+ with | V_vector n inc bits -> (n, inc, bits)
+ | _ -> Assert_extra.failwith "litV_to_vec failed" end in
+ match value with
+ | V_lit litv ->
+ if is_lit_vector litv then
+ let (n', inc', bits') = match litV_to_vec litv default_dir with
+ | V_vector n' inc' bits' -> (n', inc', bits')
+ | _ -> Assert_extra.failwith "litV_to_vec failed" end in
+ if n=n' && inc = inc' then (foldr2 (fun l r rest -> (l = r) && rest) true bits bits',false, eenv)
+ else (false,false,eenv)
+ else (false,false,eenv)
+ | V_vector n' inc' bits' ->
+ (foldr2 (fun l r rest -> (l=r) && rest) true bits bits',false,eenv)
+ | V_unknown -> (true,true,eenv)
+ | _ -> (false,false,eenv) end
+ else
+ match value with
+ | V_lit(litv) -> (lit = litv, false,eenv)
+ | V_vector _ _ [V_lit(litv)] -> (lit = litv,false,eenv)
+ | V_unknown -> (true,true,eenv)
+ | _ -> (false,false,eenv)
+ end
+ | P_wild -> (true,false,eenv)
+ | P_as pat id ->
+ let (matched_p,used_unknown,bounds) = match_pattern t_level pat value in
+ if matched_p then
+ (matched_p,used_unknown,(add_to_env (id,value_whole) bounds))
+ else (false,false,eenv)
+ | P_typ typ pat -> match_pattern t_level pat value_whole
+ | P_id id -> (true, false, (LEnv 0 (Map.fromList [((get_id id),value_whole)])))
+ | P_app (Id_aux id _) pats ->
+ match value with
+ | V_ctor (Id_aux cid _) t ckind (V_tuple vals) ->
+ if (id = cid && ((List.length pats) = (List.length vals)))
+ then foldr2
+ (fun pat value (matched_p,used_unknown,bounds) ->
+ if matched_p then
+ let (matched_p,used_unknown',new_bounds) = match_pattern t_level pat (taint_pat value) in
+ (matched_p, (used_unknown || used_unknown'), (union_env new_bounds bounds))
+ else (false,false,eenv)) (true,false,eenv) pats vals
+ else (false,false,eenv)
+ | V_ctor (Id_aux cid _) t ckind (V_track (V_tuple vals) r) ->
+ if (id = cid && ((List.length pats) = (List.length vals)))
+ then foldr2
+ (fun pat value (matched_p,used_unknown,bounds) ->
+ if matched_p then
+ let (matched_p,used_unknown',new_bounds) = match_pattern t_level pat (taint value r) in
+ (matched_p, (used_unknown || used_unknown'), (union_env new_bounds bounds))
+ else (false,false,eenv)) (true,false,eenv) pats vals
+ else (false,false,eenv)
+ | V_ctor (Id_aux cid _) t ckind v ->
+ if id = cid
+ then (match (pats,detaint v) with
+ | ([],(V_lit (L_aux L_unit _))) -> (true,false,eenv)
+ | ([P_aux (P_lit (L_aux L_unit _)) _],(V_lit (L_aux L_unit _))) -> (true,false,eenv)
+ | ([p],_) -> match_pattern t_level p v
+ | _ -> (false,false,eenv) end)
+ else (false,false,eenv)
+ | V_lit (L_aux (L_num i) _) ->
+ match tag with
+ | Tag_enum _ ->
+ match Map.lookup (get_id (Id_aux id Unknown)) lets with
+ | Just(V_ctor _ t (C_Enum j) _) ->
+ if i = (integerFromNat j) then (true,false,eenv)
+ else (false,false,eenv)
+ | _ -> (false,false,eenv) end
+ | _ -> (false,false,eenv) end
+ | V_unknown -> (true,true,eenv)
+ | _ -> (false,false,eenv) end
+ | P_record fpats _ ->
+ match value with
+ | V_record t fvals ->
+ let fvals_env = env_from_list fvals in
+ List.foldr
+ (fun (FP_aux (FP_Fpat id pat) _) (matched_p,used_unknown,bounds) ->
+ if matched_p then
+ let (matched_p,used_unknown',new_bounds) = match in_env fvals_env (get_id id) with
+ | Nothing -> (false,false,eenv)
+ | Just v -> match_pattern t_level pat v end in
+ (matched_p, (used_unknown || used_unknown'), (union_env new_bounds bounds))
+ else (false,false,eenv)) (true,false,eenv) fpats
+ | V_unknown -> (true,true,eenv)
+ | _ -> (false,false,eenv)
+ end
+ | P_vector pats ->
+ match value with
+ | V_vector n dir vals ->
+ if ((List.length vals) = (List.length pats))
+ then foldr2
+ (fun pat value (matched_p,used_unknown,bounds) ->
+ if matched_p then
+ let (matched_p,used_unknown',new_bounds) = match_pattern t_level pat (taint_pat value) in
+ (matched_p, (used_unknown||used_unknown'), (union_env new_bounds bounds))
+ else (false,false,eenv))
+ (true,false,eenv) pats vals
+ else (false,false,eenv)
+ | V_vector_sparse n m dir vals d ->
+ if (m = (List.length pats))
+ then let (_,matched_p,used_unknown,bounds) =
+ foldr
+ (fun pat (i,matched_p,used_unknown,bounds) ->
+ if matched_p
+ then let (matched_p,used_unknown',new_bounds) =
+ match_pattern t_level pat (match List.lookup i vals with
+ | Nothing -> d
+ | Just v -> (taint_pat v) end) in
+ ((if is_inc(dir) then i+1 else i-1),
+ matched_p,used_unknown||used_unknown',(union_env new_bounds bounds))
+ else (i,false,false,eenv)) (n,true,false,eenv) pats in
+ (matched_p,used_unknown,bounds)
+ else (false,false,eenv)
+ | V_unknown -> (true,true,eenv)
+ | _ -> (false,false,eenv)
+ end
+ | P_vector_concat pats ->
+ match value with
+ | V_vector n dir vals ->
+ let (matched_p,used_unknown,bounds,remaining_vals) = vec_concat_match_top t_level pats vals dir in
+ (*List.foldl
+ (fun (matched_p,used_unknown,bounds,r_vals) (P_aux pat (l,Just(t,_,_,_))) ->
+ let (matched_p,used_unknown',bounds',matcheds,r_vals) = vec_concat_match_plev t_level pat r_vals inc l t in
+ (matched_p,(used_unknown || used_unknown'),(union_env bounds' bounds),r_vals)) (true,false,eenv,vals) pats in*)
+ if matched_p && ([] = remaining_vals) then (matched_p,used_unknown,bounds) else (false,false,eenv)
+ | V_unknown -> (true,true,eenv)
+ | _ -> (false,false, eenv)
+ end
+ | P_tup(pats) ->
+ match value with
+ | V_tuple(vals) ->
+ if ((List.length pats)= (List.length vals))
+ then foldr2
+ (fun pat v (matched_p,used_unknown,bounds) -> if matched_p then
+ let (matched_p,used_unknown',new_bounds) = match_pattern t_level pat (taint_pat v) in
+ (matched_p,used_unknown ||used_unknown', (union_env new_bounds bounds))
+ else (false,false,eenv))
+ (true,false,eenv) pats vals
+ else (false,false,eenv)
+ | V_unknown -> (true,true,eenv)
+ | _ -> (false,false,eenv)
+ end
+ | P_list(pats) ->
+ match value with
+ | V_list(vals) ->
+ if ((List.length pats)= (List.length vals))
+ then foldr2
+ (fun pat v (matched_p,used_unknown,bounds) -> if matched_p then
+ let (matched_p,used_unknown',new_bounds) = match_pattern t_level pat (taint_pat v) in
+ (matched_p,used_unknown|| used_unknown', (union_env new_bounds bounds))
+ else (false,false,eenv))
+ (true,false,eenv) pats vals
+ else (false,false,eenv)
+ | V_unknown -> (true,true,eenv)
+ | _ -> (false,false,eenv) end
+ end
+
+and vec_concat_match_top t_level pats r_vals dir : ((*matched_p*) bool * (*used_unknown*) bool * lenv * (list value)) =
+ match pats with
+ | [] -> (true,false,eenv,r_vals)
+ | [(P_aux p (l,Just(t,_,_,_,_)))] ->
+ let (matched_p,used_unknown,bounds,_,r_vals) = vec_concat_match_plev t_level p r_vals dir l true t in
+ (matched_p,used_unknown,bounds,r_vals)
+ | (P_aux p (l,Just(t,_,_,_,_)))::pats ->
+ let (matched_p,used_unknown,bounds,matcheds,r_vals) = vec_concat_match_plev t_level p r_vals dir l false t in
+ if matched_p then
+ let (matched_p',used_unknown',bounds',r_vals) = vec_concat_match_top t_level pats r_vals dir in
+ (matched_p',(used_unknown || used_unknown'),union_env bounds' bounds, r_vals)
+ else (false,false,eenv,r_vals)
+ | _ -> Assert_extra.failwith "Type annotation illformed"
+end
+
+and vec_concat_match_plev t_level pat r_vals dir l last_pat t =
+ match pat with
+ | P_lit (L_aux (L_bin bin_string) l') ->
+ let bin_chars = toCharList bin_string in
+ let binpats = List.map
+ (fun b -> P_aux (match b with
+ | #'0' -> P_lit (L_aux L_zero l')
+ | #'1' -> P_lit (L_aux L_one l')
+ | _ -> Assert_extra.failwith "bin not 0 or 1" end) (l',Nothing)) bin_chars in
+ vec_concat_match t_level binpats r_vals
+ | P_vector pats -> vec_concat_match t_level pats r_vals
+ | P_id id ->
+ (match t with
+ | Typ_aux (Typ_app (Id_aux (Id "vector") _) [_;Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant i) _)) _;_;_]) _ ->
+ let wilds = List.genlist (fun _ -> P_aux P_wild (l,Nothing)) (natFromInteger i) in
+ let (matched_p,used_unknown,bounds,matcheds,r_vals) = vec_concat_match t_level wilds r_vals in
+ if matched_p
+ then (matched_p, used_unknown,
+ (add_to_env (id,(V_vector (if is_inc(dir) then 0 else ((List.length matcheds) - 1)) dir matcheds))
+ bounds),
+ matcheds,r_vals)
+ else (false,false,eenv,[],[])
+ | Typ_aux (Typ_app (Id_aux (Id "vector") _) [_;Typ_arg_aux (Typ_arg_nexp nc) _;_;_]) _ ->
+ if last_pat
+ then
+ (true,false,
+ (add_to_env (id,(V_vector (if is_inc(dir) then 0 else ((List.length r_vals) - 1)) dir r_vals)) eenv),
+ r_vals,[])
+ else (false,false,eenv,[],[]) (*TODO use some constraint bounds here*)
+ | _ ->
+ if last_pat
+ then
+ (true,false,
+ (add_to_env (id,(V_vector (if is_inc(dir) then 0 else ((List.length r_vals) -1 )) dir r_vals)) eenv),
+ r_vals,[])
+ else (false,false,eenv,[],[]) end)
+ | P_wild -> (match t with
+ | Typ_aux (Typ_app (Id_aux (Id "vector") _) [_;Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant i) _)) _;_;_]) _ ->
+ let wilds = List.genlist (fun _ -> P_aux P_wild (l,Nothing)) (natFromInteger i) in
+ vec_concat_match t_level wilds r_vals
+ | Typ_aux (Typ_app (Id_aux (Id "vector") _) [_;Typ_arg_aux (Typ_arg_nexp nc) _;_;_]) _ ->
+ if last_pat
+ then
+ (true,false,eenv,r_vals,[])
+ else (false,false,eenv,[],[]) (*TODO use some constraint bounds here*)
+ | _ ->
+ if last_pat
+ then
+ (true,false,eenv,r_vals,[])
+ else (false,false,eenv,[],[]) end)
+ | P_as (P_aux pat (l',Just(t',_,_,_,_))) id ->
+ let (matched_p, used_unknown, bounds,matcheds,r_vals) =
+ vec_concat_match_plev t_level pat r_vals dir l last_pat t' in
+ if matched_p
+ then (matched_p, used_unknown,
+ (add_to_env (id,V_vector (if is_inc(dir) then 0 else (List.length matcheds)) dir matcheds) bounds),
+ matcheds,r_vals)
+ else (false,false,eenv,[],[])
+ | P_typ _ (P_aux p (l',Just(t',_,_,_,_))) -> vec_concat_match_plev t_level p r_vals dir l last_pat t
+ | _ -> (false,false,eenv,[],[]) end
+ (*TODO Need to support indexed here, skipping intermediate numbers but consumming r_vals, and as *)
+
+and vec_concat_match t_level pats r_vals =
+ match pats with
+ | [] -> (true,false,eenv,[],r_vals)
+ | pat::pats -> match r_vals with
+ | [] -> (false,false,eenv,[],[])
+ | r::r_vals ->
+ let (matched_p,used_unknown,new_bounds) = match_pattern t_level pat r in
+ if matched_p then
+ let (matched_p,used_unknown',bounds,matcheds,r_vals) = vec_concat_match t_level pats r_vals in
+ (matched_p, used_unknown||used_unknown',(union_env new_bounds bounds),r :: matcheds,r_vals)
+ else (false,false,eenv,[],[]) end
+ end
+
+
+(* Returns all matches using Unknown until either there are no more matches or a pattern matches with no Unknowns used *)
+val find_funcl : top_level -> list (funcl tannot) -> value -> list (lenv * bool * (exp tannot))
+let rec find_funcl t_level funcls value =
+ match funcls with
+ | [] -> []
+ | (FCL_aux (FCL_Funcl id (Pat_aux (Pat_exp pat exp) _)) _)::funcls ->
+ let (is_matching,used_unknown,env) = match_pattern t_level pat value in
+ if (is_matching && used_unknown)
+ then (env,used_unknown,exp)::(find_funcl t_level funcls value)
+ else if is_matching then [(env,used_unknown,exp)]
+ else find_funcl t_level funcls value
+ end
+
+(*see above comment*)
+val find_case : top_level -> list (pexp tannot) -> value -> list (lenv * bool * (exp tannot))
+let rec find_case t_level pexps value =
+ match pexps with
+ | [] -> []
+ | (Pat_aux (Pat_exp p e) _)::pexps ->
+ let (is_matching,used_unknown,env) = match_pattern t_level p value in
+ if (is_matching && used_unknown)
+ then (env,used_unknown,e)::find_case t_level pexps value
+ else if is_matching then [(env,used_unknown,e)]
+ else find_case t_level pexps value
+ end
+
+val interp_main : interp_mode -> top_level -> lenv -> lmem -> (exp tannot) -> (outcome * lmem * lenv)
+val exp_list : interp_mode -> top_level -> ((list (exp tannot)) -> lenv -> ((exp tannot) * lenv)) -> (list value -> value) -> lenv -> lmem -> list value -> list (exp tannot) -> (outcome * lmem * lenv)
+val interp_lbind : interp_mode -> top_level -> lenv -> lmem -> (letbind tannot) -> ((outcome * lmem * lenv) * (maybe ((exp tannot) -> (letbind tannot))))
+val interp_alias_read : interp_mode -> top_level -> lenv -> lmem -> (alias_spec tannot) -> (outcome * lmem * lenv)
+
+let resolve_outcome to_match value_thunk action_thunk =
+ match to_match with
+ | (Value v,lm,le) -> value_thunk v lm le
+ | (Action action stack,lm,le) -> (action_thunk (Action action stack), lm,le)
+ | (Error l s,lm,le) -> (Error l s,lm,le)
+end
+
+let string_of_action a =
+ (match a with
+ | Read_reg r _ -> "(Read_reg " ^ string_of_reg_form r ^ " _)"
+ | Write_reg r _ _ -> "(Write_reg " ^ string_of_reg_form r ^ " _ _)"
+ | Read_mem id v _ -> "(Read_mem " ^ string_of_id id ^ " " ^ debug_print_value v ^ " _)"
+ | Read_mem_tagged id v _ -> "(Read_mem_tagged " ^ string_of_id id ^ " " ^ debug_print_value v ^ " _)"
+ | Write_mem _ _ _ _ -> "(Write_mem _ _ _ _)"
+ | Write_ea id v -> "(Write_ea " ^ string_of_id id ^ " " ^ debug_print_value v ^ " _)"
+ | Write_memv _ _ _ -> "(Write_memv _ _ _)"
+ | Excl_res id -> "(Excl_res " ^ string_of_id id ^ ")"
+ | Write_memv_tagged _ _ _ _ -> "(Write_memv_tagged _ _ _ _)"
+ | Barrier id v -> "(Barrier " ^ string_of_id id ^ " " ^ debug_print_value v ^ ")"
+ | Footprint id v -> "(Footprint " ^ string_of_id id ^ " " ^ debug_print_value v ^ ")"
+ | Nondet exps _ -> "(Nondet [" ^ String.concat "; " (List.map string_of_exp exps) ^ "] _)"
+ | Call_extern s v -> "(Call_extern \"" ^ s ^ "\" " ^ debug_print_value v ^ ")"
+ | Return v -> "(Return " ^ debug_print_value v ^ ")"
+ | Exit exp -> "(Exit " ^ string_of_exp exp ^ ")"
+ | Fail v -> "(Fail " ^ debug_print_value v ^ ")"
+ | Step _ _ _ -> "(Step _ _ _)"
+ end)
+
+instance (Show action)
+ let show action = string_of_action action
+end
+
+let string_of_outcome outcome =
+ (match outcome with
+ | Value v -> "(Value " ^ debug_print_value v ^ ")"
+ | Action a _ -> "(Action " ^ string_of_action a ^ " _)"
+ | Error _ s -> "(Error _ \"" ^ s ^ "\")"
+ end)
+
+instance (Show outcome)
+ let show outcome = string_of_outcome outcome
+end
+
+let update_stack o fn = match o with
+ | Action act stack -> Action act (fn stack)
+ | _ -> o
+end
+
+let debug_out fn value e tl lm le =
+ (Action (Step (get_exp_l e) fn value) (Thunk_frame e tl le lm Top),lm,le)
+
+let to_exps mode env vals =
+ List.foldr (fun v (es,env) -> let (e,env') = to_exp mode env v in (e::es, union_env env' env)) ([],env) vals
+
+let get_num v = match v with
+ | V_lit (L_aux (L_num n) _) -> n
+ | _ -> 0 end
+
+(*Interpret a list of expressions, tracking local state but evaluating in the same scope (i.e. not tracking env) *)
+let rec __exp_list mode t_level build_e build_v l_env l_mem vals exps =
+ match exps with
+ | [ ] -> (Value (build_v vals), l_mem, l_env)
+ | e::exps ->
+ resolve_outcome (interp_main mode t_level l_env l_mem e)
+ (fun value lm le -> exp_list mode t_level build_e build_v l_env lm (vals++[value]) exps)
+ (fun a -> update_stack a (add_to_top_frame
+ (fun e env ->
+ let (es,env') = to_exps mode env vals in
+ let (e,env'') = build_e (es++(e::exps)) env' in
+ (e,env''))))
+ end
+
+and exp_list mode t_level build_e build_v l_env l_mem vals exps =
+ let _ = debug_fun_enter mode "exp_list" [show vals; show exps] in
+ let retval = __exp_list (indent_mode mode) t_level build_e build_v l_env l_mem vals exps in
+ let _ = debug_fun_exit mode "exp_list" retval in
+ retval
+
+and __interp_main mode t_level l_env l_mem (E_aux exp (l,annot)) =
+ let (Env fdefs instrs default_dir lets regs ctors subregs aliases debug) = t_level in
+ let (typ,tag,ncs,effect,reffect) = match annot with
+ | Nothing ->
+ (mk_typ_var "fresh_v", Tag_empty,[],(Effect_aux (Effect_set []) Unknown),(Effect_aux (Effect_set []) Unknown))
+ | Just(t, tag, ncs, ef,efr) -> (t,tag,ncs,ef,efr) end in
+ match exp with
+ | E_internal_value v -> (Value v, l_mem, l_env)
+ | E_lit lit ->
+ if is_lit_vector lit
+ then let is_inc = (match typ with
+ | Typ_aux (Typ_app (Id_aux (Id "vector") _) [_;_;Typ_arg_aux (Typ_arg_order (Ord_aux Ord_inc _)) _;_]) _ -> IInc | _ -> IDec end) in
+ (Value (litV_to_vec lit is_inc),l_mem,l_env)
+ else (Value (V_lit (match lit with
+ | L_aux L_false loc -> L_aux L_zero loc
+ | L_aux L_true loc -> L_aux L_one loc
+ | _ -> lit end)), l_mem,l_env)
+ | E_comment _ -> (Value unitv, l_mem,l_env)
+ | E_comment_struc _ -> (Value unitv, l_mem, l_env)
+ | E_cast ((Typ_aux typ _) as ctyp) exp ->
+ (*Cast is either a no-op, a signal to read a register, or a signal to change the start of a vector *)
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem exp)
+ (fun v lm le ->
+ (* Potentially use cast to change vector start position *)
+ let conditional_update_vstart () =
+ match typ with
+ | Typ_app (Id_aux (Id "vector") _) [Typ_arg_aux (Typ_arg_nexp(Nexp_aux (Nexp_constant i) _)) _;_;_;_] ->
+ let i = natFromInteger i in
+ match (detaint v) with
+ | V_vector start dir vs ->
+ if start = i then (Value v,lm,le) else (Value (update_vector_start dir i 1 v),lm,le)
+ | _ -> (Value v,lm,le) end
+ | (Typ_var (Kid_aux (Var "length") _))->
+ match (detaint v) with
+ | V_vector start dir vs ->
+ let i = (List.length vs) - 1 in
+ if start = i then (Value v,lm,le) else (Value (update_vector_start dir i 1 v),lm,le)
+ | _ -> (Value v,lm,le) end
+ | _ -> (Value v,lm,le) end in
+ (match (tag,detaint v) with
+ (*Cast is telling us to read a register*)
+ | (Tag_extern _, V_register regform) ->
+ (Action (Read_reg regform Nothing) (mk_hole l (val_annot (reg_to_t regform)) t_level le lm), lm,le)
+ (*Cast is changing vector start position, potentially*)
+ | (_,v) -> conditional_update_vstart () end))
+ (fun a -> update_stack a (add_to_top_frame (fun e env -> (E_aux (E_cast ctyp e) (l,annot), env))))
+ | E_id id ->
+ let name = get_id id in
+ match tag with
+ | Tag_empty ->
+ match in_lenv l_env id with
+ | V_boxref n t -> (Value (in_mem l_mem n),l_mem,l_env)
+ | value -> (Value value,l_mem,l_env) end
+ | Tag_global ->
+ match in_env lets name with
+ | Just(value) -> (Value value, l_mem,l_env)
+ | Nothing ->
+ (match in_env regs name with
+ | Just(value) -> (Value value, l_mem,l_env)
+ | Nothing -> (Error l ("Internal error: " ^ name ^ " unbound on Tag_global"),l_mem,l_env) end) end
+ | Tag_enum _ ->
+ match in_env lets name with
+ | Just(value) -> (Value value,l_mem,l_env)
+ | Nothing -> (Error l ("Internal error: " ^ name ^ " unbound on Tag_enum "), l_mem,l_env)
+ end
+ | Tag_extern _ -> (* update with id here when it's never just "register" *)
+ let regf = match in_lenv l_env id with (* Check for local treatment of a register as a value *)
+ | V_register regform -> regform
+ | _ ->
+ match in_env regs name with (* Register isn't a local value, so pull from global environment *)
+ | Just(V_register regform) -> regform
+ | _ -> Form_Reg id annot default_dir end end in
+ (Action (Read_reg regf Nothing) (mk_hole l annot t_level l_env l_mem), l_mem, l_env)
+ | Tag_alias ->
+ match in_env aliases name with
+ | Just aspec -> interp_alias_read mode t_level l_env l_mem aspec
+ | _ -> (Error l ("Internal error: alias not found"), l_mem,l_env) end
+ | _ ->
+ (Error l
+ ("Internal error: tag " ^ (string_of_tag tag) ^ " expected empty,enum,alias,or extern for " ^ name),
+ l_mem,l_env)
+ end
+ | E_if cond thn els ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem cond)
+ (fun value_whole lm le ->
+ let value = detaint value_whole in
+ match (value,mode.eager_eval) with
+ (*TODO remove booleans here when fully removed elsewhere *)
+ | (V_lit(L_aux L_one _),true) -> interp_main mode t_level l_env lm thn
+ | (V_lit(L_aux L_one _),false) -> debug_out Nothing Nothing thn t_level lm l_env
+ | (V_vector _ _ [(V_lit(L_aux L_one _))],true) -> interp_main mode t_level l_env lm thn
+ | (V_vector _ _ [(V_lit(L_aux L_one _))],false) -> debug_out Nothing Nothing thn t_level lm l_env
+ | (V_unknown,_) ->
+ let (branches,maybe_id) = fix_up_nondet typ [thn;els] (l,annot) in
+ interp_main mode t_level l_env lm (E_aux (E_nondet branches) (l,non_det_annot annot maybe_id))
+ | (_,true) -> interp_main mode t_level l_env lm els
+ | (_,false) -> debug_out Nothing Nothing els t_level lm l_env end)
+ (fun a -> update_stack a (add_to_top_frame (fun c env -> (E_aux (E_if c thn els) (l,annot), env))))
+ | E_for id from to_ by ((Ord_aux o _) as order) exp ->
+ let is_inc = match o with | Ord_inc -> true | _ -> false end in
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem from)
+ (fun from_val_whole lm le ->
+ let from_val = detaint from_val_whole in
+ let (from_e,env) = to_exp mode le from_val_whole in
+ match from_val with
+ | V_lit(L_aux(L_num from_num) fl) ->
+ resolve_outcome
+ (interp_main mode t_level env lm to_)
+ (fun to_val_whole lm le ->
+ let to_val = detaint to_val_whole in
+ let (to_e,env) = to_exp mode le to_val_whole in
+ match to_val with
+ | V_lit(L_aux (L_num to_num) tl) ->
+ resolve_outcome
+ (interp_main mode t_level env lm by)
+ (fun by_val_whole lm le ->
+ let by_val = detaint by_val_whole in
+ let (by_e,env) = to_exp mode le by_val_whole in
+ match by_val with
+ | V_lit (L_aux (L_num by_num) bl) ->
+ if ((is_inc && (from_num > to_num)) || (not(is_inc) && (from_num < to_num)))
+ then (Value(V_lit (L_aux L_unit l)),lm,le)
+ else
+ let (ftyp,ttyp,btyp) = (val_typ from_val,val_typ to_val,val_typ by_val) in
+ let augment_annot = (fl, val_annot (combine_typs [ftyp;ttyp])) in
+ let diff = L_aux (L_num (if is_inc then from_num+by_num else from_num - by_num)) fl in
+ let (augment_e,env) = match (from_val_whole,by_val_whole) with
+ | (V_lit _, V_lit _) -> ((E_aux (E_lit diff) augment_annot), env)
+ | (V_track _ rs, V_lit _) -> to_exp mode env (taint (V_lit diff) rs)
+ | (V_lit _, V_track _ rs) -> to_exp mode env (taint (V_lit diff) rs)
+ | (V_track _ r1, V_track _ r2) ->
+ (to_exp mode env (taint (V_lit diff) (r1 union r2)))
+ | _ -> Assert_extra.failwith "For loop from and by values not range" end in
+ let e =
+ (E_aux
+ (E_block
+ [(E_aux
+ (E_let
+ (LB_aux (LB_val (P_aux (P_id id) (fl,val_annot ftyp)) from_e)
+ (Unknown,val_annot ftyp))
+ exp) (l,annot));
+ (E_aux (E_for id augment_e to_e by_e order exp) (l,annot))])
+ (l,annot)) in
+ if mode.eager_eval
+ then interp_main mode t_level env lm e
+ else debug_out Nothing Nothing e t_level lm env
+ | V_unknown ->
+ let e =
+ (E_aux
+ (E_let
+ (LB_aux
+ (LB_val (P_aux (P_id id) (fl, val_annot (val_typ from_val))) from_e)
+ (fl, val_annot (val_typ from_val)))
+ exp) (l,annot)) in
+ interp_main mode t_level env lm e
+ | _ -> (Error l "internal error: by must be a number",lm,le) end)
+ (fun a -> update_stack a
+ (add_to_top_frame (fun b env -> (E_aux (E_for id from_e to_e b order exp) (l,annot), env))))
+ | V_unknown ->
+ let e =
+ (E_aux
+ (E_let (LB_aux
+ (LB_val (P_aux (P_id id) (fl, val_annot (val_typ from_val))) from_e)
+ (fl, val_annot (val_typ from_val))) exp) (l,annot)) in
+ interp_main mode t_level env lm e
+ | _ -> (Error l "internal error: to must be a number",lm,env) end)
+ (fun a -> update_stack a
+ (add_to_top_frame (fun t env ->
+ (E_aux (E_for id from_e t by order exp) (l,annot), env))))
+ | V_unknown ->
+ let e =
+ (E_aux
+ (E_let (LB_aux (LB_val (P_aux (P_id id) (Unknown, val_annot (val_typ from_val))) from_e)
+ (Unknown, val_annot (val_typ from_val))) exp) (l,annot)) in
+ interp_main mode t_level env lm e
+ | _ -> (Error l "internal error: from must be a number",lm,le) end)
+ (fun a -> update_stack a
+ (add_to_top_frame (fun f env -> (E_aux (E_for id f to_ by order exp) (l,annot), env))))
+ | E_case exp pats ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem exp)
+ (fun v lm le ->
+ match find_case t_level pats v with
+ | [] -> (Error l ("No matching patterns in case for value " ^ (string_of_value v)),lm,le)
+ | [(env,_,exp)] ->
+ if mode.eager_eval
+ then interp_main mode t_level (union_env env l_env) lm exp
+ else debug_out Nothing Nothing exp t_level lm (union_env env l_env)
+ | multi_matches ->
+ let (lets,taint_env) =
+ List.foldr (fun (env,_,exp) (rst,taint_env) ->
+ let (e,t_e) = env_to_let mode env exp taint_env in (e::rst,t_e)) ([],l_env) multi_matches in
+ let (branches,maybe_id) = fix_up_nondet typ lets (l,annot) in
+ interp_main mode t_level taint_env lm (E_aux (E_nondet branches) (l,(non_det_annot annot maybe_id)))
+ end)
+ (fun a -> update_stack a (add_to_top_frame (fun e env -> (E_aux (E_case e pats) (l,annot), env))))
+ | E_record(FES_aux (FES_Fexps fexps _) fes_annot) ->
+ let (fields,exps) = List.unzip (List.map (fun (FE_aux (FE_Fexp id exp) _) -> (id,exp)) fexps) in
+ exp_list mode t_level
+ (fun es env' ->
+ ((E_aux
+ (E_record
+ (FES_aux (FES_Fexps
+ (map2 (fun id exp -> (FE_aux (FE_Fexp id exp) (Unknown,Nothing))) fields es)
+ false) fes_annot))
+ (l,annot)), env'))
+ (fun vs -> (V_record typ (List.zip fields vs))) l_env l_mem [] exps
+ | E_record_update exp (FES_aux (FES_Fexps fexps _) fes_annot) ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem exp)
+ (fun rv lm le -> match rv with
+ | V_record t fvs ->
+ let (fields,exps) = List.unzip (List.map (fun (FE_aux (FE_Fexp id exp) _) -> (id,exp)) fexps) in
+ resolve_outcome
+ (exp_list mode t_level
+ (fun es env'->
+ let (e,env'') = (to_exp mode env' rv) in
+ ((E_aux (E_record_update e
+ (FES_aux (FES_Fexps
+ (map2 (fun id exp -> (FE_aux (FE_Fexp id exp) (Unknown,Nothing)))
+ fields es) false) fes_annot))
+ (l,annot)), env''))
+ (fun vs -> (V_record t (List.zip fields vs))) l_env l_mem [] exps)
+ (fun vs lm le -> (Value (fupdate_record rv vs), lm, le))
+ (fun a -> a) (*Due to exp_list this won't happen, but we want to functionaly update on Value *)
+ | V_unknown -> (Value V_unknown, lm, le)
+ | _ -> (Error l "internal error: record update requires record",lm,le) end)
+ (fun a -> update_stack a
+ (add_to_top_frame
+ (fun e env -> (E_aux(E_record_update e (FES_aux(FES_Fexps fexps false) fes_annot)) (l,annot), env))))
+ | E_list(exps) ->
+ exp_list mode t_level (fun exps env' -> (E_aux (E_list exps) (l,annot),env')) V_list l_env l_mem [] exps
+ | E_cons hd tl ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem hd)
+ (fun hdv lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm tl)
+ (fun tlv lm le -> match detaint tlv with
+ | V_list t -> (Value (retaint tlv (V_list (hdv::t))),lm,le)
+ | V_unknown -> (Value (retaint tlv V_unknown),lm,le)
+ | _ -> (Error l ("Internal error '::' of non-list value " ^ (string_of_value tlv)),lm,le) end)
+ (fun a -> update_stack a
+ (add_to_top_frame
+ (fun t env -> let (hde,env') = to_exp mode env hdv in (E_aux (E_cons hde t) (l,annot),env')))))
+ (fun a -> update_stack a (add_to_top_frame (fun h env -> (E_aux (E_cons h tl) (l,annot), env))))
+ | E_field exp id ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem exp)
+ (fun value_whole lm le ->
+ match detaint value_whole with
+ | V_record t fexps ->
+ (match in_env (env_from_list fexps) (get_id id) with
+ | Just v -> (Value (retaint value_whole v),lm,l_env)
+ | Nothing -> (Error l "Internal_error: Field not found in record",lm,le) end)
+ | V_register ((Form_Reg _ annot _) as reg_form) ->
+ let id' = match annot with
+ | Just((Typ_aux (Typ_id (Id_aux (Id id') _)) _),_,_,_,_) -> id'
+ | _ -> Assert_extra.failwith "annotation not well formed for field access"
+ end in
+ (match in_env subregs id' with
+ | Just(indexes) ->
+ (match in_env indexes (get_id id) with
+ | Just ir ->
+ let sub_reg = Form_SubReg id reg_form ir in
+ (Action (Read_reg sub_reg Nothing)
+ (mk_hole l (val_annot (reg_to_t sub_reg)) t_level le lm),lm,le)
+ | _ -> (Error l "Internal error: unrecognized read, no id",lm,le) end)
+ | Nothing -> (Error l "Internal error: subregs indexes not found", lm, le) end)
+ | V_unknown -> (Value (retaint value_whole V_unknown),lm,l_env)
+ | _ ->
+ (Error l ("Internal error: neither register nor record at field access "
+ ^ (string_of_value value_whole)),lm,le) end)
+ (fun a ->
+ match (exp,a) with
+ | (E_aux _ (l,Just(_,Tag_extern _,_,_,_)),
+ (Action (Read_reg ((Form_Reg _ (Just((Typ_aux (Typ_id (Id_aux (Id id') _)) _),_,_,_,_)) _) as regf) Nothing) s)) ->
+ match in_env subregs id' with
+ | Just(indexes) ->
+ (match in_env indexes (get_id id) with
+ | Just ir ->
+ (Action (Read_reg (Form_SubReg id regf ir) Nothing) s)
+ | _ -> Error l "Internal error, unrecognized read, no id"
+ end)
+ | Nothing -> Error l "Internal error, unrecognized read, no reg" end
+ | _ -> update_stack a (add_to_top_frame (fun e env -> (E_aux(E_field e id) (l,annot),env))) end)
+ | E_vector_access vec i ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem vec)
+ (fun vvec lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm i)
+ (fun iv lm le ->
+ (match detaint iv with
+ | V_unknown -> (Value iv,lm,le)
+ | V_lit (L_aux (L_num n) ln) ->
+ let n = natFromInteger n in
+ let v_access vvec num =
+ (match (detaint vvec, detaint num) with
+ | (V_vector _ _ _,V_lit _) -> Value (access_vector vvec n)
+ | (V_vector_sparse _ _ _ _ _,V_lit _) -> Value (access_vector vvec n)
+ | (V_register reg, V_lit _) ->
+ Action (Read_reg reg (Just (n,n))) (mk_hole l annot t_level l_env lm)
+ | (V_unknown,_) -> Value V_unknown
+ | _ -> Assert_extra.failwith
+ ("Vector access error: " ^ (string_of_value vvec) ^ "[" ^ (show n) ^ "]")
+ end)
+ in
+ (v_access (retaint iv vvec) iv,lm,le)
+ | _ -> (Error l "Vector access not given a number for index",lm,l_env)
+ end))
+ (fun a -> update_stack a (add_to_top_frame(fun i' env ->
+ let (vec_e, env') = to_exp mode env vvec in
+ (E_aux (E_vector_access vec_e i') (l,annot), env')))))
+ (fun a ->
+ update_stack a (add_to_top_frame (fun vec' env ->
+ (E_aux (E_vector_access vec' i) (l,annot), env))))
+ | E_vector_subrange vec i1 i2 ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem vec)
+ (fun vvec lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm i1)
+ (fun i1v lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm i2)
+ (fun i2v lm le ->
+ match detaint i1v with
+ | V_unknown -> (Value i1v,lm,le)
+ | V_lit (L_aux (L_num n1) nl1) ->
+ match detaint i2v with
+ | V_unknown -> (Value i2v,lm,le)
+ | V_lit (L_aux (L_num n2) nl2) ->
+ let slice = binary_taint (fun v1 v2 -> V_tuple[v1;v2]) i1v i2v in
+ let take_slice vvec =
+ let (n1,n2) = (natFromInteger n1,natFromInteger n2) in
+ (match detaint vvec with
+ | V_vector _ _ _ -> Value (slice_vector vvec n1 n2)
+ | V_vector_sparse _ _ _ _ _ -> Value (slice_vector vvec n1 n2)
+ | V_unknown ->
+ let inc = n1 < n2 in
+ Value (retaint vvec (V_vector n1 (if inc then IInc else IDec)
+ (List.replicate ((if inc then n1-n2 else n2-n1)+1) V_unknown)))
+ | V_register reg ->
+ Action (Read_reg reg (Just (n1,n2))) (mk_hole l annot t_level le lm)
+ | _ -> (Error l ("Vector slice of non-vector " ^ (string_of_value vvec))) end) in
+ ((take_slice (retaint slice vvec)), lm,le)
+ | _ -> (Error l "vector subrange did not receive a range value", l_mem, l_env)
+ end
+ | _ -> (Error l "vector subrange did not receive a range value", l_mem, l_env)
+ end)
+ (fun a -> update_stack a (add_to_top_frame (fun i2' env ->
+ let (vec_e, env') = to_exp mode env vvec in
+ let (i1_e, env'') = to_exp mode env' i1v in
+ (E_aux (E_vector_subrange vec_e i1_e i2') (l,annot), env'')))))
+ (fun a ->
+ update_stack a (add_to_top_frame (fun i1' env ->
+ let (vec_e, env') = to_exp mode env vvec in
+ (E_aux (E_vector_subrange vec_e i1' i2) (l,annot), env')))))
+ (fun a ->
+ update_stack a (add_to_top_frame (fun vec' env ->
+ (E_aux (E_vector_subrange vec' i1 i2) (l,annot), env))))
+ | E_vector_update vec i exp ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem vec)
+ (fun vvec lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm i)
+ (fun vi lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm exp)
+ (fun vup lm le ->
+ (match (detaint vi) with
+ | V_lit (L_aux (L_num n1) ln1) ->
+ let fvup vi vvec =
+ (match vvec with
+ | V_vector _ _ _ -> fupdate_vec vvec (natFromInteger n1) vup
+ | V_vector_sparse _ _ _ _ _ -> fupdate_vec vvec (natFromInteger n1) vup
+ | V_unknown -> V_unknown
+ | _ -> Assert_extra.failwith "Update of vector given non-vector"
+ end)
+ in
+ (Value (binary_taint fvup vi vvec),lm,le)
+ | V_unknown -> (Value vi,lm,le)
+ | _ -> Assert_extra.failwith "Update of vector requires number for access"
+ end))
+ (fun a -> update_stack a (add_to_top_frame (fun exp' env ->
+ let (vec_e, env') = to_exp mode env vvec in
+ let (i_e, env'') = to_exp mode env' vi in
+ (E_aux (E_vector_update vec_e i_e exp') (l,annot), env'')))))
+ (fun a -> update_stack a (add_to_top_frame (fun i' env ->
+ let (vec_e, env') = to_exp mode env vvec in
+ (E_aux (E_vector_update vec_e i' exp) (l,annot), env')))))
+ (fun a -> update_stack a (add_to_top_frame (fun vec' env ->
+ (E_aux (E_vector_update vec' i exp) (l,annot), env))))
+ | E_vector_update_subrange vec i1 i2 exp ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem vec)
+ (fun vvec lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm i1)
+ (fun vi1 lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm i2)
+ (fun vi2 lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm exp)
+ (fun v_rep lm le ->
+ (match detaint vi1 with
+ | V_unknown -> (Value vi1,lm,le)
+ | V_lit (L_aux (L_num n1) ln1) ->
+ (match detaint vi2 with
+ | V_unknown -> (Value vi2,lm,le)
+ | V_lit (L_aux (L_num n2) ln2) ->
+ let slice = binary_taint (fun v1 v2 -> V_tuple[v1;v2]) vi1 vi2 in
+ let fup_v_slice v1 vvec =
+ (match vvec with
+ | V_vector _ _ _ ->
+ fupdate_vector_slice vvec v_rep (natFromInteger n1) (natFromInteger n2)
+ | V_vector_sparse _ _ _ _ _ ->
+ fupdate_vector_slice vvec v_rep (natFromInteger n1) (natFromInteger n2)
+ | V_unknown -> V_unknown
+ | _ -> Assert_extra.failwith "Vector update requires vector"
+ end) in
+ (Value (binary_taint fup_v_slice slice vvec),lm,le)
+ | _ -> Assert_extra.failwith "vector update requires number"
+ end)
+ | _ -> Assert_extra.failwith "vector update requires number"
+ end))
+ (fun a -> update_stack a (add_to_top_frame (fun exp' env ->
+ let (vec_e, env') = to_exp mode env vvec in
+ let (i1_e, env'') = to_exp mode env' vi1 in
+ let (i2_e, env''') = to_exp mode env'' vi1 in
+ (E_aux (E_vector_update_subrange vec_e i1_e i2_e exp') (l,annot), env''')))))
+ (fun a -> update_stack a (add_to_top_frame (fun i2' env ->
+ let (vec_e, env') = to_exp mode env vvec in
+ let (i1_e, env'') = to_exp mode env' vi1 in
+ (E_aux (E_vector_update_subrange vec_e i1_e i2' exp) (l,annot), env'')))))
+ (fun a -> update_stack a (add_to_top_frame (fun i1' env ->
+ let (vec_e, env') = to_exp mode env vvec in
+ (E_aux (E_vector_update_subrange vec_e i1' i2 exp) (l,annot), env')))))
+ (fun a -> update_stack a (add_to_top_frame (fun vec' env ->
+ (E_aux (E_vector_update_subrange vec' i1 i2 exp) (l,annot), env))))
+ | E_vector_append e1 e2 ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem e1)
+ (fun v1 lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm e2)
+ (fun v2 lm le ->
+ (match detaint v1 with
+ | V_unknown -> (Value v1,lm,le)
+ | _ ->
+ let append v1 v2 =
+ (match (v1,v2) with
+ | (V_vector _ dir vals1, V_vector _ _ vals2) ->
+ let vals = vals1++vals2 in
+ let len = List.length vals in
+ if is_inc(dir)
+ then V_vector 0 dir vals
+ else V_vector (len-1) dir vals
+ | (V_vector m dir vals1, V_vector_sparse _ len _ vals2 d) ->
+ let original_len = List.length vals1 in
+ let (_,sparse_vals) = List.foldr (fun v (i,vals) -> (i+1,(i,v)::vals)) (m,[]) vals1 in
+ let sparse_update = List.map (fun (i,v) -> (i+m+original_len,v)) vals2 in
+ V_vector_sparse m (len+original_len) dir (sparse_vals ++ sparse_update) d
+ | (V_vector_sparse m len dir vals1 d, V_vector _ _ vals2) ->
+ let new_len = List.length vals2 in
+ let (_,sparse_vals) = List.foldr (fun v (i,vals) -> (i+1,(i,v)::vals)) (len,[]) vals2 in
+ V_vector_sparse m (len+new_len) dir (vals1++sparse_vals) d
+ | (V_vector_sparse m len dir vals1 d, V_vector_sparse _ new_len _ vals2 _) ->
+ let sparse_update = List.map (fun (i,v) -> (i+len,v)) vals2 in
+ V_vector_sparse m (len+new_len) dir (vals1 ++ sparse_update) d
+ | (V_unknown,_) -> V_unknown (*update to get length from type*)
+ | (_,V_unknown) -> V_unknown (*see above*)
+ | _ -> Assert_extra.failwith ("vector concat requires two vectors but given "
+ ^ (string_of_value v1) ^ " " ^ (string_of_value v2))
+ end)
+ in
+ (Value (binary_taint append v1 v2),lm,le)
+ end))
+ (fun a -> update_stack a (add_to_top_frame (fun e2' env ->
+ let (e1_e, env') = to_exp mode env v1 in
+ (E_aux (E_vector_append e1_e e2') (l,annot), env')))))
+ (fun a -> update_stack a (add_to_top_frame (fun e1' env ->
+ (E_aux (E_vector_append e1' e2) (l,annot), env))))
+ | E_tuple(exps) ->
+ exp_list mode t_level (fun exps env' -> (E_aux (E_tuple exps) (l,annot), env')) V_tuple l_env l_mem [] exps
+ | E_vector(exps) ->
+ let (is_inc,dir) = (match typ with
+ | Typ_aux (Typ_app (Id_aux (Id "vector") _) [ _; _; Typ_arg_aux (Typ_arg_order (Ord_aux Ord_inc _)) _; _]) _ -> (true,IInc)
+ | _ -> (false,IDec) end) in
+ let base = (if is_inc then 0 else (List.length exps) - 1) in
+ exp_list mode t_level
+ (fun exps env' -> (E_aux (E_vector exps) (l,annot),env'))
+ (fun vals -> V_vector base dir vals) l_env l_mem [] exps
+ | E_block exps -> interp_block mode t_level l_env l_env l_mem l annot exps
+ | E_nondet exps ->
+ (Action (Nondet exps tag)
+ (match tag with
+ | Tag_unknown (Just id) -> mk_hole l annot t_level l_env l_mem
+ | _ -> mk_thunk l annot t_level l_env l_mem end),
+ l_mem, l_env)
+ | E_app f args ->
+ (match (exp_list mode t_level
+ (fun es env -> (E_aux (E_app f es) (l,annot),env))
+ (fun vs -> match vs with | [] -> V_lit (L_aux L_unit l) | [v] -> v | vs -> V_tuple vs end)
+ l_env l_mem [] args) with
+ | (Value v,lm,le) ->
+ let name = get_id f in
+ (match tag with
+ | Tag_global ->
+ (match Map.lookup name fdefs with
+ | Just(funcls) ->
+ (match find_funcl t_level funcls v with
+ | [] ->
+ (Error l ("No matching pattern for function " ^ name ^
+ " on value " ^ (string_of_value v)),l_mem,l_env)
+ | [(env,_,exp)] ->
+ resolve_outcome
+ (if mode.eager_eval
+ then (interp_main mode t_level env (emem name) exp)
+ else (debug_out (Just name) (Just v) exp t_level (emem name) env))
+ (fun ret lm le -> (Value ret, l_mem,l_env))
+ (fun a -> update_stack a
+ (fun stack -> (Hole_frame redex_id (E_aux (E_id redex_id) (l,(intern_annot annot)))
+ t_level l_env l_mem stack)))
+ | multi_matches ->
+ let (lets,taint_env) =
+ List.foldr (fun (env,_,exp) (rst,taint_env) ->
+ let (e,t_e) = env_to_let mode env exp taint_env in (e::rst,t_e)) ([],l_env) multi_matches in
+ let (branches,maybe_id) = fix_up_nondet typ lets (l,annot) in
+ let exp = E_aux (E_nondet branches) (l,(non_det_annot annot maybe_id)) in
+ interp_main mode t_level taint_env lm exp
+ end)
+ | Nothing ->
+ (Error l ("Internal error: function with tag global unfound " ^ name),lm,le) end)
+ | Tag_empty ->
+ (match Map.lookup name fdefs with
+ | Just(funcls) ->
+ (match find_funcl t_level funcls v with
+ | [] ->
+ (Error l ("No matching pattern for function " ^ name ^ " on value " ^ (string_of_value v)),l_mem,l_env)
+ | [(env,used_unknown,exp)] ->
+ resolve_outcome
+ (if mode.eager_eval
+ then (interp_main mode t_level env (emem name) exp)
+ else (debug_out (Just name) (Just v) exp t_level (emem name) env))
+ (fun ret lm le -> (Value ret, l_mem,l_env))
+ (fun a -> update_stack a
+ (fun stack -> (Hole_frame redex_id (E_aux (E_id redex_id) (l,(intern_annot annot)))
+ t_level l_env l_mem stack)))
+ | _ -> (Error l ("Internal error: multiple pattern matches found for " ^ name), l_mem, l_env)
+ end)
+ | Nothing ->
+ (Error l ("Internal error: function with local tag unfound " ^ name),lm,le) end)
+ | Tag_spec ->
+ (match Map.lookup name fdefs with
+ | Just(funcls) ->
+ (match find_funcl t_level funcls v with
+ | [] ->
+ (Error l ("No matching pattern for function " ^ name ^ " on value " ^ (string_of_value v)),l_mem,l_env)
+ | [(env,used_unknown,exp)] ->
+ resolve_outcome
+ (if mode.eager_eval
+ then (interp_main mode t_level env (emem name) exp)
+ else (debug_out (Just name) (Just v) exp t_level (emem name) env))
+ (fun ret lm le -> (Value ret, l_mem,l_env))
+ (fun a -> update_stack a
+ (fun stack ->
+ (Hole_frame redex_id
+ (E_aux (E_id redex_id) (l,(intern_annot annot))) t_level l_env l_mem stack)))
+ | _ -> (Error l ("Internal error: multiple pattern matches for " ^ name), l_mem, l_env)
+ end)
+ | Nothing ->
+ (Error l (String.stringAppend "Specified function must be defined before executing " name),lm,le) end)
+ | Tag_ctor ->
+ (match Map.lookup name ctors with
+ | Just(_) -> (Value (V_ctor f typ C_Union v), lm, le)
+ | Nothing -> (Error l (String.stringAppend "Internal error: function with ctor tag unfound " name),lm,le)
+ end)
+ | Tag_extern opt_name ->
+ let effects = (match effect with | Effect_aux(Effect_set es) _ -> es | _ -> [] end) in
+ let name_ext = match opt_name with | Just s -> s | Nothing -> name end in
+ let mk_hole_frame act = (Action act (mk_hole l annot t_level le lm), lm, le) in
+ let mk_thunk_frame act = (Action act (mk_thunk l annot t_level le lm), lm, le) in
+ if has_rmem_effect effects
+ then mk_hole_frame (Read_mem (id_of_string name_ext) v Nothing)
+ else if has_rmemt_effect effects
+ then mk_hole_frame (Read_mem_tagged (id_of_string name_ext) v Nothing)
+ else if has_barr_effect effects
+ then mk_thunk_frame (Barrier (id_of_string name_ext) v)
+ else if has_depend_effect effects
+ then mk_thunk_frame (Footprint (id_of_string name_ext) v)
+ else if has_wmem_effect effects
+ then let (wv,v) =
+ match v with
+ | V_tuple [p;v] -> (v,p)
+ | V_tuple params_list ->
+ let reved = List.reverse params_list in
+ (List_extra.head reved,V_tuple (List.reverse (List_extra.tail reved)))
+ | _ -> Assert_extra.failwith ("Expected tuple found " ^ (string_of_value v)) end in
+ mk_hole_frame (Write_mem (id_of_string name_ext) v Nothing wv)
+ else if has_eamem_effect effects
+ then mk_thunk_frame (Write_ea (id_of_string name_ext) v)
+ else if has_exmem_effect effects
+ then mk_hole_frame (Excl_res (id_of_string name_ext))
+ else if has_wmv_effect effects
+ then let (wv,v) =
+ match v with
+ | V_tuple [p;v] -> (v,p)
+ | V_tuple params_list ->
+ let reved= List.reverse params_list in
+ (List_extra.head reved,V_tuple (List.reverse (List_extra.tail reved)))
+ | _ -> (v,unitv) end in
+ mk_hole_frame (Write_memv (id_of_string name_ext) v wv)
+ else if has_wmvt_effect effects
+ then match v with
+ | V_tuple [addr; size; tag; data] ->
+ mk_hole_frame (Write_memv_tagged (id_of_string name_ext) (V_tuple([addr; size])) tag data)
+ | _ -> Assert_extra.failwith("wmvt: expected tuple of four elements") end
+ else mk_hole_frame (Call_extern name_ext v)
+ | _ ->
+ (Error l (String.stringAppend "Tag not empty, spec, ctor, or extern on function call " name),lm,le) end)
+ | out -> out end)
+ | E_app_infix lft op r ->
+ let op = match op with
+ | Id_aux (Id x) il -> Id_aux (DeIid x) il
+ | _ -> op
+ end in
+ let name = get_id op in
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem lft)
+ (fun lv lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm r)
+ (fun rv lm le ->
+ match tag with
+ | Tag_global ->
+ (match Map.lookup name fdefs with
+ | Nothing -> (Error l ("Internal error: no function def for " ^ name),lm,le)
+ | Just (funcls) ->
+ (match find_funcl t_level funcls (V_tuple [lv;rv]) with
+ | [] -> (Error l ("No matching pattern for function " ^ name),lm,l_env)
+ | [(env,used_unknown,exp)] ->
+ resolve_outcome
+ (if mode.eager_eval
+ then (interp_main mode t_level env (emem name) exp)
+ else (debug_out (Just name) (Just (V_tuple [lv;rv])) exp t_level (emem name) env))
+ (fun ret lm le -> (Value ret,l_mem,l_env))
+ (fun a -> update_stack a
+ (fun stack ->
+ (Hole_frame redex_id (E_aux (E_id redex_id) (l,(intern_annot annot)))
+ t_level l_env l_mem stack)))
+ | _ -> (Error l ("Internal error: multiple pattern matches for " ^ name),lm,le)
+ end)end)
+ | Tag_empty ->
+ (match Map.lookup name fdefs with
+ | Nothing -> (Error l ("Internal error: no function def for " ^ name),lm,le)
+ | Just (funcls) ->
+ (match find_funcl t_level funcls (V_tuple [lv;rv]) with
+ | [] -> (Error l ("No matching pattern for function " ^ name),lm,l_env)
+ | [(env,used_unknown,exp)] ->
+ resolve_outcome
+ (if mode.eager_eval
+ then (interp_main mode t_level env (emem name) exp)
+ else (debug_out (Just name) (Just (V_tuple [lv;rv])) exp t_level (emem name) env))
+ (fun ret lm le -> (Value ret,l_mem,l_env))
+ (fun a -> update_stack a
+ (fun stack -> (Hole_frame redex_id (E_aux (E_id redex_id) (l,annot))
+ t_level l_env l_mem stack)))
+ | _ -> (Error l ("Internal error: multiple pattern matches for " ^ name),lm,le)
+ end)end)
+ | Tag_spec ->
+ (match Map.lookup name fdefs with
+ | Nothing -> (Error l ("Internal error: No function definition found for " ^ name),lm,le)
+ | Just (funcls) ->
+ (match find_funcl t_level funcls (V_tuple [lv;rv]) with
+ | [] -> (Error l ("No matching pattern for function " ^ name),lm,l_env)
+ | [(env,used_unknown,exp)] ->
+ resolve_outcome
+ (if mode.eager_eval
+ then (interp_main mode t_level env (emem name) exp)
+ else (debug_out (Just name) (Just (V_tuple [lv;rv])) exp t_level (emem name) env))
+ (fun ret lm le -> (Value ret,l_mem,l_env))
+ (fun a -> update_stack a
+ (fun stack -> (Hole_frame redex_id
+ (E_aux (E_id redex_id) (l,(intern_annot annot)))
+ t_level l_env l_mem stack)))
+ | _ -> (Error l ("Internal error: multiple pattern matches for " ^ name), lm, le)
+ end)end)
+ | Tag_extern ext_name ->
+ let ext_name = match ext_name with Just s -> s | Nothing -> name end in
+ (Action (Call_extern ext_name (V_tuple [lv;rv]))
+ (Hole_frame redex_id
+ (E_aux (E_id redex_id) (l,intern_annot annot)) t_level le lm Top),lm,le)
+ | _ -> (Error l "Internal error: unexpected tag for app_infix", l_mem, l_env) end)
+ (fun a -> update_stack a
+ (add_to_top_frame
+ (fun r env -> let (el,env') = to_exp mode env lv in (E_aux (E_app_infix el op r) (l,annot), env')))))
+ (fun a -> update_stack a (add_to_top_frame (fun lft env -> (E_aux (E_app_infix lft op r) (l,annot), env))))
+ | E_exit exp ->
+ (Action (Exit exp) (mk_thunk l annot t_level l_env l_mem),l_mem, l_env)
+ | E_return exp ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem exp)
+ (fun v lm le -> (Action (Return v) Top, l_mem, l_env))
+ (fun a -> update_stack a (add_to_top_frame (fun e env -> (E_aux (E_return e) (l,annot), env))))
+ | E_assert cond msg ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem msg)
+ (fun v lm le ->
+ resolve_outcome
+ (interp_main mode t_level l_env lm cond)
+ (fun c lm le ->
+ (match detaint c with
+ | V_lit (L_aux L_one _) -> (Value unitv,lm,l_env)
+ | V_lit (L_aux L_true _) -> (Value unitv,lm,l_env)
+ | V_lit (L_aux L_zero _) -> (Action (Fail v) (mk_thunk l annot t_level l_env l_mem), lm,le)
+ | V_lit (L_aux L_false _) -> (Action (Fail v) (mk_thunk l annot t_level l_env l_mem), lm,le)
+ | V_unknown ->
+ let (branches,maybe_id) =
+ fix_up_nondet typ [unit_e;
+ E_aux (E_assert (E_aux (E_lit (L_aux L_zero l))
+ (l,val_annot (mk_typ_id "bit"))) msg) (l,annot)]
+ (l,annot) in
+ interp_main mode t_level l_env lm (E_aux (E_nondet branches) (l,non_det_annot annot maybe_id))
+ | _ -> (Error l ("assert given unexpected " ^ (string_of_value c)),l_mem,l_env)
+ end))
+ (fun a -> update_stack a (add_to_top_frame (fun c env -> (E_aux (E_assert c msg) (l,annot), env)))))
+ (fun a -> update_stack a (add_to_top_frame (fun m env -> (E_aux (E_assert cond m) (l,annot), env))))
+ | E_let (lbind : letbind tannot) exp ->
+ match (interp_letbind mode t_level l_env l_mem lbind) with
+ | ((Value v,lm,le),_) ->
+ if mode.eager_eval
+ then interp_main mode t_level le lm exp
+ else debug_out Nothing Nothing exp t_level lm le
+ | (((Action a s as o),lm,le),Just lbuild) ->
+ ((update_stack o (add_to_top_frame (fun e env -> (E_aux (E_let (lbuild e) exp) (l,annot), env)))),lm,le)
+ | (e,_) -> e end
+ | E_assign lexp exp ->
+ resolve_outcome
+ (interp_main mode t_level l_env l_mem exp)
+ (fun v lm le ->
+ (match create_write_message_or_update mode t_level v l_env lm true lexp with
+ | (outcome,Nothing,_) -> outcome
+ | (outcome,Just lexp_builder,Nothing) ->
+ resolve_outcome outcome
+ (fun v lm le -> (Value v,lm,le))
+ (fun a ->
+ (match a with
+ | (Action (Write_reg regf range value) stack) -> a
+ | (Action (Write_mem id a_ range value) stack) -> a
+ | (Action (Write_memv _ _ _) stack) -> a
+ | (Action (Write_memv_tagged _ _ _ _) stack) -> a
+ | _ -> update_stack a (add_to_top_frame
+ (fun e env ->
+ let (ev,env') = (to_exp mode env v) in
+ let (lexp,env') = (lexp_builder e env') in
+ (E_aux (E_assign lexp ev) (l,annot),env'))) end))
+ | (outcome,Just lexp_builder, Just v) ->
+ resolve_outcome outcome
+ (fun v lm le -> (Value v,lm,le))
+ (fun a -> update_stack a (add_to_top_frame
+ (fun e env ->
+ let (ev,env') = to_exp mode env v in
+ let (lexp,env') = (lexp_builder e env') in
+ (E_aux (E_assign lexp ev) (l,annot),env'))))
+ end))
+ (fun a -> update_stack a (add_to_top_frame (fun v env -> (E_aux (E_assign lexp v) (l,annot), env))))
+ | _ -> (Error l "Internal expression escaped to interpreter", l_mem, l_env)
+ end
+
+and interp_main mode t_level l_env l_mem exp =
+ let _ = debug_fun_enter mode "interp_main" [show exp] in
+ let retval = __interp_main (indent_mode mode) t_level l_env l_mem exp in
+ let _ = debug_fun_exit mode "interp_main" retval in
+ retval
+
+(*TODO shrink location information on recursive calls *)
+and __interp_block mode t_level init_env local_env local_mem l tannot exps =
+ match exps with
+ | [] -> (Value (V_lit (L_aux (L_unit) Unknown)), local_mem, init_env)
+ | [exp] ->
+ if mode.eager_eval
+ then interp_main mode t_level local_env local_mem exp
+ else debug_out Nothing Nothing exp t_level local_mem local_env
+ | exp:: exps ->
+ resolve_outcome (interp_main mode t_level local_env local_mem exp)
+ (fun _ lm le ->
+ if mode.eager_eval
+ then interp_block mode t_level init_env le lm l tannot exps
+ else debug_out Nothing Nothing (E_aux (E_block exps) (l,tannot)) t_level lm le)
+ (fun a -> update_stack a
+ (add_to_top_frame (fun e env-> (E_aux (E_block(e::exps)) (l,tannot), env))))
+ end
+
+and interp_block mode t_level init_env local_env local_mem l tannot exps =
+ let _ = debug_fun_enter mode "interp_block" [show exps] in
+ let retval = __interp_block (indent_mode mode) t_level init_env local_env local_mem l tannot exps in
+ let _ = debug_fun_exit mode "interp_block" retval in
+ retval
+
+and __create_write_message_or_update mode t_level value l_env l_mem is_top_level
+ ((LEXP_aux lexp (l,annot)):lexp tannot)
+ : ((outcome * lmem * lenv) * maybe ((exp tannot) -> lenv -> ((lexp tannot) * lenv)) * maybe value) =
+ let (Env fdefs instrs default_dir lets regs ctors subregs aliases debug) = t_level in
+ let (typ,tag,ncs,ef,efr) = match annot with
+ | Nothing -> (mk_typ_var "fresh_v", Tag_empty, [],
+ (Effect_aux (Effect_set []) Unknown),(Effect_aux (Effect_set []) Unknown))
+ | Just(t, tag, ncs, ef,efr) -> (t,tag,ncs,ef,efr) end in
+ let recenter_val (Typ_aux typ _) value = match typ with
+ | Typ_app (Id_aux (Id "reg") _) [Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_app (Id_aux (Id "vector") _)
+ [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant start) _)) _; Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant size) _)) _;_;_]) _)) _] ->
+ update_vector_start default_dir (natFromInteger start) (natFromInteger size) value
+ | _ -> value end in
+ match lexp with
+ | LEXP_id id ->
+ let name = get_id id in
+ match tag with
+ | Tag_intro ->
+ match detaint (in_lenv l_env id) with
+ | V_unknown ->
+ if is_top_level then
+ if name = "0" then
+ ((Value (V_lit (L_aux L_unit l)), update_mem true l_mem 0 value, l_env), Nothing, Nothing)
+ else
+ let (LMem owner c m s) = l_mem in
+ let l_mem = (LMem owner (c+1) m s) in
+ ((Value (V_lit (L_aux L_unit l)),
+ update_mem mode.track_lmem l_mem c value,
+ (add_to_env (id,(V_boxref c typ)) l_env)),Nothing, Nothing)
+ else ((Error l ("Unknown local id " ^ (get_id id)),l_mem,l_env),Nothing,Nothing)
+ | v ->
+ if is_top_level
+ then
+ if name = "0" then
+ ((Value (V_lit (L_aux L_unit l)), update_mem true l_mem 0 value, l_env), Nothing,Nothing)
+ else
+ ((Error l ("Writes must be to reg values given " ^ (string_of_value v)),l_mem,l_env),
+ Nothing, Nothing)
+ else ((Value v,l_mem,l_env),Just (fun e env -> (LEXP_aux(LEXP_id id) (l,annot), env)), Nothing)
+ end
+ | Tag_set ->
+ match detaint (in_lenv l_env id) with
+ | ((V_boxref n t) as v) ->
+ if is_top_level
+ then ((Value (V_lit (L_aux L_unit l)),
+ update_mem mode.track_lmem l_mem n (recenter_val t value), l_env),Nothing, Nothing)
+ else ((Value v, l_mem, l_env),Just (fun e env -> (LEXP_aux (LEXP_id id) (l,annot), env)), Nothing)
+ | V_unknown ->
+ if is_top_level then
+ if name = "0" then
+ ((Value (V_lit (L_aux L_unit l)), update_mem true l_mem 0 value, l_env), Nothing, Nothing)
+ else
+ let (LMem owner c m s) = l_mem in
+ let l_mem = (LMem owner (c+1) m s) in
+ ((Value (V_lit (L_aux L_unit l)),
+ update_mem mode.track_lmem l_mem c value,
+ (add_to_env (id,(V_boxref c typ)) l_env)),Nothing,Nothing)
+ else ((Error l ("Unknown local id " ^ (get_id id)),l_mem,l_env),Nothing, Nothing)
+ | v ->
+ if is_top_level
+ then
+ if name = "0" then
+ ((Value (V_lit (L_aux L_unit l)), update_mem true l_mem 0 value, l_env), Nothing, Nothing)
+ else
+ ((Error l ("Writes must be to reg values given " ^ (string_of_value v)),l_mem,l_env),
+ Nothing, Nothing)
+ else ((Value v,l_mem,l_env),Just (fun e env -> (LEXP_aux(LEXP_id id) (l,annot), env)), Nothing)
+ end
+ | Tag_empty ->
+ match detaint (in_lenv l_env id) with
+ | ((V_boxref n t) as v) ->
+ if is_top_level
+ then ((Value (V_lit (L_aux L_unit l)),
+ update_mem mode.track_lmem l_mem n (recenter_val t value), l_env),Nothing, Nothing)
+ else ((Value v, l_mem, l_env),Just (fun e env -> (LEXP_aux (LEXP_id id) (l,annot), env)), Nothing)
+ | V_unknown ->
+ if is_top_level then
+ if name = "0" then
+ ((Value (V_lit (L_aux L_unit l)), update_mem true l_mem 0 value, l_env), Nothing, Nothing)
+ else
+ let (LMem owner c m s) = l_mem in
+ let l_mem = (LMem owner (c+1) m s) in
+ ((Value (V_lit (L_aux L_unit l)),
+ update_mem mode.track_lmem l_mem c value,
+ (add_to_env (id,(V_boxref c typ)) l_env)),Nothing, Nothing)
+ else ((Error l ("Unknown local id " ^ (get_id id)),l_mem,l_env),Nothing,Nothing)
+ | v ->
+ if is_top_level
+ then
+ if name = "0" then
+ ((Value (V_lit (L_aux L_unit l)), update_mem true l_mem 0 value, l_env), Nothing, Nothing)
+ else
+ ((Error l ("Writes must be to reg values given " ^ (string_of_value v)),l_mem,l_env),
+ Nothing, Nothing)
+ else ((Value v,l_mem,l_env),Just (fun e env -> (LEXP_aux(LEXP_id id) (l,annot), env)), Nothing)
+ end
+ | Tag_global ->
+ (match in_env lets name with
+ | Just v ->
+ if is_top_level then ((Error l "Writes must be to reg or registers",l_mem,l_env),Nothing,Nothing)
+ else ((Value v,l_mem,l_env),Just (fun e env -> (LEXP_aux(LEXP_id id) (l,annot), env)), Nothing)
+ | Nothing ->
+ let regf =
+ match in_env regs name with (*pull the regform with the most specific type annotation from env *)
+ | Just(V_register regform) -> regform
+ | _ -> Assert_extra.failwith "Register not known in regenv" end in
+ let start_pos = reg_start_pos regf in
+ let reg_size = reg_size regf in
+ let request =
+ (Action (Write_reg regf Nothing
+ (if is_top_level then (update_vector_start default_dir start_pos reg_size value) else value))
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l)) (l,intern_annot annot)) t_level l_env l_mem Top),
+ l_mem,l_env) in
+ if is_top_level then (request,Nothing,Nothing)
+ else (request,Just (fun e env -> (LEXP_aux (LEXP_id id) (l,annot), env)), Nothing) end)
+ | Tag_extern _ ->
+ let regf =
+ match in_env regs name with (*pull the regform with the most specific type annotation from env *)
+ | Just(V_register regform) -> regform
+ | _ -> Assert_extra.failwith "Register not known in regenv" end in
+ let start_pos = reg_start_pos regf in
+ let reg_size = reg_size regf in
+ let request =
+ (Action (Write_reg regf Nothing
+ (if is_top_level then (update_vector_start default_dir start_pos reg_size value) else value))
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l)) (l,intern_annot annot)) t_level l_env l_mem Top),
+ l_mem,l_env) in
+ if is_top_level then (request,Nothing,Nothing)
+ else (request,Just (fun e env -> (LEXP_aux (LEXP_id id) (l,annot), env)),Nothing)
+ | Tag_alias ->
+ let request =
+ (match in_env aliases name with
+ | Just (AL_aux aspec (l,_)) ->
+ (match aspec with
+ | AL_subreg (RI_aux (RI_id reg) (li, ((Just((Typ_aux (Typ_id (Id_aux (Id id) _)) _),_,_,_,_)) as annot'))) subreg ->
+ (match in_env subregs id with
+ | Just indexes ->
+ (match in_env indexes (get_id subreg) with
+ | Just ir ->
+ (Action
+ (Write_reg (Form_SubReg subreg (Form_Reg reg annot' default_dir) ir) Nothing
+ (update_vector_start default_dir (get_first_index_range ir)
+ (get_index_range_size ir) value))
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l)) (l, intern_annot annot))
+ t_level l_env l_mem Top), l_mem, l_env)
+ | _ -> (Error l "Internal error, alias spec has unknown field", l_mem, l_env) end)
+ | _ ->
+ (Error l ("Internal error: alias spec has unknown register type " ^ id), l_mem, l_env) end)
+ | AL_bit (RI_aux (RI_id reg) (_,annot')) e ->
+ resolve_outcome (interp_main mode t_level l_env l_mem e)
+ (fun v le lm -> match v with
+ | V_lit (L_aux (L_num i) _) ->
+ let i = natFromInteger i in
+ (Action (Write_reg (Form_Reg reg annot' default_dir) (Just (i,i))
+ (update_vector_start default_dir i 1 value))
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l)) (l, intern_annot annot))
+ t_level l_env l_mem Top), l_mem, l_env)
+ | _ -> (Error l "Internal error: alias bit has non number", l_mem, l_env) end)
+ (fun a -> a)
+ | AL_slice (RI_aux (RI_id reg) (_,annot')) start stop ->
+ resolve_outcome (interp_main mode t_level l_env l_mem start)
+ (fun v lm le ->
+ match detaint v with
+ | V_lit (L_aux (L_num start) _) ->
+ (resolve_outcome (interp_main mode t_level l_env lm stop)
+ (fun v le lm ->
+ (match detaint v with
+ | V_lit (L_aux (L_num stop) _) ->
+ let (start,stop) = (natFromInteger start,natFromInteger stop) in
+ let size = if start < stop then stop - start +1 else start -stop +1 in
+ (Action (Write_reg (Form_Reg reg annot' default_dir) (Just (start,stop))
+ (update_vector_start default_dir start size value))
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l)) (l, intern_annot annot))
+ t_level l_env l_mem Top),
+ l_mem, l_env)
+ | _ -> (Error l "Alias slice has non number",l_mem, l_env) end))
+ (fun a -> a))
+ | _ -> (Error l "Alias slice has non number",l_mem,l_env) end)
+ (fun a -> a)
+ | AL_concat (RI_aux (RI_id reg1) (l1,annot1)) (RI_aux (RI_id reg2) annot2) ->
+ let val_typ (Typ_aux t _) = match t with
+ | Typ_app (Id_aux (Id "register") _) [Typ_arg_aux (Typ_arg_typ t) _] -> t
+ | _ -> Assert_extra.failwith "alias type ill formed" end in
+ let (t1,t2) = match (annot1,annot2) with
+ | (Just (t1,_,_,_,_), (_,(Just (t2,_,_,_,_)))) -> (val_typ t1,val_typ t2)
+ | _ -> Assert_extra.failwith "type annotations ill formed" end in
+ (match (t1,t2) with
+ | (Typ_aux (Typ_app (Id_aux (Id "vector") _) [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant b1) _)) _;
+ Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant r1) _)) _; _;_]) _,
+ Typ_aux (Typ_app (Id_aux (Id "vector") _) [Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant b2) _)) _;
+ Typ_arg_aux (Typ_arg_nexp (Nexp_aux (Nexp_constant r2) _)) _; _;_]) _) ->
+ (Action
+ (Write_reg (Form_Reg reg1 annot1 default_dir) Nothing
+ (slice_vector value (natFromInteger b1) (natFromInteger r1)))
+ (Thunk_frame
+ (E_aux (E_assign (LEXP_aux (LEXP_id reg2) annot2)
+ (fst (to_exp <| mode with track_values =false|> eenv
+ (slice_vector value (natFromInteger (r1+1)) (natFromInteger r2)))))
+ annot2)
+ t_level l_env l_mem Top), l_mem,l_env)
+ | _ -> (Error l "Internal error: alias vector types ill formed", l_mem, l_env) end)
+ | _ -> (Error l "Internal error: alias spec ill formed", l_mem, l_env) end)
+ | _ -> (Error l ("Internal error: alias not found for id " ^(get_id id)),l_mem,l_env) end) in
+ (request,Nothing,Nothing)
+ | _ ->
+ ((Error l ("Internal error: writing to id with tag other than extern, empty, or alias " ^ (get_id id)),
+ l_mem,l_env),Nothing,Nothing)
+ end
+ | LEXP_memory id exps ->
+ match (exp_list mode t_level (fun exps env -> (E_aux (E_tuple exps) (Unknown,Nothing),env))
+ (fun vs ->
+ match vs with | [] -> V_lit (L_aux L_unit Unknown) | [v] -> v | vs -> V_tuple vs end)
+ l_env l_mem [] exps) with
+ | (Value v,lm,le) ->
+ (match tag with
+ | Tag_extern _ ->
+ let request =
+ let effects = (match ef with | Effect_aux(Effect_set es) _ -> es | _ -> [] end) in
+ let act = if has_wmem_effect effects then (Write_mem id v Nothing value)
+ else if has_wmv_effect effects then (Write_memv id v value)
+ else Assert_extra.failwith "LEXP_memory with neither wmem or wmv event" in
+ (Action act
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l)) (l,intern_annot annot)) t_level l_env lm Top),
+ lm,l_env) in
+ if is_top_level then (request,Nothing,Nothing)
+ else
+ (request,
+ Just (fun e env->
+ let (parms,env) = (to_exps mode env (match v with | V_tuple vs -> vs | v -> [v] end)) in
+ (LEXP_aux (LEXP_memory id parms) (l,annot), env)), Nothing)
+ | Tag_global ->
+ let name = get_id id in
+ (match Map.lookup name fdefs with
+ | Just(funcls) ->
+ let new_vals = match v with
+ | V_tuple vs -> V_tuple (vs ++ [value])
+ | V_lit (L_aux L_unit _) -> V_tuple [v;value] (*hmmm may be wrong in some code*)
+ | v -> V_tuple [v;value] end in
+ (match find_funcl t_level funcls new_vals with
+ | [] -> ((Error l ("No matching pattern for function " ^ name ^
+ " on value " ^ (string_of_value new_vals)),l_mem,l_env),Nothing, Nothing)
+ | [(env,used_unknown,exp)] ->
+ (match (if mode.eager_eval
+ then (interp_main mode t_level env (emem name) exp)
+ else (debug_out (Just name) (Just new_vals) exp t_level (emem name) env)) with
+ | (Value ret, _,_) -> ((Value ret, l_mem,l_env),Nothing, Nothing)
+ | (Action action stack,lm,le) ->
+ (((update_stack (Action action stack)
+ (fun stack -> (Hole_frame redex_id (E_aux (E_id redex_id) (l,(intern_annot annot)))
+ t_level l_env l_mem stack))), l_mem,l_env), Nothing, Nothing)
+ | (e,lm,le) -> ((e,lm,le),Nothing,Nothing) end)
+ | multi_matches ->
+ let (lets,taint_env) =
+ List.foldr (fun (env,_,exp) (rst,taint_env) ->
+ let (e,t_e) = env_to_let mode env exp taint_env in (e::rst,t_e)) ([],l_env) multi_matches in
+ let (branches,maybe_id) = fix_up_nondet typ lets (l,annot) in
+ (interp_main mode t_level taint_env lm (E_aux (E_nondet branches)
+ (l,non_det_annot annot maybe_id)),
+ Nothing, Nothing)
+ end)
+ | Nothing ->
+ ((Error l ("Internal error: function unfound " ^ name),lm,le),Nothing,Nothing) end)
+ | Tag_spec ->
+ let name = get_id id in
+ (match Map.lookup name fdefs with
+ | Just(funcls) ->
+ let new_vals = match v with
+ | V_tuple vs -> V_tuple (vs ++ [value])
+ | V_lit (L_aux L_unit _) -> V_tuple [v;value] (*hmmm may be wrong in some code*)
+ | v -> V_tuple [v;value] end in
+ (match find_funcl t_level funcls new_vals with
+ | [] -> ((Error l ("No matching pattern for function " ^ name ^
+ " on value " ^ (string_of_value new_vals)),l_mem,l_env),Nothing,Nothing)
+ | [(env,used_unknown,exp)] ->
+ (match (if mode.eager_eval
+ then (interp_main mode t_level env (emem name) exp)
+ else (debug_out (Just name) (Just new_vals) exp t_level (emem name) env)) with
+ | (Value ret, _,_) -> ((Value ret, l_mem,l_env),Nothing,Nothing)
+ | (Action action stack,lm,le) ->
+ (((update_stack (Action action stack)
+ (fun stack -> (Hole_frame redex_id (E_aux (E_id redex_id) (l,(intern_annot annot)))
+ t_level l_env l_mem stack))), l_mem,l_env), Nothing, Nothing)
+ | (e,lm,le) -> ((e,lm,le),Nothing,Nothing) end)
+ | multi_matches ->
+ let (lets,taint_env) =
+ List.foldr (fun (env,_,exp) (rst,taint_env) ->
+ let (e,t_e) = env_to_let mode env exp taint_env in (e::rst,t_e)) ([],l_env) multi_matches in
+ let (branches,maybe_id) = fix_up_nondet typ lets (l,annot) in
+ (interp_main mode t_level taint_env lm (E_aux (E_nondet branches)
+ (l,non_det_annot annot maybe_id)),
+ Nothing,Nothing)
+ end)
+ | Nothing ->
+ ((Error l ("Internal error: function unfound " ^ name),lm,le),Nothing,Nothing) end)
+ | _ -> ((Error l "Internal error: unexpected tag for memory or register write", lm,le),Nothing,Nothing)
+ end)
+ | (Action a s,lm, le) ->
+ ((Action a s,lm,le),
+ Just (fun (E_aux e _) env ->
+ (match e with | E_tuple es -> (LEXP_aux (LEXP_memory id es) (l,annot), env)
+ | _ -> Assert_extra.failwith "Lexp builder not well formed" end)), Nothing)
+ | e -> (e,Nothing,Nothing) end
+ | LEXP_cast typc id ->
+ let name = get_id id in
+ match tag with
+ | Tag_intro ->
+ match detaint (in_lenv l_env id) with
+ | V_unknown ->
+ if is_top_level
+ then begin
+ let (LMem owner c m s) = l_mem in
+ let l_mem = (LMem owner (c+1) m s) in
+ ((Value (V_lit (L_aux L_unit l)), update_mem mode.track_lmem l_mem c value,
+ (add_to_env (id,(V_boxref c typ)) l_env)),Nothing, Nothing)
+ end
+ else ((Error l ("LEXP:cast1: Undefined id " ^ (get_id id)),l_mem,l_env),Nothing, Nothing)
+ | v ->
+ if is_top_level then ((Error l "Writes must be to reg values",l_mem,l_env),Nothing, Nothing)
+ else ((Value v,l_mem,l_env),Just (fun e env -> (LEXP_aux(LEXP_cast typc id) (l,annot), env)), Nothing)
+ end
+ | Tag_set ->
+ match detaint (in_lenv l_env id) with
+ | ((V_boxref n t) as v) ->
+ if is_top_level
+ then ((Value (V_lit (L_aux L_unit l)),
+ update_mem mode.track_lmem l_mem n (recenter_val t value), l_env),Nothing,Nothing)
+ else ((Value v, l_mem, l_env),
+ Just (fun e env -> (LEXP_aux (LEXP_cast typc id) (l,annot), env)), Nothing)
+ | V_unknown ->
+ if is_top_level
+ then begin
+ let (LMem owner c m s) = l_mem in
+ let l_mem = (LMem owner (c+1) m s) in
+ ((Value (V_lit (L_aux L_unit l)), update_mem mode.track_lmem l_mem c value,
+ (add_to_env (id,(V_boxref c typ)) l_env)),Nothing,Nothing)
+ end
+ else ((Error l ("LEXP:cast2: Undefined id " ^ (get_id id)),l_mem,l_env),Nothing,Nothing)
+ | v ->
+ if is_top_level then ((Error l "Writes must be to reg values",l_mem,l_env),Nothing,Nothing)
+ else ((Value v,l_mem,l_env),
+ Just (fun e env -> (LEXP_aux(LEXP_cast typc id) (l,annot), env)),Nothing)
+ end
+ | Tag_empty ->
+ match detaint (in_lenv l_env id) with
+ | ((V_boxref n t) as v) ->
+ if is_top_level
+ then ((Value (V_lit (L_aux L_unit l)),
+ update_mem mode.track_lmem l_mem n (recenter_val t value), l_env),Nothing,Nothing)
+ else ((Value v, l_mem, l_env),
+ Just (fun e env -> (LEXP_aux (LEXP_cast typc id) (l,annot), env)), Nothing)
+ | V_unknown ->
+ if is_top_level
+ then begin
+ let (LMem owner c m s) = l_mem in
+ let l_mem = (LMem owner (c+1) m s) in
+ ((Value (V_lit (L_aux L_unit l)), update_mem mode.track_lmem l_mem c value,
+ (add_to_env (id,(V_boxref c typ)) l_env)),Nothing,Nothing)
+ end
+ else ((Error l ("LEXP:cast3: Undefined id " ^ (get_id id)),l_mem,l_env),Nothing,Nothing)
+ | v ->
+ if is_top_level then ((Error l "Writes must be to reg values",l_mem,l_env),Nothing,Nothing)
+ else ((Value v,l_mem,l_env),Just (fun e env -> (LEXP_aux(LEXP_cast typc id) (l,annot), env)),Nothing)
+ end
+ | Tag_extern _ ->
+ let regf =
+ match in_env regs name with (*pull the regform with the most specific type annotation from env *)
+ | Just(V_register regform) -> regform
+ | _ -> Assert_extra.failwith "Register not known in regenv" end in
+ let start_pos = reg_start_pos regf in
+ let reg_size = reg_size regf in
+ let request =
+ (Action (Write_reg regf Nothing
+ (if is_top_level
+ then (update_vector_start default_dir start_pos reg_size value)
+ else value))
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l)) (l,intern_annot annot)) t_level l_env l_mem Top),
+ l_mem,l_env) in
+ if is_top_level then (request,Nothing,Nothing)
+ else (request,Just (fun e env -> (LEXP_aux (LEXP_cast typc id) (l,annot), env)),Nothing)
+ | _ ->
+ ((Error l ("Internal error: writing to id not extern or empty " ^(get_id id)),l_mem,l_env),
+ Nothing,Nothing)
+ end
+ | LEXP_tup ltups ->
+ match (ltups,value) with
+ | ([],_) ->
+ ((Error l "Internal error: found an empty tuple of assignments as an lexp", l_mem, l_env), Nothing,Nothing)
+ | ([le],V_tuple[v]) -> create_write_message_or_update mode t_level v l_env l_mem true le
+ | (le::ltups,V_tuple (v::vs)) ->
+ let new_v = V_tuple vs in
+ (match (create_write_message_or_update mode t_level v l_env l_mem true le) with
+ | ((Value v_whole,lm,le),Nothing,Nothing) ->
+ create_write_message_or_update mode t_level new_v le lm true (LEXP_aux (LEXP_tup ltups) (l,annot))
+ | ((Action act stack,lm,le),Nothing,Nothing) ->
+ ((Action act stack,lm,le), Just (fun e env -> (LEXP_aux (LEXP_tup ltups) (l,annot),env)), Just new_v)
+ | ((Action act stack,lm,le), Just le_builder, Nothing) ->
+ ((Action act stack,lm,le),
+ Just (fun e env ->
+ let (lexp,env) = le_builder e env in
+ (LEXP_aux (LEXP_tup (lexp::ltups)) (l,annot),env)), Just value)
+ | ((Action act stack, lm,le), Just le_builder, Just v) ->
+ ((Action act stack, lm, le),
+ Just (fun e env ->
+ let (lexp,env) = le_builder e env in
+ (LEXP_aux (LEXP_tup (lexp::ltups)) (l,annot),env)), Just (V_tuple (v::vs)))
+ | ((Error l msg,lm,le),_,_) -> ((Error l msg,lm,le),Nothing,Nothing)
+ | _ ->
+ ((Error l "Internal error: Unexpected pattern match failure in LEXP_tup",l_mem,l_env),Nothing,Nothing)
+ end)
+ end
+ | LEXP_vector lexp exp ->
+ match (interp_main mode t_level l_env l_mem exp) with
+ | (Value i,lm,le) ->
+ (match detaint i with
+ | V_unknown -> ((Value i,lm,le),Nothing,Nothing)
+ | V_lit (L_aux (L_num n) ln) ->
+ let next_builder le_builder =
+ (fun e env ->
+ let (lexp,env) = le_builder e env in
+ let (ie,env) = to_exp mode env i in
+ (LEXP_aux (LEXP_vector lexp ie) (l,annot), env)) in
+ let n = natFromInteger n in
+ (match (create_write_message_or_update mode t_level value l_env lm false lexp) with
+ | ((Value v_whole,lm,le),maybe_builder,maybe_value) ->
+ let v = detaint v_whole in
+ let nth _ = detaint (access_vector v n) in
+ (match v with
+ | V_unknown -> ((Value v_whole,lm,le),Nothing,Nothing)
+ | V_boxref i _ ->
+ (match (in_mem lm i,is_top_level,maybe_builder) with
+ | ((V_vector _ _ _ as vec),true,_) ->
+ let new_vec = fupdate_vector_slice vec (V_vector 1 default_dir [value]) n n in
+ ((Value (V_lit (L_aux L_unit Unknown)),
+ update_mem mode.track_lmem lm i new_vec, l_env), Nothing,Nothing)
+ | ((V_track (V_vector _ _ _ as vec) r), true,_) ->
+ let new_vec = fupdate_vector_slice vec (V_vector 1 default_dir [value]) n n in
+ ((Value (V_lit (L_aux L_unit Unknown)),
+ update_mem mode.track_lmem lm i (taint new_vec r),l_env),Nothing,Nothing)
+ | ((V_vector _ _ _ as vec),false, Just lexp_builder) ->
+ ((Value (access_vector vec n), lm, l_env), Just (next_builder lexp_builder),Nothing)
+ | (v,_,_) ->
+ Assert_extra.failwith("no vector findable in set bit, found " ^ (string_of_value v))
+ end )
+ | V_vector inc m vs ->
+ (match (nth(),is_top_level,maybe_builder) with
+ | (V_register regform,true,_) ->
+ let start_pos = reg_start_pos regform in
+ let reg_size = reg_size regform in
+ ((Action (Write_reg regform Nothing (update_vector_start default_dir start_pos reg_size value))
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l))
+ (l,intern_annot annot)) t_level l_env l_mem Top),
+ l_mem,l_env),
+ Nothing,Nothing)
+ | (V_register regform,false,Just lexp_builder) ->
+ let start_pos = reg_start_pos regform in
+ let reg_size = reg_size regform in
+ ((Action (Write_reg regform Nothing (update_vector_start default_dir start_pos reg_size value))
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l))
+ (l,intern_annot annot)) t_level l_env l_mem Top),
+ l_mem,l_env),
+ Just (next_builder lexp_builder),maybe_value)
+ | (V_boxref n t,true,_) ->
+ ((Value (V_lit (L_aux L_unit Unknown)), update_mem mode.track_lmem lm n value, l_env),
+ Nothing,Nothing)
+ | (V_unknown,true,_) -> ((Value (V_lit (L_aux L_unit Unknown)), lm, l_env),Nothing,Nothing)
+ | (v,true,_) ->
+ ((Error l "Vector does not contain reg or register values",lm,l_env),Nothing,Nothing)
+ | ((V_boxref n t),false, Just lexp_builder) ->
+ ((Value (in_mem lm n),lm, l_env),Just (next_builder lexp_builder),Nothing)
+ | (v,false, Just lexp_builder) ->
+ ((Value v,lm,le), Just (next_builder lexp_builder),Nothing)
+ | _ -> Assert_extra.failwith "Vector assignment logic incomplete"
+ end)
+ | V_vector_sparse n m inc vs d ->
+ (match (nth(),is_top_level,maybe_builder) with
+ | (V_register regform,true,_) ->
+ let start_pos = reg_start_pos regform in
+ let reg_size = reg_size regform in
+ ((Action (Write_reg regform Nothing (update_vector_start default_dir start_pos reg_size value))
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l)) (l,intern_annot annot)) t_level l_env l_mem Top),
+ l_mem,l_env),Nothing,Nothing)
+ | (V_register regform,false,Just lexp_builder) ->
+ let start_pos = reg_start_pos regform in
+ let reg_size = reg_size regform in
+ ((Action (Write_reg regform Nothing (update_vector_start default_dir start_pos reg_size value))
+ (Thunk_frame (E_aux (E_lit (L_aux L_unit l)) (l,intern_annot annot)) t_level l_env l_mem Top),
+ l_mem,l_env),
+ Just (next_builder lexp_builder),Nothing)
+ | (V_boxref n t,true,_) ->
+ ((Value (V_lit (L_aux L_unit Unknown)), update_mem mode.track_lmem lm n value, l_env),
+ Nothing,Nothing)
+ | (v,true,_) ->
+ ((Error l ("Vector does not contain reg or register values " ^ (string_of_value v)),
+ lm,l_env), Nothing,Nothing)
+ | ((V_boxref n t),false, Just lexp_builder) ->
+ ((Value (in_mem lm n),lm, l_env),Just (next_builder lexp_builder),Nothing)
+ | (v,false, Just lexp_builder) ->
+ ((Value v,lm,le), Just (next_builder lexp_builder), Nothing)
+ | _ -> Assert_extra.failwith "Vector assignment logic incomplete"
+ end)
+ | v ->
+ ((Error l ("Vector access to write of non-vector" ^ (string_of_value v)),lm,l_env),Nothing,Nothing)
+ end)
+ | ((Action a s,lm,le),Just lexp_builder,maybe_value) ->
+ (match (a,is_top_level) with
+ | ((Write_reg regf Nothing value),true) ->
+ ((Action (Write_reg regf (Just (n,n))
+ (if (vector_length value) = 1
+ then (update_vector_start default_dir n 1 value)
+ else (access_vector value n))) s, lm,le), Nothing, Nothing)
+ | ((Write_reg regf Nothing value),false) ->
+ ((Action (Write_reg regf (Just (n,n))
+ (if (vector_length value) = 1
+ then (update_vector_start default_dir n 1 value)
+ else (access_vector value n))) s,lm,le),
+ Just (next_builder lexp_builder), Nothing)
+ | ((Write_mem id a Nothing value),true) ->
+ ((Action (Write_mem id a (Just (n,n)) value) s,lm,le), Nothing, Nothing)
+ | ((Write_mem id a Nothing value),false) ->
+ ((Action (Write_mem id a (Just (n,n)) value) s,lm,le), Just (next_builder lexp_builder), Nothing)
+ | _ -> ((Action a s,lm,le), Just (next_builder lexp_builder), Nothing) end)
+ | e -> e end)
+ | v ->
+ ((Error l ("Vector access must be a number given " ^ (string_of_value v)),lm,le),Nothing,Nothing) end)
+ | (Action a s,lm,le) ->
+ ((Action a s,lm,le), Just (fun e env -> (LEXP_aux (LEXP_vector lexp e) (l,annot), env)), Nothing)
+ | e -> (e,Nothing,Nothing) end
+ | LEXP_vector_range lexp exp1 exp2 ->
+ match (interp_main mode t_level l_env l_mem exp1) with
+ | (Value i1, lm, le) ->
+ (match detaint i1 with
+ | V_unknown -> ((Value i1,lm,le),Nothing,Nothing)
+ | V_lit (L_aux (L_num n1) ln1) ->
+ (match (interp_main mode t_level l_env l_mem exp2) with
+ | (Value i2,lm,le) ->
+ (match detaint i2 with
+ | V_unknown -> ((Value i2,lm,le),Nothing,Nothing)
+ | V_lit (L_aux (L_num n2) ln2) ->
+ let next_builder le_builder =
+ (fun e env ->
+ let (e1,env) = to_exp mode env i1 in
+ let (e2,env) = to_exp mode env i2 in
+ let (lexp,env) = le_builder e env in
+ (LEXP_aux (LEXP_vector_range lexp e1 e2) (l,annot), env)) in
+ let (n1,n2) = (natFromInteger n1,natFromInteger n2) in
+ (match (create_write_message_or_update mode t_level value l_env lm false lexp) with
+ | ((Value v,lm,le), Just lexp_builder,_) ->
+ (match (detaint v,is_top_level) with
+ | (V_vector m inc vs,true) ->
+ ((Value (V_lit (L_aux L_unit Unknown)),
+ update_vector_slice mode.track_lmem v value n1 n2 lm, l_env), Nothing, Nothing)
+ | (V_boxref _ _, true) ->
+ ((Value (V_lit (L_aux L_unit Unknown)),
+ update_vector_slice mode.track_lmem v value n1 n2 lm, l_env), Nothing, Nothing)
+ | (V_vector m inc vs,false) ->
+ ((Value (slice_vector v n1 n2),lm,l_env), Just (next_builder lexp_builder), Nothing)
+ | (V_register regform,true) ->
+ let start_pos = reg_start_pos regform in
+ let reg_size = reg_size regform in
+ ((Action (Write_reg regform (Just (n1,n2)) (update_vector_start default_dir start_pos reg_size v))
+ (mk_thunk l annot t_level l_env l_mem),
+ l_mem,l_env),
+ Just (next_builder lexp_builder), Nothing)
+ | (V_unknown,_) ->
+ let inc = n1 < n2 in
+ let start = if inc then n1 else (n2-1) in
+ let size = if inc then n2-n1 +1 else n1 -n2 +1 in
+ ((Value (V_vector start (if inc then IInc else IDec) (List.replicate size V_unknown)),
+ lm,l_env),Nothing,Nothing)
+ | _ -> ((Error l "Vector required",lm,le),Nothing,Nothing) end)
+ | ((Action (Write_reg regf Nothing value) s, lm,le), Just lexp_builder,_) ->
+ let len = (if n1 < n2 then n2 -n1 else n1 - n2) +1 in
+ ((Action
+ (Write_reg regf (Just (n1,n2))
+ (if (vector_length value) <= len
+ then (update_vector_start default_dir n1 len value)
+ else (slice_vector value n1 n2))) s,lm,le),
+ Just (next_builder lexp_builder), Nothing)
+ | ((Action (Write_mem id a Nothing value) s,lm,le), Just lexp_builder,_) ->
+ ((Action (Write_mem id a (Just (n1,n2)) value) s,lm,le), Just (next_builder lexp_builder), Nothing)
+ | ((Action a s,lm,le), Just lexp_builder,_ ) ->
+ ((Action a s,lm,le), Just (next_builder lexp_builder), Nothing)
+ | e -> e end)
+ | _ -> ((Error l "Vector slice requires a number", lm, le),Nothing,Nothing) end)
+ | (Action a s,lm,le) ->
+ ((Action a s,lm, le),
+ Just (fun e env ->
+ let (e1,env) = to_exp mode env i1 in
+ (LEXP_aux (LEXP_vector_range lexp e1 e) (l,annot), env)), Nothing)
+ | e -> (e,Nothing,Nothing) end)
+ | _ -> ((Error l "Vector slice requires a number", lm, le),Nothing,Nothing) end)
+ | (Action a s,lm,le) ->
+ ((Action a s, lm,le), Just (fun e env -> (LEXP_aux (LEXP_vector_range lexp e exp2) (l,annot), env)), Nothing)
+ | e -> (e,Nothing,Nothing) end
+ | LEXP_field lexp id ->
+ (match (create_write_message_or_update mode t_level value l_env l_mem false lexp) with
+ | ((Value (V_record t fexps),lm,le),Just lexp_builder,_) ->
+ let next_builder = Just (fun e env -> let (lexp,env) = (lexp_builder e env) in
+ (LEXP_aux (LEXP_field lexp id) (l,annot), env)) in
+ match (in_env (env_from_list fexps) (get_id id),is_top_level) with
+ | (Just (V_boxref n t),true) ->
+ ((Value (V_lit (L_aux L_unit l)), update_mem mode.track_lmem lm n value, l_env),Nothing,Nothing)
+ | (Just (V_boxref n t),false) -> ((Value (in_mem lm n),lm,l_env),next_builder,Nothing)
+ | (Just v, true) -> ((Error l "Mutating a field access requires a reg type",lm,le),Nothing,Nothing)
+ | (Just v,false) -> ((Value v,lm,l_env),next_builder,Nothing)
+ | (Nothing,_) -> ((Error l "Field not found in specified record",lm,le),Nothing,Nothing) end
+ | ((Action a s,lm,le), Just lexp_builder,_) ->
+ let next_builder = Just (fun e env -> let (lexp,env) = (lexp_builder e env) in
+ (LEXP_aux (LEXP_field lexp id) (l,annot), env)) in
+ match a with
+ | Read_reg _ _ -> ((Action a s,lm,le), next_builder, Nothing)
+ | Read_mem _ _ _ -> ((Action a s,lm,le), next_builder, Nothing)
+ | Read_mem_tagged _ _ _ -> ((Action a s,lm,le), next_builder, Nothing)
+ | Call_extern _ _ -> ((Action a s,lm,le), next_builder, Nothing)
+ | Write_reg ((Form_Reg _ (Just(Typ_aux (Typ_id (Id_aux (Id id') _)) _,_,_,_,_)) _) as regf) Nothing value ->
+ match in_env subregs id' with
+ | Just(indexes) ->
+ match in_env indexes (get_id id) with
+ | Just ir ->
+ ((Action
+ (Write_reg (Form_SubReg id regf ir) Nothing
+ (update_vector_start default_dir (get_first_index_range ir)
+ (get_index_range_size ir) value)) s,
+ lm,le),
+ (if is_top_level then Nothing else next_builder), Nothing)
+ | _ -> ((Error l "Internal error, unrecognized write, no field",lm,le),Nothing,Nothing)
+ end
+ | Nothing -> ((Error l "Internal error, unrecognized write, no subreges",lm,le),Nothing,Nothing) end
+ | _ -> ((Error l "Internal error, unrecognized write, no matching action",lm,le),Nothing,Nothing)
+ end
+ | e -> e end)
+ end
+
+and create_write_message_or_update mode t_level value l_env l_mem is_top_level le =
+ let _ = debug_fun_enter mode "create_write_message_or_update" [show le] in
+ let retval = __create_write_message_or_update (indent_mode mode) t_level value l_env l_mem is_top_level le in
+ let _ = debug_fun_exit mode "create_write_message_or_update" "_" in
+ retval
+
+and __interp_letbind mode t_level l_env l_mem (LB_aux lbind (l,annot)) =
+ match lbind with
+ | LB_val pat exp ->
+ match (interp_main mode t_level l_env l_mem exp) with
+ | (Value v,lm,le) ->
+ (match match_pattern t_level pat v with
+ | (true,used_unknown,env) -> ((Value (V_lit (L_aux L_unit l)), lm, (union_env env l_env)),Nothing)
+ | _ -> ((Error l "Pattern in letbind did not match value",lm,le),Nothing) end)
+ | (Action a s,lm,le) -> ((Action a s,lm,le),(Just (fun e -> (LB_aux (LB_val pat e) (l,annot)))))
+ | e -> (e,Nothing) end
+end
+
+and interp_letbind mode t_level l_env l_mem lb =
+ let _ = debug_fun_enter mode "interp_letbind" [show lb] in
+ let retval = __interp_letbind (indent_mode mode) t_level l_env l_mem lb in
+ let _ = debug_fun_exit mode "interp_letbind" "_" in
+ retval
+
+and __interp_alias_read mode t_level l_env l_mem (AL_aux alspec (l,annot)) =
+ let (Env defs instrs default_dir lets regs ctors subregs aliases debug) = t_level in
+ let stack = Hole_frame redex_id (E_aux (E_id redex_id) (l,(intern_annot annot))) t_level l_env l_mem Top in
+ let get_reg_typ_name typ =
+ match typ with
+ | Typ_aux (Typ_id (Id_aux (Id i) _)) _ -> i
+ | _ -> Assert_extra.failwith "Alias reg typ not well formed"
+ end in
+ match alspec with
+ | AL_subreg (RI_aux (RI_id reg) (li,((Just (t,_,_,_,_)) as annot'))) subreg ->
+ let reg_ti = get_reg_typ_name t in
+ (match in_env subregs reg_ti with
+ | Just indexes ->
+ (match in_env indexes (get_id subreg) with
+ | Just ir -> (Action (Read_reg (Form_SubReg subreg (Form_Reg reg annot' default_dir) ir) Nothing) stack,
+ l_mem, l_env)
+ | _ -> (Error l "Internal error, alias spec has unknown field", l_mem, l_env) end)
+ | _ -> (Error l (String.stringAppend "Internal error: alias spec has unknown register type " reg_ti),
+ l_mem, l_env) end)
+ | AL_bit (RI_aux (RI_id reg) (_,annot')) e ->
+ resolve_outcome (interp_main mode t_level l_env l_mem e)
+ (fun v le lm -> match v with
+ | V_lit (L_aux (L_num i) _) ->
+ let i = natFromInteger i in
+ (Action (Read_reg (Form_Reg reg annot' default_dir) (Just (i,i))) stack, l_mem, l_env)
+ | _ -> Assert_extra.failwith "alias bit did not reduce to number" end)
+ (fun a -> a) (*Should not currently happen as type system enforces constants*)
+ | AL_slice (RI_aux (RI_id reg) (_,annot')) start stop ->
+ resolve_outcome (interp_main mode t_level l_env l_mem start)
+ (fun v lm le ->
+ match v with
+ | V_lit (L_aux (L_num start) _) ->
+ (resolve_outcome
+ (interp_main mode t_level l_env lm stop)
+ (fun v le lm ->
+ (match v with
+ | V_lit (L_aux (L_num stop) _) ->
+ let (start,stop) = (natFromInteger start,natFromInteger stop) in
+ (Action (Read_reg (Form_Reg reg annot' default_dir) (Just (start,stop))) stack, l_mem, l_env)
+ | _ -> Assert_extra.failwith ("Alias slice evaluted non-lit " ^ (string_of_value v))
+ end))
+ (fun a -> a))
+ | _ -> Assert_extra.failwith ("Alias slice evaluated non-lit "^ string_of_value v)
+ end)
+ (fun a -> a) (*Neither action function should occur, due to above*)
+ | AL_concat (RI_aux (RI_id reg1) (l1, annot1)) (RI_aux (RI_id reg2) annot2) ->
+ (Action (Read_reg (Form_Reg reg1 annot1 default_dir) Nothing)
+ (Hole_frame redex_id
+ (E_aux (E_vector_append (E_aux (E_id redex_id) (l1, (intern_annot annot1)))
+ (E_aux (E_id reg2) annot2))
+ (l,(intern_annot annot))) t_level l_env l_mem Top), l_mem,l_env)
+ | _ -> Assert_extra.failwith "alias spec not well formed"
+end
+
+and interp_alias_read mode t_level l_env l_mem al =
+ let _ = debug_fun_enter mode "interp_alias_read" [show al] in
+ let retval = __interp_alias_read (indent_mode mode) t_level l_env l_mem al in
+ let _ = debug_fun_exit mode "interp_alias_read" retval in
+ retval
+
+let rec eval_toplevel_let handle_action tlevel env mem lbind =
+ match interp_letbind <| eager_eval=true; track_values=false; track_lmem=false; debug=false; debug_indent="" |> tlevel env mem lbind with
+ | ((Value v, lm, (LEnv _ le)),_) -> Just le
+ | ((Action a s,lm,le), Just le_builder) ->
+ (match handle_action (Action a s) with
+ | Just value ->
+ (match s with
+ | Hole_frame id exp tl lenv lmem s ->
+ eval_toplevel_let handle_action tl (add_to_env (id,value) lenv) lmem (le_builder exp)
+ | _ -> Assert_extra.failwith "Top level def evaluation created a thunk frame" end)
+ | Nothing -> Nothing end)
+ | _ -> Nothing end
+
+let rec to_global_letbinds handle_action (Defs defs) t_level =
+ let (Env fdefs instrs default_dir lets regs ctors subregs aliases debug) = t_level in
+ match defs with
+ | [] -> ((Value (V_lit (L_aux L_unit Unknown)), (emem "global_letbinds"), eenv),t_level)
+ | def::defs ->
+ match def with
+ | DEF_val lbind ->
+ match eval_toplevel_let handle_action t_level eenv (emem "global_letbinds") lbind with
+ | Just le ->
+ to_global_letbinds handle_action
+ (Defs defs)
+ (Env fdefs instrs default_dir (Map.(union) lets le) regs ctors subregs aliases debug)
+ | Nothing ->
+ to_global_letbinds handle_action (Defs defs)
+ (Env fdefs instrs default_dir lets regs ctors subregs aliases debug) end
+ | DEF_type (TD_aux tdef _) ->
+ match tdef with
+ | TD_enum id ns ids _ ->
+ let typ = mk_typ_id (get_id id) in
+ let enum_vals =
+ Map.fromList
+ (snd
+ (List.foldl (fun (c,rst) eid -> (1+c,(get_id eid,V_ctor eid typ (C_Enum c) unitv)::rst)) (0,[]) ids)) in
+ to_global_letbinds
+ handle_action (Defs defs)
+ (Env fdefs instrs default_dir (Map.(union) lets enum_vals) regs ctors subregs aliases debug)
+ | _ -> to_global_letbinds handle_action (Defs defs) t_level end
+ | _ -> to_global_letbinds handle_action (Defs defs) t_level
+ end
+ end
+
+let rec extract_default_direction (Defs defs) = match defs with
+ | [] -> IInc (*When lack of a declared default, go for inc*)
+ | def::defs ->
+ match def with
+ | DEF_default (DT_aux (DT_order (Ord_aux Ord_inc _)) _) -> IInc
+ | DEF_default (DT_aux (DT_order (Ord_aux Ord_dec _)) _) -> IDec
+ | _ -> extract_default_direction (Defs defs) end end
+
+(*TODO Contemplate making execute environment variable instead of constant*)
+let to_top_env debug external_functions defs =
+ let direction = (extract_default_direction defs) in
+ let t_level = Env (to_fdefs defs)
+ (extract_instructions "execute" defs)
+ direction
+ Map.empty (* empty letbind and enum values, call below will fill in any *)
+ (to_registers direction defs)
+ (to_data_constructors defs) (to_register_fields defs) (to_aliases defs) debug in
+ let (o,t_level) = to_global_letbinds (external_functions direction) defs t_level in
+ match o with
+ | (Value _,_,_) -> (Nothing,t_level)
+ | (o,_,_) -> (Just o,t_level)
+ end
+
+let __interp mode external_functions defs exp =
+ match (to_top_env mode.debug external_functions defs) with
+ | (Nothing,t_level) ->
+ interp_main mode t_level eenv (emem "top level") exp
+ | (Just o,_) -> (o,(emem "top level error"),eenv)
+ end
+
+let interp mode external_functions defs exp =
+ let _ = debug_fun_enter mode "interp" [show exp] in
+ let retval = __interp (indent_mode mode) external_functions defs exp in
+ let _ = debug_fun_exit mode "interp" retval in
+ retval
+
+let rec __resume_with_env mode stack value =
+ match (stack,value) with
+ | (Top,_) -> (Error Unknown "Top hit without expression to evaluate in resume_with_env",eenv)
+ | (Hole_frame id exp t_level env mem Top,Just value) ->
+ match interp_main mode t_level (add_to_env (id,value) env) mem exp with | (o,_,e) -> (o,e) end
+ | (Hole_frame id exp t_level env mem stack,Just value) ->
+ match resume_with_env mode stack (Just value) with
+ | (Value v,e) ->
+ match interp_main mode t_level (add_to_env (id,v) env) mem exp with | (o,_,e) -> (o,e) end
+ | (Action action stack,e) -> (Action action (Hole_frame id exp t_level env mem stack),e)
+ | (Error l s,e) -> (Error l s,e)
+ end
+ | (Hole_frame id exp t_level env mem stack, Nothing) ->
+ match resume_with_env mode stack Nothing with
+ | (Value v,e) ->
+ match interp_main mode t_level (add_to_env (id,v) env) mem exp with | (o,_,e) -> (o,e) end
+ | (Action action stack,e) -> (Action action (Hole_frame id exp t_level env mem stack),e)
+ | (Error l s,e) -> (Error l s,e)
+ end
+ | (Thunk_frame exp t_level env mem Top,_) ->
+ match interp_main mode t_level env mem exp with | (o,_,e) -> (o,e) end
+ | (Thunk_frame exp t_level env mem stack,value) ->
+ match resume_with_env mode stack value with
+ | (Value v,e) ->
+ match interp_main mode t_level env mem exp with | (o,_,e) -> (o,e) end
+ | (Action action stack,e) -> (Action action (Thunk_frame exp t_level env mem stack),e)
+ | (Error l s,e) -> (Error l s,e)
+ end
+ end
+
+and resume_with_env mode stack value =
+ let _ = debug_fun_enter mode "resume_with_env" [show value] in
+ let retval = __resume_with_env (indent_mode mode) stack value in
+ let _ = debug_fun_exit mode "interp" retval in
+ retval
+
+
+let rec __resume mode stack value =
+ match (stack,value) with
+ | (Top,_) -> (Error Unknown "Top hit without expression to evaluate in resume",(emem "top level error"),eenv)
+ | (Hole_frame id exp t_level env mem Top,Just value) ->
+ interp_main mode t_level (add_to_env (id,value) env) mem exp
+ | (Hole_frame id exp t_level env mem Top,Nothing) ->
+ (Error Unknown "Top hole frame hit wihtout a value in resume", mem, env)
+ | (Hole_frame id exp t_level env mem stack,Just value) ->
+ match resume mode stack (Just value) with
+ | (Value v,_,_) ->
+ interp_main mode t_level (add_to_env (id,v) env) mem exp
+ | (Action action stack,lm,le) -> (Action action (Hole_frame id exp t_level env mem stack),lm,le)
+ | (Error l s,lm,le) -> (Error l s,lm,le)
+ end
+ | (Hole_frame id exp t_level env mem stack, Nothing) ->
+ match resume mode stack Nothing with
+ | (Value v,_,_) ->
+ interp_main mode t_level (add_to_env (id,v) env) mem exp
+ | (Action action stack,lm,le) -> (Action action (Hole_frame id exp t_level env mem stack),lm,le)
+ | (Error l s,lm,le) -> (Error l s,lm,le)
+ end
+ | (Thunk_frame exp t_level env mem Top,_) ->
+ interp_main mode t_level env mem exp
+ | (Thunk_frame exp t_level env mem stack,value) ->
+ match resume mode stack value with
+ | (Value v,_,_) -> interp_main mode t_level env mem exp
+ | (Action action stack,lm,le) -> (Action action (Thunk_frame exp t_level env mem stack), lm, le)
+ | (Error l s,lm,le) -> (Error l s,lm,le)
+ end
+ end
+
+and resume mode stack value =
+ let _ = debug_fun_enter mode "resume" [show value] in
+ let retval = __resume (indent_mode mode) stack value in
+ let _ = debug_fun_exit mode "resume" retval in
+ retval