From 719a4749857281fd42de0a408630c09f1b5374c0 Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Thu, 4 Dec 2025 12:48:09 -0800 Subject: [PATCH 01/13] add type prelude --- .../Languages/Python/BoogieTypePrelude.lean | 341 ++++++++++++++++++ 1 file changed, 341 insertions(+) create mode 100644 Strata/Languages/Python/BoogieTypePrelude.lean diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean new file mode 100644 index 000000000..794498d79 --- /dev/null +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -0,0 +1,341 @@ +import Strata.DDM.Elab +import Strata.DDM.AST +import Strata.Languages.Boogie.DDMTransform.Parse +import Strata.Languages.Boogie.Verifier + +namespace Strata + +def boogieTypePrelude := +#strata +program Boogie; + +//Generic tag for List +type List_tag; +const CONS : List_tag; +const NIL : List_tag; +axiom [list_tag_unique]: CONS != NIL; + +//Will be merged with BoogiePrelude.lean +type Error; +function Error_message (s: string): Error; + +// Value and ListValue types +type Value; +type ListValue; +// Constructors +function Value_bool (b : bool) : (Value); +function Value_int (i : int) : (Value); +function Value_float (f : real) : (Value); +function Value_str (s : string) : (Value); +function Value_none() : (Value); +function Value_Exception (e : Error): (Value); +function Value_List (lv : ListValue) : (Value); +function ListValue_nil() : (ListValue); +function ListValue_cons(x0 : Value, x1 : ListValue) : (ListValue); +//Tags +function ListValue_tag (l: ListValue) : List_tag; +axiom [ListValue_tag_nil_def]: (ListValue_tag (ListValue_nil()) == NIL); +axiom [ListValue_tag_cons_def]: (forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} (ListValue_tag (ListValue_cons(v, vs)) == CONS)); + +// Types of Value +type ValueType; +type ListValueType; +const BOOL : ValueType; +const INT : ValueType; +const FLOAT : ValueType; +const STR : ValueType; +const NONE : ValueType; +const EXCEPTION : ValueType; +//Uniqueness axioms +axiom [unique_ValueType_bool]: BOOL != INT && BOOL != FLOAT && BOOL != STR && BOOL != NONE && BOOL != EXCEPTION; +axiom [unique_ValueType_int]: INT != STR && INT != FLOAT && INT != NONE && INT != EXCEPTION; +axiom [unique_ValueType_float]: FLOAT != STR && FLOAT != NONE && FLOAT != EXCEPTION; +axiom [unique_ValueType_str]: STR != NONE && STR != EXCEPTION; +axiom [unique_ValueType_none]: NONE != EXCEPTION; +//Eq axioms +axiom [value_int_eq]: forall i: int, j: int :: {Value_int(i) == Value_int(j)} (Value_int(i) == Value_int(j)) == (i == j); +axiom [value_bool_eq]: forall b1: bool, b2: bool :: {Value_bool(b1) == Value_bool(b2)} (Value_bool(b1) == Value_bool(b2)) == (b1 == b2); +axiom [value_float_eq]: forall r1: real, r2: real :: {Value_float(r1) == Value_float(r2)} (Value_float(r1) == Value_float(r2)) == (r1 == r2); +axiom [value_str_eq]: forall s1: string, s2: string :: {Value_str(s1) == Value_str(s2)} (Value_str(s1) == Value_str(s2)) == (s1 == s2); + + +//Constructors and tag functions of ListType +function ListType_nil() : (ListValueType); +function ListType_cons(x0 : ValueType, x1 : ListValueType) : (ListValueType); +function ValueType_List (l: ListValueType) : ValueType; +function ListValueType_tag (l: ListValueType) : List_tag; +axiom [ListValueType_tag_nil_def]: (ListValueType_tag (ListType_nil()) == NIL); +axiom [ListValueType_tag_cons_def]: (forall t: ValueType, ts: ListValueType ::{ListType_cons(t, ts)} (ListValueType_tag (ListType_cons(t, ts)) == CONS)); +function isList (v: Value): bool; + + +// TypeOf and TypesOf functions +function TypeOf (v : Value) : (ValueType); +function TypesOf (v: ListValue) : ListValueType; +// Definitions +axiom [TypesOf_nil_def]: (TypesOf(ListValue_nil()) == ListType_nil()); +axiom [TypesOf_cons_def]: (forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} (TypesOf(ListValue_cons(v, vs)) == ListType_cons(TypeOf(v), TypesOf(vs)))); +axiom [TypeOf_list_def]: (forall l: ListValue ::{Value_List(l)} (TypeOf(Value_List(l)) == ValueType_List(TypesOf(l)))); +axiom [TypeOf_ret_set]: (forall v: Value :: {TypeOf(v)} ((TypeOf(v) == BOOL) || (TypeOf(v) == INT) || (TypeOf(v) == FLOAT) || (TypeOf(v) == STR) || (TypeOf(v) == NONE) || (TypeOf(v) == EXCEPTION)) || isList(v)); +axiom [TypeOf_bool_constr]: (forall b: bool :: {TypeOf(Value_bool(b))} ((TypeOf(Value_bool(b)) == BOOL))); +axiom [TypeOf_int_constr]: (forall i: int :: {Value_int(i)} ((TypeOf(Value_int(i)) == INT))); +axiom [TypeOf_float_constr]: (forall f: real :: {Value_float(f)} ((TypeOf(Value_float(f)) == FLOAT))); +axiom [TypeOf_str_constr]: (forall s: string :: {Value_str(s)} ((TypeOf(Value_str(s)) == STR))); +axiom [TypeOf_list_constr]: (forall l: ListValue :: {Value_List(l)} ((TypeOf(Value_List(l)) == ValueType_List(TypesOf(l))))); +axiom [TypeOf_exception_constr]: (forall e: Error :: {Value_Exception(e)} ((TypeOf(Value_Exception(e)) == EXCEPTION))); +axiom [TypeOf_none_constr]: (((TypeOf(Value_none()) == NONE))); + +axiom [isList_def]: (forall l: ListValue :: {Value_List(l)} (isList(Value_List(l)))); +axiom [list_neq_single_type]: forall v: Value :: {} ! ((TypeOf(v) == BOOL) || (TypeOf(v) == INT) || (TypeOf(v) == FLOAT) || (TypeOf(v) == STR) || (TypeOf(v) == NONE) || (TypeOf(v) == EXCEPTION)) == (isList(v)); +axiom [list_neq_single_type']: forall l: ListValue :: {Value_List(l)} TypeOf(Value_List(l))!=BOOL && TypeOf(Value_List(l))!=INT && TypeOf(Value_List(l))!=FLOAT && TypeOf(Value_List(l))!=STR && TypeOf(Value_List(l))!=NONE && TypeOf(Value_List(l))!=EXCEPTION; + +// isSubType functions +function isSubType (t1: ValueType, t2: ValueType) : bool; +function isSubTypes (t1: ListValueType, t2: ListValueType) : bool; +//Definitions +axiom [isSubTypes_nil_def]: (isSubTypes(ListType_nil(), ListType_nil())); +axiom [not_isSubTypes_nil]: forall ty: ValueType, l: ListValueType :: !isSubTypes(ListType_nil(), ListType_cons(ty,l)); +axiom [not_isSubTypes_nil']: forall ty: ValueType, l: ListValueType :: !isSubTypes(ListType_cons(ty,l), ListType_nil()); +axiom [isSubTypes_cons_def]: (forall t: ValueType, ts: ListValueType, t': ValueType, ts': ListValueType ::{ListType_cons(t, ts), ListType_cons(t', ts')} isSubTypes(ListType_cons(t, ts), ListType_cons(t', ts')) == (isSubType(t, t') && isSubTypes(ts, ts'))); +axiom [isSubType_list_def]: (forall l: ListValueType, l': ListValueType :: {ValueType_List(l), ValueType_List(l')} (isSubType(ValueType_List(l), ValueType_List(l')) == isSubTypes(l, l'))); +axiom [bool_substype_int]: (isSubType(BOOL, INT)); +axiom [int_substype_float]: (isSubType(INT, FLOAT)); +axiom [not_isSubstype_string]: (forall t: ValueType ::{} (t == STR || (!isSubType(STR, t) && !isSubType(t,STR)))); +axiom [not_isSubstype_none]: (forall t: ValueType ::{} (t == NONE || (!isSubType(NONE, t) && !isSubType(t,NONE)))); +axiom [not_isSubstype_exception]: (forall t: ValueType ::{} (t == EXCEPTION || (!isSubType(EXCEPTION, t) && !isSubType(t, EXCEPTION)))); +// Supporting lemmas +axiom [isSubtype_rfl]: (forall t: ValueType::{isSubType (t,t)} (isSubType (t,t))); +axiom [isSubtype_mono]: (forall t1: ValueType, t2: ValueType ::{} (!isSubType (t1,t2) || (t1 == t2 || !isSubType(t2,t1))) ); +axiom [isSubtype_trans]: (forall t1: ValueType, t2: ValueType, t3: ValueType::{} (!(isSubType(t1, t2) && isSubType(t2, t3)) || isSubType(t1, t3))); + + +// isInstance function: +function isInstance (v: Value, vt: ValueType) : bool; +axiom [isInstance_of_isSubtype]: (forall v: Value, t: ValueType::{isInstance(v,t)} (isInstance(v,t) == isSubType(TypeOf(v), t))); + +function is_IntReal (v: Value) : bool; +function Value_real_to_int (v: Value) : int; +// to be extended +function normalize_value (v : Value) : Value { + if v == Value_bool(true) then Value_int(1) + else (if v == Value_bool(false) then Value_int(0) else + if TypeOf(v) == FLOAT && is_IntReal(v) then Value_int(Value_real_to_int(v)) else + v) +} + +// ListValue functions +function List_contains (l : ListValue, x: Value) : bool; +function List_len (l : ListValue) : int; +function List_extend (l1 : ListValue, l2: ListValue) : ListValue; +function List_append (l: ListValue, x: Value) : ListValue; +function List_index (l : ListValue, i : int) : Value; +function List_reverse (l: ListValue) : ListValue; + +//List function axioms +axiom [List_contains_nil_def]: (forall x : Value ::{List_contains(ListValue_nil(), x)} !List_contains(ListValue_nil(), x)); +axiom [List_contains_cons_def]: (forall x : Value, h : Value, t : ListValue ::{} List_contains(ListValue_cons(h,t),x) == ((normalize_value(x)==normalize_value(h)) || List_contains(t, x))); +axiom [List_len_nil_def]: (List_len (ListValue_nil()) == 0); +axiom [List_len_cons_def]: (forall h : Value, t : ListValue ::{} (List_len (ListValue_cons(h,t)) == 1 + List_len(t))); +axiom [List_len_nonneg]: forall l: ListValue :: List_len(l) >= 0 ; +axiom [List_extend_nil_def]: (forall l1: ListValue ::{List_extend (l1, ListValue_nil())} (List_extend (l1, ListValue_nil()) == l1)); +axiom [List_nil_extend_def]: (forall l1: ListValue ::{List_extend (ListValue_nil(), l1)} (List_extend (ListValue_nil(), l1) == l1)); +axiom [List_cons_extend_def]: (forall h: Value, t: ListValue, l2: ListValue ::{} (List_extend (ListValue_cons(h,t), l2) == ListValue_cons(h, List_extend(t,l2)))); +axiom [List_cons_extend_contains]: (forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} (List_contains (List_extend(l1,l2), x) == List_contains (l1,x) || List_contains(l2,x))); +axiom [List_cons_extend_contains_symm]: (forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} (List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x))); +axiom [List_len_extend]: (forall l1: ListValue, l2: ListValue ::{List_len (List_extend(l1,l2))} (List_len (List_extend(l1,l2)) == List_len (l1) + List_len(l2))); +axiom [List_index_nil]: (forall i : int ::{List_index (ListValue_nil(), i)} (List_index (ListValue_nil(), i)) == Value_Exception(Error_message("index out of bound"))); +axiom [List_index_zero]: (forall h : Value, t : ListValue ::{List_index (ListValue_cons(h,t), 0)} (List_index (ListValue_cons(h,t), 0)) == h); +axiom [List_index_ind]: (forall h : Value, t : ListValue, i : int ::{List_index (ListValue_cons(h,t), i)} (!(i>0) || (List_index (ListValue_cons(h,t), i)) == List_index (t, i - 1))); +axiom [List_index_contains]: forall l: ListValue, i: int, x: Value :: {} !(List_index(l,i) == x) || List_contains(l,x); +axiom [List_index_ok]: forall l: ListValue, i: int:: {List_index(l,i)} ((List_index(l,i)) != Value_Exception(Error_message("index out of bound"))) == (i < List_len(l)); +axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: List_index(l1, i) == List_index(List_extend(l2,l1), i + List_len(l2)); +axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: List_extend(List_extend(l1,l2), l3) == List_extend(l1,List_extend(l2,l3)); +axiom [List_append_def]: forall l: ListValue, x: Value :: List_append(l,x) == List_extend(l, ListValue_cons(x, ListValue_nil())); +axiom [List_reverse_def_nil]: List_reverse(ListValue_nil()) == ListValue_nil(); +axiom [List_reverse_def_cons]: forall h: Value, t: ListValue:: {List_reverse(ListValue_cons(h,t))} List_reverse(ListValue_cons(h,t)) == List_append(List_reverse(t), h); +axiom [List_reverse_len]: forall l: ListValue :: {List_len(List_reverse(l))} List_len(l) == List_len(List_reverse(l)); +axiom [List_reverse_index]: forall l: ListValue, i: int :: List_index(l, i) == List_index(List_reverse(l), List_len(l)-1-i); +axiom [List_reverse_extend]: forall l1: ListValue, l2: ListValue :: {List_reverse(List_extend(l1,l2))} List_reverse(List_extend(l1,l2)) == List_extend(List_reverse(l2), List_reverse(l1)); +axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (List_reverse(l), v)} List_contains (List_reverse(l), v) == List_contains(l,v); + +// Dict type +type Dict; +const EMPTYDICT : Dict; + + +//Dictionary functions +function Dict_insert (d: Dict, k: Value, v: Value) : Dict; +function Dict_get (d: Dict, k: Value) : Value; +function Dict_remove (d: Dict, k: Value) : Dict; +inline function Dict_contains (d: Dict, k: Value) : bool { + Dict_get (d,k) != Value_none() +} + + +//function upType (v: Value) : Value; + +//Dictionary axioms +axiom [emptydict_def]: forall k: Value :: Dict_get(EMPTYDICT, k) == Value_none(); +axiom [Dict_insert_def1']: forall k: Value, v: Value, d: Dict ::{Dict_insert(d,k,v)} Dict_get(Dict_insert(d,k,v), normalize_value(k)) == v; +axiom [Dict_insert_def2]: forall k: Value, k': Value, v: Value, d: Dict ::{Dict_insert(d,k,v)} (normalize_value(k) == normalize_value(k')) || Dict_get(Dict_insert(d,k,v), k') == Dict_get(d,k'); +axiom [Dict_get_upType]: forall k: Value, d: Dict ::{Dict_get(d,k)} Dict_get(d, k) == Dict_get(d, normalize_value(k)); +axiom [Dict_remove_def1]: forall k: Value, d: Dict ::{Dict_remove(d,k)} Dict_get(Dict_remove(d,k), normalize_value(k)) == Value_none(); +axiom [Dict_remove_def2]: forall k: Value, k': Value, d: Dict ::{Dict_remove(d,k)} (normalize_value(k) == normalize_value(k')) || Dict_get(Dict_remove(d,k), k') == Dict_get(d,k'); + + +// List of pairs of Value, used to construct Dict +type DictList; +// Constructor +function DictList_nil(): DictList; +function DictList_cons(k: Value, v: Value, d: DictList): DictList; +//Tag and tag functions +type DictListTag; +function DictList_tag (dl: DictList) : DictListTag; +const DICTLISTNIL : DictListTag; +const DICTLISTCONS : DictListTag; +axiom [DistListTag_unique]: DICTLISTCONS != DICTLISTNIL; +axiom [DistListTag_nil_def]: DictList_tag (DictList_nil()) == DICTLISTNIL; +axiom [DistListTag_cons_def]: forall k: Value, v: Value, d: DictList ::{DictList_cons(k,v,d)} DictList_tag (DictList_cons(k,v,d)) == DICTLISTCONS; +// as a constructor for Dict +function Dict_from_DicList (l : DictList) : Dict; +function Dict_from_DicList_rev (l : DictList, acc: Dict) : Dict; +axiom [Dict_from_DicList_rev_nil]: forall acc: Dict :: Dict_from_DicList_rev(DictList_nil(), acc) == acc; +axiom [Dict_from_DicList_rev_cons]: forall k: Value, v: Value, d: DictList, acc: Dict :: Dict_from_DicList_rev(DictList_cons(k,v,d), acc) == Dict_from_DicList_rev(d,Dict_insert(acc, k, v)); +axiom [Dict_from_DicList_def]: forall dl: DictList:: {Dict_from_DicList(dl)} Dict_from_DicList(dl) == Dict_from_DicList_rev(dl, EMPTYDICT); + + +//Binary op function +function int_to_real (i: int) : real; +function str_repeat (s: string, i: int) : string; +function Py_add (v1: Value, v2: Value) : (Value); +function Py_sub (v1: Value, v2: Value) : (Value); +function Py_mul (v1: Value, v2: Value) : (Value); +inline function bool_to_int (b: bool) : (int) {if b then 1 else 0} +inline function bool_to_real (b: bool) : (real) {if b then 1.0 else 0.0} + + +axiom [Py_add_ints]: (forall i1: int, i2: int :: {Value_int(i1), Value_int(i2)} ((Py_add(Value_int(i1), Value_int(i2)) == Value_int(i1 + i2)))); +axiom [Py_add_floats]: (forall f1: real, f2: real :: {Value_float(f1), Value_float(f2)} ((Py_add(Value_float(f1), Value_float(f2)) == Value_float(f1 + f2)))); +axiom [Py_add_bools]: (forall b1: bool, b2: bool :: {Value_bool(b1), Value_bool(b2)} ((Py_add(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) + bool_to_int(b2))))); +axiom [Py_add_int_bool]: (forall i: int, b: bool :: {Value_int(i), Value_bool(b)} ((Py_add(Value_int(i), Value_bool(b)) == Value_int(i + bool_to_int(b))))); +axiom [Py_add_bool_int]: (forall b: bool, i: int :: {Value_bool(b), Value_int(i)} ((Py_add(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) + i)))); +axiom [Py_add_int_float]: (forall i: int, r: real :: {Value_int(i), Value_float(r)} ((Py_add(Value_int(i), Value_float(r)) == Value_float(r + int_to_real(i))))); +axiom [Py_add_float_int]: (forall r: real, i: int :: {Value_float(r), Value_int(i)} ((Py_add(Value_float(r), Value_int(i)) == Value_float(int_to_real(i) + r)))); +axiom [Py_add_float_bool]: (forall r: real, b: bool :: {Value_float(r), Value_bool(b)} ((Py_add(Value_float(r), Value_bool(b)) == Value_float(r + bool_to_real(b))))); +axiom [Py_add_bool_float]: (forall b: bool, r: real :: {Value_bool(b), Value_float(r)} ((Py_add(Value_bool(b), Value_float(r)) == Value_float(bool_to_real(b) + r)))); +axiom [Py_add_none]: (forall v: Value :: {} ((Py_add(v, Value_none()) == Value_Exception(Error_message("Operand is None"))))); +axiom [Py_none_add]: (forall v: Value :: {} ((Py_add(Value_none(), v) == Value_Exception(Error_message("Operand is None"))))); +axiom [Py_add_exception]: (forall v: Value, e: Error :: {Value_Exception(e)} ((Py_add(v, Value_Exception(e)) == Value_Exception(Error_message("Operand is Exception"))))); +axiom [Py_exception_add]: (forall v: Value, e: Error :: {Value_Exception(e)} ((Py_add(Value_Exception(e), v) == Value_Exception(Error_message("Operand is Exception"))))); +axiom [Py_add_strs]: (forall s1: string, s2: string :: {Value_str(s1), Value_str(s2)} ((Py_add(Value_str(s1), Value_str(s2)) == Value_str(str.concat(s1, s2))))); +axiom [Py_add_str_int]: (forall s: string, i: int :: {Value_str(s), Value_int(i)} ((Py_add(Value_str(s), Value_int(i)) == Value_Exception(Error_message("Cannot add string to int"))))); +axiom [Py_add_int_str]: (forall s: string, i: int :: {Value_str(s), Value_int(i)} ((Py_add(Value_int(i), Value_str(s)) == Value_Exception(Error_message("Cannot add string to int"))))); +axiom [Py_add_str_bool]: (forall s: string, b: bool :: {Value_str(s), Value_bool(b)} ((Py_add(Value_str(s), Value_bool(b)) == Value_Exception(Error_message("Cannot add string to bool"))))); +axiom [Py_add_bool_str]: (forall s: string, b: bool :: {Value_str(s), Value_bool(b)} ((Py_add(Value_bool(b), Value_str(s)) == Value_Exception(Error_message("Cannot add bool to string"))))); + +axiom [Py_mul_ints]: (forall i1: int, i2: int :: {Value_int(i1), Value_int(i2)} ((Py_mul(Value_int(i1), Value_int(i2)) == Value_int(i1 * i2)))); +axiom [Py_mul_bools]: (forall b1: bool, b2: bool :: {Value_bool(b1), Value_bool(b2)} ((Py_mul(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) * bool_to_int(b2))))); +axiom [Py_mul_int_bool]: (forall i: int, b: bool :: {Value_int(i), Value_bool(b)} ((Py_mul(Value_int(i), Value_bool(b)) == Value_int(i * bool_to_int(b))))); +axiom [Py_mul_bool_int]: (forall b: bool, i: int :: {Value_bool(b), Value_int(i)} ((Py_mul(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) * i)))); +axiom [Py_mul_none]: (forall v: Value :: {} ((Py_mul(v, Value_none()) == Value_Exception(Error_message("Operand is None"))))); +axiom [Py_mul_add]: (forall v: Value :: {} ((Py_mul(Value_none(), v) == Value_Exception(Error_message("Operand is None"))))); +axiom [Py_mul_exception]: (forall v: Value, e: Error :: {Value_Exception(e)} ((Py_mul(v, Value_Exception(e)) == Value_Exception(Error_message("Operand is Exception"))))); +axiom [Py_exception_mul]: (forall v: Value, e: Error :: {Value_Exception(e)} ((Py_mul(Value_Exception(e), v) == Value_Exception(Error_message("Operand is Exception"))))); +axiom [Py_mul_strs]: (forall s1: string, s2: string :: {Value_str(s1), Value_str(s2)} ((Py_mul(Value_str(s1), Value_str(s2)) == Value_Exception(Error_message("Cannot multiply two strings"))))); +axiom [Py_mul_str_int]: (forall s: string, i: int :: {Value_str(s), Value_int(i)} ((Py_add(Value_str(s), Value_int(i)) == Value_str(str_repeat(s, i))))); +axiom [Py_mul_int_str]: (forall s: string, i: int :: {Value_str(s), Value_int(i)} ((Py_add(Value_int(i), Value_str(s)) == Value_str(str_repeat(s, i))))); +axiom [Py_mul_str_bool]: (forall s: string, b: bool :: {Value_str(s), Value_bool(b)} ((Py_add(Value_str(s), Value_bool(b)) == Value_str(if b then s else "")))); +axiom [Py_mul_bool_str]: (forall s: string, b: bool :: {Value_str(s), Value_bool(b)} ((Py_add(Value_bool(b), Value_str(s)) == Value_str(if b then s else "")))); + + +//Testing +procedure list_functions_test() returns () +{ + var l1: ListValue, l2: ListValue; + l1 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil()))); + assert [index_1]: List_index(l1,1) == Value_int(2); + assert [contain_true]: List_contains(l1, Value_bool(true)); + assert [ValueEq]: !(Value_int(4) == Value_int(3)); + assert [normalize_value]: !(normalize_value(Value_int(4)) == Value_int(3)); + assert [contain_3]: List_contains(l1, Value_int(2)); +}; + +procedure list_generic_test() returns () { + var l1: ListValue; + assert [contains_append]: forall l: ListValue, x: Value :: List_contains(List_append(l,x), x); + assert [len_append]: forall l: ListValue, x: Value :: List_len(List_append(l,x)) == List_len(l) + 1; + l1 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil()))); + assert [l1_contains_3]: List_contains (l1, Value_int(3)); + assert [l1l2_contains_3]: forall l2: ListValue :: List_contains (List_extend(l1, l2), Value_int(3)); + assert [revl1_contain_3]: List_contains (List_reverse(l1), Value_int(3)); + assert [rev_contain]: forall l: ListValue, v: Value :: List_contains (List_reverse(l), v) == List_contains(l,v); + assert [l1r_l2_contains_3]: forall l2: ListValue :: List_contains (List_extend(List_reverse(l1), l2), Value_int(3)); + assert [l1r_l2_contains_3']: forall l2: ListValue :: List_contains (List_reverse(List_extend(List_reverse(l1), l2)), Value_int(3)); +}; + + +procedure simple_call(v1: Value, v2: Value) returns () + spec { + requires [v1_type]: isInstance(v1, BOOL) || isInstance(v1, STR); + requires [v2_type]: isInstance(v2, ValueType_List(ListType_cons(INT, ListType_cons(INT, ListType_nil())))); + } +{}; + +procedure test() returns () { + var ty1: ValueType, ty2: ValueType, tl: ValueType; + ty1 := TypeOf(Value_int(5)); + ty2 := TypeOf(Value_bool(true)); + assert [subtype1]: isSubType(ty2,ty1); + assert [subtypeList]: forall l: ListValueType :: isSubType (ValueType_List(ListType_cons(ty2, l)), ValueType_List(ListType_cons(ty1, l))); + assert [subtypeList2]: forall l1: ListValueType, l2: ListValueType :: !(isSubTypes(l1,l2)) || isSubType (ValueType_List(ListType_cons(ty2, l1)), ValueType_List(ListType_cons(ty1, l2))); +}; + +procedure test_simple_call_argument_typecheck() returns () { + var arg1: Value, arg2: Value; + arg1 := Value_bool(true); + arg2 := Value_List(ListValue_cons(Value_int(3), ListValue_cons (Value_bool(true), ListValue_nil()))); + assert [subtype_bool]: isInstance(arg1,BOOL); + call simple_call(arg1, arg2); +}; + +procedure dict_functions_test () returns () { + var d1: Dict, d2: Dict, d3: Dict; + d1:= Dict_insert(EMPTYDICT, Value_int(1), Value_int(1)); + d2:= Dict_insert(d1, Value_bool(true), Value_int(2)); + assert [uptype]: normalize_value(Value_bool(true)) == Value_int(1); + assert [uptype2]: normalize_value(Value_int(1)) == Value_int(1); + assert [uptype3]: normalize_value(Value_str("fd")) == Value_str("fd"); + assert [get_1]: Dict_get(d2, Value_int(1)) == Value_int(2); +}; + + +procedure test_dict_listconstructor () returns () { + var d: Dict, dl: DictList, d2: Dict, d3: Dict; + dl := DictList_cons(Value_bool(true), Value_int(10), DictList_cons(Value_int(1), Value_int(11), DictList_nil())); + d := Dict_from_DicList(dl); + assert [get_1]: Dict_get(d, Value_int(1)) == Value_int(11); + assert [get_true]: Dict_get(d, Value_bool(true)) == Value_int(11); + d2 := Dict_insert(Dict_insert(d, Value_int(10), Value_int(8)), Value_int(1), Value_str("abc")); + assert [get_true2]: Dict_get(d2, Value_bool(true)) == Value_str("abc"); + d3 := Dict_remove(d2, Value_bool(true)); + assert [get_1_d3]: Dict_get(d3, Value_int(1)) == Value_none(); + assert [ncontain]: !Dict_contains(d3, Value_bool(true)); +}; + +procedure forall_dict_test () returns () { + assert [ncontain_general]: forall d: Dict, k: Value :: !Dict_contains(Dict_remove(d,k), k); + assert [ncontain_general']: forall d: Dict, k: Value :: !Dict_contains(Dict_remove(d,normalize_value(k)), k); + assert [contain_general]: forall d: Dict, k: Value, v: Value :: (v == Value_none()) || Dict_contains(Dict_insert(d,k,v), k); + assert [remove_insert]: forall d: Dict, k: Value, v: Value, k': Value :: !(Dict_get(d,k) == v) || Dict_get((Dict_insert(Dict_remove(d,k), k, v)), k') == Dict_get(d, k'); + assert [remove_insert_eq]: forall d: Dict, k: Value, v: Value:: !(Dict_get(d,k) == v) || (Dict_insert(Dict_remove(d,k), k, v)) == d; +}; + +#end + +#eval verify "cvc5" boogieTypePrelude + + +def Boogie.prelude : Boogie.Program := + Boogie.getProgram Strata.boogieTypePrelude |>.fst + +end Strata From 8d667664a7c97201cfd08562f3979fb2943139d4 Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Fri, 5 Dec 2025 08:49:12 -0800 Subject: [PATCH 02/13] add copyright --- Strata/Languages/Python/BoogieTypePrelude.lean | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean index 794498d79..563fcc990 100644 --- a/Strata/Languages/Python/BoogieTypePrelude.lean +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -1,3 +1,9 @@ +/- + Copyright Strata Contributors + + SPDX-License-Identifier: Apache-2.0 OR MIT +-/ + import Strata.DDM.Elab import Strata.DDM.AST import Strata.Languages.Boogie.DDMTransform.Parse From 30c715992d04d493b218a80980be4d47ec1a2856 Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Fri, 5 Dec 2025 11:26:01 -0800 Subject: [PATCH 03/13] add supporting axiom for Dict --- Strata/Languages/Python/BoogieTypePrelude.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean index 563fcc990..2e003e45e 100644 --- a/Strata/Languages/Python/BoogieTypePrelude.lean +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -208,7 +208,7 @@ function Dict_from_DicList_rev (l : DictList, acc: Dict) : Dict; axiom [Dict_from_DicList_rev_nil]: forall acc: Dict :: Dict_from_DicList_rev(DictList_nil(), acc) == acc; axiom [Dict_from_DicList_rev_cons]: forall k: Value, v: Value, d: DictList, acc: Dict :: Dict_from_DicList_rev(DictList_cons(k,v,d), acc) == Dict_from_DicList_rev(d,Dict_insert(acc, k, v)); axiom [Dict_from_DicList_def]: forall dl: DictList:: {Dict_from_DicList(dl)} Dict_from_DicList(dl) == Dict_from_DicList_rev(dl, EMPTYDICT); - +axiom [remove_insert_eq]: forall d: Dict, k: Value, v: Value:: !(Dict_get(d,k) == v) || (Dict_insert(Dict_remove(d,k), k, v)) == d; //Binary op function function int_to_real (i: int) : real; @@ -333,7 +333,6 @@ procedure forall_dict_test () returns () { assert [ncontain_general']: forall d: Dict, k: Value :: !Dict_contains(Dict_remove(d,normalize_value(k)), k); assert [contain_general]: forall d: Dict, k: Value, v: Value :: (v == Value_none()) || Dict_contains(Dict_insert(d,k,v), k); assert [remove_insert]: forall d: Dict, k: Value, v: Value, k': Value :: !(Dict_get(d,k) == v) || Dict_get((Dict_insert(Dict_remove(d,k), k, v)), k') == Dict_get(d, k'); - assert [remove_insert_eq]: forall d: Dict, k: Value, v: Value:: !(Dict_get(d,k) == v) || (Dict_insert(Dict_remove(d,k), k, v)) == d; }; #end From 658780ce3fa2d4be1d511b30542087e998cc1a65 Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Fri, 12 Dec 2025 13:20:10 -0800 Subject: [PATCH 04/13] add Class type + code refining --- .../Languages/Python/BoogieTypePrelude.lean | 465 +++++++++++++----- 1 file changed, 343 insertions(+), 122 deletions(-) diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean index 2e003e45e..a379c0f4c 100644 --- a/Strata/Languages/Python/BoogieTypePrelude.lean +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -24,18 +24,30 @@ axiom [list_tag_unique]: CONS != NIL; //Will be merged with BoogiePrelude.lean type Error; function Error_message (s: string): Error; +type Error_tag; +const OK : Error_tag; +const ERR : Error_tag; +axiom [error_tag_unique]: OK != ERR; // Value and ListValue types type Value; type ListValue; + +// Class type +type Class; +type AttributeValues := Map string Value; +type ClassInstance; + // Constructors function Value_bool (b : bool) : (Value); function Value_int (i : int) : (Value); function Value_float (f : real) : (Value); function Value_str (s : string) : (Value); function Value_none() : (Value); -function Value_Exception (e : Error): (Value); -function Value_List (lv : ListValue) : (Value); +function Value_exception (e : Error): (Value); +function Value_list (lv : ListValue) : (Value); +function Value_class (ci: ClassInstance) : Value; + function ListValue_nil() : (ListValue); function ListValue_cons(x0 : Value, x1 : ListValue) : (ListValue); //Tags @@ -52,72 +64,117 @@ const FLOAT : ValueType; const STR : ValueType; const NONE : ValueType; const EXCEPTION : ValueType; +function ValueType_class(c: Class): ValueType; + +function isList (v: Value): bool; +function isClassInstance (v: Value): bool; + //Uniqueness axioms axiom [unique_ValueType_bool]: BOOL != INT && BOOL != FLOAT && BOOL != STR && BOOL != NONE && BOOL != EXCEPTION; axiom [unique_ValueType_int]: INT != STR && INT != FLOAT && INT != NONE && INT != EXCEPTION; axiom [unique_ValueType_float]: FLOAT != STR && FLOAT != NONE && FLOAT != EXCEPTION; axiom [unique_ValueType_str]: STR != NONE && STR != EXCEPTION; axiom [unique_ValueType_none]: NONE != EXCEPTION; + //Eq axioms axiom [value_int_eq]: forall i: int, j: int :: {Value_int(i) == Value_int(j)} (Value_int(i) == Value_int(j)) == (i == j); axiom [value_bool_eq]: forall b1: bool, b2: bool :: {Value_bool(b1) == Value_bool(b2)} (Value_bool(b1) == Value_bool(b2)) == (b1 == b2); axiom [value_float_eq]: forall r1: real, r2: real :: {Value_float(r1) == Value_float(r2)} (Value_float(r1) == Value_float(r2)) == (r1 == r2); axiom [value_str_eq]: forall s1: string, s2: string :: {Value_str(s1) == Value_str(s2)} (Value_str(s1) == Value_str(s2)) == (s1 == s2); - //Constructors and tag functions of ListType function ListType_nil() : (ListValueType); -function ListType_cons(x0 : ValueType, x1 : ListValueType) : (ListValueType); +function ListType_cons(x0 : ValueType, x1 : ListValueType) : ListValueType; function ValueType_List (l: ListValueType) : ValueType; function ListValueType_tag (l: ListValueType) : List_tag; axiom [ListValueType_tag_nil_def]: (ListValueType_tag (ListType_nil()) == NIL); axiom [ListValueType_tag_cons_def]: (forall t: ValueType, ts: ListValueType ::{ListType_cons(t, ts)} (ListValueType_tag (ListType_cons(t, ts)) == CONS)); -function isList (v: Value): bool; - // TypeOf and TypesOf functions -function TypeOf (v : Value) : (ValueType); +function TypeOf (v : Value) : ValueType; function TypesOf (v: ListValue) : ListValueType; // Definitions -axiom [TypesOf_nil_def]: (TypesOf(ListValue_nil()) == ListType_nil()); -axiom [TypesOf_cons_def]: (forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} (TypesOf(ListValue_cons(v, vs)) == ListType_cons(TypeOf(v), TypesOf(vs)))); -axiom [TypeOf_list_def]: (forall l: ListValue ::{Value_List(l)} (TypeOf(Value_List(l)) == ValueType_List(TypesOf(l)))); -axiom [TypeOf_ret_set]: (forall v: Value :: {TypeOf(v)} ((TypeOf(v) == BOOL) || (TypeOf(v) == INT) || (TypeOf(v) == FLOAT) || (TypeOf(v) == STR) || (TypeOf(v) == NONE) || (TypeOf(v) == EXCEPTION)) || isList(v)); -axiom [TypeOf_bool_constr]: (forall b: bool :: {TypeOf(Value_bool(b))} ((TypeOf(Value_bool(b)) == BOOL))); -axiom [TypeOf_int_constr]: (forall i: int :: {Value_int(i)} ((TypeOf(Value_int(i)) == INT))); -axiom [TypeOf_float_constr]: (forall f: real :: {Value_float(f)} ((TypeOf(Value_float(f)) == FLOAT))); -axiom [TypeOf_str_constr]: (forall s: string :: {Value_str(s)} ((TypeOf(Value_str(s)) == STR))); -axiom [TypeOf_list_constr]: (forall l: ListValue :: {Value_List(l)} ((TypeOf(Value_List(l)) == ValueType_List(TypesOf(l))))); -axiom [TypeOf_exception_constr]: (forall e: Error :: {Value_Exception(e)} ((TypeOf(Value_Exception(e)) == EXCEPTION))); -axiom [TypeOf_none_constr]: (((TypeOf(Value_none()) == NONE))); - -axiom [isList_def]: (forall l: ListValue :: {Value_List(l)} (isList(Value_List(l)))); -axiom [list_neq_single_type]: forall v: Value :: {} ! ((TypeOf(v) == BOOL) || (TypeOf(v) == INT) || (TypeOf(v) == FLOAT) || (TypeOf(v) == STR) || (TypeOf(v) == NONE) || (TypeOf(v) == EXCEPTION)) == (isList(v)); -axiom [list_neq_single_type']: forall l: ListValue :: {Value_List(l)} TypeOf(Value_List(l))!=BOOL && TypeOf(Value_List(l))!=INT && TypeOf(Value_List(l))!=FLOAT && TypeOf(Value_List(l))!=STR && TypeOf(Value_List(l))!=NONE && TypeOf(Value_List(l))!=EXCEPTION; +axiom [TypesOf_nil_def]: TypesOf(ListValue_nil()) == ListType_nil(); +axiom [TypesOf_cons_def]: forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} TypesOf(ListValue_cons(v, vs)) == ListType_cons(TypeOf(v), TypesOf(vs)); +axiom [TypeOf_list_def]: forall l: ListValue ::{Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); +axiom [TypeOf_ret_set]: forall v: Value :: {TypeOf(v)} + TypeOf(v) == BOOL || + TypeOf(v) == INT || + TypeOf(v) == FLOAT || + TypeOf(v) == STR || + TypeOf(v) == NONE || + TypeOf(v) == EXCEPTION || + isList(v) || + isClassInstance(v); +axiom [TypeOf_bool]: forall b: bool :: {TypeOf(Value_bool(b))} TypeOf(Value_bool(b)) == BOOL; +axiom [TypeOf_int]: forall i: int :: {Value_int(i)} TypeOf(Value_int(i)) == INT; +axiom [TypeOf_float]: forall f: real :: {Value_float(f)} TypeOf(Value_float(f)) == FLOAT; +axiom [TypeOf_str]: forall s: string :: {Value_str(s)} TypeOf(Value_str(s)) == STR; +axiom [TypeOf_exception]: forall e: Error :: {Value_exception(e)} TypeOf(Value_exception(e)) == EXCEPTION; +axiom [TypeOf_none]: TypeOf(Value_none()) == NONE; +axiom [TypeOf_list]: forall l: ListValue :: {Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); + +axiom [isList_def]: forall l: ListValue :: {Value_list(l)} isList(Value_list(l)); +axiom [list_neq_other_types]: forall v: Value :: {isList(v)} isList(v) == ( + TypeOf(v) != BOOL && + TypeOf(v) != INT) && + TypeOf(v) != FLOAT && + TypeOf(v) != STR && + TypeOf(v) != NONE && + TypeOf(v) != EXCEPTION && + !isClassInstance(v); +axiom [list_neq_other_types']: forall l: ListValue, ci: ClassInstance :: {TypeOf(Value_list(l))} + TypeOf(Value_list(l))!=BOOL && + TypeOf(Value_list(l))!=INT && + TypeOf(Value_list(l))!=FLOAT && + TypeOf(Value_list(l))!=STR && + TypeOf(Value_list(l))!=NONE && + TypeOf(Value_list(l))!=EXCEPTION && + TypeOf(Value_list(l))!=TypeOf(Value_class(ci)); + +axiom [isClassInstance_def]: forall ci: ClassInstance :: {Value_class(ci)} isClassInstance(Value_class(ci)); +axiom [ClassInstantType_neq_other_types]: forall v: Value :: {isClassInstance(v)} isClassInstance(v) == ( + TypeOf(v) != BOOL && + TypeOf(v) != INT) && + TypeOf(v) != FLOAT && + TypeOf(v) != STR && + TypeOf(v) != NONE && + TypeOf(v) != EXCEPTION && + !isList(v); +axiom [list_neq_single_type']: forall ci: ClassInstance, l: ListValue :: {TypeOf(Value_list(l))} + TypeOf(Value_class(ci))!=BOOL && + TypeOf(Value_class(ci))!=INT && + TypeOf(Value_class(ci))!=FLOAT && + TypeOf(Value_class(ci))!=STR && + TypeOf(Value_class(ci))!=NONE && + TypeOf(Value_class(ci))!=EXCEPTION && + TypeOf(Value_class(ci))!=TypeOf(Value_list(l)); // isSubType functions function isSubType (t1: ValueType, t2: ValueType) : bool; function isSubTypes (t1: ListValueType, t2: ListValueType) : bool; //Definitions -axiom [isSubTypes_nil_def]: (isSubTypes(ListType_nil(), ListType_nil())); +axiom [isSubTypes_nil_def]: isSubTypes(ListType_nil(), ListType_nil()); axiom [not_isSubTypes_nil]: forall ty: ValueType, l: ListValueType :: !isSubTypes(ListType_nil(), ListType_cons(ty,l)); axiom [not_isSubTypes_nil']: forall ty: ValueType, l: ListValueType :: !isSubTypes(ListType_cons(ty,l), ListType_nil()); -axiom [isSubTypes_cons_def]: (forall t: ValueType, ts: ListValueType, t': ValueType, ts': ListValueType ::{ListType_cons(t, ts), ListType_cons(t', ts')} isSubTypes(ListType_cons(t, ts), ListType_cons(t', ts')) == (isSubType(t, t') && isSubTypes(ts, ts'))); -axiom [isSubType_list_def]: (forall l: ListValueType, l': ListValueType :: {ValueType_List(l), ValueType_List(l')} (isSubType(ValueType_List(l), ValueType_List(l')) == isSubTypes(l, l'))); -axiom [bool_substype_int]: (isSubType(BOOL, INT)); -axiom [int_substype_float]: (isSubType(INT, FLOAT)); -axiom [not_isSubstype_string]: (forall t: ValueType ::{} (t == STR || (!isSubType(STR, t) && !isSubType(t,STR)))); -axiom [not_isSubstype_none]: (forall t: ValueType ::{} (t == NONE || (!isSubType(NONE, t) && !isSubType(t,NONE)))); -axiom [not_isSubstype_exception]: (forall t: ValueType ::{} (t == EXCEPTION || (!isSubType(EXCEPTION, t) && !isSubType(t, EXCEPTION)))); +axiom [isSubTypes_cons_def]:forall t: ValueType, ts: ListValueType, t': ValueType, ts': ListValueType ::{ListType_cons(t, ts), ListType_cons(t', ts')} + isSubTypes(ListType_cons(t, ts), ListType_cons(t', ts')) == (isSubType(t, t') && isSubTypes(ts, ts')); +axiom [isSubType_list_def]: forall l: ListValueType, l': ListValueType :: {ValueType_List(l), ValueType_List(l')} + isSubType(ValueType_List(l), ValueType_List(l')) == isSubTypes(l, l'); +axiom [bool_substype_int]: isSubType(BOOL, INT); +axiom [int_substype_float]: isSubType(INT, FLOAT); +axiom [not_isSubstype_string]: forall t: ValueType ::{} t == STR || (!isSubType(STR, t) && !isSubType(t,STR)); +axiom [not_isSubstype_none]: forall t: ValueType ::{} (t == NONE || (!isSubType(NONE, t) && !isSubType(t,NONE))); +axiom [not_isSubstype_exception]: forall t: ValueType ::{} t == EXCEPTION || (!isSubType(EXCEPTION, t) && !isSubType(t, EXCEPTION)); +axiom [not_isSubstype_class]: forall t: ValueType, c: Class ::{} t != ValueType_class(c) ==> (!isSubType(ValueType_class(c), t) && !isSubType(t,ValueType_class(c))); // Supporting lemmas -axiom [isSubtype_rfl]: (forall t: ValueType::{isSubType (t,t)} (isSubType (t,t))); -axiom [isSubtype_mono]: (forall t1: ValueType, t2: ValueType ::{} (!isSubType (t1,t2) || (t1 == t2 || !isSubType(t2,t1))) ); -axiom [isSubtype_trans]: (forall t1: ValueType, t2: ValueType, t3: ValueType::{} (!(isSubType(t1, t2) && isSubType(t2, t3)) || isSubType(t1, t3))); - +axiom [isSubtype_rfl]: forall t: ValueType::{isSubType (t,t)} isSubType (t,t); +axiom [isSubtype_mono]: forall t1: ValueType, t2: ValueType ::{} !isSubType (t1,t2) || (t1 == t2 || !isSubType(t2,t1)); +axiom [isSubtype_trans]: forall t1: ValueType, t2: ValueType, t3: ValueType::{} !(isSubType(t1, t2) && isSubType(t2, t3)) || isSubType(t1, t3); // isInstance function: function isInstance (v: Value, vt: ValueType) : bool; -axiom [isInstance_of_isSubtype]: (forall v: Value, t: ValueType::{isInstance(v,t)} (isInstance(v,t) == isSubType(TypeOf(v), t))); +axiom [isInstance_of_isSubtype]: forall v: Value, t: ValueType::{isInstance(v,t)} isInstance(v,t) == isSubType(TypeOf(v), t); function is_IntReal (v: Value) : bool; function Value_real_to_int (v: Value) : int; @@ -138,56 +195,69 @@ function List_index (l : ListValue, i : int) : Value; function List_reverse (l: ListValue) : ListValue; //List function axioms -axiom [List_contains_nil_def]: (forall x : Value ::{List_contains(ListValue_nil(), x)} !List_contains(ListValue_nil(), x)); -axiom [List_contains_cons_def]: (forall x : Value, h : Value, t : ListValue ::{} List_contains(ListValue_cons(h,t),x) == ((normalize_value(x)==normalize_value(h)) || List_contains(t, x))); -axiom [List_len_nil_def]: (List_len (ListValue_nil()) == 0); -axiom [List_len_cons_def]: (forall h : Value, t : ListValue ::{} (List_len (ListValue_cons(h,t)) == 1 + List_len(t))); +axiom [List_contains_nil_def]: forall x : Value ::{List_contains(ListValue_nil(), x)} + !List_contains(ListValue_nil(), x); +axiom [List_contains_cons_def]: forall x : Value, h : Value, t : ListValue ::{} + List_contains(ListValue_cons(h,t),x) == ((normalize_value(x)==normalize_value(h)) || List_contains(t, x)); +axiom [List_len_nil_def]: List_len (ListValue_nil()) == 0; +axiom [List_len_cons_def]: forall h : Value, t : ListValue ::{} List_len (ListValue_cons(h,t)) == 1 + List_len(t); axiom [List_len_nonneg]: forall l: ListValue :: List_len(l) >= 0 ; -axiom [List_extend_nil_def]: (forall l1: ListValue ::{List_extend (l1, ListValue_nil())} (List_extend (l1, ListValue_nil()) == l1)); -axiom [List_nil_extend_def]: (forall l1: ListValue ::{List_extend (ListValue_nil(), l1)} (List_extend (ListValue_nil(), l1) == l1)); -axiom [List_cons_extend_def]: (forall h: Value, t: ListValue, l2: ListValue ::{} (List_extend (ListValue_cons(h,t), l2) == ListValue_cons(h, List_extend(t,l2)))); -axiom [List_cons_extend_contains]: (forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} (List_contains (List_extend(l1,l2), x) == List_contains (l1,x) || List_contains(l2,x))); -axiom [List_cons_extend_contains_symm]: (forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} (List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x))); -axiom [List_len_extend]: (forall l1: ListValue, l2: ListValue ::{List_len (List_extend(l1,l2))} (List_len (List_extend(l1,l2)) == List_len (l1) + List_len(l2))); -axiom [List_index_nil]: (forall i : int ::{List_index (ListValue_nil(), i)} (List_index (ListValue_nil(), i)) == Value_Exception(Error_message("index out of bound"))); -axiom [List_index_zero]: (forall h : Value, t : ListValue ::{List_index (ListValue_cons(h,t), 0)} (List_index (ListValue_cons(h,t), 0)) == h); -axiom [List_index_ind]: (forall h : Value, t : ListValue, i : int ::{List_index (ListValue_cons(h,t), i)} (!(i>0) || (List_index (ListValue_cons(h,t), i)) == List_index (t, i - 1))); -axiom [List_index_contains]: forall l: ListValue, i: int, x: Value :: {} !(List_index(l,i) == x) || List_contains(l,x); -axiom [List_index_ok]: forall l: ListValue, i: int:: {List_index(l,i)} ((List_index(l,i)) != Value_Exception(Error_message("index out of bound"))) == (i < List_len(l)); -axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: List_index(l1, i) == List_index(List_extend(l2,l1), i + List_len(l2)); -axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: List_extend(List_extend(l1,l2), l3) == List_extend(l1,List_extend(l2,l3)); -axiom [List_append_def]: forall l: ListValue, x: Value :: List_append(l,x) == List_extend(l, ListValue_cons(x, ListValue_nil())); +axiom [List_extend_nil_def]: forall l1: ListValue ::{List_extend (l1, ListValue_nil())} + List_extend (l1, ListValue_nil()) == l1; +axiom [List_nil_extend_def]: forall l1: ListValue ::{List_extend (ListValue_nil(), l1)} + List_extend (ListValue_nil(), l1) == l1; +axiom [List_cons_extend_def]: forall h: Value, t: ListValue, l2: ListValue ::{} + List_extend (ListValue_cons(h,t), l2) == ListValue_cons(h, List_extend(t,l2)); +axiom [List_cons_extend_contains]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} + List_contains (List_extend(l1,l2), x) == List_contains (l1,x) || List_contains(l2,x); +axiom [List_cons_extend_contains_symm]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} + List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x); +axiom [List_len_extend]: forall l1: ListValue, l2: ListValue ::{List_len (List_extend(l1,l2))} + List_len (List_extend(l1,l2)) == List_len (l1) + List_len(l2); +axiom [List_index_nil]: forall i : int ::{List_index (ListValue_nil(), i)} + List_index (ListValue_nil(), i) == Value_exception(Error_message("index out of bound")); +axiom [List_index_zero]: forall h : Value, t : ListValue ::{List_index (ListValue_cons(h,t), 0)} + List_index (ListValue_cons(h,t), 0) == h; +axiom [List_index_ind]: forall h : Value, t : ListValue, i : int ::{List_index (ListValue_cons(h,t), i)} + (i > 0) ==> (List_index (ListValue_cons(h,t), i)) == List_index (t, i - 1); +axiom [List_index_contains]: forall l: ListValue, i: int, x: Value :: {} + (List_index(l,i) == x) ==> List_contains(l,x); +axiom [List_index_ok]: forall l: ListValue, i: int:: {List_index(l,i)} + ((List_index(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l)); +axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: {List_extend(l2,l1)} + List_index(l1, i) == List_index(List_extend(l2,l1), i + List_len(l2)); +axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: {} + List_extend(List_extend(l1,l2), l3) == List_extend(l1,List_extend(l2,l3)); +axiom [List_append_def]: forall l: ListValue, x: Value :: {List_append(l,x)} + List_append(l,x) == List_extend(l, ListValue_cons(x, ListValue_nil())); axiom [List_reverse_def_nil]: List_reverse(ListValue_nil()) == ListValue_nil(); -axiom [List_reverse_def_cons]: forall h: Value, t: ListValue:: {List_reverse(ListValue_cons(h,t))} List_reverse(ListValue_cons(h,t)) == List_append(List_reverse(t), h); -axiom [List_reverse_len]: forall l: ListValue :: {List_len(List_reverse(l))} List_len(l) == List_len(List_reverse(l)); -axiom [List_reverse_index]: forall l: ListValue, i: int :: List_index(l, i) == List_index(List_reverse(l), List_len(l)-1-i); -axiom [List_reverse_extend]: forall l1: ListValue, l2: ListValue :: {List_reverse(List_extend(l1,l2))} List_reverse(List_extend(l1,l2)) == List_extend(List_reverse(l2), List_reverse(l1)); -axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (List_reverse(l), v)} List_contains (List_reverse(l), v) == List_contains(l,v); +axiom [List_reverse_def_cons]: forall h: Value, t: ListValue:: {List_reverse(ListValue_cons(h,t))} + List_reverse(ListValue_cons(h,t)) == List_append(List_reverse(t), h); +axiom [List_reverse_len]: forall l: ListValue :: {List_len(List_reverse(l))} + List_len(l) == List_len(List_reverse(l)); +axiom [List_reverse_index]: forall l: ListValue, i: int :: {List_reverse(l)} + List_index(l, i) == List_index(List_reverse(l), List_len(l)-1-i); +axiom [List_reverse_extend]: forall l1: ListValue, l2: ListValue :: {List_reverse(List_extend(l1,l2))} + List_reverse(List_extend(l1,l2)) == List_extend(List_reverse(l2), List_reverse(l1)); +axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (List_reverse(l), v)} + List_contains (List_reverse(l), v) == List_contains(l,v); // Dict type -type Dict; -const EMPTYDICT : Dict; - +type Dict := Map Value Value; //Dictionary functions +function Dict_empty() : Dict; function Dict_insert (d: Dict, k: Value, v: Value) : Dict; function Dict_get (d: Dict, k: Value) : Value; function Dict_remove (d: Dict, k: Value) : Dict; -inline function Dict_contains (d: Dict, k: Value) : bool { - Dict_get (d,k) != Value_none() -} - - -//function upType (v: Value) : Value; +function Dict_contains (d: Dict, k: Value) : bool; //Dictionary axioms -axiom [emptydict_def]: forall k: Value :: Dict_get(EMPTYDICT, k) == Value_none(); -axiom [Dict_insert_def1']: forall k: Value, v: Value, d: Dict ::{Dict_insert(d,k,v)} Dict_get(Dict_insert(d,k,v), normalize_value(k)) == v; -axiom [Dict_insert_def2]: forall k: Value, k': Value, v: Value, d: Dict ::{Dict_insert(d,k,v)} (normalize_value(k) == normalize_value(k')) || Dict_get(Dict_insert(d,k,v), k') == Dict_get(d,k'); -axiom [Dict_get_upType]: forall k: Value, d: Dict ::{Dict_get(d,k)} Dict_get(d, k) == Dict_get(d, normalize_value(k)); -axiom [Dict_remove_def1]: forall k: Value, d: Dict ::{Dict_remove(d,k)} Dict_get(Dict_remove(d,k), normalize_value(k)) == Value_none(); -axiom [Dict_remove_def2]: forall k: Value, k': Value, d: Dict ::{Dict_remove(d,k)} (normalize_value(k) == normalize_value(k')) || Dict_get(Dict_remove(d,k), k') == Dict_get(d,k'); - +axiom [emptydict_def]: forall k: Value :: {Dict_empty() [k]} Dict_empty() [k] == Value_none(); +axiom [Dict_get_def]: forall d: Dict, k: Value :: {Dict_get(d,k)} Dict_get(d,k) == d[normalize_value(k)]; +axiom [Dict_insert_def]: forall d: Dict, k: Value, v: Value :: {Dict_insert(d,k,v)} Dict_insert(d,k,v) == d[normalize_value(k):= v]; +axiom [Dict_remove_def]: forall d: Dict, k: Value :: {Dict_remove(d,k)} Dict_remove(d,k) == d[normalize_value(k):= Value_none()]; +axiom [Dict_contains_def]: forall d: Dict, k: Value :: {Dict_contains(d,k)} Dict_contains(d,k) == (Dict_get (d,k) != Value_none()); // List of pairs of Value, used to construct Dict type DictList; @@ -195,20 +265,129 @@ type DictList; function DictList_nil(): DictList; function DictList_cons(k: Value, v: Value, d: DictList): DictList; //Tag and tag functions -type DictListTag; -function DictList_tag (dl: DictList) : DictListTag; -const DICTLISTNIL : DictListTag; -const DICTLISTCONS : DictListTag; -axiom [DistListTag_unique]: DICTLISTCONS != DICTLISTNIL; -axiom [DistListTag_nil_def]: DictList_tag (DictList_nil()) == DICTLISTNIL; -axiom [DistListTag_cons_def]: forall k: Value, v: Value, d: DictList ::{DictList_cons(k,v,d)} DictList_tag (DictList_cons(k,v,d)) == DICTLISTCONS; +function DictList_tag (dl: DictList) : List_tag; +axiom [DistListTag_nil_def]: DictList_tag (DictList_nil()) == NIL; +axiom [DistListTag_cons_def]: forall k: Value, v: Value, d: DictList ::{DictList_cons(k,v,d)} DictList_tag (DictList_cons(k,v,d)) == CONS; // as a constructor for Dict function Dict_from_DicList (l : DictList) : Dict; function Dict_from_DicList_rev (l : DictList, acc: Dict) : Dict; axiom [Dict_from_DicList_rev_nil]: forall acc: Dict :: Dict_from_DicList_rev(DictList_nil(), acc) == acc; -axiom [Dict_from_DicList_rev_cons]: forall k: Value, v: Value, d: DictList, acc: Dict :: Dict_from_DicList_rev(DictList_cons(k,v,d), acc) == Dict_from_DicList_rev(d,Dict_insert(acc, k, v)); -axiom [Dict_from_DicList_def]: forall dl: DictList:: {Dict_from_DicList(dl)} Dict_from_DicList(dl) == Dict_from_DicList_rev(dl, EMPTYDICT); -axiom [remove_insert_eq]: forall d: Dict, k: Value, v: Value:: !(Dict_get(d,k) == v) || (Dict_insert(Dict_remove(d,k), k, v)) == d; +axiom [Dict_from_DicList_rev_cons]: forall k: Value, v: Value, d: DictList, acc: Dict :: + Dict_from_DicList_rev(DictList_cons(k,v,d), acc) == Dict_from_DicList_rev(d,Dict_insert(acc, k, v)); +axiom [Dict_from_DicList_def]: forall dl: DictList:: {Dict_from_DicList(dl)} + Dict_from_DicList(dl) == Dict_from_DicList_rev(dl, Dict_empty()); + +type AttributeNames; +function AttributeNames_nil() : (AttributeNames); +function AttributeNames_cons(x0 : string, x1 : AttributeNames) : (AttributeNames); +function AttributeNames_tag (f: AttributeNames) : List_tag; +function AttributeNames_contains (l : AttributeNames, x: string) : bool; +function AttributeNames_len (l : AttributeNames) : int; +function AttributeNames_index (l : AttributeNames, i : int) : string; +function AttributeName_to_index (l : AttributeNames, f: string) : int; + +axiom [AttributeNames_len_nil_def]: AttributeNames_len (AttributeNames_nil()) == 0; +axiom [AttributeNames_len_cons_def]: forall h : string, t : AttributeNames ::{} + AttributeNames_len (AttributeNames_cons(h,t)) == 1 + AttributeNames_len(t); +axiom [AttributeNames_tag_nil_def]: AttributeNames_tag(AttributeNames_nil()) == NIL; +axiom [AttributeNames_tag_cons_def]: forall h : string, t : AttributeNames ::{} AttributeNames_tag (AttributeNames_cons(h,t)) == CONS; +axiom [AttributeNames_contains_nil_def]: (forall x : string ::{AttributeNames_contains(AttributeNames_nil(), x)} + !AttributeNames_contains(AttributeNames_nil(), x)); +axiom [AttributeNames_contains_cons_def]: forall x : string, h : string, t : AttributeNames ::{AttributeNames_contains(AttributeNames_cons(h,t),x)} + AttributeNames_contains(AttributeNames_cons(h,t),x) == ((x==h) || AttributeNames_contains(t,x)); +axiom [AttributeNames_len_nonneg]: forall l: AttributeNames :: AttributeNames_len(l) >= 0; +axiom [AttributeNames_index_nil]: forall i : int ::{AttributeNames_index (AttributeNames_nil(), i)} (AttributeNames_index (AttributeNames_nil(), i)) == ""; +axiom [AttributeNames_index_zero]: forall h : string, t : AttributeNames ::{AttributeNames_index (AttributeNames_cons(h,t), 0)} + AttributeNames_index (AttributeNames_cons(h,t), 0) == h; +axiom [AttributeNames_index_ind]: forall h : string, t : AttributeNames, i : int ::{AttributeNames_index (AttributeNames_cons(h,t), i)} + (i > 0) ==> (AttributeNames_index (AttributeNames_cons(h,t), i)) == AttributeNames_index (t, i - 1); +axiom [AttributeNames_index_contains]: forall l: AttributeNames, i: int, x: string :: {} + (AttributeNames_index(l,i) == x) ==> AttributeNames_contains(l,x); +axiom [AttributeNames_index_ok]: forall l: AttributeNames, i: int:: {AttributeNames_index(l,i)} + ((AttributeNames_index(l,i)) != "") == (i < AttributeNames_len(l)); +axiom [AttributeName_to_index_nil_def]: forall f: string :: {AttributeName_to_index(AttributeNames_nil(), f)} + AttributeName_to_index(AttributeNames_nil(), f) == 0; +axiom [AttributeName_to_index_cons_def_1]: forall h: string, t: AttributeNames :: {AttributeName_to_index(AttributeNames_cons(h,t), h)} + AttributeName_to_index(AttributeNames_cons(h,t), h) == 0; +axiom [AttributeName_to_index_cons_def_2]: forall f: string, h: string, t: AttributeNames :: {AttributeName_to_index(AttributeNames_cons(h,t), f)} + !(h == f) ==> AttributeName_to_index(AttributeNames_cons(h,t), f) == AttributeName_to_index(t, f) + 1; + +function Class_mk (name: string, attributes: AttributeNames): Class; +function Class_attributes (c: Class) : AttributeNames; +function Class_name (c: Class): string; +axiom [Class_attributes_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} Class_attributes(Class_mk (name, attributes)) == attributes; +axiom [Class_name_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} Class_name(Class_mk (name, attributes)) == name; +axiom [Class_eq_def]: forall c: Class, c': Class :: {} (c == c') == (Class_name(c) == Class_name(c')); + +function Class_hasAttribute (c: Class, attribute: string): bool; +axiom [Class_hasAttribute_def]: forall c: Class, attribute: string :: {Class_hasAttribute(c, attribute)} + Class_hasAttribute(c, attribute) == AttributeNames_contains(Class_attributes(c), attribute); + +function Class_err() : Class; +axiom [Class_err_attributes_def]: Class_attributes(Class_err()) == AttributeNames_nil(); + +function AttributeValues_empty (c: Class) : AttributeValues; +axiom [AttributeValues_empty_def_valid]: forall c: Class, attribute: string :: {AttributeValues_empty(c)[attribute]} + Class_hasAttribute(c, attribute) ==> AttributeValues_empty(c)[attribute] == Value_none(); +axiom [AttributeValues_empty_def_invalid]: forall c: Class, attribute: string :: {AttributeValues_empty(c)[attribute]} + !Class_hasAttribute(c, attribute) ==> AttributeValues_empty(c)[attribute] == Value_exception(Error_message("Invalid Attribute of Class")); + +function AttributeValues_err () : AttributeValues; +axiom [AttributeValues_err_def]: forall attribute: string :: {AttributeValues_err[attribute]} + AttributeValues_err()[attribute] == Value_exception(Error_message("Error ClassInstance")); + +function ClassInstance_mk (c: Class, av: AttributeValues) : ClassInstance; + +function ClassInstance_getAttributeValues (ci: ClassInstance) : AttributeValues; +axiom [get_fielvalue_def]: forall c: Class, av: AttributeValues :: {ClassInstance_mk (c, av)} ClassInstance_getAttributeValues(ClassInstance_mk (c, av)) == av; +function ClassInstance_getClass (ci: ClassInstance) : Class; +axiom [get_class_def]: forall c: Class, av: AttributeValues :: {ClassInstance_mk (c, av)} ClassInstance_getClass(ClassInstance_mk (c, av)) == c; + +axiom [TypeOf_class]: forall ci: ClassInstance :: {TypeOf(Value_class(ci))} TypeOf(Value_class(ci)) == ValueType_class(ClassInstance_getClass(ci)); + +function ClassInstance_empty (c: Class) : ClassInstance; +axiom [ClassInstance_mk_empty_get_attributevalues]: forall c: Class :: {ClassInstance_empty (c)} ClassInstance_getAttributeValues(ClassInstance_empty (c)) == AttributeValues_empty(c); +axiom [ClassInstance_mk_empty_get_class]: forall c: Class :: {ClassInstance_empty (c)} ClassInstance_getClass(ClassInstance_empty (c)) == c; + +function ClassInstance_err (err: string) : ClassInstance; +function ClassInstance_errortag (ci: ClassInstance): Error_tag; +axiom [ClassInstance_err_tag]: forall err: string :: {ClassInstance_err(err)} ClassInstance_errortag(ClassInstance_err(err)) == ERR; +axiom [ClassInstance_err_get_class_def]: forall err: string :: {ClassInstance_err(err)} ClassInstance_getClass(ClassInstance_err(err)) == Class_err(); +axiom [ClassInstance_err_get_attributevalues_def]: forall err: string :: {ClassInstance_err(err)} ClassInstance_getAttributeValues(ClassInstance_err (err)) == AttributeValues_err(); + +function ClassInstance_get_attribute(ci: ClassInstance, attribute: string) : Value; +axiom [ClassInstance_get_attribute_def]: forall ci: ClassInstance, attribute: string ::{ClassInstance_get_attribute(ci, attribute)} + ClassInstance_get_attribute(ci, attribute) == ClassInstance_getAttributeValues(ci)[attribute]; + +function ClassInstance_set_attribute (ci: ClassInstance, attribute: string, value: Value): ClassInstance; +axiom [ClassInstance_set_attribute_def]: forall ci: ClassInstance, attribute: string, v: Value::{ClassInstance_set_attribute(ci, attribute, v)} + ClassInstance_set_attribute(ci, attribute, v) == if Class_hasAttribute(ClassInstance_getClass(ci), attribute) then ClassInstance_mk(ClassInstance_getClass(ci), ClassInstance_getAttributeValues(ci)[attribute:=v]) + else ClassInstance_err("Set value for invalid"); + +function get_ClassInstance (v: Value) : ClassInstance; +axiom [get_ClassInstance_valid]: forall ci: ClassInstance :: {get_ClassInstance(Value_class(ci))} get_ClassInstance(Value_class(ci)) == ci; +axiom [get_ClassInstance_invalid]: forall v: Value :: {get_ClassInstance(v)} + !isClassInstance(v) ==> get_ClassInstance(v) == ClassInstance_err ("Not of Class type"); + +function get_attribute(v: Value, attribute: string) : Value; +axiom [get_attribute_def]: forall v: Value, attribute: string ::{get_attribute(v, attribute)} + get_attribute(v, attribute) == if isClassInstance(v) then + ClassInstance_get_attribute(get_ClassInstance(v), attribute) + else Value_exception(Error_message("Not of Class type")); + +function set_attribute(v: Value, attribute: string, v': Value) : Value; +axiom [set_attribute_def]: forall v: Value, attribute: string, v': Value ::{set_attribute(v, attribute, v')} + set_attribute(v, attribute, v') == if isClassInstance(v) then + Value_class(ClassInstance_set_attribute(get_ClassInstance(v), attribute, v')) + else Value_exception(Error_message("Not of Class type")); + +function get_Class (v: Value) : Class { + ClassInstance_getClass(get_ClassInstance (v)) +} + +function hasAttribute(v: Value, attribute: string): bool { + Class_hasAttribute (get_Class(v), attribute) +} //Binary op function function int_to_real (i: int) : real; @@ -219,40 +398,69 @@ function Py_mul (v1: Value, v2: Value) : (Value); inline function bool_to_int (b: bool) : (int) {if b then 1 else 0} inline function bool_to_real (b: bool) : (real) {if b then 1.0 else 0.0} - -axiom [Py_add_ints]: (forall i1: int, i2: int :: {Value_int(i1), Value_int(i2)} ((Py_add(Value_int(i1), Value_int(i2)) == Value_int(i1 + i2)))); -axiom [Py_add_floats]: (forall f1: real, f2: real :: {Value_float(f1), Value_float(f2)} ((Py_add(Value_float(f1), Value_float(f2)) == Value_float(f1 + f2)))); -axiom [Py_add_bools]: (forall b1: bool, b2: bool :: {Value_bool(b1), Value_bool(b2)} ((Py_add(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) + bool_to_int(b2))))); -axiom [Py_add_int_bool]: (forall i: int, b: bool :: {Value_int(i), Value_bool(b)} ((Py_add(Value_int(i), Value_bool(b)) == Value_int(i + bool_to_int(b))))); -axiom [Py_add_bool_int]: (forall b: bool, i: int :: {Value_bool(b), Value_int(i)} ((Py_add(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) + i)))); -axiom [Py_add_int_float]: (forall i: int, r: real :: {Value_int(i), Value_float(r)} ((Py_add(Value_int(i), Value_float(r)) == Value_float(r + int_to_real(i))))); -axiom [Py_add_float_int]: (forall r: real, i: int :: {Value_float(r), Value_int(i)} ((Py_add(Value_float(r), Value_int(i)) == Value_float(int_to_real(i) + r)))); -axiom [Py_add_float_bool]: (forall r: real, b: bool :: {Value_float(r), Value_bool(b)} ((Py_add(Value_float(r), Value_bool(b)) == Value_float(r + bool_to_real(b))))); -axiom [Py_add_bool_float]: (forall b: bool, r: real :: {Value_bool(b), Value_float(r)} ((Py_add(Value_bool(b), Value_float(r)) == Value_float(bool_to_real(b) + r)))); -axiom [Py_add_none]: (forall v: Value :: {} ((Py_add(v, Value_none()) == Value_Exception(Error_message("Operand is None"))))); -axiom [Py_none_add]: (forall v: Value :: {} ((Py_add(Value_none(), v) == Value_Exception(Error_message("Operand is None"))))); -axiom [Py_add_exception]: (forall v: Value, e: Error :: {Value_Exception(e)} ((Py_add(v, Value_Exception(e)) == Value_Exception(Error_message("Operand is Exception"))))); -axiom [Py_exception_add]: (forall v: Value, e: Error :: {Value_Exception(e)} ((Py_add(Value_Exception(e), v) == Value_Exception(Error_message("Operand is Exception"))))); -axiom [Py_add_strs]: (forall s1: string, s2: string :: {Value_str(s1), Value_str(s2)} ((Py_add(Value_str(s1), Value_str(s2)) == Value_str(str.concat(s1, s2))))); -axiom [Py_add_str_int]: (forall s: string, i: int :: {Value_str(s), Value_int(i)} ((Py_add(Value_str(s), Value_int(i)) == Value_Exception(Error_message("Cannot add string to int"))))); -axiom [Py_add_int_str]: (forall s: string, i: int :: {Value_str(s), Value_int(i)} ((Py_add(Value_int(i), Value_str(s)) == Value_Exception(Error_message("Cannot add string to int"))))); -axiom [Py_add_str_bool]: (forall s: string, b: bool :: {Value_str(s), Value_bool(b)} ((Py_add(Value_str(s), Value_bool(b)) == Value_Exception(Error_message("Cannot add string to bool"))))); -axiom [Py_add_bool_str]: (forall s: string, b: bool :: {Value_str(s), Value_bool(b)} ((Py_add(Value_bool(b), Value_str(s)) == Value_Exception(Error_message("Cannot add bool to string"))))); - -axiom [Py_mul_ints]: (forall i1: int, i2: int :: {Value_int(i1), Value_int(i2)} ((Py_mul(Value_int(i1), Value_int(i2)) == Value_int(i1 * i2)))); -axiom [Py_mul_bools]: (forall b1: bool, b2: bool :: {Value_bool(b1), Value_bool(b2)} ((Py_mul(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) * bool_to_int(b2))))); -axiom [Py_mul_int_bool]: (forall i: int, b: bool :: {Value_int(i), Value_bool(b)} ((Py_mul(Value_int(i), Value_bool(b)) == Value_int(i * bool_to_int(b))))); -axiom [Py_mul_bool_int]: (forall b: bool, i: int :: {Value_bool(b), Value_int(i)} ((Py_mul(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) * i)))); -axiom [Py_mul_none]: (forall v: Value :: {} ((Py_mul(v, Value_none()) == Value_Exception(Error_message("Operand is None"))))); -axiom [Py_mul_add]: (forall v: Value :: {} ((Py_mul(Value_none(), v) == Value_Exception(Error_message("Operand is None"))))); -axiom [Py_mul_exception]: (forall v: Value, e: Error :: {Value_Exception(e)} ((Py_mul(v, Value_Exception(e)) == Value_Exception(Error_message("Operand is Exception"))))); -axiom [Py_exception_mul]: (forall v: Value, e: Error :: {Value_Exception(e)} ((Py_mul(Value_Exception(e), v) == Value_Exception(Error_message("Operand is Exception"))))); -axiom [Py_mul_strs]: (forall s1: string, s2: string :: {Value_str(s1), Value_str(s2)} ((Py_mul(Value_str(s1), Value_str(s2)) == Value_Exception(Error_message("Cannot multiply two strings"))))); -axiom [Py_mul_str_int]: (forall s: string, i: int :: {Value_str(s), Value_int(i)} ((Py_add(Value_str(s), Value_int(i)) == Value_str(str_repeat(s, i))))); -axiom [Py_mul_int_str]: (forall s: string, i: int :: {Value_str(s), Value_int(i)} ((Py_add(Value_int(i), Value_str(s)) == Value_str(str_repeat(s, i))))); -axiom [Py_mul_str_bool]: (forall s: string, b: bool :: {Value_str(s), Value_bool(b)} ((Py_add(Value_str(s), Value_bool(b)) == Value_str(if b then s else "")))); -axiom [Py_mul_bool_str]: (forall s: string, b: bool :: {Value_str(s), Value_bool(b)} ((Py_add(Value_bool(b), Value_str(s)) == Value_str(if b then s else "")))); - +axiom [Py_add_ints]: forall i1: int, i2: int :: {Py_add(Value_int(i1), Value_int(i2))} + Py_add(Value_int(i1), Value_int(i2)) == Value_int(i1 + i2); +axiom [Py_add_floats]: forall f1: real, f2: real :: {Py_add(Value_float(f1), Value_float(f2))} + Py_add(Value_float(f1), Value_float(f2)) == Value_float(f1 + f2); +axiom [Py_add_bools]: forall b1: bool, b2: bool :: {Py_add(Value_bool(b1), Value_bool(b2))} + Py_add(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) + bool_to_int(b2)); +axiom [Py_add_int_bool]: forall i: int, b: bool :: {Py_add(Value_int(i), Value_bool(b))} + Py_add(Value_int(i), Value_bool(b)) == Value_int(i + bool_to_int(b)); +axiom [Py_add_bool_int]: forall b: bool, i: int :: {Py_add(Value_bool(b), Value_int(i))} + Py_add(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) + i); +axiom [Py_add_int_float]: forall i: int, r: real :: {Py_add(Value_int(i), Value_float(r))} + Py_add(Value_int(i), Value_float(r)) == Value_float(r + int_to_real(i)); +axiom [Py_add_float_int]: forall r: real, i: int :: {Py_add(Value_float(r), Value_int(i))} + Py_add(Value_float(r), Value_int(i)) == Value_float(int_to_real(i) + r); +axiom [Py_add_float_bool]: forall r: real, b: bool :: {Py_add(Value_float(r), Value_bool(b))} + Py_add(Value_float(r), Value_bool(b)) == Value_float(r + bool_to_real(b)); +axiom [Py_add_bool_float]: forall b: bool, r: real :: {Py_add(Value_bool(b), Value_float(r))} + Py_add(Value_bool(b), Value_float(r)) == Value_float(bool_to_real(b) + r); +axiom [Py_add_none]: forall v: Value :: {Py_add(v, Value_none())} + Py_add(v, Value_none()) == Value_exception(Error_message("Operand is None")); +axiom [Py_none_add]: forall v: Value :: {Py_add(Value_none(), v)} + Py_add(Value_none(), v) == Value_exception(Error_message("Operand is None")); +axiom [Py_add_exception]: forall v: Value, e: Error :: {Py_add(v, Value_exception(e))} + Py_add(v, Value_exception(e)) == Value_exception(Error_message("Operand is Exception")); +axiom [Py_exception_add]: forall v: Value, e: Error :: {Py_add(Value_exception(e), v)} + Py_add(Value_exception(e), v) == Value_exception(Error_message("Operand is Exception")); +axiom [Py_add_strs]:forall s1: string, s2: string :: {Py_add(Value_str(s1), Value_str(s2))} + Py_add(Value_str(s1), Value_str(s2)) == Value_str(str.concat(s1, s2)); +axiom [Py_add_str_int]: forall s: string, i: int :: {Py_add(Value_str(s), Value_int(i))} + Py_add(Value_str(s), Value_int(i)) == Value_exception(Error_message("Cannot add string to int")); +axiom [Py_add_int_str]: forall s: string, i: int :: {Py_add(Value_int(i), Value_str(s)) } + Py_add(Value_int(i), Value_str(s)) == Value_exception(Error_message("Cannot add string to int")); +axiom [Py_add_str_bool]: forall s: string, b: bool :: {Py_add(Value_str(s), Value_bool(b))} + Py_add(Value_str(s), Value_bool(b)) == Value_exception(Error_message("Cannot add string to bool")); +axiom [Py_add_bool_str]: forall s: string, b: bool :: {Py_add(Value_bool(b), Value_str(s))} + Py_add(Value_bool(b), Value_str(s)) == Value_exception(Error_message("Cannot add bool to string")); + +axiom [Py_mul_ints]: forall i1: int, i2: int :: {Py_mul(Value_int(i1), Value_int(i2))} + Py_mul(Value_int(i1), Value_int(i2)) == Value_int(i1 * i2); +axiom [Py_mul_bools]: forall b1: bool, b2: bool :: {Py_mul(Value_bool(b1), Value_bool(b2))} + Py_mul(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) * bool_to_int(b2)); +axiom [Py_mul_int_bool]: forall i: int, b: bool :: {Py_mul(Value_int(i), Value_bool(b))} + Py_mul(Value_int(i), Value_bool(b)) == Value_int(i * bool_to_int(b)); +axiom [Py_mul_bool_int]: forall b: bool, i: int :: {Py_mul(Value_bool(b), Value_int(i))} + Py_mul(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) * i); +axiom [Py_mul_none]: forall v: Value :: {Py_mul(v, Value_none())} + Py_mul(v, Value_none()) == Value_exception(Error_message("Operand is None")); +axiom [Py_mul_add]: forall v: Value :: {Py_mul(Value_none(), v)} + Py_mul(Value_none(), v) == Value_exception(Error_message("Operand is None")); +axiom [Py_mul_exception]: forall v: Value, e: Error :: {Py_mul(v, Value_exception(e))} + Py_mul(v, Value_exception(e)) == Value_exception(Error_message("Operand is Exception")); +axiom [Py_exception_mul]: forall v: Value, e: Error :: {Py_mul(Value_exception(e), v)} + Py_mul(Value_exception(e), v) == Value_exception(Error_message("Operand is Exception")); +axiom [Py_mul_str]: forall s1: string, s2: string :: {Py_mul(Value_str(s1), Value_str(s2))} + Py_mul(Value_str(s1), Value_str(s2)) == Value_exception(Error_message("Cannot multiply two strings")); +axiom [Py_mul_str_int]: forall s: string, i: int :: {Py_mul(Value_str(s), Value_int(i))} + Py_mul(Value_str(s), Value_int(i)) == Value_str(str_repeat(s, i)); +axiom [Py_mul_int_str]: forall s: string, i: int :: {Py_mul(Value_int(i), Value_str(s))} + Py_mul(Value_int(i), Value_str(s)) == Value_str(str_repeat(s, i)); +axiom [Py_mul_str_bool]: forall s: string, b: bool :: {Py_mul(Value_str(s), Value_bool(b))} + Py_mul(Value_str(s), Value_bool(b)) == Value_str(if b then s else ""); +axiom [Py_mul_bool_str]: forall s: string, b: bool :: {Py_mul(Value_bool(b), Value_str(s)) } + Py_mul(Value_bool(b), Value_str(s)) == Value_str(if b then s else ""); //Testing procedure list_functions_test() returns () @@ -299,14 +507,14 @@ procedure test() returns () { procedure test_simple_call_argument_typecheck() returns () { var arg1: Value, arg2: Value; arg1 := Value_bool(true); - arg2 := Value_List(ListValue_cons(Value_int(3), ListValue_cons (Value_bool(true), ListValue_nil()))); + arg2 := Value_list(ListValue_cons(Value_int(3), ListValue_cons (Value_bool(true), ListValue_nil()))); assert [subtype_bool]: isInstance(arg1,BOOL); call simple_call(arg1, arg2); }; procedure dict_functions_test () returns () { var d1: Dict, d2: Dict, d3: Dict; - d1:= Dict_insert(EMPTYDICT, Value_int(1), Value_int(1)); + d1:= Dict_insert(Dict_empty(), Value_int(1), Value_int(1)); d2:= Dict_insert(d1, Value_bool(true), Value_int(2)); assert [uptype]: normalize_value(Value_bool(true)) == Value_int(1); assert [uptype2]: normalize_value(Value_int(1)) == Value_int(1); @@ -314,7 +522,6 @@ procedure dict_functions_test () returns () { assert [get_1]: Dict_get(d2, Value_int(1)) == Value_int(2); }; - procedure test_dict_listconstructor () returns () { var d: Dict, dl: DictList, d2: Dict, d3: Dict; dl := DictList_cons(Value_bool(true), Value_int(10), DictList_cons(Value_int(1), Value_int(11), DictList_nil())); @@ -335,11 +542,25 @@ procedure forall_dict_test () returns () { assert [remove_insert]: forall d: Dict, k: Value, v: Value, k': Value :: !(Dict_get(d,k) == v) || Dict_get((Dict_insert(Dict_remove(d,k), k, v)), k') == Dict_get(d, k'); }; +procedure ValueClass_test() returns () { + var c: Class, ci: Value, ci': Value, v: Value; + c := Class_mk ("point", AttributeNames_cons("x", AttributeNames_cons("y", AttributeNames_nil()))); + ci := Value_class(ClassInstance_empty (c)); + assert [has_x]: hasAttribute(ci,"x"); + assert [nhas_z]: !hasAttribute(ci,"z"); + assert [isInstance_class]: isInstance(ci, ValueType_class(c)); + assert [get_x_empty]: get_attribute(ci, "x") == Value_none(); + assert [get_y_empty]: get_attribute(ci, "y") == Value_none(); + assert [get_x']: get_attribute(set_attribute(ci, "x", Value_int(1)), "x") == Value_int(1); + ci := set_attribute(ci, "x", Value_int(1)); + assert [get_x]: get_attribute(ci, "x") == Value_int(1); + assert [get_y]: get_attribute(ci, "y") == Value_none(); +}; + #end #eval verify "cvc5" boogieTypePrelude - def Boogie.prelude : Boogie.Program := Boogie.getProgram Strata.boogieTypePrelude |>.fst From 004728ca05d0905605a4a001129bbe2c00715ad7 Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Fri, 12 Dec 2025 14:10:07 -0800 Subject: [PATCH 05/13] add + edit triggers --- .../Languages/Python/BoogieTypePrelude.lean | 112 ++++++++++-------- 1 file changed, 65 insertions(+), 47 deletions(-) diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean index a379c0f4c..f98d613fc 100644 --- a/Strata/Languages/Python/BoogieTypePrelude.lean +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -39,21 +39,21 @@ type AttributeValues := Map string Value; type ClassInstance; // Constructors -function Value_bool (b : bool) : (Value); -function Value_int (i : int) : (Value); -function Value_float (f : real) : (Value); -function Value_str (s : string) : (Value); -function Value_none() : (Value); -function Value_exception (e : Error): (Value); -function Value_list (lv : ListValue) : (Value); +function Value_bool (b : bool) : Value; +function Value_int (i : int) : Value; +function Value_float (f : real) : Value; +function Value_str (s : string) : Value; +function Value_none() : Value; +function Value_exception (e : Error): Value; +function Value_list (lv : ListValue) : Value; function Value_class (ci: ClassInstance) : Value; -function ListValue_nil() : (ListValue); -function ListValue_cons(x0 : Value, x1 : ListValue) : (ListValue); +function ListValue_nil() : ListValue; +function ListValue_cons(x0 : Value, x1 : ListValue) : ListValue; //Tags function ListValue_tag (l: ListValue) : List_tag; -axiom [ListValue_tag_nil_def]: (ListValue_tag (ListValue_nil()) == NIL); -axiom [ListValue_tag_cons_def]: (forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} (ListValue_tag (ListValue_cons(v, vs)) == CONS)); +axiom [ListValue_tag_nil_def]: ListValue_tag (ListValue_nil()) == NIL; +axiom [ListValue_tag_cons_def]: forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} ListValue_tag (ListValue_cons(v, vs)) == CONS; // Types of Value type ValueType; @@ -87,8 +87,8 @@ function ListType_nil() : (ListValueType); function ListType_cons(x0 : ValueType, x1 : ListValueType) : ListValueType; function ValueType_List (l: ListValueType) : ValueType; function ListValueType_tag (l: ListValueType) : List_tag; -axiom [ListValueType_tag_nil_def]: (ListValueType_tag (ListType_nil()) == NIL); -axiom [ListValueType_tag_cons_def]: (forall t: ValueType, ts: ListValueType ::{ListType_cons(t, ts)} (ListValueType_tag (ListType_cons(t, ts)) == CONS)); +axiom [ListValueType_tag_nil_def]: ListValueType_tag (ListType_nil()) == NIL; +axiom [ListValueType_tag_cons_def]: forall t: ValueType, ts: ListValueType ::{ListType_cons(t, ts)} (ListValueType_tag (ListType_cons(t, ts)) == CONS); // TypeOf and TypesOf functions function TypeOf (v : Value) : ValueType; @@ -163,14 +163,18 @@ axiom [isSubType_list_def]: forall l: ListValueType, l': ListValueType :: {Value isSubType(ValueType_List(l), ValueType_List(l')) == isSubTypes(l, l'); axiom [bool_substype_int]: isSubType(BOOL, INT); axiom [int_substype_float]: isSubType(INT, FLOAT); -axiom [not_isSubstype_string]: forall t: ValueType ::{} t == STR || (!isSubType(STR, t) && !isSubType(t,STR)); -axiom [not_isSubstype_none]: forall t: ValueType ::{} (t == NONE || (!isSubType(NONE, t) && !isSubType(t,NONE))); -axiom [not_isSubstype_exception]: forall t: ValueType ::{} t == EXCEPTION || (!isSubType(EXCEPTION, t) && !isSubType(t, EXCEPTION)); -axiom [not_isSubstype_class]: forall t: ValueType, c: Class ::{} t != ValueType_class(c) ==> (!isSubType(ValueType_class(c), t) && !isSubType(t,ValueType_class(c))); +axiom [not_isSubstype_string]: forall t: ValueType ::{isSubType(STR, t), isSubType(t,STR)} + t == STR || (!isSubType(STR, t) && !isSubType(t,STR)); +axiom [not_isSubstype_none]: forall t: ValueType ::{isSubType(NONE, t), isSubType(NONE, t)} + t == NONE || (!isSubType(NONE, t) && !isSubType(t,NONE)); +axiom [not_isSubstype_exception]: forall t: ValueType ::{isSubType(EXCEPTION, t), isSubType(t, EXCEPTION)} + t == EXCEPTION || (!isSubType(EXCEPTION, t) && !isSubType(t, EXCEPTION)); +axiom [not_isSubstype_class]: forall t: ValueType, c: Class ::{isSubType(ValueType_class(c), t), isSubType(t,ValueType_class(c))} + t != ValueType_class(c) ==> (!isSubType(ValueType_class(c), t) && !isSubType(t,ValueType_class(c))); // Supporting lemmas axiom [isSubtype_rfl]: forall t: ValueType::{isSubType (t,t)} isSubType (t,t); -axiom [isSubtype_mono]: forall t1: ValueType, t2: ValueType ::{} !isSubType (t1,t2) || (t1 == t2 || !isSubType(t2,t1)); -axiom [isSubtype_trans]: forall t1: ValueType, t2: ValueType, t3: ValueType::{} !(isSubType(t1, t2) && isSubType(t2, t3)) || isSubType(t1, t3); +axiom [isSubtype_mono]: forall t1: ValueType, t2: ValueType ::{isSubType (t1,t2)} !isSubType (t1,t2) || (t1 == t2 || !isSubType(t2,t1)); +axiom [isSubtype_trans]: forall t1: ValueType, t2: ValueType, t3: ValueType::{isSubType(t1, t2)} !(isSubType(t1, t2) && isSubType(t2, t3)) || isSubType(t1, t3); // isInstance function: function isInstance (v: Value, vt: ValueType) : bool; @@ -197,16 +201,17 @@ function List_reverse (l: ListValue) : ListValue; //List function axioms axiom [List_contains_nil_def]: forall x : Value ::{List_contains(ListValue_nil(), x)} !List_contains(ListValue_nil(), x); -axiom [List_contains_cons_def]: forall x : Value, h : Value, t : ListValue ::{} +axiom [List_contains_cons_def]: forall x : Value, h : Value, t : ListValue ::{List_contains(ListValue_cons(h,t),x)} List_contains(ListValue_cons(h,t),x) == ((normalize_value(x)==normalize_value(h)) || List_contains(t, x)); axiom [List_len_nil_def]: List_len (ListValue_nil()) == 0; -axiom [List_len_cons_def]: forall h : Value, t : ListValue ::{} List_len (ListValue_cons(h,t)) == 1 + List_len(t); -axiom [List_len_nonneg]: forall l: ListValue :: List_len(l) >= 0 ; +axiom [List_len_cons_def]: forall h : Value, t : ListValue ::{List_len (ListValue_cons(h,t))} + List_len (ListValue_cons(h,t)) == 1 + List_len(t); +axiom [List_len_nonneg]: forall l: ListValue :: {List_len(l)} List_len(l) >= 0 ; axiom [List_extend_nil_def]: forall l1: ListValue ::{List_extend (l1, ListValue_nil())} List_extend (l1, ListValue_nil()) == l1; axiom [List_nil_extend_def]: forall l1: ListValue ::{List_extend (ListValue_nil(), l1)} List_extend (ListValue_nil(), l1) == l1; -axiom [List_cons_extend_def]: forall h: Value, t: ListValue, l2: ListValue ::{} +axiom [List_cons_extend_def]: forall h: Value, t: ListValue, l2: ListValue ::{List_extend (ListValue_cons(h,t), l2)} List_extend (ListValue_cons(h,t), l2) == ListValue_cons(h, List_extend(t,l2)); axiom [List_cons_extend_contains]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} List_contains (List_extend(l1,l2), x) == List_contains (l1,x) || List_contains(l2,x); @@ -220,13 +225,13 @@ axiom [List_index_zero]: forall h : Value, t : ListValue ::{List_index (ListValu List_index (ListValue_cons(h,t), 0) == h; axiom [List_index_ind]: forall h : Value, t : ListValue, i : int ::{List_index (ListValue_cons(h,t), i)} (i > 0) ==> (List_index (ListValue_cons(h,t), i)) == List_index (t, i - 1); -axiom [List_index_contains]: forall l: ListValue, i: int, x: Value :: {} +axiom [List_index_contains]: forall l: ListValue, i: int, x: Value :: {List_contains(l,x), List_index(l,i)} (List_index(l,i) == x) ==> List_contains(l,x); axiom [List_index_ok]: forall l: ListValue, i: int:: {List_index(l,i)} ((List_index(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l)); axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: {List_extend(l2,l1)} List_index(l1, i) == List_index(List_extend(l2,l1), i + List_len(l2)); -axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: {} +axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: {List_extend(List_extend(l1,l2), l3)} List_extend(List_extend(l1,l2), l3) == List_extend(l1,List_extend(l2,l3)); axiom [List_append_def]: forall l: ListValue, x: Value :: {List_append(l,x)} List_append(l,x) == List_extend(l, ListValue_cons(x, ListValue_nil())); @@ -287,7 +292,7 @@ function AttributeNames_index (l : AttributeNames, i : int) : string; function AttributeName_to_index (l : AttributeNames, f: string) : int; axiom [AttributeNames_len_nil_def]: AttributeNames_len (AttributeNames_nil()) == 0; -axiom [AttributeNames_len_cons_def]: forall h : string, t : AttributeNames ::{} +axiom [AttributeNames_len_cons_def]: forall h : string, t : AttributeNames ::{AttributeNames_len (AttributeNames_cons(h,t))} AttributeNames_len (AttributeNames_cons(h,t)) == 1 + AttributeNames_len(t); axiom [AttributeNames_tag_nil_def]: AttributeNames_tag(AttributeNames_nil()) == NIL; axiom [AttributeNames_tag_cons_def]: forall h : string, t : AttributeNames ::{} AttributeNames_tag (AttributeNames_cons(h,t)) == CONS; @@ -295,13 +300,13 @@ axiom [AttributeNames_contains_nil_def]: (forall x : string ::{AttributeNames_co !AttributeNames_contains(AttributeNames_nil(), x)); axiom [AttributeNames_contains_cons_def]: forall x : string, h : string, t : AttributeNames ::{AttributeNames_contains(AttributeNames_cons(h,t),x)} AttributeNames_contains(AttributeNames_cons(h,t),x) == ((x==h) || AttributeNames_contains(t,x)); -axiom [AttributeNames_len_nonneg]: forall l: AttributeNames :: AttributeNames_len(l) >= 0; +axiom [AttributeNames_len_nonneg]: forall l: AttributeNames :: {AttributeNames_len(l)} AttributeNames_len(l) >= 0; axiom [AttributeNames_index_nil]: forall i : int ::{AttributeNames_index (AttributeNames_nil(), i)} (AttributeNames_index (AttributeNames_nil(), i)) == ""; axiom [AttributeNames_index_zero]: forall h : string, t : AttributeNames ::{AttributeNames_index (AttributeNames_cons(h,t), 0)} AttributeNames_index (AttributeNames_cons(h,t), 0) == h; axiom [AttributeNames_index_ind]: forall h : string, t : AttributeNames, i : int ::{AttributeNames_index (AttributeNames_cons(h,t), i)} (i > 0) ==> (AttributeNames_index (AttributeNames_cons(h,t), i)) == AttributeNames_index (t, i - 1); -axiom [AttributeNames_index_contains]: forall l: AttributeNames, i: int, x: string :: {} +axiom [AttributeNames_index_contains]: forall l: AttributeNames, i: int, x: string :: {AttributeNames_index(l,i), AttributeNames_contains(l,x)} (AttributeNames_index(l,i) == x) ==> AttributeNames_contains(l,x); axiom [AttributeNames_index_ok]: forall l: AttributeNames, i: int:: {AttributeNames_index(l,i)} ((AttributeNames_index(l,i)) != "") == (i < AttributeNames_len(l)); @@ -315,9 +320,12 @@ axiom [AttributeName_to_index_cons_def_2]: forall f: string, h: string, t: Attri function Class_mk (name: string, attributes: AttributeNames): Class; function Class_attributes (c: Class) : AttributeNames; function Class_name (c: Class): string; -axiom [Class_attributes_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} Class_attributes(Class_mk (name, attributes)) == attributes; -axiom [Class_name_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} Class_name(Class_mk (name, attributes)) == name; -axiom [Class_eq_def]: forall c: Class, c': Class :: {} (c == c') == (Class_name(c) == Class_name(c')); +axiom [Class_attributes_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} + Class_attributes(Class_mk (name, attributes)) == attributes; +axiom [Class_name_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} + Class_name(Class_mk (name, attributes)) == name; +axiom [Class_eq_def]: forall c: Class, c': Class :: {c == c'} + (c == c') == (Class_name(c) == Class_name(c')); function Class_hasAttribute (c: Class, attribute: string): bool; axiom [Class_hasAttribute_def]: forall c: Class, attribute: string :: {Class_hasAttribute(c, attribute)} @@ -339,33 +347,43 @@ axiom [AttributeValues_err_def]: forall attribute: string :: {AttributeValues_er function ClassInstance_mk (c: Class, av: AttributeValues) : ClassInstance; function ClassInstance_getAttributeValues (ci: ClassInstance) : AttributeValues; -axiom [get_fielvalue_def]: forall c: Class, av: AttributeValues :: {ClassInstance_mk (c, av)} ClassInstance_getAttributeValues(ClassInstance_mk (c, av)) == av; +axiom [getAttributeValues_def]: forall c: Class, av: AttributeValues :: { ClassInstance_getAttributeValues(ClassInstance_mk (c, av))} + ClassInstance_getAttributeValues(ClassInstance_mk (c, av)) == av; + function ClassInstance_getClass (ci: ClassInstance) : Class; -axiom [get_class_def]: forall c: Class, av: AttributeValues :: {ClassInstance_mk (c, av)} ClassInstance_getClass(ClassInstance_mk (c, av)) == c; +axiom [get_Class_def]: forall c: Class, av: AttributeValues :: {ClassInstance_getClass(ClassInstance_mk (c, av))} + ClassInstance_getClass(ClassInstance_mk (c, av)) == c; axiom [TypeOf_class]: forall ci: ClassInstance :: {TypeOf(Value_class(ci))} TypeOf(Value_class(ci)) == ValueType_class(ClassInstance_getClass(ci)); function ClassInstance_empty (c: Class) : ClassInstance; -axiom [ClassInstance_mk_empty_get_attributevalues]: forall c: Class :: {ClassInstance_empty (c)} ClassInstance_getAttributeValues(ClassInstance_empty (c)) == AttributeValues_empty(c); -axiom [ClassInstance_mk_empty_get_class]: forall c: Class :: {ClassInstance_empty (c)} ClassInstance_getClass(ClassInstance_empty (c)) == c; +axiom [ClassInstance_mk_empty_get_attributevalues]: forall c: Class :: {ClassInstance_getAttributeValues(ClassInstance_empty (c))} + ClassInstance_getAttributeValues(ClassInstance_empty (c)) == AttributeValues_empty(c); +axiom [ClassInstance_mk_empty_get_class]: forall c: Class :: {ClassInstance_getClass(ClassInstance_empty (c))} + ClassInstance_getClass(ClassInstance_empty (c)) == c; function ClassInstance_err (err: string) : ClassInstance; function ClassInstance_errortag (ci: ClassInstance): Error_tag; -axiom [ClassInstance_err_tag]: forall err: string :: {ClassInstance_err(err)} ClassInstance_errortag(ClassInstance_err(err)) == ERR; -axiom [ClassInstance_err_get_class_def]: forall err: string :: {ClassInstance_err(err)} ClassInstance_getClass(ClassInstance_err(err)) == Class_err(); -axiom [ClassInstance_err_get_attributevalues_def]: forall err: string :: {ClassInstance_err(err)} ClassInstance_getAttributeValues(ClassInstance_err (err)) == AttributeValues_err(); +axiom [ClassInstance_err_tag]: forall err: string :: {ClassInstance_errortag(ClassInstance_err(err))} + ClassInstance_errortag(ClassInstance_err(err)) == ERR; +axiom [ClassInstance_err_get_class_def]: forall err: string :: {ClassInstance_getClass(ClassInstance_err(err)) } + ClassInstance_getClass(ClassInstance_err(err)) == Class_err(); +axiom [ClassInstance_err_get_attributevalues_def]: forall err: string :: {ClassInstance_getAttributeValues(ClassInstance_err (err))} + ClassInstance_getAttributeValues(ClassInstance_err (err)) == AttributeValues_err(); function ClassInstance_get_attribute(ci: ClassInstance, attribute: string) : Value; axiom [ClassInstance_get_attribute_def]: forall ci: ClassInstance, attribute: string ::{ClassInstance_get_attribute(ci, attribute)} ClassInstance_get_attribute(ci, attribute) == ClassInstance_getAttributeValues(ci)[attribute]; function ClassInstance_set_attribute (ci: ClassInstance, attribute: string, value: Value): ClassInstance; -axiom [ClassInstance_set_attribute_def]: forall ci: ClassInstance, attribute: string, v: Value::{ClassInstance_set_attribute(ci, attribute, v)} - ClassInstance_set_attribute(ci, attribute, v) == if Class_hasAttribute(ClassInstance_getClass(ci), attribute) then ClassInstance_mk(ClassInstance_getClass(ci), ClassInstance_getAttributeValues(ci)[attribute:=v]) - else ClassInstance_err("Set value for invalid"); +axiom [ClassInstance_set_attribute_def]: forall ci: ClassInstance, attribute: string, v: Value:: {ClassInstance_set_attribute(ci, attribute, v)} + ClassInstance_set_attribute(ci, attribute, v) == if Class_hasAttribute(ClassInstance_getClass(ci), attribute) then + ClassInstance_mk(ClassInstance_getClass(ci), ClassInstance_getAttributeValues(ci)[attribute:=v]) + else ClassInstance_err("Set value for invalid"); function get_ClassInstance (v: Value) : ClassInstance; -axiom [get_ClassInstance_valid]: forall ci: ClassInstance :: {get_ClassInstance(Value_class(ci))} get_ClassInstance(Value_class(ci)) == ci; +axiom [get_ClassInstance_valid]: forall ci: ClassInstance :: {get_ClassInstance(Value_class(ci))} + get_ClassInstance(Value_class(ci)) == ci; axiom [get_ClassInstance_invalid]: forall v: Value :: {get_ClassInstance(v)} !isClassInstance(v) ==> get_ClassInstance(v) == ClassInstance_err ("Not of Class type"); @@ -392,11 +410,11 @@ function hasAttribute(v: Value, attribute: string): bool { //Binary op function function int_to_real (i: int) : real; function str_repeat (s: string, i: int) : string; -function Py_add (v1: Value, v2: Value) : (Value); -function Py_sub (v1: Value, v2: Value) : (Value); -function Py_mul (v1: Value, v2: Value) : (Value); -inline function bool_to_int (b: bool) : (int) {if b then 1 else 0} -inline function bool_to_real (b: bool) : (real) {if b then 1.0 else 0.0} +function Py_add (v1: Value, v2: Value) : Value; +function Py_sub (v1: Value, v2: Value) : Value; +function Py_mul (v1: Value, v2: Value) : Value; +inline function bool_to_int (b: bool) : int {if b then 1 else 0} +inline function bool_to_real (b: bool) : real {if b then 1.0 else 0.0} axiom [Py_add_ints]: forall i1: int, i2: int :: {Py_add(Value_int(i1), Value_int(i2))} Py_add(Value_int(i1), Value_int(i2)) == Value_int(i1 + i2); From ac7c5ab82985358132e6123bebae46e69606adee Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Wed, 17 Dec 2025 10:55:48 -0800 Subject: [PATCH 06/13] fix type error --- .../Languages/Python/BoogieTypePrelude.lean | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean index f98d613fc..7fc18a99d 100644 --- a/Strata/Languages/Python/BoogieTypePrelude.lean +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -117,12 +117,12 @@ axiom [TypeOf_list]: forall l: ListValue :: {Value_list(l)} TypeOf(Value_list(l) axiom [isList_def]: forall l: ListValue :: {Value_list(l)} isList(Value_list(l)); axiom [list_neq_other_types]: forall v: Value :: {isList(v)} isList(v) == ( TypeOf(v) != BOOL && - TypeOf(v) != INT) && + TypeOf(v) != INT && TypeOf(v) != FLOAT && TypeOf(v) != STR && TypeOf(v) != NONE && TypeOf(v) != EXCEPTION && - !isClassInstance(v); + !isClassInstance(v)); axiom [list_neq_other_types']: forall l: ListValue, ci: ClassInstance :: {TypeOf(Value_list(l))} TypeOf(Value_list(l))!=BOOL && TypeOf(Value_list(l))!=INT && @@ -135,12 +135,12 @@ axiom [list_neq_other_types']: forall l: ListValue, ci: ClassInstance :: {TypeOf axiom [isClassInstance_def]: forall ci: ClassInstance :: {Value_class(ci)} isClassInstance(Value_class(ci)); axiom [ClassInstantType_neq_other_types]: forall v: Value :: {isClassInstance(v)} isClassInstance(v) == ( TypeOf(v) != BOOL && - TypeOf(v) != INT) && + TypeOf(v) != INT && TypeOf(v) != FLOAT && TypeOf(v) != STR && TypeOf(v) != NONE && TypeOf(v) != EXCEPTION && - !isList(v); + !isList(v)); axiom [list_neq_single_type']: forall ci: ClassInstance, l: ListValue :: {TypeOf(Value_list(l))} TypeOf(Value_class(ci))!=BOOL && TypeOf(Value_class(ci))!=INT && @@ -228,7 +228,7 @@ axiom [List_index_ind]: forall h : Value, t : ListValue, i : int ::{List_index ( axiom [List_index_contains]: forall l: ListValue, i: int, x: Value :: {List_contains(l,x), List_index(l,i)} (List_index(l,i) == x) ==> List_contains(l,x); axiom [List_index_ok]: forall l: ListValue, i: int:: {List_index(l,i)} - ((List_index(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l)); + ((List_index(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l) && i>=0); axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: {List_extend(l2,l1)} List_index(l1, i) == List_index(List_extend(l2,l1), i + List_len(l2)); axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: {List_extend(List_extend(l1,l2), l3)} @@ -240,8 +240,8 @@ axiom [List_reverse_def_cons]: forall h: Value, t: ListValue:: {List_reverse(Lis List_reverse(ListValue_cons(h,t)) == List_append(List_reverse(t), h); axiom [List_reverse_len]: forall l: ListValue :: {List_len(List_reverse(l))} List_len(l) == List_len(List_reverse(l)); -axiom [List_reverse_index]: forall l: ListValue, i: int :: {List_reverse(l)} - List_index(l, i) == List_index(List_reverse(l), List_len(l)-1-i); +axiom [List_reverse_index]: forall l: ListValue, i: int :: {List_index(List_reverse(l), i)} + List_index(List_reverse(l), i) == List_index(l, List_len(l)-1-i); axiom [List_reverse_extend]: forall l1: ListValue, l2: ListValue :: {List_reverse(List_extend(l1,l2))} List_reverse(List_extend(l1,l2)) == List_extend(List_reverse(l2), List_reverse(l1)); axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (List_reverse(l), v)} @@ -434,14 +434,6 @@ axiom [Py_add_float_bool]: forall r: real, b: bool :: {Py_add(Value_float(r), Va Py_add(Value_float(r), Value_bool(b)) == Value_float(r + bool_to_real(b)); axiom [Py_add_bool_float]: forall b: bool, r: real :: {Py_add(Value_bool(b), Value_float(r))} Py_add(Value_bool(b), Value_float(r)) == Value_float(bool_to_real(b) + r); -axiom [Py_add_none]: forall v: Value :: {Py_add(v, Value_none())} - Py_add(v, Value_none()) == Value_exception(Error_message("Operand is None")); -axiom [Py_none_add]: forall v: Value :: {Py_add(Value_none(), v)} - Py_add(Value_none(), v) == Value_exception(Error_message("Operand is None")); -axiom [Py_add_exception]: forall v: Value, e: Error :: {Py_add(v, Value_exception(e))} - Py_add(v, Value_exception(e)) == Value_exception(Error_message("Operand is Exception")); -axiom [Py_exception_add]: forall v: Value, e: Error :: {Py_add(Value_exception(e), v)} - Py_add(Value_exception(e), v) == Value_exception(Error_message("Operand is Exception")); axiom [Py_add_strs]:forall s1: string, s2: string :: {Py_add(Value_str(s1), Value_str(s2))} Py_add(Value_str(s1), Value_str(s2)) == Value_str(str.concat(s1, s2)); axiom [Py_add_str_int]: forall s: string, i: int :: {Py_add(Value_str(s), Value_int(i))} @@ -452,6 +444,11 @@ axiom [Py_add_str_bool]: forall s: string, b: bool :: {Py_add(Value_str(s), Valu Py_add(Value_str(s), Value_bool(b)) == Value_exception(Error_message("Cannot add string to bool")); axiom [Py_add_bool_str]: forall s: string, b: bool :: {Py_add(Value_bool(b), Value_str(s))} Py_add(Value_bool(b), Value_str(s)) == Value_exception(Error_message("Cannot add bool to string")); +axiom [Py_add_unsupport]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} + ((TypeOf(v1)!=BOOL && TypeOf(v1)!=INT && TypeOf(v1)!=FLOAT && TypeOf(v1)!=STR) || + (TypeOf(v2)!=BOOL && TypeOf(v2)!=INT && TypeOf(v2)!=FLOAT && TypeOf(v2)!=STR)) ==> + Py_add(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + axiom [Py_mul_ints]: forall i1: int, i2: int :: {Py_mul(Value_int(i1), Value_int(i2))} Py_mul(Value_int(i1), Value_int(i2)) == Value_int(i1 * i2); @@ -461,14 +458,6 @@ axiom [Py_mul_int_bool]: forall i: int, b: bool :: {Py_mul(Value_int(i), Value_b Py_mul(Value_int(i), Value_bool(b)) == Value_int(i * bool_to_int(b)); axiom [Py_mul_bool_int]: forall b: bool, i: int :: {Py_mul(Value_bool(b), Value_int(i))} Py_mul(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) * i); -axiom [Py_mul_none]: forall v: Value :: {Py_mul(v, Value_none())} - Py_mul(v, Value_none()) == Value_exception(Error_message("Operand is None")); -axiom [Py_mul_add]: forall v: Value :: {Py_mul(Value_none(), v)} - Py_mul(Value_none(), v) == Value_exception(Error_message("Operand is None")); -axiom [Py_mul_exception]: forall v: Value, e: Error :: {Py_mul(v, Value_exception(e))} - Py_mul(v, Value_exception(e)) == Value_exception(Error_message("Operand is Exception")); -axiom [Py_exception_mul]: forall v: Value, e: Error :: {Py_mul(Value_exception(e), v)} - Py_mul(Value_exception(e), v) == Value_exception(Error_message("Operand is Exception")); axiom [Py_mul_str]: forall s1: string, s2: string :: {Py_mul(Value_str(s1), Value_str(s2))} Py_mul(Value_str(s1), Value_str(s2)) == Value_exception(Error_message("Cannot multiply two strings")); axiom [Py_mul_str_int]: forall s: string, i: int :: {Py_mul(Value_str(s), Value_int(i))} @@ -479,8 +468,16 @@ axiom [Py_mul_str_bool]: forall s: string, b: bool :: {Py_mul(Value_str(s), Valu Py_mul(Value_str(s), Value_bool(b)) == Value_str(if b then s else ""); axiom [Py_mul_bool_str]: forall s: string, b: bool :: {Py_mul(Value_bool(b), Value_str(s)) } Py_mul(Value_bool(b), Value_str(s)) == Value_str(if b then s else ""); +axiom [Py_mul_unsupport]: forall v1: Value, v2: Value :: {Py_mul(v1,v2)} + ((TypeOf(v1)!=BOOL && TypeOf(v1)!=INT && TypeOf(v1)!=FLOAT && TypeOf(v1)!=STR) || + (TypeOf(v2)!=BOOL && TypeOf(v2)!=INT && TypeOf(v2)!=FLOAT && TypeOf(v2)!=STR)) ==> + Py_mul(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); //Testing +procedure non_contradiction_test() returns () { + assert [one_eq_two]: 1 == 2; +}; + procedure list_functions_test() returns () { var l1: ListValue, l2: ListValue; From 1cbf5dc9da079576420c15ac622cf7c443b11776 Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Wed, 17 Dec 2025 13:02:07 -0800 Subject: [PATCH 07/13] add exists axioms for TypeOf --- .../Languages/Python/BoogieTypePrelude.lean | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean index 7fc18a99d..2e60a0b47 100644 --- a/Strata/Languages/Python/BoogieTypePrelude.lean +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -66,15 +66,31 @@ const NONE : ValueType; const EXCEPTION : ValueType; function ValueType_class(c: Class): ValueType; +function isListValueType (t: ValueType): bool; +function isClassValueType (t: ValueType): bool; +axiom [isClassType_def]: forall c: Class :: {isClassValueType(ValueType_class(c))} isClassValueType(ValueType_class(c)); + function isList (v: Value): bool; function isClassInstance (v: Value): bool; + //Uniqueness axioms -axiom [unique_ValueType_bool]: BOOL != INT && BOOL != FLOAT && BOOL != STR && BOOL != NONE && BOOL != EXCEPTION; -axiom [unique_ValueType_int]: INT != STR && INT != FLOAT && INT != NONE && INT != EXCEPTION; -axiom [unique_ValueType_float]: FLOAT != STR && FLOAT != NONE && FLOAT != EXCEPTION; -axiom [unique_ValueType_str]: STR != NONE && STR != EXCEPTION; -axiom [unique_ValueType_none]: NONE != EXCEPTION; +axiom [unique_ValueType_bool]: BOOL != INT && BOOL != FLOAT && BOOL != STR && BOOL != NONE && BOOL != EXCEPTION && !isListValueType(BOOL) && !(isClassValueType(BOOL)); +axiom [unique_ValueType_int]: INT != STR && INT != FLOAT && INT != NONE && INT != EXCEPTION && !isListValueType(INT) && !(isClassValueType(INT)); +axiom [unique_ValueType_float]: FLOAT != STR && FLOAT != NONE && FLOAT != EXCEPTION && !isListValueType(FLOAT) && !(isClassValueType(FLOAT)); +axiom [unique_ValueType_str]: STR != NONE && STR != EXCEPTION && !isListValueType(STR) && !(isClassValueType(STR)); +axiom [unique_ValueType_none]: NONE != EXCEPTION && !isListValueType(NONE) && !(isClassValueType(NONE)); +axiom [unique_ValueType_exception]: !isListValueType(EXCEPTION) && !(isClassValueType(EXCEPTION)); +axiom [classtype_ne_listtype]: forall t: ValueType :: {isListValueType (t), isClassValueType (t)} !(isListValueType (t) && isClassValueType (t)); +axiom [all_ValueType_cases]: forall t: ValueType :: + t == BOOL || + t == INT || + t == FLOAT || + t == STR || + t == NONE || + t == EXCEPTION || + isListValueType (t) || + isClassValueType (t); //Eq axioms axiom [value_int_eq]: forall i: int, j: int :: {Value_int(i) == Value_int(j)} (Value_int(i) == Value_int(j)) == (i == j); @@ -89,6 +105,7 @@ function ValueType_List (l: ListValueType) : ValueType; function ListValueType_tag (l: ListValueType) : List_tag; axiom [ListValueType_tag_nil_def]: ListValueType_tag (ListType_nil()) == NIL; axiom [ListValueType_tag_cons_def]: forall t: ValueType, ts: ListValueType ::{ListType_cons(t, ts)} (ListValueType_tag (ListType_cons(t, ts)) == CONS); +axiom [isListValueType_def]: forall l: ListValueType ::{isListValueType(ValueType_List (l))} isListValueType(ValueType_List (l)); // TypeOf and TypesOf functions function TypeOf (v : Value) : ValueType; @@ -97,15 +114,6 @@ function TypesOf (v: ListValue) : ListValueType; axiom [TypesOf_nil_def]: TypesOf(ListValue_nil()) == ListType_nil(); axiom [TypesOf_cons_def]: forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} TypesOf(ListValue_cons(v, vs)) == ListType_cons(TypeOf(v), TypesOf(vs)); axiom [TypeOf_list_def]: forall l: ListValue ::{Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); -axiom [TypeOf_ret_set]: forall v: Value :: {TypeOf(v)} - TypeOf(v) == BOOL || - TypeOf(v) == INT || - TypeOf(v) == FLOAT || - TypeOf(v) == STR || - TypeOf(v) == NONE || - TypeOf(v) == EXCEPTION || - isList(v) || - isClassInstance(v); axiom [TypeOf_bool]: forall b: bool :: {TypeOf(Value_bool(b))} TypeOf(Value_bool(b)) == BOOL; axiom [TypeOf_int]: forall i: int :: {Value_int(i)} TypeOf(Value_int(i)) == INT; axiom [TypeOf_float]: forall f: real :: {Value_float(f)} TypeOf(Value_float(f)) == FLOAT; @@ -114,41 +122,19 @@ axiom [TypeOf_exception]: forall e: Error :: {Value_exception(e)} TypeOf(Value_e axiom [TypeOf_none]: TypeOf(Value_none()) == NONE; axiom [TypeOf_list]: forall l: ListValue :: {Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); -axiom [isList_def]: forall l: ListValue :: {Value_list(l)} isList(Value_list(l)); -axiom [list_neq_other_types]: forall v: Value :: {isList(v)} isList(v) == ( - TypeOf(v) != BOOL && - TypeOf(v) != INT && - TypeOf(v) != FLOAT && - TypeOf(v) != STR && - TypeOf(v) != NONE && - TypeOf(v) != EXCEPTION && - !isClassInstance(v)); -axiom [list_neq_other_types']: forall l: ListValue, ci: ClassInstance :: {TypeOf(Value_list(l))} - TypeOf(Value_list(l))!=BOOL && - TypeOf(Value_list(l))!=INT && - TypeOf(Value_list(l))!=FLOAT && - TypeOf(Value_list(l))!=STR && - TypeOf(Value_list(l))!=NONE && - TypeOf(Value_list(l))!=EXCEPTION && - TypeOf(Value_list(l))!=TypeOf(Value_class(ci)); +axiom [TypeOf_bool_exists]: forall v: Value :: {TypeOf(v) == BOOL} TypeOf(v) == BOOL ==> exists b: bool :: v == Value_bool(b); +axiom [TypeOf_int_exists]: forall v: Value :: {TypeOf(v) == INT} TypeOf(v) == INT ==> exists i: int :: v == Value_int(i); +axiom [TypeOf_float_exists]: forall v: Value :: {TypeOf(v) == FLOAT} TypeOf(v) == FLOAT ==> exists r: real :: v == Value_float(r); +axiom [TypeOf_string_exists]: forall v: Value :: {TypeOf(v) == STR} TypeOf(v) == STR ==> exists s: string :: v == Value_str(s); +axiom [TypeOf_exception_exists]: forall v: Value :: {TypeOf(v) == EXCEPTION} TypeOf(v) == EXCEPTION ==> exists e: Error :: v == Value_exception(e); +axiom [TypeOf_none']: forall v: Value :: {TypeOf(v) == NONE} (TypeOf(v) == NONE) == (v == Value_none()) ; +axiom [TypeOf_list_exists]: forall v: Value :: {isList(v)} isList(v) ==> exists l: ListValue :: v == Value_list(l); +axiom [TypeOf_class_exists]: forall v: Value :: {isClassInstance(v)} isClassInstance(v) ==> exists ci: ClassInstance :: v == Value_class(ci); +axiom [isList_def]: forall l: ListValue :: {Value_list(l)} isList(Value_list(l)); +axiom [isList_def']: forall v: Value :: {isListValueType(TypeOf(v))} isList(v) == isListValueType(TypeOf(v)); axiom [isClassInstance_def]: forall ci: ClassInstance :: {Value_class(ci)} isClassInstance(Value_class(ci)); -axiom [ClassInstantType_neq_other_types]: forall v: Value :: {isClassInstance(v)} isClassInstance(v) == ( - TypeOf(v) != BOOL && - TypeOf(v) != INT && - TypeOf(v) != FLOAT && - TypeOf(v) != STR && - TypeOf(v) != NONE && - TypeOf(v) != EXCEPTION && - !isList(v)); -axiom [list_neq_single_type']: forall ci: ClassInstance, l: ListValue :: {TypeOf(Value_list(l))} - TypeOf(Value_class(ci))!=BOOL && - TypeOf(Value_class(ci))!=INT && - TypeOf(Value_class(ci))!=FLOAT && - TypeOf(Value_class(ci))!=STR && - TypeOf(Value_class(ci))!=NONE && - TypeOf(Value_class(ci))!=EXCEPTION && - TypeOf(Value_class(ci))!=TypeOf(Value_list(l)); +axiom [isClassInstance_def']: forall v: Value :: {isClassValueType(TypeOf(v))} isClassInstance(v) == isClassValueType(TypeOf(v)); // isSubType functions function isSubType (t1: ValueType, t2: ValueType) : bool; @@ -169,6 +155,10 @@ axiom [not_isSubstype_none]: forall t: ValueType ::{isSubType(NONE, t), isSubTyp t == NONE || (!isSubType(NONE, t) && !isSubType(t,NONE)); axiom [not_isSubstype_exception]: forall t: ValueType ::{isSubType(EXCEPTION, t), isSubType(t, EXCEPTION)} t == EXCEPTION || (!isSubType(EXCEPTION, t) && !isSubType(t, EXCEPTION)); +axiom [not_isSubstype_list]: forall t: ValueType, t': ValueType ::{isSubType(t, t')} + ((isListValueType(t) && !isListValueType(t')) || (!isListValueType(t) && isListValueType(t'))) ==> (!isSubType(t, t') && !isSubType(t', t)); +axiom [not_isSubstype_class_othertypes]: forall t: ValueType, t': ValueType ::{isSubType(t, t')} + ((isClassValueType(t) && !isClassValueType(t')) || (!isClassValueType(t) && isClassValueType(t'))) ==> (!isSubType(t, t') && !isSubType(t', t)); axiom [not_isSubstype_class]: forall t: ValueType, c: Class ::{isSubType(ValueType_class(c), t), isSubType(t,ValueType_class(c))} t != ValueType_class(c) ==> (!isSubType(ValueType_class(c), t) && !isSubType(t,ValueType_class(c))); // Supporting lemmas @@ -228,7 +218,7 @@ axiom [List_index_ind]: forall h : Value, t : ListValue, i : int ::{List_index ( axiom [List_index_contains]: forall l: ListValue, i: int, x: Value :: {List_contains(l,x), List_index(l,i)} (List_index(l,i) == x) ==> List_contains(l,x); axiom [List_index_ok]: forall l: ListValue, i: int:: {List_index(l,i)} - ((List_index(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l) && i>=0); + ((List_index(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l) && i >= 0); axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: {List_extend(l2,l1)} List_index(l1, i) == List_index(List_extend(l2,l1), i + List_len(l2)); axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: {List_extend(List_extend(l1,l2), l3)} @@ -240,12 +230,12 @@ axiom [List_reverse_def_cons]: forall h: Value, t: ListValue:: {List_reverse(Lis List_reverse(ListValue_cons(h,t)) == List_append(List_reverse(t), h); axiom [List_reverse_len]: forall l: ListValue :: {List_len(List_reverse(l))} List_len(l) == List_len(List_reverse(l)); +axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (List_reverse(l), v)} + List_contains (List_reverse(l), v) == List_contains(l,v); axiom [List_reverse_index]: forall l: ListValue, i: int :: {List_index(List_reverse(l), i)} List_index(List_reverse(l), i) == List_index(l, List_len(l)-1-i); axiom [List_reverse_extend]: forall l1: ListValue, l2: ListValue :: {List_reverse(List_extend(l1,l2))} List_reverse(List_extend(l1,l2)) == List_extend(List_reverse(l2), List_reverse(l1)); -axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (List_reverse(l), v)} - List_contains (List_reverse(l), v) == List_contains(l,v); // Dict type type Dict := Map Value Value; @@ -449,7 +439,6 @@ axiom [Py_add_unsupport]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} (TypeOf(v2)!=BOOL && TypeOf(v2)!=INT && TypeOf(v2)!=FLOAT && TypeOf(v2)!=STR)) ==> Py_add(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); - axiom [Py_mul_ints]: forall i1: int, i2: int :: {Py_mul(Value_int(i1), Value_int(i2))} Py_mul(Value_int(i1), Value_int(i2)) == Value_int(i1 * i2); axiom [Py_mul_bools]: forall b1: bool, b2: bool :: {Py_mul(Value_bool(b1), Value_bool(b2))} @@ -478,6 +467,17 @@ procedure non_contradiction_test() returns () { assert [one_eq_two]: 1 == 2; }; +procedure binary_op_and_types_test () returns () { + assert [int_add_ok]: forall i: int :: TypeOf(Py_add(Value_int(1), Value_int(i))) != EXCEPTION; + assert [int_add_class_except]: forall v: Value :: isClassInstance(v) ==> TypeOf(Py_add(Value_int(1), v)) == EXCEPTION; + assert [int_add_class_except']: forall v: Value :: hasAttribute(v, "a") ==> TypeOf(Py_add(Value_int(1), v)) == EXCEPTION; + assert [float_add_isInstance_int_ok]: forall v: Value :: isInstance(v,INT) ==> TypeOf(Py_add(Value_float(1.1), v)) != EXCEPTION; + //assert [exists_type1]: exists t: ValueType, v: Value :: (TypeOf(Py_add(Value_int(1), v)) != EXCEPTION) && (TypeOf(v) == t); + //assert [exist_value]: exists v: Value:: TypeOf(Py_add(Value_int(1), v)) != EXCEPTION; + //assert [exist_value'']: exists i: int :: {Value_int(2)} TypeOf(Py_add(Value_int(1), Value_int(i))) != EXCEPTION; + //assert [exists_type3]: exists v: Value :: (TypeOf(Py_add(Value_none(), v)) == STR); +}; + procedure list_functions_test() returns () { var l1: ListValue, l2: ListValue; From 8772da211ee5c1d322ae7a3829e59ef90ad0eebb Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Fri, 19 Dec 2025 11:59:11 -0800 Subject: [PATCH 08/13] add more function and binary operations --- .../Languages/Python/BoogieTypePrelude.lean | 183 ++++++++++++++---- 1 file changed, 147 insertions(+), 36 deletions(-) diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean index 2e60a0b47..54a4e6b6d 100644 --- a/Strata/Languages/Python/BoogieTypePrelude.lean +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -185,46 +185,57 @@ function List_contains (l : ListValue, x: Value) : bool; function List_len (l : ListValue) : int; function List_extend (l1 : ListValue, l2: ListValue) : ListValue; function List_append (l: ListValue, x: Value) : ListValue; -function List_index (l : ListValue, i : int) : Value; +function List_get (l : ListValue, i : int) : Value; function List_reverse (l: ListValue) : ListValue; +function List_index! (l: ListValue, v: Value): int; +function List_index (l: ListValue, v: Value): Value; +function List_repeat (l: ListValue, n: int): ListValue; +//TO BE done +function List_remove (l: ListValue, v: Value): ListValue; +function List_pop (l: ListValue, i: int): ListValue; +function List_insert (l: ListValue, i: int, v: Value): ListValue; //List function axioms axiom [List_contains_nil_def]: forall x : Value ::{List_contains(ListValue_nil(), x)} !List_contains(ListValue_nil(), x); axiom [List_contains_cons_def]: forall x : Value, h : Value, t : ListValue ::{List_contains(ListValue_cons(h,t),x)} List_contains(ListValue_cons(h,t),x) == ((normalize_value(x)==normalize_value(h)) || List_contains(t, x)); + axiom [List_len_nil_def]: List_len (ListValue_nil()) == 0; axiom [List_len_cons_def]: forall h : Value, t : ListValue ::{List_len (ListValue_cons(h,t))} List_len (ListValue_cons(h,t)) == 1 + List_len(t); axiom [List_len_nonneg]: forall l: ListValue :: {List_len(l)} List_len(l) >= 0 ; + axiom [List_extend_nil_def]: forall l1: ListValue ::{List_extend (l1, ListValue_nil())} List_extend (l1, ListValue_nil()) == l1; axiom [List_nil_extend_def]: forall l1: ListValue ::{List_extend (ListValue_nil(), l1)} List_extend (ListValue_nil(), l1) == l1; axiom [List_cons_extend_def]: forall h: Value, t: ListValue, l2: ListValue ::{List_extend (ListValue_cons(h,t), l2)} List_extend (ListValue_cons(h,t), l2) == ListValue_cons(h, List_extend(t,l2)); + axiom [List_cons_extend_contains]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} List_contains (List_extend(l1,l2), x) == List_contains (l1,x) || List_contains(l2,x); -axiom [List_cons_extend_contains_symm]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} - List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x); axiom [List_len_extend]: forall l1: ListValue, l2: ListValue ::{List_len (List_extend(l1,l2))} List_len (List_extend(l1,l2)) == List_len (l1) + List_len(l2); -axiom [List_index_nil]: forall i : int ::{List_index (ListValue_nil(), i)} - List_index (ListValue_nil(), i) == Value_exception(Error_message("index out of bound")); -axiom [List_index_zero]: forall h : Value, t : ListValue ::{List_index (ListValue_cons(h,t), 0)} - List_index (ListValue_cons(h,t), 0) == h; -axiom [List_index_ind]: forall h : Value, t : ListValue, i : int ::{List_index (ListValue_cons(h,t), i)} - (i > 0) ==> (List_index (ListValue_cons(h,t), i)) == List_index (t, i - 1); -axiom [List_index_contains]: forall l: ListValue, i: int, x: Value :: {List_contains(l,x), List_index(l,i)} - (List_index(l,i) == x) ==> List_contains(l,x); -axiom [List_index_ok]: forall l: ListValue, i: int:: {List_index(l,i)} - ((List_index(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l) && i >= 0); -axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: {List_extend(l2,l1)} - List_index(l1, i) == List_index(List_extend(l2,l1), i + List_len(l2)); axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: {List_extend(List_extend(l1,l2), l3)} List_extend(List_extend(l1,l2), l3) == List_extend(l1,List_extend(l2,l3)); + +axiom [List_get_nil]: forall i : int ::{List_get (ListValue_nil(), i)} + List_get (ListValue_nil(), i) == Value_exception(Error_message("index out of bound")); +axiom [List_get_zero]: forall h : Value, t : ListValue ::{List_get (ListValue_cons(h,t), 0)} + List_get (ListValue_cons(h,t), 0) == h; +axiom [List_get_ind]: forall h : Value, t : ListValue, i : int ::{List_get (ListValue_cons(h,t), i)} + (i > 0) ==> (List_get (ListValue_cons(h,t), i)) == List_get (t, i - 1); +axiom [List_get_contains]: forall l: ListValue, i: int, x: Value :: {List_contains(l,x), List_get(l,i)} + (List_get(l,i) == x) ==> List_contains(l,x); +axiom [List_get_ok]: forall l: ListValue, i: int:: {List_get(l,i)} + ((List_get(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l) && i >= 0); +axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: {List_extend(l2,l1)} + List_get(l1, i) == List_get(List_extend(l2,l1), i + List_len(l2)); + axiom [List_append_def]: forall l: ListValue, x: Value :: {List_append(l,x)} List_append(l,x) == List_extend(l, ListValue_cons(x, ListValue_nil())); + axiom [List_reverse_def_nil]: List_reverse(ListValue_nil()) == ListValue_nil(); axiom [List_reverse_def_cons]: forall h: Value, t: ListValue:: {List_reverse(ListValue_cons(h,t))} List_reverse(ListValue_cons(h,t)) == List_append(List_reverse(t), h); @@ -232,11 +243,27 @@ axiom [List_reverse_len]: forall l: ListValue :: {List_len(List_reverse(l))} List_len(l) == List_len(List_reverse(l)); axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (List_reverse(l), v)} List_contains (List_reverse(l), v) == List_contains(l,v); -axiom [List_reverse_index]: forall l: ListValue, i: int :: {List_index(List_reverse(l), i)} - List_index(List_reverse(l), i) == List_index(l, List_len(l)-1-i); +axiom [List_reverse_index]: forall l: ListValue, i: int :: {List_get(List_reverse(l), i)} + List_get(List_reverse(l), i) == List_get(l, List_len(l)-1-i); axiom [List_reverse_extend]: forall l1: ListValue, l2: ListValue :: {List_reverse(List_extend(l1,l2))} List_reverse(List_extend(l1,l2)) == List_extend(List_reverse(l2), List_reverse(l1)); +axiom [List_index!_nil_def]: forall v: Value :: {List_index!(ListValue_nil(), v)} + List_index!(ListValue_nil(), v) == 0; +axiom [List_index!_cons_def_1]: forall h: Value, t: ListValue :: {List_index!(ListValue_cons(h,t), h)} + List_index!(ListValue_cons(h,t), h) == 0; +axiom [List_index!_cons_def_2]: forall v: Value, h: Value, t: ListValue :: {List_index!(ListValue_cons(h,t), v)} + !(normalize_value(v)==normalize_value(h)) ==> List_index!(ListValue_cons(h,t), v) == List_index!(t, v) + 1; +axiom [List_index_def]: forall v: Value, l: ListValue :: {List_index(l, v)} + List_index(l,v) == if (List_index!(l,v) == List_len(l)) then Value_exception(Error_message("List does not contain element")) + else Value_int(List_index!(l,v)); + +axiom [List_repeat_def]: forall l: ListValue, n: int :: {List_repeat(l, n)} + List_repeat(l, n) == if (n <= 0) then ListValue_nil() else + if (n == 1) then l else List_extend(l, List_repeat(l, n-1)); +axiom [List_repeat_mul]: forall l: ListValue, n: int, m: int :: {List_repeat(List_repeat(l, n),m)} + List_repeat(List_repeat(l, n),m) == List_repeat(l, n * m); + // Dict type type Dict := Map Value Value; @@ -403,6 +430,9 @@ function str_repeat (s: string, i: int) : string; function Py_add (v1: Value, v2: Value) : Value; function Py_sub (v1: Value, v2: Value) : Value; function Py_mul (v1: Value, v2: Value) : Value; +function Py_gt (v1: Value, v2: Value) : Value; +function Py_lt (v1: Value, v2: Value) : Value; +function Py_eq (v1: Value, v2: Value) : Value; inline function bool_to_int (b: bool) : int {if b then 1 else 0} inline function bool_to_real (b: bool) : real {if b then 1.0 else 0.0} @@ -424,20 +454,37 @@ axiom [Py_add_float_bool]: forall r: real, b: bool :: {Py_add(Value_float(r), Va Py_add(Value_float(r), Value_bool(b)) == Value_float(r + bool_to_real(b)); axiom [Py_add_bool_float]: forall b: bool, r: real :: {Py_add(Value_bool(b), Value_float(r))} Py_add(Value_bool(b), Value_float(r)) == Value_float(bool_to_real(b) + r); -axiom [Py_add_strs]:forall s1: string, s2: string :: {Py_add(Value_str(s1), Value_str(s2))} +axiom [Py_add_strs]: forall s1: string, s2: string :: {Py_add(Value_str(s1), Value_str(s2))} Py_add(Value_str(s1), Value_str(s2)) == Value_str(str.concat(s1, s2)); -axiom [Py_add_str_int]: forall s: string, i: int :: {Py_add(Value_str(s), Value_int(i))} - Py_add(Value_str(s), Value_int(i)) == Value_exception(Error_message("Cannot add string to int")); -axiom [Py_add_int_str]: forall s: string, i: int :: {Py_add(Value_int(i), Value_str(s)) } - Py_add(Value_int(i), Value_str(s)) == Value_exception(Error_message("Cannot add string to int")); -axiom [Py_add_str_bool]: forall s: string, b: bool :: {Py_add(Value_str(s), Value_bool(b))} - Py_add(Value_str(s), Value_bool(b)) == Value_exception(Error_message("Cannot add string to bool")); -axiom [Py_add_bool_str]: forall s: string, b: bool :: {Py_add(Value_bool(b), Value_str(s))} - Py_add(Value_bool(b), Value_str(s)) == Value_exception(Error_message("Cannot add bool to string")); +axiom [Py_add_lists]: forall l1: ListValue, l2: ListValue :: {Py_add(Value_list(l1), Value_list(l2))} + Py_add(Value_list(l1), Value_list(l2)) == Value_list(List_extend(l1, l2)); axiom [Py_add_unsupport]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} - ((TypeOf(v1)!=BOOL && TypeOf(v1)!=INT && TypeOf(v1)!=FLOAT && TypeOf(v1)!=STR) || - (TypeOf(v2)!=BOOL && TypeOf(v2)!=INT && TypeOf(v2)!=FLOAT && TypeOf(v2)!=STR)) ==> - Py_add(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_add(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + +axiom [Py_sub_ints]: forall i1: int, i2: int :: {Py_sub(Value_int(i1), Value_int(i2))} + Py_sub(Value_int(i1), Value_int(i2)) == Value_int(i1 - i2); +axiom [Py_sub_floats]: forall f1: real, f2: real :: {Py_sub(Value_float(f1), Value_float(f2))} + Py_sub(Value_float(f1), Value_float(f2)) == Value_float(f1 - f2); +axiom [Py_sub_bools]: forall b1: bool, b2: bool :: {Py_sub(Value_bool(b1), Value_bool(b2))} + Py_sub(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) - bool_to_int(b2)); +axiom [Py_sub_int_bool]: forall i: int, b: bool :: {Py_sub(Value_int(i), Value_bool(b))} + Py_sub(Value_int(i), Value_bool(b)) == Value_int(i - bool_to_int(b)); +axiom [Py_sub_bool_int]: forall b: bool, i: int :: {Py_sub(Value_bool(b), Value_int(i))} + Py_sub(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) - i); +axiom [Py_sub_int_float]: forall i: int, r: real :: {Py_sub(Value_int(i), Value_float(r))} + Py_sub(Value_int(i), Value_float(r)) == Value_float(r - int_to_real(i)); +axiom [Py_sub_float_int]: forall r: real, i: int :: {Py_sub(Value_float(r), Value_int(i))} + Py_sub(Value_float(r), Value_int(i)) == Value_float(int_to_real(i) - r); +axiom [Py_sub_float_bool]: forall r: real, b: bool :: {Py_sub(Value_float(r), Value_bool(b))} + Py_sub(Value_float(r), Value_bool(b)) == Value_float(r - bool_to_real(b)); +axiom [Py_sub_bool_float]: forall b: bool, r: real :: {Py_sub(Value_bool(b), Value_float(r))} + Py_sub(Value_bool(b), Value_float(r)) == Value_float(bool_to_real(b) - r); +axiom [Py_sub_unsupport]: forall v1: Value, v2: Value :: {Py_sub(v1,v2)} + !(isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) ==> + Py_sub(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); axiom [Py_mul_ints]: forall i1: int, i2: int :: {Py_mul(Value_int(i1), Value_int(i2))} Py_mul(Value_int(i1), Value_int(i2)) == Value_int(i1 * i2); @@ -447,8 +494,6 @@ axiom [Py_mul_int_bool]: forall i: int, b: bool :: {Py_mul(Value_int(i), Value_b Py_mul(Value_int(i), Value_bool(b)) == Value_int(i * bool_to_int(b)); axiom [Py_mul_bool_int]: forall b: bool, i: int :: {Py_mul(Value_bool(b), Value_int(i))} Py_mul(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) * i); -axiom [Py_mul_str]: forall s1: string, s2: string :: {Py_mul(Value_str(s1), Value_str(s2))} - Py_mul(Value_str(s1), Value_str(s2)) == Value_exception(Error_message("Cannot multiply two strings")); axiom [Py_mul_str_int]: forall s: string, i: int :: {Py_mul(Value_str(s), Value_int(i))} Py_mul(Value_str(s), Value_int(i)) == Value_str(str_repeat(s, i)); axiom [Py_mul_int_str]: forall s: string, i: int :: {Py_mul(Value_int(i), Value_str(s))} @@ -457,10 +502,66 @@ axiom [Py_mul_str_bool]: forall s: string, b: bool :: {Py_mul(Value_str(s), Valu Py_mul(Value_str(s), Value_bool(b)) == Value_str(if b then s else ""); axiom [Py_mul_bool_str]: forall s: string, b: bool :: {Py_mul(Value_bool(b), Value_str(s)) } Py_mul(Value_bool(b), Value_str(s)) == Value_str(if b then s else ""); -axiom [Py_mul_unsupport]: forall v1: Value, v2: Value :: {Py_mul(v1,v2)} - ((TypeOf(v1)!=BOOL && TypeOf(v1)!=INT && TypeOf(v1)!=FLOAT && TypeOf(v1)!=STR) || - (TypeOf(v2)!=BOOL && TypeOf(v2)!=INT && TypeOf(v2)!=FLOAT && TypeOf(v2)!=STR)) ==> - Py_mul(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); +axiom [Py_mul_list_int]: forall l: ListValue, i: int :: {Py_mul(Value_list(l), Value_int(i))} + Py_mul(Value_list(l), Value_int(i)) == Value_list(List_repeat(l, i)); +axiom [Py_mul_int_list]: forall l: ListValue, i: int :: {Py_mul(Value_int(i), Value_list(l))} + Py_mul(Value_int(i), Value_list(l)) == Value_list(List_repeat(l, i)); +axiom [Py_mul_list_bool]: forall l: ListValue, b: bool :: {Py_mul(Value_list(l), Value_bool(b))} + Py_mul(Value_list(l), Value_bool(b)) == Value_list(if b then l else ListValue_nil()); +axiom [Py_mul_bool_list]: forall l: ListValue, b: bool :: {Py_mul(Value_bool(b), Value_list(l)) } + Py_mul(Value_bool(b), Value_list(l)) == Value_list(if b then l else ListValue_nil()); +axiom [Py_mul_unsupport]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && isInstance(v2, INT)) || + (TypeOf(v2) == STR && isInstance(v1, INT)) || + (isList(v1) && isInstance(v2, INT)) || + (isList(v2) && isInstance(v1, INT)) ) + ==> Py_mul(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + +axiom [Py_lt_ints]: forall i1: int, i2: int :: {Py_lt(Value_int(i1), Value_int(i2))} + Py_lt(Value_int(i1), Value_int(i2)) == Value_bool(i1 < i2); +axiom [Py_lt_floats]: forall f1: real, f2: real :: {Py_lt(Value_float(f1), Value_float(f2))} + Py_lt(Value_float(f1), Value_float(f2)) == Value_bool(f1 < f2); +axiom [Py_lt_bools]: forall b1: bool, b2: bool :: {Py_lt(Value_bool(b1), Value_bool(b2))} + Py_lt(Value_bool(b1), Value_bool(b2)) == Value_bool(bool_to_int(b1) < bool_to_int(b2)); +axiom [Py_lt_int_bool]: forall i: int, b: bool :: {Py_lt(Value_int(i), Value_bool(b))} + Py_lt(Value_int(i), Value_bool(b)) == Value_bool(i < bool_to_int(b)); +axiom [Py_lt_bool_int]: forall b: bool, i: int :: {Py_lt(Value_bool(b), Value_int(i))} + Py_lt(Value_bool(b), Value_int(i)) == Value_bool(bool_to_int(b) < i); +axiom [Py_lt_int_float]: forall i: int, r: real :: {Py_lt(Value_int(i), Value_float(r))} + Py_lt(Value_int(i), Value_float(r)) == Value_bool(r < int_to_real(i)); +axiom [Py_lt_float_int]: forall r: real, i: int :: {Py_lt(Value_float(r), Value_int(i))} + Py_lt(Value_float(r), Value_int(i)) == Value_bool(int_to_real(i) < r); +axiom [Py_lt_float_bool]: forall r: real, b: bool :: {Py_lt(Value_float(r), Value_bool(b))} + Py_lt(Value_float(r), Value_bool(b)) == Value_bool(r < bool_to_real(b)); +axiom [Py_lt_bool_float]: forall b: bool, r: real :: {Py_lt(Value_bool(b), Value_float(r))} + Py_lt(Value_bool(b), Value_float(r)) == Value_bool(bool_to_real(b) < r); +axiom [Py_lt_unsupport]: forall v1: Value, v2: Value :: {Py_lt(v1,v2)} + !(isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) ==> + Py_lt(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + +axiom [Py_gt_ints]: forall i1: int, i2: int :: {Py_gt(Value_int(i1), Value_int(i2))} + Py_gt(Value_int(i1), Value_int(i2)) == Value_bool(i1 > i2); +axiom [Py_gt_floats]: forall f1: real, f2: real :: {Py_gt(Value_float(f1), Value_float(f2))} + Py_gt(Value_float(f1), Value_float(f2)) == Value_bool(f1 > f2); +axiom [Py_gt_bools]: forall b1: bool, b2: bool :: {Py_gt(Value_bool(b1), Value_bool(b2))} + Py_gt(Value_bool(b1), Value_bool(b2)) == Value_bool(bool_to_int(b1) > bool_to_int(b2)); +axiom [Py_gt_int_bool]: forall i: int, b: bool :: {Py_gt(Value_int(i), Value_bool(b))} + Py_gt(Value_int(i), Value_bool(b)) == Value_bool(i > bool_to_int(b)); +axiom [Py_gt_bool_int]: forall b: bool, i: int :: {Py_gt(Value_bool(b), Value_int(i))} + Py_gt(Value_bool(b), Value_int(i)) == Value_bool(bool_to_int(b) > i); +axiom [Py_gt_int_float]: forall i: int, r: real :: {Py_gt(Value_int(i), Value_float(r))} + Py_gt(Value_int(i), Value_float(r)) == Value_bool(r > int_to_real(i)); +axiom [Py_gt_float_int]: forall r: real, i: int :: {Py_gt(Value_float(r), Value_int(i))} + Py_gt(Value_float(r), Value_int(i)) == Value_bool(int_to_real(i) > r); +axiom [Py_gt_float_bool]: forall r: real, b: bool :: {Py_gt(Value_float(r), Value_bool(b))} + Py_gt(Value_float(r), Value_bool(b)) == Value_bool(r > bool_to_real(b)); +axiom [Py_gt_bool_float]: forall b: bool, r: real :: {Py_gt(Value_bool(b), Value_float(r))} + Py_gt(Value_bool(b), Value_float(r)) == Value_bool(bool_to_real(b) > r); +axiom [Py_gt_unsupport]: forall v1: Value, v2: Value :: {Py_gt(v1,v2)} + !(isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) ==> + Py_gt(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + //Testing procedure non_contradiction_test() returns () { @@ -482,11 +583,18 @@ procedure list_functions_test() returns () { var l1: ListValue, l2: ListValue; l1 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil()))); - assert [index_1]: List_index(l1,1) == Value_int(2); + l2 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), + ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil())))))); + assert [index_1]: List_get(l1,1) == Value_int(2); assert [contain_true]: List_contains(l1, Value_bool(true)); assert [ValueEq]: !(Value_int(4) == Value_int(3)); assert [normalize_value]: !(normalize_value(Value_int(4)) == Value_int(3)); assert [contain_3]: List_contains(l1, Value_int(2)); + assert [list_index_test1]: List_index(l1, Value_int(3)) == Value_int(2); + assert [list_index_test2]: TypeOf(List_index(l1, Value_int(9))) == EXCEPTION; + assert [list_extend]: List_extend(l1, l1) == l2; + assert [list_repeat1]: List_repeat(l1, 2) == l2; + assert [list_repeat2]: List_repeat(l1, 6) == List_repeat(l2, 3); }; procedure list_generic_test() returns () { @@ -500,6 +608,9 @@ procedure list_generic_test() returns () { assert [rev_contain]: forall l: ListValue, v: Value :: List_contains (List_reverse(l), v) == List_contains(l,v); assert [l1r_l2_contains_3]: forall l2: ListValue :: List_contains (List_extend(List_reverse(l1), l2), Value_int(3)); assert [l1r_l2_contains_3']: forall l2: ListValue :: List_contains (List_reverse(List_extend(List_reverse(l1), l2)), Value_int(3)); + assert [list_repeat_contain]: forall l: ListValue, v: Value, n: int :: List_contains(l, v) == List_contains(List_repeat(l, n), v); + assert [List_cons_extend_contains_symm]: forall x: Value, l1: ListValue, l2: ListValue :: + List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x); }; From 2488bb86da7ad8b6a9cef67708b349644bef3359 Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Mon, 22 Dec 2025 10:45:44 -0800 Subject: [PATCH 09/13] refine TypePrelude --- .../Languages/Python/BoogieTypePrelude.lean | 62 ++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean index 54a4e6b6d..1f990abfa 100644 --- a/Strata/Languages/Python/BoogieTypePrelude.lean +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -20,6 +20,7 @@ type List_tag; const CONS : List_tag; const NIL : List_tag; axiom [list_tag_unique]: CONS != NIL; +axiom [all_list_tag]: forall lt: List_tag :: lt == CONS || lt == NIL; //Will be merged with BoogiePrelude.lean type Error; @@ -28,6 +29,7 @@ type Error_tag; const OK : Error_tag; const ERR : Error_tag; axiom [error_tag_unique]: OK != ERR; +axiom [all_error_tag]: forall et: Error_tag :: et == OK || et == ERR; // Value and ListValue types type Value; @@ -190,10 +192,11 @@ function List_reverse (l: ListValue) : ListValue; function List_index! (l: ListValue, v: Value): int; function List_index (l: ListValue, v: Value): Value; function List_repeat (l: ListValue, n: int): ListValue; -//TO BE done +function List_insert (l: ListValue, i: int, v: Value): ListValue; function List_remove (l: ListValue, v: Value): ListValue; +//TO BE done function List_pop (l: ListValue, i: int): ListValue; -function List_insert (l: ListValue, i: int, v: Value): ListValue; + //List function axioms axiom [List_contains_nil_def]: forall x : Value ::{List_contains(ListValue_nil(), x)} @@ -205,6 +208,8 @@ axiom [List_len_nil_def]: List_len (ListValue_nil()) == 0; axiom [List_len_cons_def]: forall h : Value, t : ListValue ::{List_len (ListValue_cons(h,t))} List_len (ListValue_cons(h,t)) == 1 + List_len(t); axiom [List_len_nonneg]: forall l: ListValue :: {List_len(l)} List_len(l) >= 0 ; +axiom [List_nil_of_len_zero]: forall l: ListValue :: {List_len(l) == 0} + (List_len(l) == 0) == (l == ListValue_nil()); axiom [List_extend_nil_def]: forall l1: ListValue ::{List_extend (l1, ListValue_nil())} List_extend (l1, ListValue_nil()) == l1; @@ -214,7 +219,7 @@ axiom [List_cons_extend_def]: forall h: Value, t: ListValue, l2: ListValue ::{L List_extend (ListValue_cons(h,t), l2) == ListValue_cons(h, List_extend(t,l2)); axiom [List_cons_extend_contains]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} - List_contains (List_extend(l1,l2), x) == List_contains (l1,x) || List_contains(l2,x); + List_contains (List_extend(l1,l2), x) == (List_contains (l1,x) || List_contains(l2,x)); axiom [List_len_extend]: forall l1: ListValue, l2: ListValue ::{List_len (List_extend(l1,l2))} List_len (List_extend(l1,l2)) == List_len (l1) + List_len(l2); axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: {List_extend(List_extend(l1,l2), l3)} @@ -227,11 +232,13 @@ axiom [List_get_zero]: forall h : Value, t : ListValue ::{List_get (ListValue_co axiom [List_get_ind]: forall h : Value, t : ListValue, i : int ::{List_get (ListValue_cons(h,t), i)} (i > 0) ==> (List_get (ListValue_cons(h,t), i)) == List_get (t, i - 1); axiom [List_get_contains]: forall l: ListValue, i: int, x: Value :: {List_contains(l,x), List_get(l,i)} - (List_get(l,i) == x) ==> List_contains(l,x); + (List_get(l,i) == x && TypeOf(x)!= EXCEPTION) ==> List_contains(l,x); axiom [List_get_ok]: forall l: ListValue, i: int:: {List_get(l,i)} ((List_get(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l) && i >= 0); -axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: {List_extend(l2,l1)} - List_get(l1, i) == List_get(List_extend(l2,l1), i + List_len(l2)); +axiom [List_get_ok']: forall l: ListValue, i: int:: {List_get(l,i)} + (TypeOf(List_get(l,i)) != EXCEPTION) == (i < List_len(l) && i >= 0); +axiom [List_extend_get]: forall l1: ListValue, l2: ListValue, i: int :: {List_get(List_extend(l1,l2), i)} + List_get(List_extend(l1,l2), i) == if i < List_len(l1) then List_get(l1, i) else List_get(l2, i - List_len(l1)); axiom [List_append_def]: forall l: ListValue, x: Value :: {List_append(l,x)} List_append(l,x) == List_extend(l, ListValue_cons(x, ListValue_nil())); @@ -245,6 +252,8 @@ axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (L List_contains (List_reverse(l), v) == List_contains(l,v); axiom [List_reverse_index]: forall l: ListValue, i: int :: {List_get(List_reverse(l), i)} List_get(List_reverse(l), i) == List_get(l, List_len(l)-1-i); +axiom [List_reverse_reverse]: forall l: ListValue :: {List_reverse(List_reverse(l))} + List_reverse(List_reverse(l)) == l; axiom [List_reverse_extend]: forall l1: ListValue, l2: ListValue :: {List_reverse(List_extend(l1,l2))} List_reverse(List_extend(l1,l2)) == List_extend(List_reverse(l2), List_reverse(l1)); @@ -263,6 +272,41 @@ axiom [List_repeat_def]: forall l: ListValue, n: int :: {List_repeat(l, n)} if (n == 1) then l else List_extend(l, List_repeat(l, n-1)); axiom [List_repeat_mul]: forall l: ListValue, n: int, m: int :: {List_repeat(List_repeat(l, n),m)} List_repeat(List_repeat(l, n),m) == List_repeat(l, n * m); +axiom [List_repeat_contain]: forall l: ListValue, v: Value, n: int :: {List_contains(List_repeat(l, n), v)} + n > 0 ==> (List_contains(List_repeat(l, n), v) == List_contains(l, v)); +axiom [List_repeat_get]: forall l: ListValue, v: Value, i: int, n: int, m: int :: {List_get(List_repeat(l, n), i + m * List_len(l))} + (i >= 0 && i < List_len(l) && m >= 0 && m < n) ==> (List_get(List_repeat(l, n), i + m * List_len(l)) == List_get(l, i)); + +axiom [List_insert_def0]: forall i: int, v: Value :: {List_insert(ListValue_nil(), i, v)} + List_insert(ListValue_nil(), i, v) == ListValue_cons(v, ListValue_nil()); +axiom [List_insert_def1]: forall l: ListValue, i: int, v: Value :: {List_insert(l, i, v)} + List_insert(l, 0, v) == ListValue_cons(v, l); +axiom [List_insert_def2]: forall h: Value, t: ListValue, i: int, v: Value :: {List_insert(ListValue_cons(h,t), i, v)} + (i > 0) ==> List_insert(ListValue_cons(h,t), i, v) == ListValue_cons(h, List_insert(t, i-1, v)); +axiom [List_insert_def3]: forall h: Value, t: ListValue, i: int, v: Value :: {List_insert(ListValue_cons(h,t), i, v)} + (i < 0) ==> List_insert(ListValue_cons(h,t), i, v) == List_insert(ListValue_cons(h,t), i mod (List_len(t)+1) , v); +axiom [List_insert_len]: forall l: ListValue, i: int, v: Value :: {List_len(List_insert(l, i, v))} + List_len(List_insert(l, i, v)) == List_len(l) + 1; +axiom [List_insert_get0]: forall l: ListValue, p: int, v: Value:: {List_get(List_insert(l, p, v), p)} + (p >= 0 && p < List_len(l)) ==> (List_get(List_insert(l, p, v), p) == v); +axiom [List_insert_get1]: forall l: ListValue, p: int, v: Value:: {List_get(List_insert(l, p, v), p)} + p >= List_len(l) ==> (List_get(List_insert(l, p, v), List_len(l)) == v); +axiom [List_insert_get2]: forall l: ListValue, p: int, v: Value, i: int :: {List_get(List_insert(l, p, v), i)} + (p >= List_len(l) && i < List_len(l)) ==> (List_get(List_insert(l, p, v),i) == List_get(l, i)); +axiom [List_insert_get3]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} + (p >= 0 && p < List_len(l) && i < p) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i)); +axiom [List_insert_get4]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} + (p >= 0 && p < List_len(l) && i > p) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i -1)); +axiom [List_insert_get5]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} + (p < 0 && i < p mod List_len(l)) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i)); +axiom [List_insert_get6]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} + (p < 0 && i > p mod List_len(l)) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i -1)); + +axiom [List_remove_nil_def]: forall x : Value ::{List_remove(ListValue_nil(), x)} + List_remove(ListValue_nil(), x) == ListValue_nil(); +axiom [List_remove_cons_def]: forall x : Value, h : Value, t : ListValue ::{List_remove(ListValue_cons(h,t),x)} + List_remove(ListValue_cons(h,t),x) == if (normalize_value(x)==normalize_value(h)) then t + else ListValue_cons(h, List_remove(t, x)); // Dict type type Dict := Map Value Value; @@ -432,7 +476,7 @@ function Py_sub (v1: Value, v2: Value) : Value; function Py_mul (v1: Value, v2: Value) : Value; function Py_gt (v1: Value, v2: Value) : Value; function Py_lt (v1: Value, v2: Value) : Value; -function Py_eq (v1: Value, v2: Value) : Value; +function Py_eq (v1: Value, v2: Value) : bool; inline function bool_to_int (b: bool) : int {if b then 1 else 0} inline function bool_to_real (b: bool) : real {if b then 1.0 else 0.0} @@ -562,6 +606,8 @@ axiom [Py_gt_unsupport]: forall v1: Value, v2: Value :: {Py_gt(v1,v2)} !(isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) ==> Py_gt(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); +axiom [Py_eq_def]: forall v: Value, v': Value :: {Py_eq(v, v')} + Py_eq(v, v') == (normalize_value(v) == normalize_value (v')); //Testing procedure non_contradiction_test() returns () { @@ -603,12 +649,12 @@ procedure list_generic_test() returns () { assert [len_append]: forall l: ListValue, x: Value :: List_len(List_append(l,x)) == List_len(l) + 1; l1 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil()))); assert [l1_contains_3]: List_contains (l1, Value_int(3)); + assert [contains_len]: forall l: ListValue, x: Value:: List_contains(l,x) ==> (List_len(l) >0); assert [l1l2_contains_3]: forall l2: ListValue :: List_contains (List_extend(l1, l2), Value_int(3)); assert [revl1_contain_3]: List_contains (List_reverse(l1), Value_int(3)); assert [rev_contain]: forall l: ListValue, v: Value :: List_contains (List_reverse(l), v) == List_contains(l,v); assert [l1r_l2_contains_3]: forall l2: ListValue :: List_contains (List_extend(List_reverse(l1), l2), Value_int(3)); assert [l1r_l2_contains_3']: forall l2: ListValue :: List_contains (List_reverse(List_extend(List_reverse(l1), l2)), Value_int(3)); - assert [list_repeat_contain]: forall l: ListValue, v: Value, n: int :: List_contains(l, v) == List_contains(List_repeat(l, n), v); assert [List_cons_extend_contains_symm]: forall x: Value, l1: ListValue, l2: ListValue :: List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x); }; From 3825d5e27c4fd0aa7506d63036a43c532c9b951b Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Mon, 22 Dec 2025 10:56:43 -0800 Subject: [PATCH 10/13] add tests for TypePrelude --- .../typepreludetests/BoogieTypeClassTest.lean | 534 ++++++++++++++++++ .../BoogieTypeTestSimple.lean | 514 +++++++++++++++++ 2 files changed, 1048 insertions(+) create mode 100644 StrataTest/Languages/Python/typepreludetests/BoogieTypeClassTest.lean create mode 100644 StrataTest/Languages/Python/typepreludetests/BoogieTypeTestSimple.lean diff --git a/StrataTest/Languages/Python/typepreludetests/BoogieTypeClassTest.lean b/StrataTest/Languages/Python/typepreludetests/BoogieTypeClassTest.lean new file mode 100644 index 000000000..bd5112769 --- /dev/null +++ b/StrataTest/Languages/Python/typepreludetests/BoogieTypeClassTest.lean @@ -0,0 +1,534 @@ +/- + Copyright Strata Contributors + + SPDX-License-Identifier: Apache-2.0 OR MIT +-/ + +import Strata.DDM.Elab +import Strata.DDM.AST +import Strata.Languages.Boogie.DDMTransform.Parse +import Strata.Languages.Boogie.Verifier + +namespace Strata + +def boogieTypePrelude := +#strata +program Boogie; + +//Generic tag for List +type List_tag; +const CONS : List_tag; +const NIL : List_tag; +axiom [list_tag_unique]: CONS != NIL; + +//Will be merged with BoogiePrelude.lean +type Error; +function Error_message (s: string): Error; +type Error_tag; +const OK : Error_tag; +const ERR : Error_tag; +axiom [error_tag_unique]: OK != ERR; + +// Value and ListValue types +type Value; +type ListValue; + +// Class type +type Class; +type AttributeValues := Map string Value; +type ClassInstance; + +// Constructors +function Value_bool (b : bool) : Value; +function Value_int (i : int) : Value; +function Value_float (f : real) : Value; +function Value_str (s : string) : Value; +function Value_none() : Value; +function Value_exception (e : Error): Value; +function Value_list (lv : ListValue) : Value; +function Value_class (ci: ClassInstance) : Value; + +function ListValue_nil() : ListValue; +function ListValue_cons(x0 : Value, x1 : ListValue) : ListValue; +//Tags +function ListValue_tag (l: ListValue) : List_tag; +axiom [ListValue_tag_nil_def]: ListValue_tag (ListValue_nil()) == NIL; +axiom [ListValue_tag_cons_def]: forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} ListValue_tag (ListValue_cons(v, vs)) == CONS; + +// Types of Value +type ValueType; +type ListValueType; +const BOOL : ValueType; +const INT : ValueType; +const FLOAT : ValueType; +const STR : ValueType; +const NONE : ValueType; +const EXCEPTION : ValueType; +function ValueType_class(c: Class): ValueType; + +function isListValueType (t: ValueType): bool; +function isClassValueType (t: ValueType): bool; +axiom [isClassType_def]: forall c: Class :: {isClassValueType(ValueType_class(c))} isClassValueType(ValueType_class(c)); + +function isList (v: Value): bool; +function isClassInstance (v: Value): bool; + + +//Uniqueness axioms +axiom [unique_ValueType_bool]: BOOL != INT && BOOL != FLOAT && BOOL != STR && BOOL != NONE && BOOL != EXCEPTION && !isListValueType(BOOL) && !(isClassValueType(BOOL)); +axiom [unique_ValueType_int]: INT != STR && INT != FLOAT && INT != NONE && INT != EXCEPTION && !isListValueType(INT) && !(isClassValueType(INT)); +axiom [unique_ValueType_float]: FLOAT != STR && FLOAT != NONE && FLOAT != EXCEPTION && !isListValueType(FLOAT) && !(isClassValueType(FLOAT)); +axiom [unique_ValueType_str]: STR != NONE && STR != EXCEPTION && !isListValueType(STR) && !(isClassValueType(STR)); +axiom [unique_ValueType_none]: NONE != EXCEPTION && !isListValueType(NONE) && !(isClassValueType(NONE)); +axiom [unique_ValueType_exception]: !isListValueType(EXCEPTION) && !(isClassValueType(EXCEPTION)); +axiom [classtype_ne_listtype]: forall t: ValueType :: {isListValueType (t), isClassValueType (t)} !(isListValueType (t) && isClassValueType (t)); +axiom [all_ValueType_cases]: forall t: ValueType :: + t == BOOL || + t == INT || + t == FLOAT || + t == STR || + t == NONE || + t == EXCEPTION || + isListValueType (t) || + isClassValueType (t); + +//Eq axioms +axiom [value_int_eq]: forall i: int, j: int :: {Value_int(i) == Value_int(j)} (Value_int(i) == Value_int(j)) == (i == j); +axiom [value_bool_eq]: forall b1: bool, b2: bool :: {Value_bool(b1) == Value_bool(b2)} (Value_bool(b1) == Value_bool(b2)) == (b1 == b2); +axiom [value_float_eq]: forall r1: real, r2: real :: {Value_float(r1) == Value_float(r2)} (Value_float(r1) == Value_float(r2)) == (r1 == r2); +axiom [value_str_eq]: forall s1: string, s2: string :: {Value_str(s1) == Value_str(s2)} (Value_str(s1) == Value_str(s2)) == (s1 == s2); + +//Constructors and tag functions of ListType +function ListType_nil() : (ListValueType); +function ListType_cons(x0 : ValueType, x1 : ListValueType) : ListValueType; +function ValueType_List (l: ListValueType) : ValueType; +function ListValueType_tag (l: ListValueType) : List_tag; +axiom [ListValueType_tag_nil_def]: ListValueType_tag (ListType_nil()) == NIL; +axiom [ListValueType_tag_cons_def]: forall t: ValueType, ts: ListValueType ::{ListType_cons(t, ts)} (ListValueType_tag (ListType_cons(t, ts)) == CONS); +axiom [isListValueType_def]: forall l: ListValueType ::{isListValueType(ValueType_List (l))} isListValueType(ValueType_List (l)); + +// TypeOf and TypesOf functions +function TypeOf (v : Value) : ValueType; +function TypesOf (v: ListValue) : ListValueType; +// Definitions +axiom [TypesOf_nil_def]: TypesOf(ListValue_nil()) == ListType_nil(); +axiom [TypesOf_cons_def]: forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} TypesOf(ListValue_cons(v, vs)) == ListType_cons(TypeOf(v), TypesOf(vs)); +axiom [TypeOf_list_def]: forall l: ListValue ::{Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); +axiom [TypeOf_bool]: forall b: bool :: {TypeOf(Value_bool(b))} TypeOf(Value_bool(b)) == BOOL; +axiom [TypeOf_int]: forall i: int :: {Value_int(i)} TypeOf(Value_int(i)) == INT; +axiom [TypeOf_float]: forall f: real :: {Value_float(f)} TypeOf(Value_float(f)) == FLOAT; +axiom [TypeOf_str]: forall s: string :: {Value_str(s)} TypeOf(Value_str(s)) == STR; +axiom [TypeOf_exception]: forall e: Error :: {Value_exception(e)} TypeOf(Value_exception(e)) == EXCEPTION; +axiom [TypeOf_none]: TypeOf(Value_none()) == NONE; +axiom [TypeOf_list]: forall l: ListValue :: {Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); + +axiom [TypeOf_bool_exists]: forall v: Value :: {TypeOf(v) == BOOL} TypeOf(v) == BOOL ==> exists b: bool :: v == Value_bool(b); +axiom [TypeOf_int_exists]: forall v: Value :: {TypeOf(v) == INT} TypeOf(v) == INT ==> exists i: int :: v == Value_int(i); +axiom [TypeOf_float_exists]: forall v: Value :: {TypeOf(v) == FLOAT} TypeOf(v) == FLOAT ==> exists r: real :: v == Value_float(r); +axiom [TypeOf_string_exists]: forall v: Value :: {TypeOf(v) == STR} TypeOf(v) == STR ==> exists s: string :: v == Value_str(s); +axiom [TypeOf_exception_exists]: forall v: Value :: {TypeOf(v) == EXCEPTION} TypeOf(v) == EXCEPTION ==> exists e: Error :: v == Value_exception(e); +axiom [TypeOf_none']: forall v: Value :: {TypeOf(v) == NONE} (TypeOf(v) == NONE) == (v == Value_none()) ; +axiom [TypeOf_list_exists]: forall v: Value :: {isList(v)} isList(v) ==> exists l: ListValue :: v == Value_list(l); +axiom [TypeOf_class_exists]: forall v: Value :: {isClassInstance(v)} isClassInstance(v) ==> exists ci: ClassInstance :: v == Value_class(ci); + +axiom [isList_def]: forall l: ListValue :: {Value_list(l)} isList(Value_list(l)); +axiom [isList_def']: forall v: Value :: {isListValueType(TypeOf(v))} isList(v) == isListValueType(TypeOf(v)); +axiom [isClassInstance_def]: forall ci: ClassInstance :: {Value_class(ci)} isClassInstance(Value_class(ci)); +axiom [isClassInstance_def']: forall v: Value :: {isClassValueType(TypeOf(v))} isClassInstance(v) == isClassValueType(TypeOf(v)); + +// isSubType functions +function isSubType (t1: ValueType, t2: ValueType) : bool; +function isSubTypes (t1: ListValueType, t2: ListValueType) : bool; +//Definitions +axiom [isSubTypes_nil_def]: isSubTypes(ListType_nil(), ListType_nil()); +axiom [not_isSubTypes_nil]: forall ty: ValueType, l: ListValueType :: !isSubTypes(ListType_nil(), ListType_cons(ty,l)); +axiom [not_isSubTypes_nil']: forall ty: ValueType, l: ListValueType :: !isSubTypes(ListType_cons(ty,l), ListType_nil()); +axiom [isSubTypes_cons_def]:forall t: ValueType, ts: ListValueType, t': ValueType, ts': ListValueType ::{ListType_cons(t, ts), ListType_cons(t', ts')} + isSubTypes(ListType_cons(t, ts), ListType_cons(t', ts')) == (isSubType(t, t') && isSubTypes(ts, ts')); +axiom [isSubType_list_def]: forall l: ListValueType, l': ListValueType :: {ValueType_List(l), ValueType_List(l')} + isSubType(ValueType_List(l), ValueType_List(l')) == isSubTypes(l, l'); +axiom [bool_substype_int]: isSubType(BOOL, INT); +axiom [int_substype_float]: isSubType(INT, FLOAT); +axiom [not_isSubstype_string]: forall t: ValueType ::{isSubType(STR, t), isSubType(t,STR)} + t == STR || (!isSubType(STR, t) && !isSubType(t,STR)); +axiom [not_isSubstype_none]: forall t: ValueType ::{isSubType(NONE, t), isSubType(NONE, t)} + t == NONE || (!isSubType(NONE, t) && !isSubType(t,NONE)); +axiom [not_isSubstype_exception]: forall t: ValueType ::{isSubType(EXCEPTION, t), isSubType(t, EXCEPTION)} + t == EXCEPTION || (!isSubType(EXCEPTION, t) && !isSubType(t, EXCEPTION)); +axiom [not_isSubstype_list]: forall t: ValueType, t': ValueType ::{isSubType(t, t')} + ((isListValueType(t) && !isListValueType(t')) || (!isListValueType(t) && isListValueType(t'))) ==> (!isSubType(t, t') && !isSubType(t', t)); +axiom [not_isSubstype_class_othertypes]: forall t: ValueType, t': ValueType ::{isSubType(t, t')} + ((isClassValueType(t) && !isClassValueType(t')) || (!isClassValueType(t) && isClassValueType(t'))) ==> (!isSubType(t, t') && !isSubType(t', t)); +axiom [not_isSubstype_class]: forall t: ValueType, c: Class ::{isSubType(ValueType_class(c), t), isSubType(t,ValueType_class(c))} + t != ValueType_class(c) ==> (!isSubType(ValueType_class(c), t) && !isSubType(t,ValueType_class(c))); +// Supporting lemmas +axiom [isSubtype_rfl]: forall t: ValueType::{isSubType (t,t)} isSubType (t,t); +axiom [isSubtype_mono]: forall t1: ValueType, t2: ValueType ::{isSubType (t1,t2)} !isSubType (t1,t2) || (t1 == t2 || !isSubType(t2,t1)); +axiom [isSubtype_trans]: forall t1: ValueType, t2: ValueType, t3: ValueType::{isSubType(t1, t2)} !(isSubType(t1, t2) && isSubType(t2, t3)) || isSubType(t1, t3); + +// isInstance function: +function isInstance (v: Value, vt: ValueType) : bool; +axiom [isInstance_of_isSubtype]: forall v: Value, t: ValueType::{isInstance(v,t)} isInstance(v,t) == isSubType(TypeOf(v), t); + +function is_IntReal (v: Value) : bool; +function Value_real_to_int (v: Value) : int; +// to be extended +function normalize_value (v : Value) : Value { + if v == Value_bool(true) then Value_int(1) + else (if v == Value_bool(false) then Value_int(0) else + if TypeOf(v) == FLOAT && is_IntReal(v) then Value_int(Value_real_to_int(v)) else + v) +} + +// ListValue functions +function List_contains (l : ListValue, x: Value) : bool; +function List_len (l : ListValue) : int; +function List_extend (l1 : ListValue, l2: ListValue) : ListValue; +function List_append (l: ListValue, x: Value) : ListValue; +function List_index (l : ListValue, i : int) : Value; +function List_reverse (l: ListValue) : ListValue; + +//List function axioms +axiom [List_contains_nil_def]: forall x : Value ::{List_contains(ListValue_nil(), x)} + !List_contains(ListValue_nil(), x); +axiom [List_contains_cons_def]: forall x : Value, h : Value, t : ListValue ::{List_contains(ListValue_cons(h,t),x)} + List_contains(ListValue_cons(h,t),x) == ((normalize_value(x)==normalize_value(h)) || List_contains(t, x)); +axiom [List_len_nil_def]: List_len (ListValue_nil()) == 0; +axiom [List_len_cons_def]: forall h : Value, t : ListValue ::{List_len (ListValue_cons(h,t))} + List_len (ListValue_cons(h,t)) == 1 + List_len(t); +axiom [List_len_nonneg]: forall l: ListValue :: {List_len(l)} List_len(l) >= 0 ; +axiom [List_extend_nil_def]: forall l1: ListValue ::{List_extend (l1, ListValue_nil())} + List_extend (l1, ListValue_nil()) == l1; +axiom [List_nil_extend_def]: forall l1: ListValue ::{List_extend (ListValue_nil(), l1)} + List_extend (ListValue_nil(), l1) == l1; +axiom [List_cons_extend_def]: forall h: Value, t: ListValue, l2: ListValue ::{List_extend (ListValue_cons(h,t), l2)} + List_extend (ListValue_cons(h,t), l2) == ListValue_cons(h, List_extend(t,l2)); +axiom [List_cons_extend_contains]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} + List_contains (List_extend(l1,l2), x) == List_contains (l1,x) || List_contains(l2,x); +axiom [List_cons_extend_contains_symm]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} + List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x); +axiom [List_len_extend]: forall l1: ListValue, l2: ListValue ::{List_len (List_extend(l1,l2))} + List_len (List_extend(l1,l2)) == List_len (l1) + List_len(l2); +axiom [List_index_nil]: forall i : int ::{List_index (ListValue_nil(), i)} + List_index (ListValue_nil(), i) == Value_exception(Error_message("index out of bound")); +axiom [List_index_zero]: forall h : Value, t : ListValue ::{List_index (ListValue_cons(h,t), 0)} + List_index (ListValue_cons(h,t), 0) == h; +axiom [List_index_ind]: forall h : Value, t : ListValue, i : int ::{List_index (ListValue_cons(h,t), i)} + (i > 0) ==> (List_index (ListValue_cons(h,t), i)) == List_index (t, i - 1); +axiom [List_index_contains]: forall l: ListValue, i: int, x: Value :: {List_contains(l,x), List_index(l,i)} + (List_index(l,i) == x) ==> List_contains(l,x); +axiom [List_index_ok]: forall l: ListValue, i: int:: {List_index(l,i)} + ((List_index(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l) && i >= 0); +axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: {List_extend(l2,l1)} + List_index(l1, i) == List_index(List_extend(l2,l1), i + List_len(l2)); +axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: {List_extend(List_extend(l1,l2), l3)} + List_extend(List_extend(l1,l2), l3) == List_extend(l1,List_extend(l2,l3)); +axiom [List_append_def]: forall l: ListValue, x: Value :: {List_append(l,x)} + List_append(l,x) == List_extend(l, ListValue_cons(x, ListValue_nil())); +axiom [List_reverse_def_nil]: List_reverse(ListValue_nil()) == ListValue_nil(); +axiom [List_reverse_def_cons]: forall h: Value, t: ListValue:: {List_reverse(ListValue_cons(h,t))} + List_reverse(ListValue_cons(h,t)) == List_append(List_reverse(t), h); +axiom [List_reverse_len]: forall l: ListValue :: {List_len(List_reverse(l))} + List_len(l) == List_len(List_reverse(l)); +axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (List_reverse(l), v)} + List_contains (List_reverse(l), v) == List_contains(l,v); +axiom [List_reverse_index]: forall l: ListValue, i: int :: {List_index(List_reverse(l), i)} + List_index(List_reverse(l), i) == List_index(l, List_len(l)-1-i); +axiom [List_reverse_extend]: forall l1: ListValue, l2: ListValue :: {List_reverse(List_extend(l1,l2))} + List_reverse(List_extend(l1,l2)) == List_extend(List_reverse(l2), List_reverse(l1)); + +// Dict type +type Dict := Map Value Value; + +//Dictionary functions +function Dict_empty() : Dict; +function Dict_insert (d: Dict, k: Value, v: Value) : Dict; +function Dict_get (d: Dict, k: Value) : Value; +function Dict_remove (d: Dict, k: Value) : Dict; +function Dict_contains (d: Dict, k: Value) : bool; + +//Dictionary axioms +axiom [emptydict_def]: forall k: Value :: {Dict_empty() [k]} Dict_empty() [k] == Value_none(); +axiom [Dict_get_def]: forall d: Dict, k: Value :: {Dict_get(d,k)} Dict_get(d,k) == d[normalize_value(k)]; +axiom [Dict_insert_def]: forall d: Dict, k: Value, v: Value :: {Dict_insert(d,k,v)} Dict_insert(d,k,v) == d[normalize_value(k):= v]; +axiom [Dict_remove_def]: forall d: Dict, k: Value :: {Dict_remove(d,k)} Dict_remove(d,k) == d[normalize_value(k):= Value_none()]; +axiom [Dict_contains_def]: forall d: Dict, k: Value :: {Dict_contains(d,k)} Dict_contains(d,k) == (Dict_get (d,k) != Value_none()); + +// List of pairs of Value, used to construct Dict +type DictList; +// Constructor +function DictList_nil(): DictList; +function DictList_cons(k: Value, v: Value, d: DictList): DictList; +//Tag and tag functions +function DictList_tag (dl: DictList) : List_tag; +axiom [DistListTag_nil_def]: DictList_tag (DictList_nil()) == NIL; +axiom [DistListTag_cons_def]: forall k: Value, v: Value, d: DictList ::{DictList_cons(k,v,d)} DictList_tag (DictList_cons(k,v,d)) == CONS; +// as a constructor for Dict +function Dict_from_DicList (l : DictList) : Dict; +function Dict_from_DicList_rev (l : DictList, acc: Dict) : Dict; +axiom [Dict_from_DicList_rev_nil]: forall acc: Dict :: Dict_from_DicList_rev(DictList_nil(), acc) == acc; +axiom [Dict_from_DicList_rev_cons]: forall k: Value, v: Value, d: DictList, acc: Dict :: + Dict_from_DicList_rev(DictList_cons(k,v,d), acc) == Dict_from_DicList_rev(d,Dict_insert(acc, k, v)); +axiom [Dict_from_DicList_def]: forall dl: DictList:: {Dict_from_DicList(dl)} + Dict_from_DicList(dl) == Dict_from_DicList_rev(dl, Dict_empty()); + +type AttributeNames; +function AttributeNames_nil() : (AttributeNames); +function AttributeNames_cons(x0 : string, x1 : AttributeNames) : (AttributeNames); +function AttributeNames_tag (f: AttributeNames) : List_tag; +function AttributeNames_contains (l : AttributeNames, x: string) : bool; +function AttributeNames_len (l : AttributeNames) : int; +function AttributeNames_index (l : AttributeNames, i : int) : string; +function AttributeName_to_index (l : AttributeNames, f: string) : int; + +axiom [AttributeNames_len_nil_def]: AttributeNames_len (AttributeNames_nil()) == 0; +axiom [AttributeNames_len_cons_def]: forall h : string, t : AttributeNames ::{AttributeNames_len (AttributeNames_cons(h,t))} + AttributeNames_len (AttributeNames_cons(h,t)) == 1 + AttributeNames_len(t); +axiom [AttributeNames_tag_nil_def]: AttributeNames_tag(AttributeNames_nil()) == NIL; +axiom [AttributeNames_tag_cons_def]: forall h : string, t : AttributeNames ::{} AttributeNames_tag (AttributeNames_cons(h,t)) == CONS; +axiom [AttributeNames_contains_nil_def]: (forall x : string ::{AttributeNames_contains(AttributeNames_nil(), x)} + !AttributeNames_contains(AttributeNames_nil(), x)); +axiom [AttributeNames_contains_cons_def]: forall x : string, h : string, t : AttributeNames ::{AttributeNames_contains(AttributeNames_cons(h,t),x)} + AttributeNames_contains(AttributeNames_cons(h,t),x) == ((x==h) || AttributeNames_contains(t,x)); +axiom [AttributeNames_len_nonneg]: forall l: AttributeNames :: {AttributeNames_len(l)} AttributeNames_len(l) >= 0; +axiom [AttributeNames_index_nil]: forall i : int ::{AttributeNames_index (AttributeNames_nil(), i)} (AttributeNames_index (AttributeNames_nil(), i)) == ""; +axiom [AttributeNames_index_zero]: forall h : string, t : AttributeNames ::{AttributeNames_index (AttributeNames_cons(h,t), 0)} + AttributeNames_index (AttributeNames_cons(h,t), 0) == h; +axiom [AttributeNames_index_ind]: forall h : string, t : AttributeNames, i : int ::{AttributeNames_index (AttributeNames_cons(h,t), i)} + (i > 0) ==> (AttributeNames_index (AttributeNames_cons(h,t), i)) == AttributeNames_index (t, i - 1); +axiom [AttributeNames_index_contains]: forall l: AttributeNames, i: int, x: string :: {AttributeNames_index(l,i), AttributeNames_contains(l,x)} + (AttributeNames_index(l,i) == x) ==> AttributeNames_contains(l,x); +axiom [AttributeNames_index_ok]: forall l: AttributeNames, i: int:: {AttributeNames_index(l,i)} + ((AttributeNames_index(l,i)) != "") == (i < AttributeNames_len(l)); +axiom [AttributeName_to_index_nil_def]: forall f: string :: {AttributeName_to_index(AttributeNames_nil(), f)} + AttributeName_to_index(AttributeNames_nil(), f) == 0; +axiom [AttributeName_to_index_cons_def_1]: forall h: string, t: AttributeNames :: {AttributeName_to_index(AttributeNames_cons(h,t), h)} + AttributeName_to_index(AttributeNames_cons(h,t), h) == 0; +axiom [AttributeName_to_index_cons_def_2]: forall f: string, h: string, t: AttributeNames :: {AttributeName_to_index(AttributeNames_cons(h,t), f)} + !(h == f) ==> AttributeName_to_index(AttributeNames_cons(h,t), f) == AttributeName_to_index(t, f) + 1; + +function Class_mk (name: string, attributes: AttributeNames): Class; +function Class_attributes (c: Class) : AttributeNames; +function Class_name (c: Class): string; +axiom [Class_attributes_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} + Class_attributes(Class_mk (name, attributes)) == attributes; +axiom [Class_name_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} + Class_name(Class_mk (name, attributes)) == name; +axiom [Class_eq_def]: forall c: Class, c': Class :: {c == c'} + (c == c') == (Class_name(c) == Class_name(c')); + +function Class_hasAttribute (c: Class, attribute: string): bool; +axiom [Class_hasAttribute_def]: forall c: Class, attribute: string :: {Class_hasAttribute(c, attribute)} + Class_hasAttribute(c, attribute) == AttributeNames_contains(Class_attributes(c), attribute); + +function Class_err() : Class; +axiom [Class_err_attributes_def]: Class_attributes(Class_err()) == AttributeNames_nil(); + +function AttributeValues_empty (c: Class) : AttributeValues; +axiom [AttributeValues_empty_def_valid]: forall c: Class, attribute: string :: {AttributeValues_empty(c)[attribute]} + Class_hasAttribute(c, attribute) ==> AttributeValues_empty(c)[attribute] == Value_none(); +axiom [AttributeValues_empty_def_invalid]: forall c: Class, attribute: string :: {AttributeValues_empty(c)[attribute]} + !Class_hasAttribute(c, attribute) ==> AttributeValues_empty(c)[attribute] == Value_exception(Error_message("Invalid Attribute of Class")); + +function AttributeValues_err () : AttributeValues; +axiom [AttributeValues_err_def]: forall attribute: string :: {AttributeValues_err[attribute]} + AttributeValues_err()[attribute] == Value_exception(Error_message("Error ClassInstance")); + +function ClassInstance_mk (c: Class, av: AttributeValues) : ClassInstance; + +function ClassInstance_getAttributeValues (ci: ClassInstance) : AttributeValues; +axiom [getAttributeValues_def]: forall c: Class, av: AttributeValues :: { ClassInstance_getAttributeValues(ClassInstance_mk (c, av))} + ClassInstance_getAttributeValues(ClassInstance_mk (c, av)) == av; + +function ClassInstance_getClass (ci: ClassInstance) : Class; +axiom [get_Class_def]: forall c: Class, av: AttributeValues :: {ClassInstance_getClass(ClassInstance_mk (c, av))} + ClassInstance_getClass(ClassInstance_mk (c, av)) == c; + +axiom [TypeOf_class]: forall ci: ClassInstance :: {TypeOf(Value_class(ci))} TypeOf(Value_class(ci)) == ValueType_class(ClassInstance_getClass(ci)); + +function ClassInstance_empty (c: Class) : ClassInstance; +axiom [ClassInstance_mk_empty_get_attributevalues]: forall c: Class :: {ClassInstance_getAttributeValues(ClassInstance_empty (c))} + ClassInstance_getAttributeValues(ClassInstance_empty (c)) == AttributeValues_empty(c); +axiom [ClassInstance_mk_empty_get_class]: forall c: Class :: {ClassInstance_getClass(ClassInstance_empty (c))} + ClassInstance_getClass(ClassInstance_empty (c)) == c; + +function ClassInstance_err (err: string) : ClassInstance; +function ClassInstance_errortag (ci: ClassInstance): Error_tag; +axiom [ClassInstance_err_tag]: forall err: string :: {ClassInstance_errortag(ClassInstance_err(err))} + ClassInstance_errortag(ClassInstance_err(err)) == ERR; +axiom [ClassInstance_err_get_class_def]: forall err: string :: {ClassInstance_getClass(ClassInstance_err(err)) } + ClassInstance_getClass(ClassInstance_err(err)) == Class_err(); +axiom [ClassInstance_err_get_attributevalues_def]: forall err: string :: {ClassInstance_getAttributeValues(ClassInstance_err (err))} + ClassInstance_getAttributeValues(ClassInstance_err (err)) == AttributeValues_err(); + +function ClassInstance_get_attribute(ci: ClassInstance, attribute: string) : Value; +axiom [ClassInstance_get_attribute_def]: forall ci: ClassInstance, attribute: string ::{ClassInstance_get_attribute(ci, attribute)} + ClassInstance_get_attribute(ci, attribute) == ClassInstance_getAttributeValues(ci)[attribute]; + +function ClassInstance_set_attribute (ci: ClassInstance, attribute: string, value: Value): ClassInstance; +axiom [ClassInstance_set_attribute_def]: forall ci: ClassInstance, attribute: string, v: Value:: {ClassInstance_set_attribute(ci, attribute, v)} + ClassInstance_set_attribute(ci, attribute, v) == if Class_hasAttribute(ClassInstance_getClass(ci), attribute) then + ClassInstance_mk(ClassInstance_getClass(ci), ClassInstance_getAttributeValues(ci)[attribute:=v]) + else ClassInstance_err("Set value for invalid"); + +function get_ClassInstance (v: Value) : ClassInstance; +axiom [get_ClassInstance_valid]: forall ci: ClassInstance :: {get_ClassInstance(Value_class(ci))} + get_ClassInstance(Value_class(ci)) == ci; +axiom [get_ClassInstance_invalid]: forall v: Value :: {get_ClassInstance(v)} + !isClassInstance(v) ==> get_ClassInstance(v) == ClassInstance_err ("Not of Class type"); + +function get_attribute(v: Value, attribute: string) : Value; +axiom [get_attribute_def]: forall v: Value, attribute: string ::{get_attribute(v, attribute)} + get_attribute(v, attribute) == if isClassInstance(v) then + ClassInstance_get_attribute(get_ClassInstance(v), attribute) + else Value_exception(Error_message("Not of Class type")); + +function set_attribute(v: Value, attribute: string, v': Value) : Value; +axiom [set_attribute_def]: forall v: Value, attribute: string, v': Value ::{set_attribute(v, attribute, v')} + set_attribute(v, attribute, v') == if isClassInstance(v) then + Value_class(ClassInstance_set_attribute(get_ClassInstance(v), attribute, v')) + else Value_exception(Error_message("Not of Class type")); + +function get_Class (v: Value) : Class { + ClassInstance_getClass(get_ClassInstance (v)) +} + +function get_Class_name (v: Value) : string { + Class_name(ClassInstance_getClass(get_ClassInstance (v))) +} + +function hasAttribute(v: Value, attribute: string): bool { + Class_hasAttribute (get_Class(v), attribute) +} + +//Binary op function +function int_to_real (i: int) : real; +function str_repeat (s: string, i: int) : string; +function Py_add (v1: Value, v2: Value) : Value; +function Py_sub (v1: Value, v2: Value) : Value; +function Py_mul (v1: Value, v2: Value) : Value; +inline function bool_to_int (b: bool) : int {if b then 1 else 0} +inline function bool_to_real (b: bool) : real {if b then 1.0 else 0.0} + +axiom [Py_add_ints]: forall i1: int, i2: int :: {Py_add(Value_int(i1), Value_int(i2))} + Py_add(Value_int(i1), Value_int(i2)) == Value_int(i1 + i2); +axiom [Py_add_floats]: forall f1: real, f2: real :: {Py_add(Value_float(f1), Value_float(f2))} + Py_add(Value_float(f1), Value_float(f2)) == Value_float(f1 + f2); +axiom [Py_add_bools]: forall b1: bool, b2: bool :: {Py_add(Value_bool(b1), Value_bool(b2))} + Py_add(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) + bool_to_int(b2)); +axiom [Py_add_int_bool]: forall i: int, b: bool :: {Py_add(Value_int(i), Value_bool(b))} + Py_add(Value_int(i), Value_bool(b)) == Value_int(i + bool_to_int(b)); +axiom [Py_add_bool_int]: forall b: bool, i: int :: {Py_add(Value_bool(b), Value_int(i))} + Py_add(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) + i); +axiom [Py_add_int_float]: forall i: int, r: real :: {Py_add(Value_int(i), Value_float(r))} + Py_add(Value_int(i), Value_float(r)) == Value_float(r + int_to_real(i)); +axiom [Py_add_float_int]: forall r: real, i: int :: {Py_add(Value_float(r), Value_int(i))} + Py_add(Value_float(r), Value_int(i)) == Value_float(int_to_real(i) + r); +axiom [Py_add_float_bool]: forall r: real, b: bool :: {Py_add(Value_float(r), Value_bool(b))} + Py_add(Value_float(r), Value_bool(b)) == Value_float(r + bool_to_real(b)); +axiom [Py_add_bool_float]: forall b: bool, r: real :: {Py_add(Value_bool(b), Value_float(r))} + Py_add(Value_bool(b), Value_float(r)) == Value_float(bool_to_real(b) + r); +axiom [Py_add_strs]:forall s1: string, s2: string :: {Py_add(Value_str(s1), Value_str(s2))} + Py_add(Value_str(s1), Value_str(s2)) == Value_str(str.concat(s1, s2)); +axiom [Py_add_str_int]: forall s: string, i: int :: {Py_add(Value_str(s), Value_int(i))} + Py_add(Value_str(s), Value_int(i)) == Value_exception(Error_message("Cannot add string to int")); +axiom [Py_add_int_str]: forall s: string, i: int :: {Py_add(Value_int(i), Value_str(s)) } + Py_add(Value_int(i), Value_str(s)) == Value_exception(Error_message("Cannot add string to int")); +axiom [Py_add_str_bool]: forall s: string, b: bool :: {Py_add(Value_str(s), Value_bool(b))} + Py_add(Value_str(s), Value_bool(b)) == Value_exception(Error_message("Cannot add string to bool")); +axiom [Py_add_bool_str]: forall s: string, b: bool :: {Py_add(Value_bool(b), Value_str(s))} + Py_add(Value_bool(b), Value_str(s)) == Value_exception(Error_message("Cannot add bool to string")); +axiom [Py_add_unsupport]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} + ((TypeOf(v1)!=BOOL && TypeOf(v1)!=INT && TypeOf(v1)!=FLOAT && TypeOf(v1)!=STR) || + (TypeOf(v2)!=BOOL && TypeOf(v2)!=INT && TypeOf(v2)!=FLOAT && TypeOf(v2)!=STR)) ==> + Py_add(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + +axiom [Py_mul_ints]: forall i1: int, i2: int :: {Py_mul(Value_int(i1), Value_int(i2))} + Py_mul(Value_int(i1), Value_int(i2)) == Value_int(i1 * i2); +axiom [Py_mul_bools]: forall b1: bool, b2: bool :: {Py_mul(Value_bool(b1), Value_bool(b2))} + Py_mul(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) * bool_to_int(b2)); +axiom [Py_mul_int_bool]: forall i: int, b: bool :: {Py_mul(Value_int(i), Value_bool(b))} + Py_mul(Value_int(i), Value_bool(b)) == Value_int(i * bool_to_int(b)); +axiom [Py_mul_bool_int]: forall b: bool, i: int :: {Py_mul(Value_bool(b), Value_int(i))} + Py_mul(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) * i); +axiom [Py_mul_str]: forall s1: string, s2: string :: {Py_mul(Value_str(s1), Value_str(s2))} + Py_mul(Value_str(s1), Value_str(s2)) == Value_exception(Error_message("Cannot multiply two strings")); +axiom [Py_mul_str_int]: forall s: string, i: int :: {Py_mul(Value_str(s), Value_int(i))} + Py_mul(Value_str(s), Value_int(i)) == Value_str(str_repeat(s, i)); +axiom [Py_mul_int_str]: forall s: string, i: int :: {Py_mul(Value_int(i), Value_str(s))} + Py_mul(Value_int(i), Value_str(s)) == Value_str(str_repeat(s, i)); +axiom [Py_mul_str_bool]: forall s: string, b: bool :: {Py_mul(Value_str(s), Value_bool(b))} + Py_mul(Value_str(s), Value_bool(b)) == Value_str(if b then s else ""); +axiom [Py_mul_bool_str]: forall s: string, b: bool :: {Py_mul(Value_bool(b), Value_str(s)) } + Py_mul(Value_bool(b), Value_str(s)) == Value_str(if b then s else ""); +axiom [Py_mul_unsupport]: forall v1: Value, v2: Value :: {Py_mul(v1,v2)} + ((TypeOf(v1)!=BOOL && TypeOf(v1)!=INT && TypeOf(v1)!=FLOAT && TypeOf(v1)!=STR) || + (TypeOf(v2)!=BOOL && TypeOf(v2)!=INT && TypeOf(v2)!=FLOAT && TypeOf(v2)!=STR)) ==> + Py_mul(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + + +//Testing + +procedure Class1_init (name: Value, val: Value) returns (ret: Value) +spec { + requires [name_is_string]: TypeOf(name) == STR; + ensures [ret_is_class]: get_Class(ret) == Class_mk ("Class1", AttributeNames_cons("name", AttributeNames_cons("value", AttributeNames_nil()))); + ensures [get_name_eq]: get_attribute(ret, "name") == name; + ensures [get_name_eq]: get_attribute(ret, "value") == val; +} +{ + var c: Class; + inlined: { + c := Class_mk ("Class1", AttributeNames_cons("name", AttributeNames_cons("value", AttributeNames_nil()))); + ret := Value_class(ClassInstance_empty (c)); + ret := set_attribute(ret, "name", name); + ret := set_attribute(ret, "value", val);} +}; + +procedure Class2_init (name: Value, price: Value) returns (ret: Value) +spec { + requires [name_is_string]: TypeOf(name) == STR; + ensures [ret_is_class]: get_Class(ret) == Class_mk ("Class2", AttributeNames_cons("name", AttributeNames_cons("price", AttributeNames_nil()))); + ensures [get_name_eq]: get_attribute(ret, "name") == name; + ensures [get_name_eq]: get_attribute(ret, "price") == price; +} +{ + var c: Class; + c := Class_mk ("Class2", AttributeNames_cons("name", AttributeNames_cons("price", AttributeNames_nil()))); + ret := Value_class(ClassInstance_empty (c)); + ret := set_attribute(ret, "name", name); + ret := set_attribute(ret, "price", price); +}; + +procedure get_name(v: Value) returns (name: string) +spec { + requires [has_name]: hasAttribute(v, "name") && TypeOf(get_attribute(v,"name")) == STR; + ensures [name_eq]: get_attribute(v,"name") == Value_str(name); +} +{}; + +procedure class_test(i : int) returns () { + var v: Value, name: string; + if (i > 7) { + call v := Class1_init(Value_str("foo"), Value_int(2)); + } else { + if (i > 0) { + call v := Class2_init(Value_str("bar"), Value_float(2.2)); + } else { + v := Value_int (5); + } + } + assume [i_gt_0]: i >= 1; + call name:= get_name (v); + assert [name_eq]: name == "foo" || name == "bar"; +}; + + +#end + +#eval verify "cvc5" boogieTypePrelude + +def Boogie.prelude : Boogie.Program := + Boogie.getProgram Strata.boogieTypePrelude |>.fst + +end Strata diff --git a/StrataTest/Languages/Python/typepreludetests/BoogieTypeTestSimple.lean b/StrataTest/Languages/Python/typepreludetests/BoogieTypeTestSimple.lean new file mode 100644 index 000000000..9931d2dce --- /dev/null +++ b/StrataTest/Languages/Python/typepreludetests/BoogieTypeTestSimple.lean @@ -0,0 +1,514 @@ +/- + Copyright Strata Contributors + + SPDX-License-Identifier: Apache-2.0 OR MIT +-/ + +import Strata.DDM.Elab +import Strata.DDM.AST +import Strata.Languages.Boogie.DDMTransform.Parse +import Strata.Languages.Boogie.Verifier + +namespace Strata + +def boogieTypePrelude := +#strata +program Boogie; + +//Generic tag for List +type List_tag; +const CONS : List_tag; +const NIL : List_tag; +axiom [list_tag_unique]: CONS != NIL; + +//Will be merged with BoogiePrelude.lean +type Error; +function Error_message (s: string): Error; +type Error_tag; +const OK : Error_tag; +const ERR : Error_tag; +axiom [error_tag_unique]: OK != ERR; + +// Value and ListValue types +type Value; +type ListValue; + +// Class type +type Class; +type AttributeValues := Map string Value; +type ClassInstance; + +// Constructors +function Value_bool (b : bool) : Value; +function Value_int (i : int) : Value; +function Value_float (f : real) : Value; +function Value_str (s : string) : Value; +function Value_none() : Value; +function Value_exception (e : Error): Value; +function Value_list (lv : ListValue) : Value; +function Value_class (ci: ClassInstance) : Value; + +function ListValue_nil() : ListValue; +function ListValue_cons(x0 : Value, x1 : ListValue) : ListValue; +//Tags +function ListValue_tag (l: ListValue) : List_tag; +axiom [ListValue_tag_nil_def]: ListValue_tag (ListValue_nil()) == NIL; +axiom [ListValue_tag_cons_def]: forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} ListValue_tag (ListValue_cons(v, vs)) == CONS; + +// Types of Value +type ValueType; +type ListValueType; +const BOOL : ValueType; +const INT : ValueType; +const FLOAT : ValueType; +const STR : ValueType; +const NONE : ValueType; +const EXCEPTION : ValueType; +function ValueType_class(c: Class): ValueType; + +function isListValueType (t: ValueType): bool; +function isClassValueType (t: ValueType): bool; +axiom [isClassType_def]: forall c: Class :: {isClassValueType(ValueType_class(c))} isClassValueType(ValueType_class(c)); + +function isList (v: Value): bool; +function isClassInstance (v: Value): bool; + + +//Uniqueness axioms +axiom [unique_ValueType_bool]: BOOL != INT && BOOL != FLOAT && BOOL != STR && BOOL != NONE && BOOL != EXCEPTION && !isListValueType(BOOL) && !(isClassValueType(BOOL)); +axiom [unique_ValueType_int]: INT != STR && INT != FLOAT && INT != NONE && INT != EXCEPTION && !isListValueType(INT) && !(isClassValueType(INT)); +axiom [unique_ValueType_float]: FLOAT != STR && FLOAT != NONE && FLOAT != EXCEPTION && !isListValueType(FLOAT) && !(isClassValueType(FLOAT)); +axiom [unique_ValueType_str]: STR != NONE && STR != EXCEPTION && !isListValueType(STR) && !(isClassValueType(STR)); +axiom [unique_ValueType_none]: NONE != EXCEPTION && !isListValueType(NONE) && !(isClassValueType(NONE)); +axiom [unique_ValueType_exception]: !isListValueType(EXCEPTION) && !(isClassValueType(EXCEPTION)); +axiom [classtype_ne_listtype]: forall t: ValueType :: {isListValueType (t), isClassValueType (t)} !(isListValueType (t) && isClassValueType (t)); +axiom [all_ValueType_cases]: forall t: ValueType :: + t == BOOL || + t == INT || + t == FLOAT || + t == STR || + t == NONE || + t == EXCEPTION || + isListValueType (t) || + isClassValueType (t); + +//Eq axioms +axiom [value_int_eq]: forall i: int, j: int :: {Value_int(i) == Value_int(j)} (Value_int(i) == Value_int(j)) == (i == j); +axiom [value_bool_eq]: forall b1: bool, b2: bool :: {Value_bool(b1) == Value_bool(b2)} (Value_bool(b1) == Value_bool(b2)) == (b1 == b2); +axiom [value_float_eq]: forall r1: real, r2: real :: {Value_float(r1) == Value_float(r2)} (Value_float(r1) == Value_float(r2)) == (r1 == r2); +axiom [value_str_eq]: forall s1: string, s2: string :: {Value_str(s1) == Value_str(s2)} (Value_str(s1) == Value_str(s2)) == (s1 == s2); + +//Constructors and tag functions of ListType +function ListType_nil() : (ListValueType); +function ListType_cons(x0 : ValueType, x1 : ListValueType) : ListValueType; +function ValueType_List (l: ListValueType) : ValueType; +function ListValueType_tag (l: ListValueType) : List_tag; +axiom [ListValueType_tag_nil_def]: ListValueType_tag (ListType_nil()) == NIL; +axiom [ListValueType_tag_cons_def]: forall t: ValueType, ts: ListValueType ::{ListType_cons(t, ts)} (ListValueType_tag (ListType_cons(t, ts)) == CONS); +axiom [isListValueType_def]: forall l: ListValueType ::{isListValueType(ValueType_List (l))} isListValueType(ValueType_List (l)); + +// TypeOf and TypesOf functions +function TypeOf (v : Value) : ValueType; +function TypesOf (v: ListValue) : ListValueType; +// Definitions +axiom [TypesOf_nil_def]: TypesOf(ListValue_nil()) == ListType_nil(); +axiom [TypesOf_cons_def]: forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} TypesOf(ListValue_cons(v, vs)) == ListType_cons(TypeOf(v), TypesOf(vs)); +axiom [TypeOf_list_def]: forall l: ListValue ::{Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); +axiom [TypeOf_bool]: forall b: bool :: {TypeOf(Value_bool(b))} TypeOf(Value_bool(b)) == BOOL; +axiom [TypeOf_int]: forall i: int :: {Value_int(i)} TypeOf(Value_int(i)) == INT; +axiom [TypeOf_float]: forall f: real :: {Value_float(f)} TypeOf(Value_float(f)) == FLOAT; +axiom [TypeOf_str]: forall s: string :: {Value_str(s)} TypeOf(Value_str(s)) == STR; +axiom [TypeOf_exception]: forall e: Error :: {Value_exception(e)} TypeOf(Value_exception(e)) == EXCEPTION; +axiom [TypeOf_none]: TypeOf(Value_none()) == NONE; +axiom [TypeOf_list]: forall l: ListValue :: {Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); + +axiom [TypeOf_bool_exists]: forall v: Value :: {TypeOf(v) == BOOL} TypeOf(v) == BOOL ==> exists b: bool :: v == Value_bool(b); +axiom [TypeOf_int_exists]: forall v: Value :: {TypeOf(v) == INT} TypeOf(v) == INT ==> exists i: int :: v == Value_int(i); +axiom [TypeOf_float_exists]: forall v: Value :: {TypeOf(v) == FLOAT} TypeOf(v) == FLOAT ==> exists r: real :: v == Value_float(r); +axiom [TypeOf_string_exists]: forall v: Value :: {TypeOf(v) == STR} TypeOf(v) == STR ==> exists s: string :: v == Value_str(s); +axiom [TypeOf_exception_exists]: forall v: Value :: {TypeOf(v) == EXCEPTION} TypeOf(v) == EXCEPTION ==> exists e: Error :: v == Value_exception(e); +axiom [TypeOf_none']: forall v: Value :: {TypeOf(v) == NONE} (TypeOf(v) == NONE) == (v == Value_none()) ; +axiom [TypeOf_list_exists]: forall v: Value :: {isList(v)} isList(v) ==> exists l: ListValue :: v == Value_list(l); +axiom [TypeOf_class_exists]: forall v: Value :: {isClassInstance(v)} isClassInstance(v) ==> exists ci: ClassInstance :: v == Value_class(ci); + +axiom [isList_def]: forall l: ListValue :: {Value_list(l)} isList(Value_list(l)); +axiom [isList_def']: forall v: Value :: {isListValueType(TypeOf(v))} isList(v) == isListValueType(TypeOf(v)); +axiom [isClassInstance_def]: forall ci: ClassInstance :: {Value_class(ci)} isClassInstance(Value_class(ci)); +axiom [isClassInstance_def']: forall v: Value :: {isClassValueType(TypeOf(v))} isClassInstance(v) == isClassValueType(TypeOf(v)); + +// isSubType functions +function isSubType (t1: ValueType, t2: ValueType) : bool; +function isSubTypes (t1: ListValueType, t2: ListValueType) : bool; +//Definitions +axiom [isSubTypes_nil_def]: isSubTypes(ListType_nil(), ListType_nil()); +axiom [not_isSubTypes_nil]: forall ty: ValueType, l: ListValueType :: !isSubTypes(ListType_nil(), ListType_cons(ty,l)); +axiom [not_isSubTypes_nil']: forall ty: ValueType, l: ListValueType :: !isSubTypes(ListType_cons(ty,l), ListType_nil()); +axiom [isSubTypes_cons_def]:forall t: ValueType, ts: ListValueType, t': ValueType, ts': ListValueType ::{ListType_cons(t, ts), ListType_cons(t', ts')} + isSubTypes(ListType_cons(t, ts), ListType_cons(t', ts')) == (isSubType(t, t') && isSubTypes(ts, ts')); +axiom [isSubType_list_def]: forall l: ListValueType, l': ListValueType :: {ValueType_List(l), ValueType_List(l')} + isSubType(ValueType_List(l), ValueType_List(l')) == isSubTypes(l, l'); +axiom [bool_substype_int]: isSubType(BOOL, INT); +axiom [int_substype_float]: isSubType(INT, FLOAT); +axiom [not_isSubstype_string]: forall t: ValueType ::{isSubType(STR, t), isSubType(t,STR)} + t == STR || (!isSubType(STR, t) && !isSubType(t,STR)); +axiom [not_isSubstype_none]: forall t: ValueType ::{isSubType(NONE, t), isSubType(NONE, t)} + t == NONE || (!isSubType(NONE, t) && !isSubType(t,NONE)); +axiom [not_isSubstype_exception]: forall t: ValueType ::{isSubType(EXCEPTION, t), isSubType(t, EXCEPTION)} + t == EXCEPTION || (!isSubType(EXCEPTION, t) && !isSubType(t, EXCEPTION)); +axiom [not_isSubstype_list]: forall t: ValueType, t': ValueType ::{isSubType(t, t')} + ((isListValueType(t) && !isListValueType(t')) || (!isListValueType(t) && isListValueType(t'))) ==> (!isSubType(t, t') && !isSubType(t', t)); +axiom [not_isSubstype_class_othertypes]: forall t: ValueType, t': ValueType ::{isSubType(t, t')} + ((isClassValueType(t) && !isClassValueType(t')) || (!isClassValueType(t) && isClassValueType(t'))) ==> (!isSubType(t, t') && !isSubType(t', t)); +axiom [not_isSubstype_class]: forall t: ValueType, c: Class ::{isSubType(ValueType_class(c), t), isSubType(t,ValueType_class(c))} + t != ValueType_class(c) ==> (!isSubType(ValueType_class(c), t) && !isSubType(t,ValueType_class(c))); +// Supporting lemmas +axiom [isSubtype_rfl]: forall t: ValueType::{isSubType (t,t)} isSubType (t,t); +axiom [isSubtype_mono]: forall t1: ValueType, t2: ValueType ::{isSubType (t1,t2)} !isSubType (t1,t2) || (t1 == t2 || !isSubType(t2,t1)); +axiom [isSubtype_trans]: forall t1: ValueType, t2: ValueType, t3: ValueType::{isSubType(t1, t2)} !(isSubType(t1, t2) && isSubType(t2, t3)) || isSubType(t1, t3); + +// isInstance function: +function isInstance (v: Value, vt: ValueType) : bool; +axiom [isInstance_of_isSubtype]: forall v: Value, t: ValueType::{isInstance(v,t)} isInstance(v,t) == isSubType(TypeOf(v), t); + +function is_IntReal (v: Value) : bool; +function Value_real_to_int (v: Value) : int; +// to be extended +function normalize_value (v : Value) : Value { + if v == Value_bool(true) then Value_int(1) + else (if v == Value_bool(false) then Value_int(0) else + if TypeOf(v) == FLOAT && is_IntReal(v) then Value_int(Value_real_to_int(v)) else + v) +} + +// ListValue functions +function List_contains (l : ListValue, x: Value) : bool; +function List_len (l : ListValue) : int; +function List_extend (l1 : ListValue, l2: ListValue) : ListValue; +function List_append (l: ListValue, x: Value) : ListValue; +function List_index (l : ListValue, i : int) : Value; +function List_reverse (l: ListValue) : ListValue; + +//List function axioms +axiom [List_contains_nil_def]: forall x : Value ::{List_contains(ListValue_nil(), x)} + !List_contains(ListValue_nil(), x); +axiom [List_contains_cons_def]: forall x : Value, h : Value, t : ListValue ::{List_contains(ListValue_cons(h,t),x)} + List_contains(ListValue_cons(h,t),x) == ((normalize_value(x)==normalize_value(h)) || List_contains(t, x)); +axiom [List_len_nil_def]: List_len (ListValue_nil()) == 0; +axiom [List_len_cons_def]: forall h : Value, t : ListValue ::{List_len (ListValue_cons(h,t))} + List_len (ListValue_cons(h,t)) == 1 + List_len(t); +axiom [List_len_nonneg]: forall l: ListValue :: {List_len(l)} List_len(l) >= 0 ; +axiom [List_extend_nil_def]: forall l1: ListValue ::{List_extend (l1, ListValue_nil())} + List_extend (l1, ListValue_nil()) == l1; +axiom [List_nil_extend_def]: forall l1: ListValue ::{List_extend (ListValue_nil(), l1)} + List_extend (ListValue_nil(), l1) == l1; +axiom [List_cons_extend_def]: forall h: Value, t: ListValue, l2: ListValue ::{List_extend (ListValue_cons(h,t), l2)} + List_extend (ListValue_cons(h,t), l2) == ListValue_cons(h, List_extend(t,l2)); +axiom [List_cons_extend_contains]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} + List_contains (List_extend(l1,l2), x) == List_contains (l1,x) || List_contains(l2,x); +axiom [List_cons_extend_contains_symm]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} + List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x); +axiom [List_len_extend]: forall l1: ListValue, l2: ListValue ::{List_len (List_extend(l1,l2))} + List_len (List_extend(l1,l2)) == List_len (l1) + List_len(l2); +axiom [List_index_nil]: forall i : int ::{List_index (ListValue_nil(), i)} + List_index (ListValue_nil(), i) == Value_exception(Error_message("index out of bound")); +axiom [List_index_zero]: forall h : Value, t : ListValue ::{List_index (ListValue_cons(h,t), 0)} + List_index (ListValue_cons(h,t), 0) == h; +axiom [List_index_ind]: forall h : Value, t : ListValue, i : int ::{List_index (ListValue_cons(h,t), i)} + (i > 0) ==> (List_index (ListValue_cons(h,t), i)) == List_index (t, i - 1); +axiom [List_index_contains]: forall l: ListValue, i: int, x: Value :: {List_contains(l,x), List_index(l,i)} + (List_index(l,i) == x) ==> List_contains(l,x); +axiom [List_index_ok]: forall l: ListValue, i: int:: {List_index(l,i)} + ((List_index(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l) && i >= 0); +axiom [List_extend_get_shift]: forall l1: ListValue, l2: ListValue, i: int :: {List_extend(l2,l1)} + List_index(l1, i) == List_index(List_extend(l2,l1), i + List_len(l2)); +axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: {List_extend(List_extend(l1,l2), l3)} + List_extend(List_extend(l1,l2), l3) == List_extend(l1,List_extend(l2,l3)); +axiom [List_append_def]: forall l: ListValue, x: Value :: {List_append(l,x)} + List_append(l,x) == List_extend(l, ListValue_cons(x, ListValue_nil())); +axiom [List_reverse_def_nil]: List_reverse(ListValue_nil()) == ListValue_nil(); +axiom [List_reverse_def_cons]: forall h: Value, t: ListValue:: {List_reverse(ListValue_cons(h,t))} + List_reverse(ListValue_cons(h,t)) == List_append(List_reverse(t), h); +axiom [List_reverse_len]: forall l: ListValue :: {List_len(List_reverse(l))} + List_len(l) == List_len(List_reverse(l)); +axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (List_reverse(l), v)} + List_contains (List_reverse(l), v) == List_contains(l,v); +axiom [List_reverse_index]: forall l: ListValue, i: int :: {List_index(List_reverse(l), i)} + List_index(List_reverse(l), i) == List_index(l, List_len(l)-1-i); +axiom [List_reverse_extend]: forall l1: ListValue, l2: ListValue :: {List_reverse(List_extend(l1,l2))} + List_reverse(List_extend(l1,l2)) == List_extend(List_reverse(l2), List_reverse(l1)); + +// Dict type +type Dict := Map Value Value; + +//Dictionary functions +function Dict_empty() : Dict; +function Dict_insert (d: Dict, k: Value, v: Value) : Dict; +function Dict_get (d: Dict, k: Value) : Value; +function Dict_remove (d: Dict, k: Value) : Dict; +function Dict_contains (d: Dict, k: Value) : bool; + +//Dictionary axioms +axiom [emptydict_def]: forall k: Value :: {Dict_empty() [k]} Dict_empty() [k] == Value_none(); +axiom [Dict_get_def]: forall d: Dict, k: Value :: {Dict_get(d,k)} Dict_get(d,k) == d[normalize_value(k)]; +axiom [Dict_insert_def]: forall d: Dict, k: Value, v: Value :: {Dict_insert(d,k,v)} Dict_insert(d,k,v) == d[normalize_value(k):= v]; +axiom [Dict_remove_def]: forall d: Dict, k: Value :: {Dict_remove(d,k)} Dict_remove(d,k) == d[normalize_value(k):= Value_none()]; +axiom [Dict_contains_def]: forall d: Dict, k: Value :: {Dict_contains(d,k)} Dict_contains(d,k) == (Dict_get (d,k) != Value_none()); + +// List of pairs of Value, used to construct Dict +type DictList; +// Constructor +function DictList_nil(): DictList; +function DictList_cons(k: Value, v: Value, d: DictList): DictList; +//Tag and tag functions +function DictList_tag (dl: DictList) : List_tag; +axiom [DistListTag_nil_def]: DictList_tag (DictList_nil()) == NIL; +axiom [DistListTag_cons_def]: forall k: Value, v: Value, d: DictList ::{DictList_cons(k,v,d)} DictList_tag (DictList_cons(k,v,d)) == CONS; +// as a constructor for Dict +function Dict_from_DicList (l : DictList) : Dict; +function Dict_from_DicList_rev (l : DictList, acc: Dict) : Dict; +axiom [Dict_from_DicList_rev_nil]: forall acc: Dict :: Dict_from_DicList_rev(DictList_nil(), acc) == acc; +axiom [Dict_from_DicList_rev_cons]: forall k: Value, v: Value, d: DictList, acc: Dict :: + Dict_from_DicList_rev(DictList_cons(k,v,d), acc) == Dict_from_DicList_rev(d,Dict_insert(acc, k, v)); +axiom [Dict_from_DicList_def]: forall dl: DictList:: {Dict_from_DicList(dl)} + Dict_from_DicList(dl) == Dict_from_DicList_rev(dl, Dict_empty()); + +type AttributeNames; +function AttributeNames_nil() : (AttributeNames); +function AttributeNames_cons(x0 : string, x1 : AttributeNames) : (AttributeNames); +function AttributeNames_tag (f: AttributeNames) : List_tag; +function AttributeNames_contains (l : AttributeNames, x: string) : bool; +function AttributeNames_len (l : AttributeNames) : int; +function AttributeNames_index (l : AttributeNames, i : int) : string; +function AttributeName_to_index (l : AttributeNames, f: string) : int; + +axiom [AttributeNames_len_nil_def]: AttributeNames_len (AttributeNames_nil()) == 0; +axiom [AttributeNames_len_cons_def]: forall h : string, t : AttributeNames ::{AttributeNames_len (AttributeNames_cons(h,t))} + AttributeNames_len (AttributeNames_cons(h,t)) == 1 + AttributeNames_len(t); +axiom [AttributeNames_tag_nil_def]: AttributeNames_tag(AttributeNames_nil()) == NIL; +axiom [AttributeNames_tag_cons_def]: forall h : string, t : AttributeNames ::{} AttributeNames_tag (AttributeNames_cons(h,t)) == CONS; +axiom [AttributeNames_contains_nil_def]: (forall x : string ::{AttributeNames_contains(AttributeNames_nil(), x)} + !AttributeNames_contains(AttributeNames_nil(), x)); +axiom [AttributeNames_contains_cons_def]: forall x : string, h : string, t : AttributeNames ::{AttributeNames_contains(AttributeNames_cons(h,t),x)} + AttributeNames_contains(AttributeNames_cons(h,t),x) == ((x==h) || AttributeNames_contains(t,x)); +axiom [AttributeNames_len_nonneg]: forall l: AttributeNames :: {AttributeNames_len(l)} AttributeNames_len(l) >= 0; +axiom [AttributeNames_index_nil]: forall i : int ::{AttributeNames_index (AttributeNames_nil(), i)} (AttributeNames_index (AttributeNames_nil(), i)) == ""; +axiom [AttributeNames_index_zero]: forall h : string, t : AttributeNames ::{AttributeNames_index (AttributeNames_cons(h,t), 0)} + AttributeNames_index (AttributeNames_cons(h,t), 0) == h; +axiom [AttributeNames_index_ind]: forall h : string, t : AttributeNames, i : int ::{AttributeNames_index (AttributeNames_cons(h,t), i)} + (i > 0) ==> (AttributeNames_index (AttributeNames_cons(h,t), i)) == AttributeNames_index (t, i - 1); +axiom [AttributeNames_index_contains]: forall l: AttributeNames, i: int, x: string :: {AttributeNames_index(l,i), AttributeNames_contains(l,x)} + (AttributeNames_index(l,i) == x) ==> AttributeNames_contains(l,x); +axiom [AttributeNames_index_ok]: forall l: AttributeNames, i: int:: {AttributeNames_index(l,i)} + ((AttributeNames_index(l,i)) != "") == (i < AttributeNames_len(l)); +axiom [AttributeName_to_index_nil_def]: forall f: string :: {AttributeName_to_index(AttributeNames_nil(), f)} + AttributeName_to_index(AttributeNames_nil(), f) == 0; +axiom [AttributeName_to_index_cons_def_1]: forall h: string, t: AttributeNames :: {AttributeName_to_index(AttributeNames_cons(h,t), h)} + AttributeName_to_index(AttributeNames_cons(h,t), h) == 0; +axiom [AttributeName_to_index_cons_def_2]: forall f: string, h: string, t: AttributeNames :: {AttributeName_to_index(AttributeNames_cons(h,t), f)} + !(h == f) ==> AttributeName_to_index(AttributeNames_cons(h,t), f) == AttributeName_to_index(t, f) + 1; + +function Class_mk (name: string, attributes: AttributeNames): Class; +function Class_attributes (c: Class) : AttributeNames; +function Class_name (c: Class): string; +axiom [Class_attributes_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} + Class_attributes(Class_mk (name, attributes)) == attributes; +axiom [Class_name_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} + Class_name(Class_mk (name, attributes)) == name; +axiom [Class_eq_def]: forall c: Class, c': Class :: {c == c'} + (c == c') == (Class_name(c) == Class_name(c')); + +function Class_hasAttribute (c: Class, attribute: string): bool; +axiom [Class_hasAttribute_def]: forall c: Class, attribute: string :: {Class_hasAttribute(c, attribute)} + Class_hasAttribute(c, attribute) == AttributeNames_contains(Class_attributes(c), attribute); + +function Class_err() : Class; +axiom [Class_err_attributes_def]: Class_attributes(Class_err()) == AttributeNames_nil(); + +function AttributeValues_empty (c: Class) : AttributeValues; +axiom [AttributeValues_empty_def_valid]: forall c: Class, attribute: string :: {AttributeValues_empty(c)[attribute]} + Class_hasAttribute(c, attribute) ==> AttributeValues_empty(c)[attribute] == Value_none(); +axiom [AttributeValues_empty_def_invalid]: forall c: Class, attribute: string :: {AttributeValues_empty(c)[attribute]} + !Class_hasAttribute(c, attribute) ==> AttributeValues_empty(c)[attribute] == Value_exception(Error_message("Invalid Attribute of Class")); + +function AttributeValues_err () : AttributeValues; +axiom [AttributeValues_err_def]: forall attribute: string :: {AttributeValues_err[attribute]} + AttributeValues_err()[attribute] == Value_exception(Error_message("Error ClassInstance")); + +function ClassInstance_mk (c: Class, av: AttributeValues) : ClassInstance; + +function ClassInstance_getAttributeValues (ci: ClassInstance) : AttributeValues; +axiom [getAttributeValues_def]: forall c: Class, av: AttributeValues :: { ClassInstance_getAttributeValues(ClassInstance_mk (c, av))} + ClassInstance_getAttributeValues(ClassInstance_mk (c, av)) == av; + +function ClassInstance_getClass (ci: ClassInstance) : Class; +axiom [get_Class_def]: forall c: Class, av: AttributeValues :: {ClassInstance_getClass(ClassInstance_mk (c, av))} + ClassInstance_getClass(ClassInstance_mk (c, av)) == c; + +axiom [TypeOf_class]: forall ci: ClassInstance :: {TypeOf(Value_class(ci))} TypeOf(Value_class(ci)) == ValueType_class(ClassInstance_getClass(ci)); + +function ClassInstance_empty (c: Class) : ClassInstance; +axiom [ClassInstance_mk_empty_get_attributevalues]: forall c: Class :: {ClassInstance_getAttributeValues(ClassInstance_empty (c))} + ClassInstance_getAttributeValues(ClassInstance_empty (c)) == AttributeValues_empty(c); +axiom [ClassInstance_mk_empty_get_class]: forall c: Class :: {ClassInstance_getClass(ClassInstance_empty (c))} + ClassInstance_getClass(ClassInstance_empty (c)) == c; + +function ClassInstance_err (err: string) : ClassInstance; +function ClassInstance_errortag (ci: ClassInstance): Error_tag; +axiom [ClassInstance_err_tag]: forall err: string :: {ClassInstance_errortag(ClassInstance_err(err))} + ClassInstance_errortag(ClassInstance_err(err)) == ERR; +axiom [ClassInstance_err_get_class_def]: forall err: string :: {ClassInstance_getClass(ClassInstance_err(err)) } + ClassInstance_getClass(ClassInstance_err(err)) == Class_err(); +axiom [ClassInstance_err_get_attributevalues_def]: forall err: string :: {ClassInstance_getAttributeValues(ClassInstance_err (err))} + ClassInstance_getAttributeValues(ClassInstance_err (err)) == AttributeValues_err(); + +function ClassInstance_get_attribute(ci: ClassInstance, attribute: string) : Value; +axiom [ClassInstance_get_attribute_def]: forall ci: ClassInstance, attribute: string ::{ClassInstance_get_attribute(ci, attribute)} + ClassInstance_get_attribute(ci, attribute) == ClassInstance_getAttributeValues(ci)[attribute]; + +function ClassInstance_set_attribute (ci: ClassInstance, attribute: string, value: Value): ClassInstance; +axiom [ClassInstance_set_attribute_def]: forall ci: ClassInstance, attribute: string, v: Value:: {ClassInstance_set_attribute(ci, attribute, v)} + ClassInstance_set_attribute(ci, attribute, v) == if Class_hasAttribute(ClassInstance_getClass(ci), attribute) then + ClassInstance_mk(ClassInstance_getClass(ci), ClassInstance_getAttributeValues(ci)[attribute:=v]) + else ClassInstance_err("Set value for invalid"); + +function get_ClassInstance (v: Value) : ClassInstance; +axiom [get_ClassInstance_valid]: forall ci: ClassInstance :: {get_ClassInstance(Value_class(ci))} + get_ClassInstance(Value_class(ci)) == ci; +axiom [get_ClassInstance_invalid]: forall v: Value :: {get_ClassInstance(v)} + !isClassInstance(v) ==> get_ClassInstance(v) == ClassInstance_err ("Not of Class type"); + +function get_attribute(v: Value, attribute: string) : Value; +axiom [get_attribute_def]: forall v: Value, attribute: string ::{get_attribute(v, attribute)} + get_attribute(v, attribute) == if isClassInstance(v) then + ClassInstance_get_attribute(get_ClassInstance(v), attribute) + else Value_exception(Error_message("Not of Class type")); + +function set_attribute(v: Value, attribute: string, v': Value) : Value; +axiom [set_attribute_def]: forall v: Value, attribute: string, v': Value ::{set_attribute(v, attribute, v')} + set_attribute(v, attribute, v') == if isClassInstance(v) then + Value_class(ClassInstance_set_attribute(get_ClassInstance(v), attribute, v')) + else Value_exception(Error_message("Not of Class type")); + +function get_Class (v: Value) : Class { + ClassInstance_getClass(get_ClassInstance (v)) +} + +function hasAttribute(v: Value, attribute: string): bool { + Class_hasAttribute (get_Class(v), attribute) +} + +//Binary op function +function int_to_real (i: int) : real; +function str_repeat (s: string, i: int) : string; +function Py_add (v1: Value, v2: Value) : Value; +function Py_sub (v1: Value, v2: Value) : Value; +function Py_mul (v1: Value, v2: Value) : Value; +inline function bool_to_int (b: bool) : int {if b then 1 else 0} +inline function bool_to_real (b: bool) : real {if b then 1.0 else 0.0} + +axiom [Py_add_ints]: forall i1: int, i2: int :: {Py_add(Value_int(i1), Value_int(i2))} + Py_add(Value_int(i1), Value_int(i2)) == Value_int(i1 + i2); +axiom [Py_add_floats]: forall f1: real, f2: real :: {Py_add(Value_float(f1), Value_float(f2))} + Py_add(Value_float(f1), Value_float(f2)) == Value_float(f1 + f2); +axiom [Py_add_bools]: forall b1: bool, b2: bool :: {Py_add(Value_bool(b1), Value_bool(b2))} + Py_add(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) + bool_to_int(b2)); +axiom [Py_add_int_bool]: forall i: int, b: bool :: {Py_add(Value_int(i), Value_bool(b))} + Py_add(Value_int(i), Value_bool(b)) == Value_int(i + bool_to_int(b)); +axiom [Py_add_bool_int]: forall b: bool, i: int :: {Py_add(Value_bool(b), Value_int(i))} + Py_add(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) + i); +axiom [Py_add_int_float]: forall i: int, r: real :: {Py_add(Value_int(i), Value_float(r))} + Py_add(Value_int(i), Value_float(r)) == Value_float(r + int_to_real(i)); +axiom [Py_add_float_int]: forall r: real, i: int :: {Py_add(Value_float(r), Value_int(i))} + Py_add(Value_float(r), Value_int(i)) == Value_float(int_to_real(i) + r); +axiom [Py_add_float_bool]: forall r: real, b: bool :: {Py_add(Value_float(r), Value_bool(b))} + Py_add(Value_float(r), Value_bool(b)) == Value_float(r + bool_to_real(b)); +axiom [Py_add_bool_float]: forall b: bool, r: real :: {Py_add(Value_bool(b), Value_float(r))} + Py_add(Value_bool(b), Value_float(r)) == Value_float(bool_to_real(b) + r); +axiom [Py_add_strs]:forall s1: string, s2: string :: {Py_add(Value_str(s1), Value_str(s2))} + Py_add(Value_str(s1), Value_str(s2)) == Value_str(str.concat(s1, s2)); +axiom [Py_add_str_int]: forall s: string, i: int :: {Py_add(Value_str(s), Value_int(i))} + Py_add(Value_str(s), Value_int(i)) == Value_exception(Error_message("Cannot add string to int")); +axiom [Py_add_int_str]: forall s: string, i: int :: {Py_add(Value_int(i), Value_str(s)) } + Py_add(Value_int(i), Value_str(s)) == Value_exception(Error_message("Cannot add string to int")); +axiom [Py_add_str_bool]: forall s: string, b: bool :: {Py_add(Value_str(s), Value_bool(b))} + Py_add(Value_str(s), Value_bool(b)) == Value_exception(Error_message("Cannot add string to bool")); +axiom [Py_add_bool_str]: forall s: string, b: bool :: {Py_add(Value_bool(b), Value_str(s))} + Py_add(Value_bool(b), Value_str(s)) == Value_exception(Error_message("Cannot add bool to string")); +axiom [Py_add_unsupport]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} + ((TypeOf(v1)!=BOOL && TypeOf(v1)!=INT && TypeOf(v1)!=FLOAT && TypeOf(v1)!=STR) || + (TypeOf(v2)!=BOOL && TypeOf(v2)!=INT && TypeOf(v2)!=FLOAT && TypeOf(v2)!=STR)) ==> + Py_add(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + +axiom [Py_mul_ints]: forall i1: int, i2: int :: {Py_mul(Value_int(i1), Value_int(i2))} + Py_mul(Value_int(i1), Value_int(i2)) == Value_int(i1 * i2); +axiom [Py_mul_bools]: forall b1: bool, b2: bool :: {Py_mul(Value_bool(b1), Value_bool(b2))} + Py_mul(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) * bool_to_int(b2)); +axiom [Py_mul_int_bool]: forall i: int, b: bool :: {Py_mul(Value_int(i), Value_bool(b))} + Py_mul(Value_int(i), Value_bool(b)) == Value_int(i * bool_to_int(b)); +axiom [Py_mul_bool_int]: forall b: bool, i: int :: {Py_mul(Value_bool(b), Value_int(i))} + Py_mul(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) * i); +axiom [Py_mul_str]: forall s1: string, s2: string :: {Py_mul(Value_str(s1), Value_str(s2))} + Py_mul(Value_str(s1), Value_str(s2)) == Value_exception(Error_message("Cannot multiply two strings")); +axiom [Py_mul_str_int]: forall s: string, i: int :: {Py_mul(Value_str(s), Value_int(i))} + Py_mul(Value_str(s), Value_int(i)) == Value_str(str_repeat(s, i)); +axiom [Py_mul_int_str]: forall s: string, i: int :: {Py_mul(Value_int(i), Value_str(s))} + Py_mul(Value_int(i), Value_str(s)) == Value_str(str_repeat(s, i)); +axiom [Py_mul_str_bool]: forall s: string, b: bool :: {Py_mul(Value_str(s), Value_bool(b))} + Py_mul(Value_str(s), Value_bool(b)) == Value_str(if b then s else ""); +axiom [Py_mul_bool_str]: forall s: string, b: bool :: {Py_mul(Value_bool(b), Value_str(s)) } + Py_mul(Value_bool(b), Value_str(s)) == Value_str(if b then s else ""); +axiom [Py_mul_unsupport]: forall v1: Value, v2: Value :: {Py_mul(v1,v2)} + ((TypeOf(v1)!=BOOL && TypeOf(v1)!=INT && TypeOf(v1)!=FLOAT && TypeOf(v1)!=STR) || + (TypeOf(v2)!=BOOL && TypeOf(v2)!=INT && TypeOf(v2)!=FLOAT && TypeOf(v2)!=STR)) ==> + Py_mul(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + + +//Testing + +procedure simple_add () returns () { + var x: Value, y: Value, z: Value, b: bool; + havoc b; + if (b) { + x := Value_int(1); + } + else { + x := Value_float(1.1); + } + y:= Py_add(x, Value_int(2)); + assert [y_not_exception]: TypeOf(y)!= EXCEPTION; + assert [if_b_then_y_int]: b ==> TypeOf(y)== INT; + assert [x_y_same_type]: TypeOf(x) == TypeOf(y); + assert [y_is_instance_float]: isInstance(y,FLOAT); + assert [y_is_instance_int]: isInstance(y,INT); + z:= Py_add(x, Value_float(3.3)); + assert [x_z_same_type]: TypeOf(x) == TypeOf(z); + assert [y_z_same_type]: (TypeOf(y) == TypeOf(z)) ==> !b; +}; + +procedure simple_add' (b: bool) returns (y: Value, z: Value) +spec { + ensures [ens_y_not_exception]: TypeOf(y)!= EXCEPTION; + ensures [ens_if_b_then_y_int]: b ==> TypeOf(y)== INT; + ensures [ens_y_z_same_type]: TypeOf(y) == TypeOf(z); + ensures [ens_y_z_same_type']: (TypeOf(y) == TypeOf(z)) ==> !b; +} +{ + var x: Value; + if (b) { + x := Value_int(1); + } + else { + x := Value_float(1.1); + } + y:= Py_add(x, Value_int(2)); + z:= Py_add(x, Value_float(3.3)); +}; + +#end + +#eval verify "cvc5" boogieTypePrelude + +def Boogie.prelude : Boogie.Program := + Boogie.getProgram Strata.boogieTypePrelude |>.fst + +end Strata From 43c9593fe6520f176c0301f71d86a465a4e4ac70 Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Mon, 29 Dec 2025 12:54:56 -0800 Subject: [PATCH 11/13] remove Value_exception, replace by Except --- .../Languages/Python/BoogieTypePrelude.lean | 697 +++++++++++------- 1 file changed, 414 insertions(+), 283 deletions(-) diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean index 1f990abfa..b9a71de68 100644 --- a/Strata/Languages/Python/BoogieTypePrelude.lean +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -22,22 +22,96 @@ const NIL : List_tag; axiom [list_tag_unique]: CONS != NIL; axiom [all_list_tag]: forall lt: List_tag :: lt == CONS || lt == NIL; -//Will be merged with BoogiePrelude.lean type Error; -function Error_message (s: string): Error; + +// Constructors +function Error_TypeError (msg : string) : Error; +function Error_AttributeError (msg : string) : Error; +function Error_RePatternError (msg : string) : Error; +function Error_Unimplemented (msg : string) : Error; +function Error_Undefined (msg : string) : Error; + type Error_tag; -const OK : Error_tag; -const ERR : Error_tag; -axiom [error_tag_unique]: OK != ERR; -axiom [all_error_tag]: forall et: Error_tag :: et == OK || et == ERR; +const TYPEERR : Error_tag; +const ATRERR : Error_tag; +const REERR : Error_tag; +const UNIMPLERR : Error_tag; +const UNDEFERR : Error_tag; +axiom [error_tag_unique]: TYPEERR != ATRERR && TYPEERR != REERR && TYPEERR != UNIMPLERR && TYPEERR != UNDEFERR && + ATRERR != REERR && ATRERR != UNIMPLERR && ATRERR != UNDEFERR && + REERR != UNIMPLERR && REERR != UNDEFERR && + UNIMPLERR != UNDEFERR ; + +axiom [all_error_tag]: forall et: Error_tag :: et == TYPEERR || et == ATRERR || et == REERR || et == UNIMPLERR || et == UNDEFERR; + +function ErrorTag (e: Error) : Error_tag; +axiom [ErrorTag_def_typeerr]: forall msg: string :: {ErrorTag(Error_TypeError(msg))} ErrorTag(Error_TypeError(msg)) == TYPEERR; +axiom [ErrorTag_def_attrerr]: forall msg: string :: {ErrorTag(Error_AttributeError(msg))} ErrorTag(Error_AttributeError(msg)) == ATRERR; +axiom [ErrorTag_def_reerr]: forall msg: string :: {ErrorTag(Error_RePatternError(msg))} ErrorTag(Error_RePatternError(msg)) == REERR; +axiom [ErrorTag_def_unimplerr]: forall msg: string :: {ErrorTag(Error_Unimplemented(msg))} ErrorTag(Error_Unimplemented(msg)) == UNIMPLERR; +axiom [ErrorTag_def_undeferr]: forall msg: string :: {ErrorTag(Error_Undefined(msg))} ErrorTag(Error_Undefined(msg)) == UNDEFERR; + +type Except_tag; +const OK : Except_tag; +const ERR : Except_tag; +axiom [except_tag_unique]: OK != ERR; +axiom [all_except_tag]: forall et: Except_tag :: et == OK || et == ERR; + +type stringExcept; +function stringExcept_ok (s: string): stringExcept; +function stringExcept_err (e: Error): stringExcept; +function stringExcept_tag (ie: stringExcept) : Except_tag; +axiom [stringExcept_tag_ok_def]: forall s: string :: {stringExcept_tag(stringExcept_ok(s))} + stringExcept_tag(stringExcept_ok(s)) == OK; +axiom [stringExcept_tag_err_def]: forall e: Error :: {stringExcept_tag(stringExcept_err(e))} + stringExcept_tag(stringExcept_err(e)) == ERR; +function stringExcept_unwrap (lie: stringExcept) : string; +axiom [stringExcept_unwrap_def]: forall s: string :: {stringExcept_tag(stringExcept_ok(s))} + stringExcept_unwrap(stringExcept_ok(s)) == s; + +type boolExcept; +function boolExcept_ok (b: bool): boolExcept; +function boolExcept_err (e: Error): boolExcept; +function boolExcept_tag (be: boolExcept) : Except_tag; +axiom [boolExcept_tag_ok_def]: forall b: bool :: {boolExcept_tag(boolExcept_ok(b))} + boolExcept_tag(boolExcept_ok(b)) == OK; +axiom [boolExcept_tag_err_def]: forall e: Error :: {boolExcept_tag(boolExcept_err(e))} + boolExcept_tag(boolExcept_err(e)) == ERR; +function boolExcept_unwrap (lie: boolExcept) : bool; +axiom [boolExcept_unwrap_def]: forall b: bool :: {boolExcept_tag(boolExcept_ok(b))} + boolExcept_unwrap(boolExcept_ok(b)) == b; + +type intExcept; +function intExcept_ok (i: int): intExcept; +function intExcept_err (e: Error): intExcept; +function intExcept_tag (ie: intExcept) : Except_tag; +axiom [intExcept_tag_ok_def]: forall i: int :: {intExcept_tag(intExcept_ok(i))} + intExcept_tag(intExcept_ok(i)) == OK; +axiom [intExcept_tag_err_def]: forall e: Error :: {intExcept_tag(intExcept_err(e))} + intExcept_tag(intExcept_err(e)) == ERR; +function intExcept_unwrap (lie: intExcept) : int; +axiom [intExcept_unwrap_def]: forall i: int :: {intExcept_tag(intExcept_ok(i))} + intExcept_unwrap(intExcept_ok(i)) == i; + // Value and ListValue types type Value; type ListValue; +type ValueExcept; +function ValueExcept_ok (v: Value): ValueExcept; +function ValueExcept_err (e: Error): ValueExcept; +function ValueExcept_tag (ve: ValueExcept) : Except_tag; +axiom [ValueExcept_tag_ok_def]: forall v: Value :: {ValueExcept_tag(ValueExcept_ok(v))} + ValueExcept_tag(ValueExcept_ok(v)) == OK; +axiom [ValueExcept_tag_err_def]: forall e: Error :: {ValueExcept_tag(ValueExcept_err(e))} + ValueExcept_tag(ValueExcept_err(e)) == ERR; +function ValueExcept_unwrap (lve: ValueExcept) : Value; +axiom [ValueExcept_unwrap_def]: forall v: Value :: {ValueExcept_tag(ValueExcept_ok(v))} + ValueExcept_unwrap(ValueExcept_ok(v)) == v; + // Class type -type Class; -type AttributeValues := Map string Value; +type InstanceAttributes := Map string ValueExcept; type ClassInstance; // Constructors @@ -46,7 +120,6 @@ function Value_int (i : int) : Value; function Value_float (f : real) : Value; function Value_str (s : string) : Value; function Value_none() : Value; -function Value_exception (e : Error): Value; function Value_list (lv : ListValue) : Value; function Value_class (ci: ClassInstance) : Value; @@ -65,24 +138,22 @@ const INT : ValueType; const FLOAT : ValueType; const STR : ValueType; const NONE : ValueType; -const EXCEPTION : ValueType; -function ValueType_class(c: Class): ValueType; +function ValueType_class(classname: string): ValueType; function isListValueType (t: ValueType): bool; function isClassValueType (t: ValueType): bool; -axiom [isClassType_def]: forall c: Class :: {isClassValueType(ValueType_class(c))} isClassValueType(ValueType_class(c)); +axiom [isClassType_def]: forall c: string :: {isClassValueType(ValueType_class(c))} isClassValueType(ValueType_class(c)); function isList (v: Value): bool; function isClassInstance (v: Value): bool; //Uniqueness axioms -axiom [unique_ValueType_bool]: BOOL != INT && BOOL != FLOAT && BOOL != STR && BOOL != NONE && BOOL != EXCEPTION && !isListValueType(BOOL) && !(isClassValueType(BOOL)); -axiom [unique_ValueType_int]: INT != STR && INT != FLOAT && INT != NONE && INT != EXCEPTION && !isListValueType(INT) && !(isClassValueType(INT)); -axiom [unique_ValueType_float]: FLOAT != STR && FLOAT != NONE && FLOAT != EXCEPTION && !isListValueType(FLOAT) && !(isClassValueType(FLOAT)); -axiom [unique_ValueType_str]: STR != NONE && STR != EXCEPTION && !isListValueType(STR) && !(isClassValueType(STR)); -axiom [unique_ValueType_none]: NONE != EXCEPTION && !isListValueType(NONE) && !(isClassValueType(NONE)); -axiom [unique_ValueType_exception]: !isListValueType(EXCEPTION) && !(isClassValueType(EXCEPTION)); +axiom [unique_ValueType_bool]: BOOL != INT && BOOL != FLOAT && BOOL != STR && BOOL != NONE && !isListValueType(BOOL) && !(isClassValueType(BOOL)); +axiom [unique_ValueType_int]: INT != STR && INT != FLOAT && INT != NONE && !isListValueType(INT) && !(isClassValueType(INT)); +axiom [unique_ValueType_float]: FLOAT != STR && FLOAT != NONE && !isListValueType(FLOAT) && !(isClassValueType(FLOAT)); +axiom [unique_ValueType_str]: STR != NONE && !isListValueType(STR) && !(isClassValueType(STR)); +axiom [unique_ValueType_none]: !isListValueType(NONE) && !(isClassValueType(NONE)); axiom [classtype_ne_listtype]: forall t: ValueType :: {isListValueType (t), isClassValueType (t)} !(isListValueType (t) && isClassValueType (t)); axiom [all_ValueType_cases]: forall t: ValueType :: t == BOOL || @@ -90,7 +161,6 @@ axiom [all_ValueType_cases]: forall t: ValueType :: t == FLOAT || t == STR || t == NONE || - t == EXCEPTION || isListValueType (t) || isClassValueType (t); @@ -120,7 +190,6 @@ axiom [TypeOf_bool]: forall b: bool :: {TypeOf(Value_bool(b))} TypeOf(Value_bool axiom [TypeOf_int]: forall i: int :: {Value_int(i)} TypeOf(Value_int(i)) == INT; axiom [TypeOf_float]: forall f: real :: {Value_float(f)} TypeOf(Value_float(f)) == FLOAT; axiom [TypeOf_str]: forall s: string :: {Value_str(s)} TypeOf(Value_str(s)) == STR; -axiom [TypeOf_exception]: forall e: Error :: {Value_exception(e)} TypeOf(Value_exception(e)) == EXCEPTION; axiom [TypeOf_none]: TypeOf(Value_none()) == NONE; axiom [TypeOf_list]: forall l: ListValue :: {Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); @@ -128,7 +197,6 @@ axiom [TypeOf_bool_exists]: forall v: Value :: {TypeOf(v) == BOOL} TypeOf(v) == axiom [TypeOf_int_exists]: forall v: Value :: {TypeOf(v) == INT} TypeOf(v) == INT ==> exists i: int :: v == Value_int(i); axiom [TypeOf_float_exists]: forall v: Value :: {TypeOf(v) == FLOAT} TypeOf(v) == FLOAT ==> exists r: real :: v == Value_float(r); axiom [TypeOf_string_exists]: forall v: Value :: {TypeOf(v) == STR} TypeOf(v) == STR ==> exists s: string :: v == Value_str(s); -axiom [TypeOf_exception_exists]: forall v: Value :: {TypeOf(v) == EXCEPTION} TypeOf(v) == EXCEPTION ==> exists e: Error :: v == Value_exception(e); axiom [TypeOf_none']: forall v: Value :: {TypeOf(v) == NONE} (TypeOf(v) == NONE) == (v == Value_none()) ; axiom [TypeOf_list_exists]: forall v: Value :: {isList(v)} isList(v) ==> exists l: ListValue :: v == Value_list(l); axiom [TypeOf_class_exists]: forall v: Value :: {isClassInstance(v)} isClassInstance(v) ==> exists ci: ClassInstance :: v == Value_class(ci); @@ -155,13 +223,11 @@ axiom [not_isSubstype_string]: forall t: ValueType ::{isSubType(STR, t), isSubTy t == STR || (!isSubType(STR, t) && !isSubType(t,STR)); axiom [not_isSubstype_none]: forall t: ValueType ::{isSubType(NONE, t), isSubType(NONE, t)} t == NONE || (!isSubType(NONE, t) && !isSubType(t,NONE)); -axiom [not_isSubstype_exception]: forall t: ValueType ::{isSubType(EXCEPTION, t), isSubType(t, EXCEPTION)} - t == EXCEPTION || (!isSubType(EXCEPTION, t) && !isSubType(t, EXCEPTION)); axiom [not_isSubstype_list]: forall t: ValueType, t': ValueType ::{isSubType(t, t')} ((isListValueType(t) && !isListValueType(t')) || (!isListValueType(t) && isListValueType(t'))) ==> (!isSubType(t, t') && !isSubType(t', t)); axiom [not_isSubstype_class_othertypes]: forall t: ValueType, t': ValueType ::{isSubType(t, t')} ((isClassValueType(t) && !isClassValueType(t')) || (!isClassValueType(t) && isClassValueType(t'))) ==> (!isSubType(t, t') && !isSubType(t', t)); -axiom [not_isSubstype_class]: forall t: ValueType, c: Class ::{isSubType(ValueType_class(c), t), isSubType(t,ValueType_class(c))} +axiom [not_isSubstype_class]: forall t: ValueType, c: string ::{isSubType(ValueType_class(c), t), isSubType(t,ValueType_class(c))} t != ValueType_class(c) ==> (!isSubType(ValueType_class(c), t) && !isSubType(t,ValueType_class(c))); // Supporting lemmas axiom [isSubtype_rfl]: forall t: ValueType::{isSubType (t,t)} isSubType (t,t); @@ -182,21 +248,32 @@ function normalize_value (v : Value) : Value { v) } +type ListValueExcept; +function ListValueExcept_ok (l: ListValue): ListValueExcept; +function ListValueExcept_err (e: Error): ListValueExcept; +function ListValueExcept_tag (lve: ListValueExcept) : Except_tag; +axiom [ListValueExcept_tag_ok_def]: forall l: ListValue :: {ListValueExcept_tag(ListValueExcept_ok(l))} + ListValueExcept_tag(ListValueExcept_ok(l)) == OK; +axiom [ListValueExcept_tag_err_def]: forall e: Error :: {ListValueExcept_tag(ListValueExcept_err(e))} + ListValueExcept_tag(ListValueExcept_err(e)) == ERR; +function ListValueExcept_unwrap (lve: ListValueExcept) : ListValue; +axiom [ListValueExcept_unwrap_def]: forall l: ListValue :: {ListValueExcept_tag(ListValueExcept_ok(l))} + ListValueExcept_unwrap(ListValueExcept_ok(l)) == l; + // ListValue functions function List_contains (l : ListValue, x: Value) : bool; function List_len (l : ListValue) : int; function List_extend (l1 : ListValue, l2: ListValue) : ListValue; function List_append (l: ListValue, x: Value) : ListValue; -function List_get (l : ListValue, i : int) : Value; +function List_get (l : ListValue, i : int) : ValueExcept; function List_reverse (l: ListValue) : ListValue; function List_index! (l: ListValue, v: Value): int; -function List_index (l: ListValue, v: Value): Value; +function List_index (l: ListValue, v: Value): intExcept; function List_repeat (l: ListValue, n: int): ListValue; function List_insert (l: ListValue, i: int, v: Value): ListValue; function List_remove (l: ListValue, v: Value): ListValue; //TO BE done -function List_pop (l: ListValue, i: int): ListValue; - +function List_pop (l: ListValue, i: int): ListValueExcept; //List function axioms axiom [List_contains_nil_def]: forall x : Value ::{List_contains(ListValue_nil(), x)} @@ -226,17 +303,19 @@ axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: List_extend(List_extend(l1,l2), l3) == List_extend(l1,List_extend(l2,l3)); axiom [List_get_nil]: forall i : int ::{List_get (ListValue_nil(), i)} - List_get (ListValue_nil(), i) == Value_exception(Error_message("index out of bound")); + List_get (ListValue_nil(), i) == ValueExcept_err(Error_Undefined("index out of bound")); axiom [List_get_zero]: forall h : Value, t : ListValue ::{List_get (ListValue_cons(h,t), 0)} - List_get (ListValue_cons(h,t), 0) == h; + List_get (ListValue_cons(h,t), 0) == ValueExcept_ok(h); axiom [List_get_ind]: forall h : Value, t : ListValue, i : int ::{List_get (ListValue_cons(h,t), i)} (i > 0) ==> (List_get (ListValue_cons(h,t), i)) == List_get (t, i - 1); axiom [List_get_contains]: forall l: ListValue, i: int, x: Value :: {List_contains(l,x), List_get(l,i)} - (List_get(l,i) == x && TypeOf(x)!= EXCEPTION) ==> List_contains(l,x); + (List_get(l,i) == ValueExcept_ok(x)) ==> List_contains(l,x); +axiom [List_get_contains_eq]: forall l: ListValue, x: Value :: {List_contains(l,x)} + List_contains(l,x) == (exists i:int :: {} List_get(l,i) == ValueExcept_ok(x)); axiom [List_get_ok]: forall l: ListValue, i: int:: {List_get(l,i)} - ((List_get(l,i)) != Value_exception(Error_message("index out of bound"))) == (i < List_len(l) && i >= 0); + ((List_get(l,i)) != ValueExcept_err(Error_Undefined("index out of bound"))) == (i < List_len(l) && i >= 0); axiom [List_get_ok']: forall l: ListValue, i: int:: {List_get(l,i)} - (TypeOf(List_get(l,i)) != EXCEPTION) == (i < List_len(l) && i >= 0); + (ValueExcept_tag(List_get(l,i)) != ERR) == (i < List_len(l) && i >= 0); axiom [List_extend_get]: forall l1: ListValue, l2: ListValue, i: int :: {List_get(List_extend(l1,l2), i)} List_get(List_extend(l1,l2), i) == if i < List_len(l1) then List_get(l1, i) else List_get(l2, i - List_len(l1)); @@ -264,14 +343,16 @@ axiom [List_index!_cons_def_1]: forall h: Value, t: ListValue :: {List_index!(Li axiom [List_index!_cons_def_2]: forall v: Value, h: Value, t: ListValue :: {List_index!(ListValue_cons(h,t), v)} !(normalize_value(v)==normalize_value(h)) ==> List_index!(ListValue_cons(h,t), v) == List_index!(t, v) + 1; axiom [List_index_def]: forall v: Value, l: ListValue :: {List_index(l, v)} - List_index(l,v) == if (List_index!(l,v) == List_len(l)) then Value_exception(Error_message("List does not contain element")) - else Value_int(List_index!(l,v)); + List_index(l,v) == if (List_index!(l,v) == List_len(l)) then intExcept_err(Error_Undefined("List does not contain element")) + else intExcept_ok(List_index!(l,v)); axiom [List_repeat_def]: forall l: ListValue, n: int :: {List_repeat(l, n)} List_repeat(l, n) == if (n <= 0) then ListValue_nil() else if (n == 1) then l else List_extend(l, List_repeat(l, n-1)); axiom [List_repeat_mul]: forall l: ListValue, n: int, m: int :: {List_repeat(List_repeat(l, n),m)} List_repeat(List_repeat(l, n),m) == List_repeat(l, n * m); +axiom [List_repeat_len]: forall l: ListValue, n: int :: {List_len(List_repeat(l, n))} + n > 0 ==> List_len(List_repeat(l, n)) == n * List_len(l); axiom [List_repeat_contain]: forall l: ListValue, v: Value, n: int :: {List_contains(List_repeat(l, n), v)} n > 0 ==> (List_contains(List_repeat(l, n), v) == List_contains(l, v)); axiom [List_repeat_get]: forall l: ListValue, v: Value, i: int, n: int, m: int :: {List_get(List_repeat(l, n), i + m * List_len(l))} @@ -280,33 +361,55 @@ axiom [List_repeat_get]: forall l: ListValue, v: Value, i: int, n: int, m: int : axiom [List_insert_def0]: forall i: int, v: Value :: {List_insert(ListValue_nil(), i, v)} List_insert(ListValue_nil(), i, v) == ListValue_cons(v, ListValue_nil()); axiom [List_insert_def1]: forall l: ListValue, i: int, v: Value :: {List_insert(l, i, v)} - List_insert(l, 0, v) == ListValue_cons(v, l); + i <= 0 ==> List_insert(l, i, v) == ListValue_cons(v, l); axiom [List_insert_def2]: forall h: Value, t: ListValue, i: int, v: Value :: {List_insert(ListValue_cons(h,t), i, v)} (i > 0) ==> List_insert(ListValue_cons(h,t), i, v) == ListValue_cons(h, List_insert(t, i-1, v)); -axiom [List_insert_def3]: forall h: Value, t: ListValue, i: int, v: Value :: {List_insert(ListValue_cons(h,t), i, v)} - (i < 0) ==> List_insert(ListValue_cons(h,t), i, v) == List_insert(ListValue_cons(h,t), i mod (List_len(t)+1) , v); axiom [List_insert_len]: forall l: ListValue, i: int, v: Value :: {List_len(List_insert(l, i, v))} List_len(List_insert(l, i, v)) == List_len(l) + 1; axiom [List_insert_get0]: forall l: ListValue, p: int, v: Value:: {List_get(List_insert(l, p, v), p)} - (p >= 0 && p < List_len(l)) ==> (List_get(List_insert(l, p, v), p) == v); + (p >= 0 && p < List_len(l)) ==> (List_get(List_insert(l, p, v), p) == ValueExcept_ok(v)); axiom [List_insert_get1]: forall l: ListValue, p: int, v: Value:: {List_get(List_insert(l, p, v), p)} - p >= List_len(l) ==> (List_get(List_insert(l, p, v), List_len(l)) == v); + p >= List_len(l) ==> (List_get(List_insert(l, p, v), List_len(l)) == ValueExcept_ok(v)); axiom [List_insert_get2]: forall l: ListValue, p: int, v: Value, i: int :: {List_get(List_insert(l, p, v), i)} (p >= List_len(l) && i < List_len(l)) ==> (List_get(List_insert(l, p, v),i) == List_get(l, i)); axiom [List_insert_get3]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} (p >= 0 && p < List_len(l) && i < p) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i)); axiom [List_insert_get4]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} (p >= 0 && p < List_len(l) && i > p) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i -1)); -axiom [List_insert_get5]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} - (p < 0 && i < p mod List_len(l)) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i)); axiom [List_insert_get6]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} - (p < 0 && i > p mod List_len(l)) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i -1)); + (p <= 0 && i > 0) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i -1)); +axiom [List_insert_contains]: forall l: ListValue, i: int, v: Value :: {List_contains(List_insert(l,i,v),v)} + List_contains(List_insert(l,i,v),v); axiom [List_remove_nil_def]: forall x : Value ::{List_remove(ListValue_nil(), x)} List_remove(ListValue_nil(), x) == ListValue_nil(); axiom [List_remove_cons_def]: forall x : Value, h : Value, t : ListValue ::{List_remove(ListValue_cons(h,t),x)} List_remove(ListValue_cons(h,t),x) == if (normalize_value(x)==normalize_value(h)) then t else ListValue_cons(h, List_remove(t, x)); +axiom [List_remove_len]: forall l: ListValue, x: Value :: {List_len(List_remove(l,x))} + List_len(List_remove(l,x)) == if (List_contains(l,x)) then (List_len(l) - 1) else List_len(l); +axiom [List_remove_not_contain]: forall l: ListValue, x: Value :: {List_remove(l,x)} + (!List_contains(l,x)) == (List_remove(l,x) == l); + +axiom [List_pop_def0]: forall i: int :: {List_pop(ListValue_nil(), i)} + List_pop(ListValue_nil(), i) == ListValueExcept_err(Error_Undefined("Pop from empty list")); +axiom [List_pop_def1]: forall h: Value, t: ListValue:: {List_pop(ListValue_cons(h,t), 0)} + List_pop(ListValue_cons(h,t), 0) == ListValueExcept_ok(t); +axiom [List_pop_def2]: forall h: Value, t: ListValue, i: int :: {List_pop(ListValue_cons(h,t), i)} + List_pop(ListValue_cons(h,t), i) == + if (i > 0 && i <= List_len(t)) then + ListValueExcept_ok(ListValue_cons(h, ListValueExcept_unwrap(List_pop(t, i-1)))) + else ListValueExcept_err(Error_Undefined("Pop outside of index range")); +axiom [List_pop_def3]: forall h: Value, t: ListValue, i: int :: {List_pop(ListValue_cons(h,t), i)} + (i < 0) ==> List_pop(ListValue_cons(h,t), i) == ListValueExcept_err(Error_Undefined("Pop outside of index range")); +axiom [List_pop_len]: forall l: ListValue, i: int :: {List_len(ListValueExcept_unwrap(List_pop(l, i)))} + List_len(ListValueExcept_unwrap(List_pop(l, i))) == List_len(l) - 1; +axiom [List_pop_get0]: forall l: ListValue, p: int, i :int:: {List_get(ListValueExcept_unwrap(List_pop(l, p)), i)} + (p >= 0 && p < List_len(l) && i < p) ==> + (List_get(ListValueExcept_unwrap(List_pop(l, p)), i) == List_get(l, i)); +axiom [List_pop_get2]: forall l: ListValue, p: int, i :int:: {List_get(ListValueExcept_unwrap(List_pop(l, p)), i)} + (p >= 0 && p < List_len(l) && i > p) ==> + (List_get(ListValueExcept_unwrap(List_pop(l, p)), i) == List_get(l, i + 1)); // Dict type type Dict := Map Value Value; @@ -343,286 +446,338 @@ axiom [Dict_from_DicList_rev_cons]: forall k: Value, v: Value, d: DictList, acc: axiom [Dict_from_DicList_def]: forall dl: DictList:: {Dict_from_DicList(dl)} Dict_from_DicList(dl) == Dict_from_DicList_rev(dl, Dict_empty()); -type AttributeNames; -function AttributeNames_nil() : (AttributeNames); -function AttributeNames_cons(x0 : string, x1 : AttributeNames) : (AttributeNames); -function AttributeNames_tag (f: AttributeNames) : List_tag; -function AttributeNames_contains (l : AttributeNames, x: string) : bool; -function AttributeNames_len (l : AttributeNames) : int; -function AttributeNames_index (l : AttributeNames, i : int) : string; -function AttributeName_to_index (l : AttributeNames, f: string) : int; - -axiom [AttributeNames_len_nil_def]: AttributeNames_len (AttributeNames_nil()) == 0; -axiom [AttributeNames_len_cons_def]: forall h : string, t : AttributeNames ::{AttributeNames_len (AttributeNames_cons(h,t))} - AttributeNames_len (AttributeNames_cons(h,t)) == 1 + AttributeNames_len(t); -axiom [AttributeNames_tag_nil_def]: AttributeNames_tag(AttributeNames_nil()) == NIL; -axiom [AttributeNames_tag_cons_def]: forall h : string, t : AttributeNames ::{} AttributeNames_tag (AttributeNames_cons(h,t)) == CONS; -axiom [AttributeNames_contains_nil_def]: (forall x : string ::{AttributeNames_contains(AttributeNames_nil(), x)} - !AttributeNames_contains(AttributeNames_nil(), x)); -axiom [AttributeNames_contains_cons_def]: forall x : string, h : string, t : AttributeNames ::{AttributeNames_contains(AttributeNames_cons(h,t),x)} - AttributeNames_contains(AttributeNames_cons(h,t),x) == ((x==h) || AttributeNames_contains(t,x)); -axiom [AttributeNames_len_nonneg]: forall l: AttributeNames :: {AttributeNames_len(l)} AttributeNames_len(l) >= 0; -axiom [AttributeNames_index_nil]: forall i : int ::{AttributeNames_index (AttributeNames_nil(), i)} (AttributeNames_index (AttributeNames_nil(), i)) == ""; -axiom [AttributeNames_index_zero]: forall h : string, t : AttributeNames ::{AttributeNames_index (AttributeNames_cons(h,t), 0)} - AttributeNames_index (AttributeNames_cons(h,t), 0) == h; -axiom [AttributeNames_index_ind]: forall h : string, t : AttributeNames, i : int ::{AttributeNames_index (AttributeNames_cons(h,t), i)} - (i > 0) ==> (AttributeNames_index (AttributeNames_cons(h,t), i)) == AttributeNames_index (t, i - 1); -axiom [AttributeNames_index_contains]: forall l: AttributeNames, i: int, x: string :: {AttributeNames_index(l,i), AttributeNames_contains(l,x)} - (AttributeNames_index(l,i) == x) ==> AttributeNames_contains(l,x); -axiom [AttributeNames_index_ok]: forall l: AttributeNames, i: int:: {AttributeNames_index(l,i)} - ((AttributeNames_index(l,i)) != "") == (i < AttributeNames_len(l)); -axiom [AttributeName_to_index_nil_def]: forall f: string :: {AttributeName_to_index(AttributeNames_nil(), f)} - AttributeName_to_index(AttributeNames_nil(), f) == 0; -axiom [AttributeName_to_index_cons_def_1]: forall h: string, t: AttributeNames :: {AttributeName_to_index(AttributeNames_cons(h,t), h)} - AttributeName_to_index(AttributeNames_cons(h,t), h) == 0; -axiom [AttributeName_to_index_cons_def_2]: forall f: string, h: string, t: AttributeNames :: {AttributeName_to_index(AttributeNames_cons(h,t), f)} - !(h == f) ==> AttributeName_to_index(AttributeNames_cons(h,t), f) == AttributeName_to_index(t, f) + 1; - -function Class_mk (name: string, attributes: AttributeNames): Class; -function Class_attributes (c: Class) : AttributeNames; -function Class_name (c: Class): string; -axiom [Class_attributes_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} - Class_attributes(Class_mk (name, attributes)) == attributes; -axiom [Class_name_def]: forall name: string, attributes: AttributeNames :: {Class_mk (name, attributes)} - Class_name(Class_mk (name, attributes)) == name; -axiom [Class_eq_def]: forall c: Class, c': Class :: {c == c'} - (c == c') == (Class_name(c) == Class_name(c')); - -function Class_hasAttribute (c: Class, attribute: string): bool; -axiom [Class_hasAttribute_def]: forall c: Class, attribute: string :: {Class_hasAttribute(c, attribute)} - Class_hasAttribute(c, attribute) == AttributeNames_contains(Class_attributes(c), attribute); - -function Class_err() : Class; -axiom [Class_err_attributes_def]: Class_attributes(Class_err()) == AttributeNames_nil(); - -function AttributeValues_empty (c: Class) : AttributeValues; -axiom [AttributeValues_empty_def_valid]: forall c: Class, attribute: string :: {AttributeValues_empty(c)[attribute]} - Class_hasAttribute(c, attribute) ==> AttributeValues_empty(c)[attribute] == Value_none(); -axiom [AttributeValues_empty_def_invalid]: forall c: Class, attribute: string :: {AttributeValues_empty(c)[attribute]} - !Class_hasAttribute(c, attribute) ==> AttributeValues_empty(c)[attribute] == Value_exception(Error_message("Invalid Attribute of Class")); - -function AttributeValues_err () : AttributeValues; -axiom [AttributeValues_err_def]: forall attribute: string :: {AttributeValues_err[attribute]} - AttributeValues_err()[attribute] == Value_exception(Error_message("Error ClassInstance")); - -function ClassInstance_mk (c: Class, av: AttributeValues) : ClassInstance; - -function ClassInstance_getAttributeValues (ci: ClassInstance) : AttributeValues; -axiom [getAttributeValues_def]: forall c: Class, av: AttributeValues :: { ClassInstance_getAttributeValues(ClassInstance_mk (c, av))} - ClassInstance_getAttributeValues(ClassInstance_mk (c, av)) == av; - -function ClassInstance_getClass (ci: ClassInstance) : Class; -axiom [get_Class_def]: forall c: Class, av: AttributeValues :: {ClassInstance_getClass(ClassInstance_mk (c, av))} - ClassInstance_getClass(ClassInstance_mk (c, av)) == c; - -axiom [TypeOf_class]: forall ci: ClassInstance :: {TypeOf(Value_class(ci))} TypeOf(Value_class(ci)) == ValueType_class(ClassInstance_getClass(ci)); - -function ClassInstance_empty (c: Class) : ClassInstance; -axiom [ClassInstance_mk_empty_get_attributevalues]: forall c: Class :: {ClassInstance_getAttributeValues(ClassInstance_empty (c))} - ClassInstance_getAttributeValues(ClassInstance_empty (c)) == AttributeValues_empty(c); -axiom [ClassInstance_mk_empty_get_class]: forall c: Class :: {ClassInstance_getClass(ClassInstance_empty (c))} - ClassInstance_getClass(ClassInstance_empty (c)) == c; - -function ClassInstance_err (err: string) : ClassInstance; -function ClassInstance_errortag (ci: ClassInstance): Error_tag; -axiom [ClassInstance_err_tag]: forall err: string :: {ClassInstance_errortag(ClassInstance_err(err))} - ClassInstance_errortag(ClassInstance_err(err)) == ERR; -axiom [ClassInstance_err_get_class_def]: forall err: string :: {ClassInstance_getClass(ClassInstance_err(err)) } - ClassInstance_getClass(ClassInstance_err(err)) == Class_err(); -axiom [ClassInstance_err_get_attributevalues_def]: forall err: string :: {ClassInstance_getAttributeValues(ClassInstance_err (err))} - ClassInstance_getAttributeValues(ClassInstance_err (err)) == AttributeValues_err(); - -function ClassInstance_get_attribute(ci: ClassInstance, attribute: string) : Value; -axiom [ClassInstance_get_attribute_def]: forall ci: ClassInstance, attribute: string ::{ClassInstance_get_attribute(ci, attribute)} - ClassInstance_get_attribute(ci, attribute) == ClassInstance_getAttributeValues(ci)[attribute]; - -function ClassInstance_set_attribute (ci: ClassInstance, attribute: string, value: Value): ClassInstance; -axiom [ClassInstance_set_attribute_def]: forall ci: ClassInstance, attribute: string, v: Value:: {ClassInstance_set_attribute(ci, attribute, v)} - ClassInstance_set_attribute(ci, attribute, v) == if Class_hasAttribute(ClassInstance_getClass(ci), attribute) then - ClassInstance_mk(ClassInstance_getClass(ci), ClassInstance_getAttributeValues(ci)[attribute:=v]) - else ClassInstance_err("Set value for invalid"); - -function get_ClassInstance (v: Value) : ClassInstance; +type ClassInstanceExcept; +function ClassInstanceExcept_ok (ci: ClassInstance): ClassInstanceExcept; +function ClassInstanceExcept_err (e: Error): ClassInstanceExcept; +function ClassInstanceExcept_tag (ie: ClassInstanceExcept) : Except_tag; +axiom [ClassInstanceExcept_tag_ok_def]: forall ci: ClassInstance :: {ClassInstanceExcept_tag(ClassInstanceExcept_ok(ci))} + ClassInstanceExcept_tag(ClassInstanceExcept_ok(ci)) == OK; +axiom [ClassInstanceExcept_tag_err_def]: forall e: Error :: {ClassInstanceExcept_tag(ClassInstanceExcept_err(e))} + ClassInstanceExcept_tag(ClassInstanceExcept_err(e)) == ERR; +function ClassInstanceExcept_unwrap (lie: ClassInstanceExcept) : ClassInstance; +axiom [ClassInstanceExcept_unwrap_def]: forall ci: ClassInstance :: {ClassInstanceExcept_tag(ClassInstanceExcept_ok(ci))} + ClassInstanceExcept_unwrap(ClassInstanceExcept_ok(ci)) == ci; + +// Class type modelling + +function ClassInstance_mk (c: string, av: InstanceAttributes) : ClassInstance; + +function ClassInstance_getInstanceAttributes (ci: ClassInstance) : InstanceAttributes; +axiom [getAttributes_def]: forall c: string, av: InstanceAttributes :: { ClassInstance_getInstanceAttributes(ClassInstance_mk (c, av))} + ClassInstance_getInstanceAttributes(ClassInstance_mk (c, av)) == av; + +function ClassInstance_getClassname (ci: ClassInstance) : string; +axiom [get_Class_def]: forall c: string, av: InstanceAttributes :: {ClassInstance_getClassname(ClassInstance_mk (c, av))} + ClassInstance_getClassname(ClassInstance_mk (c, av)) == c; + +axiom [TypeOf_class]: forall ci: ClassInstance :: {TypeOf(Value_class(ci))} TypeOf(Value_class(ci)) == ValueType_class(ClassInstance_getClassname(ci)); + +function InstanceAttributes_empty() : InstanceAttributes; +axiom [AttributeValues_empty_def]: forall a: string :: {InstanceAttributes_empty()[a]} + InstanceAttributes_empty()[a] == ValueExcept_err(Error_AttributeError("Invalid Instance attribute of Class")); + +function ClassInstance_empty (c: string) : ClassInstance; +axiom [ClassInstance_mk_empty_get_attributevalues]: forall c: string :: {ClassInstance_empty (c)} + ClassInstance_empty(c) == ClassInstance_mk(c,InstanceAttributes_empty()); + +function ClassInstance_init_InstanceAttribute(ci: ClassInstance, attribute: string, v: Value) : ClassInstance; +axiom [ClassInstance_init_InstanceAttribute_def]: forall ci: ClassInstance, attribute: string, v: Value :: {ClassInstance_init_InstanceAttribute(ci, attribute, v)} + ClassInstance_init_InstanceAttribute(ci, attribute, v) == ClassInstance_mk(ClassInstance_getClassname(ci), ClassInstance_getInstanceAttributes(ci)[attribute := ValueExcept_ok(v)]); + + +function ClassInstance_get_InstanceAttribute(ci: ClassInstance, attribute: string) : ValueExcept; +axiom [ClassInstance_get_InstanceAttribute_def]: forall ci: ClassInstance, attribute: string :: {ClassInstance_get_InstanceAttribute(ci, attribute)} + ClassInstance_get_InstanceAttribute(ci, attribute) == ClassInstance_getInstanceAttributes(ci)[attribute]; + + +function ClassInstance_set_InstanceAttribute (ci: ClassInstance, attribute: string, value: Value): ClassInstanceExcept; +axiom [ClassInstance_set_attribute_def]: forall ci: ClassInstance, attribute: string, v: Value:: {ClassInstance_set_InstanceAttribute(ci, attribute, v)} + ClassInstance_set_InstanceAttribute(ci, attribute, v) == + if ValueExcept_tag(ClassInstance_get_InstanceAttribute(ci, attribute)) == OK then + ClassInstanceExcept_ok(ClassInstance_mk(ClassInstance_getClassname(ci), + ClassInstance_getInstanceAttributes(ci)[attribute:=ValueExcept_ok(v)])) + else ClassInstanceExcept_err(Error_AttributeError("Invalid instance attribute of class")); + +function get_ClassInstance (v: Value) : ClassInstanceExcept; axiom [get_ClassInstance_valid]: forall ci: ClassInstance :: {get_ClassInstance(Value_class(ci))} - get_ClassInstance(Value_class(ci)) == ci; + get_ClassInstance(Value_class(ci)) == ClassInstanceExcept_ok(ci); axiom [get_ClassInstance_invalid]: forall v: Value :: {get_ClassInstance(v)} - !isClassInstance(v) ==> get_ClassInstance(v) == ClassInstance_err ("Not of Class type"); - -function get_attribute(v: Value, attribute: string) : Value; -axiom [get_attribute_def]: forall v: Value, attribute: string ::{get_attribute(v, attribute)} - get_attribute(v, attribute) == if isClassInstance(v) then - ClassInstance_get_attribute(get_ClassInstance(v), attribute) - else Value_exception(Error_message("Not of Class type")); - -function set_attribute(v: Value, attribute: string, v': Value) : Value; -axiom [set_attribute_def]: forall v: Value, attribute: string, v': Value ::{set_attribute(v, attribute, v')} - set_attribute(v, attribute, v') == if isClassInstance(v) then - Value_class(ClassInstance_set_attribute(get_ClassInstance(v), attribute, v')) - else Value_exception(Error_message("Not of Class type")); - -function get_Class (v: Value) : Class { - ClassInstance_getClass(get_ClassInstance (v)) + !isClassInstance(v) ==> get_ClassInstance(v) == ClassInstanceExcept_err (Error_TypeError("Not of Class type")); + +function get_InstanceAttribute(v: Value, attribute: string) : ValueExcept; +axiom [get_attribute_def]: forall v: Value, attribute: string ::{get_InstanceAttribute(v, attribute)} + get_InstanceAttribute(v, attribute) == if isClassInstance(v) then + ClassInstance_get_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute) + else ValueExcept_err(Error_TypeError("Not of Class type")); + +function set_InstanceAttribute(v: Value, attribute: string, v': Value) : ValueExcept; +axiom [set_attribute_def]: forall v: Value, attribute: string, v': Value ::{set_InstanceAttribute(v, attribute, v')} + set_InstanceAttribute(v, attribute, v') == if isClassInstance(v) then + if (ClassInstanceExcept_tag(ClassInstance_set_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute, v')) == OK) then + ValueExcept_ok( Value_class ( + ClassInstanceExcept_unwrap(ClassInstance_set_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute, v')) + )) + else ValueExcept_err(Error_AttributeError(("Invalid instance attribute of class"))) + else ValueExcept_err(Error_TypeError("Not of Class type")); + +function get_Classname (v: Value) : stringExcept { + if isClassInstance(v) then + stringExcept_ok(ClassInstance_getClassname(ClassInstanceExcept_unwrap(get_ClassInstance(v)))) + else stringExcept_err(Error_TypeError("Not of Class type")) } function hasAttribute(v: Value, attribute: string): bool { - Class_hasAttribute (get_Class(v), attribute) + if isClassInstance(v) then + (ValueExcept_tag(ClassInstance_get_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute)) == OK) + else false } -//Binary op function +//Binary op functions function int_to_real (i: int) : real; function str_repeat (s: string, i: int) : string; -function Py_add (v1: Value, v2: Value) : Value; -function Py_sub (v1: Value, v2: Value) : Value; -function Py_mul (v1: Value, v2: Value) : Value; -function Py_gt (v1: Value, v2: Value) : Value; -function Py_lt (v1: Value, v2: Value) : Value; +function Py_add (v1: Value, v2: Value) : ValueExcept; +function Py_sub (v1: Value, v2: Value) : ValueExcept; +function Py_mul (v1: Value, v2: Value) : ValueExcept; +function Py_gt (v1: Value, v2: Value) : boolExcept; +function Py_lt (v1: Value, v2: Value) : boolExcept; +function Py_ge (v1: Value, v2: Value) : boolExcept; +function Py_le (v1: Value, v2: Value) : boolExcept; function Py_eq (v1: Value, v2: Value) : bool; inline function bool_to_int (b: bool) : int {if b then 1 else 0} inline function bool_to_real (b: bool) : real {if b then 1.0 else 0.0} axiom [Py_add_ints]: forall i1: int, i2: int :: {Py_add(Value_int(i1), Value_int(i2))} - Py_add(Value_int(i1), Value_int(i2)) == Value_int(i1 + i2); + Py_add(Value_int(i1), Value_int(i2)) == ValueExcept_ok(Value_int(i1 + i2)); axiom [Py_add_floats]: forall f1: real, f2: real :: {Py_add(Value_float(f1), Value_float(f2))} - Py_add(Value_float(f1), Value_float(f2)) == Value_float(f1 + f2); + Py_add(Value_float(f1), Value_float(f2)) == ValueExcept_ok(Value_float(f1 + f2)); axiom [Py_add_bools]: forall b1: bool, b2: bool :: {Py_add(Value_bool(b1), Value_bool(b2))} - Py_add(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) + bool_to_int(b2)); + Py_add(Value_bool(b1), Value_bool(b2)) == ValueExcept_ok(Value_int(bool_to_int(b1) + bool_to_int(b2))); axiom [Py_add_int_bool]: forall i: int, b: bool :: {Py_add(Value_int(i), Value_bool(b))} - Py_add(Value_int(i), Value_bool(b)) == Value_int(i + bool_to_int(b)); + Py_add(Value_int(i), Value_bool(b)) == ValueExcept_ok(Value_int(i + bool_to_int(b))); axiom [Py_add_bool_int]: forall b: bool, i: int :: {Py_add(Value_bool(b), Value_int(i))} - Py_add(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) + i); + Py_add(Value_bool(b), Value_int(i)) == ValueExcept_ok(Value_int(bool_to_int(b) + i)); axiom [Py_add_int_float]: forall i: int, r: real :: {Py_add(Value_int(i), Value_float(r))} - Py_add(Value_int(i), Value_float(r)) == Value_float(r + int_to_real(i)); + Py_add(Value_int(i), Value_float(r)) == ValueExcept_ok(Value_float(r + int_to_real(i))); axiom [Py_add_float_int]: forall r: real, i: int :: {Py_add(Value_float(r), Value_int(i))} - Py_add(Value_float(r), Value_int(i)) == Value_float(int_to_real(i) + r); + Py_add(Value_float(r), Value_int(i)) == ValueExcept_ok(Value_float(int_to_real(i) + r)); axiom [Py_add_float_bool]: forall r: real, b: bool :: {Py_add(Value_float(r), Value_bool(b))} - Py_add(Value_float(r), Value_bool(b)) == Value_float(r + bool_to_real(b)); + Py_add(Value_float(r), Value_bool(b)) == ValueExcept_ok(Value_float(r + bool_to_real(b))); axiom [Py_add_bool_float]: forall b: bool, r: real :: {Py_add(Value_bool(b), Value_float(r))} - Py_add(Value_bool(b), Value_float(r)) == Value_float(bool_to_real(b) + r); + Py_add(Value_bool(b), Value_float(r)) == ValueExcept_ok(Value_float(bool_to_real(b) + r)); axiom [Py_add_strs]: forall s1: string, s2: string :: {Py_add(Value_str(s1), Value_str(s2))} - Py_add(Value_str(s1), Value_str(s2)) == Value_str(str.concat(s1, s2)); + Py_add(Value_str(s1), Value_str(s2)) == ValueExcept_ok(Value_str(str.concat(s1, s2))); axiom [Py_add_lists]: forall l1: ListValue, l2: ListValue :: {Py_add(Value_list(l1), Value_list(l2))} - Py_add(Value_list(l1), Value_list(l2)) == Value_list(List_extend(l1, l2)); -axiom [Py_add_unsupport]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} + Py_add(Value_list(l1), Value_list(l2)) == ValueExcept_ok(Value_list(List_extend(l1, l2))); +axiom [Py_add_undefined]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || (TypeOf(v1) == STR && TypeOf(v2) == STR) || (isList(v1) && isList(v2))) - ==> Py_add(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + ==> Py_add(v1, v2) == ValueExcept_err(Error_Undefined("Operand Type is not defined")); axiom [Py_sub_ints]: forall i1: int, i2: int :: {Py_sub(Value_int(i1), Value_int(i2))} - Py_sub(Value_int(i1), Value_int(i2)) == Value_int(i1 - i2); + Py_sub(Value_int(i1), Value_int(i2)) == ValueExcept_ok(Value_int(i1 - i2)); axiom [Py_sub_floats]: forall f1: real, f2: real :: {Py_sub(Value_float(f1), Value_float(f2))} - Py_sub(Value_float(f1), Value_float(f2)) == Value_float(f1 - f2); + Py_sub(Value_float(f1), Value_float(f2)) == ValueExcept_ok(Value_float(f1 - f2)); axiom [Py_sub_bools]: forall b1: bool, b2: bool :: {Py_sub(Value_bool(b1), Value_bool(b2))} - Py_sub(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) - bool_to_int(b2)); + Py_sub(Value_bool(b1), Value_bool(b2)) == ValueExcept_ok(Value_int(bool_to_int(b1) - bool_to_int(b2))); axiom [Py_sub_int_bool]: forall i: int, b: bool :: {Py_sub(Value_int(i), Value_bool(b))} - Py_sub(Value_int(i), Value_bool(b)) == Value_int(i - bool_to_int(b)); + Py_sub(Value_int(i), Value_bool(b)) == ValueExcept_ok(Value_int(i - bool_to_int(b))); axiom [Py_sub_bool_int]: forall b: bool, i: int :: {Py_sub(Value_bool(b), Value_int(i))} - Py_sub(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) - i); + Py_sub(Value_bool(b), Value_int(i)) == ValueExcept_ok(Value_int(bool_to_int(b) - i)); axiom [Py_sub_int_float]: forall i: int, r: real :: {Py_sub(Value_int(i), Value_float(r))} - Py_sub(Value_int(i), Value_float(r)) == Value_float(r - int_to_real(i)); + Py_sub(Value_int(i), Value_float(r)) == ValueExcept_ok(Value_float(r - int_to_real(i))); axiom [Py_sub_float_int]: forall r: real, i: int :: {Py_sub(Value_float(r), Value_int(i))} - Py_sub(Value_float(r), Value_int(i)) == Value_float(int_to_real(i) - r); + Py_sub(Value_float(r), Value_int(i)) == ValueExcept_ok(Value_float(int_to_real(i) - r)); axiom [Py_sub_float_bool]: forall r: real, b: bool :: {Py_sub(Value_float(r), Value_bool(b))} - Py_sub(Value_float(r), Value_bool(b)) == Value_float(r - bool_to_real(b)); + Py_sub(Value_float(r), Value_bool(b)) == ValueExcept_ok(Value_float(r - bool_to_real(b))); axiom [Py_sub_bool_float]: forall b: bool, r: real :: {Py_sub(Value_bool(b), Value_float(r))} - Py_sub(Value_bool(b), Value_float(r)) == Value_float(bool_to_real(b) - r); -axiom [Py_sub_unsupport]: forall v1: Value, v2: Value :: {Py_sub(v1,v2)} + Py_sub(Value_bool(b), Value_float(r)) == ValueExcept_ok(Value_float(bool_to_real(b) - r)); +axiom [Py_sub_undefined]: forall v1: Value, v2: Value :: {Py_sub(v1,v2)} !(isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) ==> - Py_sub(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + Py_sub(v1, v2) == ValueExcept_err(Error_Undefined("Operand Type is not defined")); axiom [Py_mul_ints]: forall i1: int, i2: int :: {Py_mul(Value_int(i1), Value_int(i2))} - Py_mul(Value_int(i1), Value_int(i2)) == Value_int(i1 * i2); + Py_mul(Value_int(i1), Value_int(i2)) == ValueExcept_ok(Value_int(i1 * i2)); axiom [Py_mul_bools]: forall b1: bool, b2: bool :: {Py_mul(Value_bool(b1), Value_bool(b2))} - Py_mul(Value_bool(b1), Value_bool(b2)) == Value_int(bool_to_int(b1) * bool_to_int(b2)); + Py_mul(Value_bool(b1), Value_bool(b2)) == ValueExcept_ok(Value_int(bool_to_int(b1) * bool_to_int(b2))); axiom [Py_mul_int_bool]: forall i: int, b: bool :: {Py_mul(Value_int(i), Value_bool(b))} - Py_mul(Value_int(i), Value_bool(b)) == Value_int(i * bool_to_int(b)); + Py_mul(Value_int(i), Value_bool(b)) == ValueExcept_ok(Value_int(i * bool_to_int(b))); axiom [Py_mul_bool_int]: forall b: bool, i: int :: {Py_mul(Value_bool(b), Value_int(i))} - Py_mul(Value_bool(b), Value_int(i)) == Value_int(bool_to_int(b) * i); + Py_mul(Value_bool(b), Value_int(i)) == ValueExcept_ok(Value_int(bool_to_int(b) * i)); axiom [Py_mul_str_int]: forall s: string, i: int :: {Py_mul(Value_str(s), Value_int(i))} - Py_mul(Value_str(s), Value_int(i)) == Value_str(str_repeat(s, i)); + Py_mul(Value_str(s), Value_int(i)) == ValueExcept_ok(Value_str(str_repeat(s, i))); axiom [Py_mul_int_str]: forall s: string, i: int :: {Py_mul(Value_int(i), Value_str(s))} - Py_mul(Value_int(i), Value_str(s)) == Value_str(str_repeat(s, i)); + Py_mul(Value_int(i), Value_str(s)) == ValueExcept_ok(Value_str(str_repeat(s, i))); axiom [Py_mul_str_bool]: forall s: string, b: bool :: {Py_mul(Value_str(s), Value_bool(b))} - Py_mul(Value_str(s), Value_bool(b)) == Value_str(if b then s else ""); + Py_mul(Value_str(s), Value_bool(b)) == ValueExcept_ok(Value_str(if b then s else "")); axiom [Py_mul_bool_str]: forall s: string, b: bool :: {Py_mul(Value_bool(b), Value_str(s)) } - Py_mul(Value_bool(b), Value_str(s)) == Value_str(if b then s else ""); + Py_mul(Value_bool(b), Value_str(s)) == ValueExcept_ok(Value_str(if b then s else "")); axiom [Py_mul_list_int]: forall l: ListValue, i: int :: {Py_mul(Value_list(l), Value_int(i))} - Py_mul(Value_list(l), Value_int(i)) == Value_list(List_repeat(l, i)); + Py_mul(Value_list(l), Value_int(i)) == ValueExcept_ok(Value_list(List_repeat(l, i))); axiom [Py_mul_int_list]: forall l: ListValue, i: int :: {Py_mul(Value_int(i), Value_list(l))} - Py_mul(Value_int(i), Value_list(l)) == Value_list(List_repeat(l, i)); + Py_mul(Value_int(i), Value_list(l)) == ValueExcept_ok(Value_list(List_repeat(l, i))); axiom [Py_mul_list_bool]: forall l: ListValue, b: bool :: {Py_mul(Value_list(l), Value_bool(b))} - Py_mul(Value_list(l), Value_bool(b)) == Value_list(if b then l else ListValue_nil()); + Py_mul(Value_list(l), Value_bool(b)) == ValueExcept_ok(Value_list(if b then l else ListValue_nil())); axiom [Py_mul_bool_list]: forall l: ListValue, b: bool :: {Py_mul(Value_bool(b), Value_list(l)) } - Py_mul(Value_bool(b), Value_list(l)) == Value_list(if b then l else ListValue_nil()); -axiom [Py_mul_unsupport]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} + Py_mul(Value_bool(b), Value_list(l)) == ValueExcept_ok(Value_list(if b then l else ListValue_nil())); +axiom [Py_mul_undefined]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || (TypeOf(v1) == STR && isInstance(v2, INT)) || (TypeOf(v2) == STR && isInstance(v1, INT)) || (isList(v1) && isInstance(v2, INT)) || (isList(v2) && isInstance(v1, INT)) ) - ==> Py_mul(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + ==> Py_mul(v1, v2) == ValueExcept_err(Error_Undefined("Operand Type is not defined")); axiom [Py_lt_ints]: forall i1: int, i2: int :: {Py_lt(Value_int(i1), Value_int(i2))} - Py_lt(Value_int(i1), Value_int(i2)) == Value_bool(i1 < i2); + Py_lt(Value_int(i1), Value_int(i2)) == boolExcept_ok(i1 < i2); axiom [Py_lt_floats]: forall f1: real, f2: real :: {Py_lt(Value_float(f1), Value_float(f2))} - Py_lt(Value_float(f1), Value_float(f2)) == Value_bool(f1 < f2); + Py_lt(Value_float(f1), Value_float(f2)) == boolExcept_ok(f1 < f2); axiom [Py_lt_bools]: forall b1: bool, b2: bool :: {Py_lt(Value_bool(b1), Value_bool(b2))} - Py_lt(Value_bool(b1), Value_bool(b2)) == Value_bool(bool_to_int(b1) < bool_to_int(b2)); + Py_lt(Value_bool(b1), Value_bool(b2)) == boolExcept_ok(bool_to_int(b1) < bool_to_int(b2)); axiom [Py_lt_int_bool]: forall i: int, b: bool :: {Py_lt(Value_int(i), Value_bool(b))} - Py_lt(Value_int(i), Value_bool(b)) == Value_bool(i < bool_to_int(b)); + Py_lt(Value_int(i), Value_bool(b)) == boolExcept_ok(i < bool_to_int(b)); axiom [Py_lt_bool_int]: forall b: bool, i: int :: {Py_lt(Value_bool(b), Value_int(i))} - Py_lt(Value_bool(b), Value_int(i)) == Value_bool(bool_to_int(b) < i); + Py_lt(Value_bool(b), Value_int(i)) == boolExcept_ok(bool_to_int(b) < i); axiom [Py_lt_int_float]: forall i: int, r: real :: {Py_lt(Value_int(i), Value_float(r))} - Py_lt(Value_int(i), Value_float(r)) == Value_bool(r < int_to_real(i)); + Py_lt(Value_int(i), Value_float(r)) == boolExcept_ok(r < int_to_real(i)); axiom [Py_lt_float_int]: forall r: real, i: int :: {Py_lt(Value_float(r), Value_int(i))} - Py_lt(Value_float(r), Value_int(i)) == Value_bool(int_to_real(i) < r); + Py_lt(Value_float(r), Value_int(i)) == boolExcept_ok(int_to_real(i) < r); axiom [Py_lt_float_bool]: forall r: real, b: bool :: {Py_lt(Value_float(r), Value_bool(b))} - Py_lt(Value_float(r), Value_bool(b)) == Value_bool(r < bool_to_real(b)); + Py_lt(Value_float(r), Value_bool(b)) == boolExcept_ok(r < bool_to_real(b)); axiom [Py_lt_bool_float]: forall b: bool, r: real :: {Py_lt(Value_bool(b), Value_float(r))} - Py_lt(Value_bool(b), Value_float(r)) == Value_bool(bool_to_real(b) < r); -axiom [Py_lt_unsupport]: forall v1: Value, v2: Value :: {Py_lt(v1,v2)} - !(isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) ==> - Py_lt(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + Py_lt(Value_bool(b), Value_float(r)) == boolExcept_ok(bool_to_real(b) < r); +axiom [Py_lt_undefined]: forall v1: Value, v2: Value :: {Py_lt(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_lt(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not defined")); +axiom [Py_lt_unsupported]: forall v1: Value, v2: Value :: {Py_lt(v1,v2)} + ((TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_lt(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not supported")); axiom [Py_gt_ints]: forall i1: int, i2: int :: {Py_gt(Value_int(i1), Value_int(i2))} - Py_gt(Value_int(i1), Value_int(i2)) == Value_bool(i1 > i2); + Py_gt(Value_int(i1), Value_int(i2)) == boolExcept_ok(i1 > i2); axiom [Py_gt_floats]: forall f1: real, f2: real :: {Py_gt(Value_float(f1), Value_float(f2))} - Py_gt(Value_float(f1), Value_float(f2)) == Value_bool(f1 > f2); + Py_gt(Value_float(f1), Value_float(f2)) == boolExcept_ok(f1 > f2); axiom [Py_gt_bools]: forall b1: bool, b2: bool :: {Py_gt(Value_bool(b1), Value_bool(b2))} - Py_gt(Value_bool(b1), Value_bool(b2)) == Value_bool(bool_to_int(b1) > bool_to_int(b2)); + Py_gt(Value_bool(b1), Value_bool(b2)) == boolExcept_ok(bool_to_int(b1) > bool_to_int(b2)); axiom [Py_gt_int_bool]: forall i: int, b: bool :: {Py_gt(Value_int(i), Value_bool(b))} - Py_gt(Value_int(i), Value_bool(b)) == Value_bool(i > bool_to_int(b)); + Py_gt(Value_int(i), Value_bool(b)) == boolExcept_ok(i > bool_to_int(b)); axiom [Py_gt_bool_int]: forall b: bool, i: int :: {Py_gt(Value_bool(b), Value_int(i))} - Py_gt(Value_bool(b), Value_int(i)) == Value_bool(bool_to_int(b) > i); + Py_gt(Value_bool(b), Value_int(i)) == boolExcept_ok(bool_to_int(b) > i); axiom [Py_gt_int_float]: forall i: int, r: real :: {Py_gt(Value_int(i), Value_float(r))} - Py_gt(Value_int(i), Value_float(r)) == Value_bool(r > int_to_real(i)); + Py_gt(Value_int(i), Value_float(r)) == boolExcept_ok(r > int_to_real(i)); axiom [Py_gt_float_int]: forall r: real, i: int :: {Py_gt(Value_float(r), Value_int(i))} - Py_gt(Value_float(r), Value_int(i)) == Value_bool(int_to_real(i) > r); + Py_gt(Value_float(r), Value_int(i)) == boolExcept_ok(int_to_real(i) > r); axiom [Py_gt_float_bool]: forall r: real, b: bool :: {Py_gt(Value_float(r), Value_bool(b))} - Py_gt(Value_float(r), Value_bool(b)) == Value_bool(r > bool_to_real(b)); + Py_gt(Value_float(r), Value_bool(b)) == boolExcept_ok(r > bool_to_real(b)); axiom [Py_gt_bool_float]: forall b: bool, r: real :: {Py_gt(Value_bool(b), Value_float(r))} - Py_gt(Value_bool(b), Value_float(r)) == Value_bool(bool_to_real(b) > r); -axiom [Py_gt_unsupport]: forall v1: Value, v2: Value :: {Py_gt(v1,v2)} - !(isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) ==> - Py_gt(v1, v2) == Value_exception(Error_message("Operand Type is not supported")); + Py_gt(Value_bool(b), Value_float(r)) == boolExcept_ok(bool_to_real(b) > r); +axiom [Py_gt_undefined]: forall v1: Value, v2: Value :: {Py_gt(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_gt(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not defined")); +axiom [Py_gt_unsupported]: forall v1: Value, v2: Value :: {Py_gt(v1,v2)} + ((TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_gt(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not supported")); + +axiom [Py_le_ints]: forall i1: int, i2: int :: {Py_le(Value_int(i1), Value_int(i2))} + Py_le(Value_int(i1), Value_int(i2)) == boolExcept_ok(i1 <= i2); +axiom [Py_le_floats]: forall f1: real, f2: real :: {Py_le(Value_float(f1), Value_float(f2))} + Py_le(Value_float(f1), Value_float(f2)) == boolExcept_ok(f1 <= f2); +axiom [Py_le_bools]: forall b1: bool, b2: bool :: {Py_le(Value_bool(b1), Value_bool(b2))} + Py_le(Value_bool(b1), Value_bool(b2)) == boolExcept_ok(bool_to_int(b1) <= bool_to_int(b2)); +axiom [Py_le_int_bool]: forall i: int, b: bool :: {Py_le(Value_int(i), Value_bool(b))} + Py_le(Value_int(i), Value_bool(b)) == boolExcept_ok(i <= bool_to_int(b)); +axiom [Py_le_bool_int]: forall b: bool, i: int :: {Py_le(Value_bool(b), Value_int(i))} + Py_le(Value_bool(b), Value_int(i)) == boolExcept_ok(bool_to_int(b) <= i); +axiom [Py_le_int_float]: forall i: int, r: real :: {Py_le(Value_int(i), Value_float(r))} + Py_le(Value_int(i), Value_float(r)) == boolExcept_ok(r <= int_to_real(i)); +axiom [Py_le_float_int]: forall r: real, i: int :: {Py_le(Value_float(r), Value_int(i))} + Py_le(Value_float(r), Value_int(i)) == boolExcept_ok(int_to_real(i) <= r); +axiom [Py_le_float_bool]: forall r: real, b: bool :: {Py_le(Value_float(r), Value_bool(b))} + Py_le(Value_float(r), Value_bool(b)) == boolExcept_ok(r <= bool_to_real(b)); +axiom [Py_le_bool_float]: forall b: bool, r: real :: {Py_le(Value_bool(b), Value_float(r))} + Py_le(Value_bool(b), Value_float(r)) == boolExcept_ok(bool_to_real(b) <= r); +axiom [Py_le_undefined]: forall v1: Value, v2: Value :: {Py_le(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_le(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not defined")); +axiom [Py_le_unsupported]: forall v1: Value, v2: Value :: {Py_le(v1,v2)} + ((TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_le(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not supported")); + +axiom [Py_ge_ints]: forall i1: int, i2: int :: {Py_ge(Value_int(i1), Value_int(i2))} + Py_ge(Value_int(i1), Value_int(i2)) == boolExcept_ok(i1 >= i2); +axiom [Py_ge_floats]: forall f1: real, f2: real :: {Py_ge(Value_float(f1), Value_float(f2))} + Py_ge(Value_float(f1), Value_float(f2)) == boolExcept_ok(f1 >= f2); +axiom [Py_ge_bools]: forall b1: bool, b2: bool :: {Py_ge(Value_bool(b1), Value_bool(b2))} + Py_ge(Value_bool(b1), Value_bool(b2)) == boolExcept_ok(bool_to_int(b1) >= bool_to_int(b2)); +axiom [Py_ge_int_bool]: forall i: int, b: bool :: {Py_ge(Value_int(i), Value_bool(b))} + Py_ge(Value_int(i), Value_bool(b)) == boolExcept_ok(i >= bool_to_int(b)); +axiom [Py_ge_bool_int]: forall b: bool, i: int :: {Py_ge(Value_bool(b), Value_int(i))} + Py_ge(Value_bool(b), Value_int(i)) == boolExcept_ok(bool_to_int(b) >= i); +axiom [Py_ge_int_float]: forall i: int, r: real :: {Py_ge(Value_int(i), Value_float(r))} + Py_ge(Value_int(i), Value_float(r)) == boolExcept_ok(r >= int_to_real(i)); +axiom [Py_ge_float_int]: forall r: real, i: int :: {Py_ge(Value_float(r), Value_int(i))} + Py_ge(Value_float(r), Value_int(i)) == boolExcept_ok(int_to_real(i) >= r); +axiom [Py_ge_float_bool]: forall r: real, b: bool :: {Py_ge(Value_float(r), Value_bool(b))} + Py_ge(Value_float(r), Value_bool(b)) == boolExcept_ok(r >= bool_to_real(b)); +axiom [Py_ge_bool_float]: forall b: bool, r: real :: {Py_ge(Value_bool(b), Value_float(r))} + Py_ge(Value_bool(b), Value_float(r)) == boolExcept_ok(bool_to_real(b) >= r); +axiom [Py_ge_undefined]: forall v1: Value, v2: Value :: {Py_ge(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_ge(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not defined")); +axiom [Py_ge_unsupported]: forall v1: Value, v2: Value :: {Py_ge(v1,v2)} + ((TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_ge(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not supported")); + axiom [Py_eq_def]: forall v: Value, v': Value :: {Py_eq(v, v')} Py_eq(v, v') == (normalize_value(v) == normalize_value (v')); //Testing procedure non_contradiction_test() returns () { - assert [one_eq_two]: 1 == 2; + assert [one_eq_two_expect_unknown]: 1 == 2; }; procedure binary_op_and_types_test () returns () { - assert [int_add_ok]: forall i: int :: TypeOf(Py_add(Value_int(1), Value_int(i))) != EXCEPTION; - assert [int_add_class_except]: forall v: Value :: isClassInstance(v) ==> TypeOf(Py_add(Value_int(1), v)) == EXCEPTION; - assert [int_add_class_except']: forall v: Value :: hasAttribute(v, "a") ==> TypeOf(Py_add(Value_int(1), v)) == EXCEPTION; - assert [float_add_isInstance_int_ok]: forall v: Value :: isInstance(v,INT) ==> TypeOf(Py_add(Value_float(1.1), v)) != EXCEPTION; - //assert [exists_type1]: exists t: ValueType, v: Value :: (TypeOf(Py_add(Value_int(1), v)) != EXCEPTION) && (TypeOf(v) == t); - //assert [exist_value]: exists v: Value:: TypeOf(Py_add(Value_int(1), v)) != EXCEPTION; - //assert [exist_value'']: exists i: int :: {Value_int(2)} TypeOf(Py_add(Value_int(1), Value_int(i))) != EXCEPTION; - //assert [exists_type3]: exists v: Value :: (TypeOf(Py_add(Value_none(), v)) == STR); + assert [int_add_ok]: forall i: int :: ValueExcept_tag(Py_add(Value_int(1), Value_int(i))) != ERR; + assert [int_add_class_except]: forall v: Value :: isClassInstance(v) ==> ValueExcept_tag(Py_add(Value_int(1), v)) == ERR; + assert [int_add_class_except']: forall v: Value :: hasAttribute(v, "a") ==> ValueExcept_tag(Py_add(Value_int(1), v)) == ERR; + assert [float_add_isInstance_int_ok]: forall v: Value :: isInstance(v,INT) ==> ValueExcept_tag(Py_add(Value_float(1.1), v)) != ERR; +}; + +procedure ValueTypeTest() returns () { + var ty1: ValueType, ty2: ValueType, tl: ValueType; + ty1 := TypeOf(Value_int(5)); + ty2 := TypeOf(Value_bool(true)); + assert [subtype1]: isSubType(ty2,ty1); + assert [subtypeList]: forall l: ListValueType :: isSubType (ValueType_List(ListType_cons(ty2, l)), ValueType_List(ListType_cons(ty1, l))); + assert [subtypeList2]: forall l1: ListValueType, l2: ListValueType :: !(isSubTypes(l1,l2)) || isSubType (ValueType_List(ListType_cons(ty2, l1)), ValueType_List(ListType_cons(ty1, l2))); +}; + +procedure simple_call(v1: Value, v2: Value) returns () + spec { + requires [v1_type]: isInstance(v1, BOOL) || isInstance(v1, STR); + requires [v2_type]: isInstance(v2, ValueType_List(ListType_cons(INT, ListType_cons(INT, ListType_nil())))); + } +{}; + +procedure test_simple_call_argument_typecheck() returns () { + var arg1: Value, arg2: Value; + arg1 := Value_bool(true); + arg2 := Value_list(ListValue_cons(Value_int(3), ListValue_cons (Value_bool(true), ListValue_nil()))); + assert [subtype_bool]: isInstance(arg1,BOOL); + call simple_call(arg1, arg2); }; procedure list_functions_test() returns () @@ -631,13 +786,14 @@ procedure list_functions_test() returns () l1 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil()))); l2 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil())))))); - assert [index_1]: List_get(l1,1) == Value_int(2); + assert [index_1]: List_get(l1,1) == ValueExcept_ok(Value_int(2)); assert [contain_true]: List_contains(l1, Value_bool(true)); assert [ValueEq]: !(Value_int(4) == Value_int(3)); assert [normalize_value]: !(normalize_value(Value_int(4)) == Value_int(3)); assert [contain_3]: List_contains(l1, Value_int(2)); - assert [list_index_test1]: List_index(l1, Value_int(3)) == Value_int(2); - assert [list_index_test2]: TypeOf(List_index(l1, Value_int(9))) == EXCEPTION; + assert [list_index_test1]: List_index(l1, Value_int(3)) == intExcept_ok(2); + assert [list_index_test_expect_unknown]: List_index(l1, Value_int(3)) == intExcept_ok(3); + assert [list_index_test2]: intExcept_tag(List_index(l1, Value_int(9))) == ERR; assert [list_extend]: List_extend(l1, l1) == l2; assert [list_repeat1]: List_repeat(l1, 2) == l2; assert [list_repeat2]: List_repeat(l1, 6) == List_repeat(l2, 3); @@ -654,43 +810,20 @@ procedure list_generic_test() returns () { assert [revl1_contain_3]: List_contains (List_reverse(l1), Value_int(3)); assert [rev_contain]: forall l: ListValue, v: Value :: List_contains (List_reverse(l), v) == List_contains(l,v); assert [l1r_l2_contains_3]: forall l2: ListValue :: List_contains (List_extend(List_reverse(l1), l2), Value_int(3)); + assert [l1r_l2_contains_4_expect_unknown]: forall l2: ListValue :: List_contains (List_extend(List_reverse(l1), l2), Value_int(4)); assert [l1r_l2_contains_3']: forall l2: ListValue :: List_contains (List_reverse(List_extend(List_reverse(l1), l2)), Value_int(3)); assert [List_cons_extend_contains_symm]: forall x: Value, l1: ListValue, l2: ListValue :: List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x); -}; - - -procedure simple_call(v1: Value, v2: Value) returns () - spec { - requires [v1_type]: isInstance(v1, BOOL) || isInstance(v1, STR); - requires [v2_type]: isInstance(v2, ValueType_List(ListType_cons(INT, ListType_cons(INT, ListType_nil())))); - } -{}; - -procedure test() returns () { - var ty1: ValueType, ty2: ValueType, tl: ValueType; - ty1 := TypeOf(Value_int(5)); - ty2 := TypeOf(Value_bool(true)); - assert [subtype1]: isSubType(ty2,ty1); - assert [subtypeList]: forall l: ListValueType :: isSubType (ValueType_List(ListType_cons(ty2, l)), ValueType_List(ListType_cons(ty1, l))); - assert [subtypeList2]: forall l1: ListValueType, l2: ListValueType :: !(isSubTypes(l1,l2)) || isSubType (ValueType_List(ListType_cons(ty2, l1)), ValueType_List(ListType_cons(ty1, l2))); -}; - -procedure test_simple_call_argument_typecheck() returns () { - var arg1: Value, arg2: Value; - arg1 := Value_bool(true); - arg2 := Value_list(ListValue_cons(Value_int(3), ListValue_cons (Value_bool(true), ListValue_nil()))); - assert [subtype_bool]: isInstance(arg1,BOOL); - call simple_call(arg1, arg2); + assert [contains_len]: forall l: ListValue, x: Value:: List_contains(l,x) ==> (List_len(l) >0); + assert [contain_remove]: forall l: ListValue, x: Value:: List_contains(l,x) ==> (List_len(l) == List_len(List_remove(l,x)) + 1); + assert [insert_len]: forall l: ListValue, i: int, v: Value :: List_len(List_insert(l, i, v)) == List_len(l) + 1; + assert [insert_contains]: forall l: ListValue, i: int, v: Value :: List_contains(List_insert(l, i, v), v); }; procedure dict_functions_test () returns () { var d1: Dict, d2: Dict, d3: Dict; d1:= Dict_insert(Dict_empty(), Value_int(1), Value_int(1)); d2:= Dict_insert(d1, Value_bool(true), Value_int(2)); - assert [uptype]: normalize_value(Value_bool(true)) == Value_int(1); - assert [uptype2]: normalize_value(Value_int(1)) == Value_int(1); - assert [uptype3]: normalize_value(Value_str("fd")) == Value_str("fd"); assert [get_1]: Dict_get(d2, Value_int(1)) == Value_int(2); }; @@ -711,22 +844,20 @@ procedure forall_dict_test () returns () { assert [ncontain_general]: forall d: Dict, k: Value :: !Dict_contains(Dict_remove(d,k), k); assert [ncontain_general']: forall d: Dict, k: Value :: !Dict_contains(Dict_remove(d,normalize_value(k)), k); assert [contain_general]: forall d: Dict, k: Value, v: Value :: (v == Value_none()) || Dict_contains(Dict_insert(d,k,v), k); - assert [remove_insert]: forall d: Dict, k: Value, v: Value, k': Value :: !(Dict_get(d,k) == v) || Dict_get((Dict_insert(Dict_remove(d,k), k, v)), k') == Dict_get(d, k'); + assert [remove_insert]: forall d: Dict, k: Value, v: Value, k': Value :: + !(Dict_get(d,k) == v) || Dict_get((Dict_insert(Dict_remove(d,k), k, v)), k') == Dict_get(d, k'); }; -procedure ValueClass_test() returns () { - var c: Class, ci: Value, ci': Value, v: Value; - c := Class_mk ("point", AttributeNames_cons("x", AttributeNames_cons("y", AttributeNames_nil()))); - ci := Value_class(ClassInstance_empty (c)); - assert [has_x]: hasAttribute(ci,"x"); - assert [nhas_z]: !hasAttribute(ci,"z"); - assert [isInstance_class]: isInstance(ci, ValueType_class(c)); - assert [get_x_empty]: get_attribute(ci, "x") == Value_none(); - assert [get_y_empty]: get_attribute(ci, "y") == Value_none(); - assert [get_x']: get_attribute(set_attribute(ci, "x", Value_int(1)), "x") == Value_int(1); - ci := set_attribute(ci, "x", Value_int(1)); - assert [get_x]: get_attribute(ci, "x") == Value_int(1); - assert [get_y]: get_attribute(ci, "y") == Value_none(); +procedure ClassType_test() returns () { + var civ: Value, ci: ClassInstance, v: Value; + ci := ClassInstance_init_InstanceAttribute(ClassInstance_empty("point"), "x", Value_int(1)); + ci := ClassInstance_init_InstanceAttribute(ci, "y", Value_int(2)); + civ := Value_class (ci); + assert [has_x]: hasAttribute(civ,"x"); + assert [nhas_z_expect_unknown]: hasAttribute(civ,"z"); + assert [isInstance_class]: isInstance(civ, ValueType_class("point")); + assert [get_x_empty_expect_unknown]: get_InstanceAttribute(civ, "x") == ValueExcept_ok(Value_none()); + assert [get_x]: get_InstanceAttribute(civ, "x") == ValueExcept_ok(Value_int(1)); }; #end From 2619853b9b400073613460f3105c4dddf6ce9b24 Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Tue, 6 Jan 2026 14:49:27 -0800 Subject: [PATCH 12/13] initial commit for translator --- .../Languages/Python/BoogieTypePrelude.lean | 273 +++-- .../Python/BoogieTypePreludeTest.lean | 922 +++++++++++++++++ .../Languages/Python/PythonToTypeBoogie.lean | 962 ++++++++++++++++++ 3 files changed, 1999 insertions(+), 158 deletions(-) create mode 100644 Strata/Languages/Python/BoogieTypePreludeTest.lean create mode 100644 Strata/Languages/Python/PythonToTypeBoogie.lean diff --git a/Strata/Languages/Python/BoogieTypePrelude.lean b/Strata/Languages/Python/BoogieTypePrelude.lean index b9a71de68..3270e9626 100644 --- a/Strata/Languages/Python/BoogieTypePrelude.lean +++ b/Strata/Languages/Python/BoogieTypePrelude.lean @@ -93,6 +93,7 @@ function intExcept_unwrap (lie: intExcept) : int; axiom [intExcept_unwrap_def]: forall i: int :: {intExcept_tag(intExcept_ok(i))} intExcept_unwrap(intExcept_ok(i)) == i; +type Datetime; // Value and ListValue types type Value; @@ -119,6 +120,7 @@ function Value_bool (b : bool) : Value; function Value_int (i : int) : Value; function Value_float (f : real) : Value; function Value_str (s : string) : Value; +function Value_datetime (d : Datetime) : Value; function Value_none() : Value; function Value_list (lv : ListValue) : Value; function Value_class (ci: ClassInstance) : Value; @@ -137,6 +139,7 @@ const BOOL : ValueType; const INT : ValueType; const FLOAT : ValueType; const STR : ValueType; +const DATETIME : ValueType; const NONE : ValueType; function ValueType_class(classname: string): ValueType; @@ -144,11 +147,8 @@ function isListValueType (t: ValueType): bool; function isClassValueType (t: ValueType): bool; axiom [isClassType_def]: forall c: string :: {isClassValueType(ValueType_class(c))} isClassValueType(ValueType_class(c)); -function isList (v: Value): bool; -function isClassInstance (v: Value): bool; - - //Uniqueness axioms +axiom [unique_ValueType_DATETIME]: DATETIME != BOOL && DATETIME != INT && DATETIME != FLOAT && DATETIME != STR && DATETIME != NONE && !isListValueType(DATETIME) && !(isClassValueType(DATETIME)); axiom [unique_ValueType_bool]: BOOL != INT && BOOL != FLOAT && BOOL != STR && BOOL != NONE && !isListValueType(BOOL) && !(isClassValueType(BOOL)); axiom [unique_ValueType_int]: INT != STR && INT != FLOAT && INT != NONE && !isListValueType(INT) && !(isClassValueType(INT)); axiom [unique_ValueType_float]: FLOAT != STR && FLOAT != NONE && !isListValueType(FLOAT) && !(isClassValueType(FLOAT)); @@ -161,6 +161,7 @@ axiom [all_ValueType_cases]: forall t: ValueType :: t == FLOAT || t == STR || t == NONE || + t == DATETIME || isListValueType (t) || isClassValueType (t); @@ -169,6 +170,7 @@ axiom [value_int_eq]: forall i: int, j: int :: {Value_int(i) == Value_int(j)} (V axiom [value_bool_eq]: forall b1: bool, b2: bool :: {Value_bool(b1) == Value_bool(b2)} (Value_bool(b1) == Value_bool(b2)) == (b1 == b2); axiom [value_float_eq]: forall r1: real, r2: real :: {Value_float(r1) == Value_float(r2)} (Value_float(r1) == Value_float(r2)) == (r1 == r2); axiom [value_str_eq]: forall s1: string, s2: string :: {Value_str(s1) == Value_str(s2)} (Value_str(s1) == Value_str(s2)) == (s1 == s2); +axiom [value_datetime_eq]: forall d1: Datetime, d2: Datetime :: {Value_datetime(d1) == Value_datetime(d2)} (Value_datetime(d1) == Value_datetime(d2)) == (d1 == d2); //Constructors and tag functions of ListType function ListType_nil() : (ListValueType); @@ -190,6 +192,7 @@ axiom [TypeOf_bool]: forall b: bool :: {TypeOf(Value_bool(b))} TypeOf(Value_bool axiom [TypeOf_int]: forall i: int :: {Value_int(i)} TypeOf(Value_int(i)) == INT; axiom [TypeOf_float]: forall f: real :: {Value_float(f)} TypeOf(Value_float(f)) == FLOAT; axiom [TypeOf_str]: forall s: string :: {Value_str(s)} TypeOf(Value_str(s)) == STR; +axiom [TypeOf_datetime]: forall d: Datetime :: {Value_datetime(d)} TypeOf(Value_datetime(d)) == DATETIME; axiom [TypeOf_none]: TypeOf(Value_none()) == NONE; axiom [TypeOf_list]: forall l: ListValue :: {Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); @@ -198,14 +201,42 @@ axiom [TypeOf_int_exists]: forall v: Value :: {TypeOf(v) == INT} TypeOf(v) == IN axiom [TypeOf_float_exists]: forall v: Value :: {TypeOf(v) == FLOAT} TypeOf(v) == FLOAT ==> exists r: real :: v == Value_float(r); axiom [TypeOf_string_exists]: forall v: Value :: {TypeOf(v) == STR} TypeOf(v) == STR ==> exists s: string :: v == Value_str(s); axiom [TypeOf_none']: forall v: Value :: {TypeOf(v) == NONE} (TypeOf(v) == NONE) == (v == Value_none()) ; -axiom [TypeOf_list_exists]: forall v: Value :: {isList(v)} isList(v) ==> exists l: ListValue :: v == Value_list(l); -axiom [TypeOf_class_exists]: forall v: Value :: {isClassInstance(v)} isClassInstance(v) ==> exists ci: ClassInstance :: v == Value_class(ci); + +function isBool (v: Value): bool { + TypeOf(v) == BOOL +} +function isInt (v: Value): bool { + TypeOf(v) == INT +} +function isStr (v: Value): bool { + TypeOf(v) == STR +} +function isFloat (v: Value): bool{ + TypeOf(v) == FLOAT +} +function isNone (v: Value): bool{ + TypeOf(v) == NONE +} +function isDatetime (v: Value): bool{ + TypeOf(v) == DATETIME +} + +function isList (v: Value): bool; +function isClassInstance (v: Value): bool; axiom [isList_def]: forall l: ListValue :: {Value_list(l)} isList(Value_list(l)); axiom [isList_def']: forall v: Value :: {isListValueType(TypeOf(v))} isList(v) == isListValueType(TypeOf(v)); axiom [isClassInstance_def]: forall ci: ClassInstance :: {Value_class(ci)} isClassInstance(Value_class(ci)); axiom [isClassInstance_def']: forall v: Value :: {isClassValueType(TypeOf(v))} isClassInstance(v) == isClassValueType(TypeOf(v)); +axiom [TypeOf_list_exists]: forall v: Value :: {isList(v)} isList(v) ==> exists l: ListValue :: v == Value_list(l); +axiom [TypeOf_class_exists]: forall v: Value :: {isClassInstance(v)} isClassInstance(v) ==> exists ci: ClassInstance :: v == Value_class(ci); + + +//Casting +function as_bool (v: Value) : bool; +axiom [as_bool_def]: forall b: bool :: {as_bool(Value_bool(b))} as_bool(Value_bool(b)) == b; + // isSubType functions function isSubType (t1: ValueType, t2: ValueType) : bool; function isSubTypes (t1: ListValueType, t2: ListValueType) : bool; @@ -235,8 +266,26 @@ axiom [isSubtype_mono]: forall t1: ValueType, t2: ValueType ::{isSubType (t1,t2) axiom [isSubtype_trans]: forall t1: ValueType, t2: ValueType, t3: ValueType::{isSubType(t1, t2)} !(isSubType(t1, t2) && isSubType(t2, t3)) || isSubType(t1, t3); // isInstance function: -function isInstance (v: Value, vt: ValueType) : bool; -axiom [isInstance_of_isSubtype]: forall v: Value, t: ValueType::{isInstance(v,t)} isInstance(v,t) == isSubType(TypeOf(v), t); +function isInstance (v: Value, vt: ValueType) : bool { + isSubType(TypeOf(v), vt) +} + +function isInstance_ofBool (v: Value): bool { + isInstance(v, BOOL) +} + +function isInstance_ofInt (v: Value): bool { + isInstance(v, INT) +} + +function isInstance_ofFloat (v: Value): bool { + isInstance(v, FLOAT) +} + +function isInstance_ofStr (v: Value): bool { + isInstance(v, STR) +} + function is_IntReal (v: Value) : bool; function Value_real_to_int (v: Value) : int; @@ -419,14 +468,15 @@ function Dict_empty() : Dict; function Dict_insert (d: Dict, k: Value, v: Value) : Dict; function Dict_get (d: Dict, k: Value) : Value; function Dict_remove (d: Dict, k: Value) : Dict; -function Dict_contains (d: Dict, k: Value) : bool; +function Dict_contains (d: Dict, k: Value) : bool { + Dict_get (d,k) != Value_none() +} //Dictionary axioms axiom [emptydict_def]: forall k: Value :: {Dict_empty() [k]} Dict_empty() [k] == Value_none(); axiom [Dict_get_def]: forall d: Dict, k: Value :: {Dict_get(d,k)} Dict_get(d,k) == d[normalize_value(k)]; axiom [Dict_insert_def]: forall d: Dict, k: Value, v: Value :: {Dict_insert(d,k,v)} Dict_insert(d,k,v) == d[normalize_value(k):= v]; axiom [Dict_remove_def]: forall d: Dict, k: Value :: {Dict_remove(d,k)} Dict_remove(d,k) == d[normalize_value(k):= Value_none()]; -axiom [Dict_contains_def]: forall d: Dict, k: Value :: {Dict_contains(d,k)} Dict_contains(d,k) == (Dict_get (d,k) != Value_none()); // List of pairs of Value, used to construct Dict type DictList; @@ -476,27 +526,24 @@ function InstanceAttributes_empty() : InstanceAttributes; axiom [AttributeValues_empty_def]: forall a: string :: {InstanceAttributes_empty()[a]} InstanceAttributes_empty()[a] == ValueExcept_err(Error_AttributeError("Invalid Instance attribute of Class")); -function ClassInstance_empty (c: string) : ClassInstance; -axiom [ClassInstance_mk_empty_get_attributevalues]: forall c: string :: {ClassInstance_empty (c)} - ClassInstance_empty(c) == ClassInstance_mk(c,InstanceAttributes_empty()); - -function ClassInstance_init_InstanceAttribute(ci: ClassInstance, attribute: string, v: Value) : ClassInstance; -axiom [ClassInstance_init_InstanceAttribute_def]: forall ci: ClassInstance, attribute: string, v: Value :: {ClassInstance_init_InstanceAttribute(ci, attribute, v)} - ClassInstance_init_InstanceAttribute(ci, attribute, v) == ClassInstance_mk(ClassInstance_getClassname(ci), ClassInstance_getInstanceAttributes(ci)[attribute := ValueExcept_ok(v)]); - +function ClassInstance_empty (c: string) : ClassInstance { + ClassInstance_mk(c,InstanceAttributes_empty()) +} -function ClassInstance_get_InstanceAttribute(ci: ClassInstance, attribute: string) : ValueExcept; -axiom [ClassInstance_get_InstanceAttribute_def]: forall ci: ClassInstance, attribute: string :: {ClassInstance_get_InstanceAttribute(ci, attribute)} - ClassInstance_get_InstanceAttribute(ci, attribute) == ClassInstance_getInstanceAttributes(ci)[attribute]; +function ClassInstance_init_InstanceAttribute(ci: ClassInstance, attribute: string, v: Value) : ClassInstance{ + ClassInstance_mk(ClassInstance_getClassname(ci), ClassInstance_getInstanceAttributes(ci)[attribute := ValueExcept_ok(v)]) +} +function ClassInstance_get_InstanceAttribute(ci: ClassInstance, attribute: string) : ValueExcept { + ClassInstance_getInstanceAttributes(ci)[attribute] +} -function ClassInstance_set_InstanceAttribute (ci: ClassInstance, attribute: string, value: Value): ClassInstanceExcept; -axiom [ClassInstance_set_attribute_def]: forall ci: ClassInstance, attribute: string, v: Value:: {ClassInstance_set_InstanceAttribute(ci, attribute, v)} - ClassInstance_set_InstanceAttribute(ci, attribute, v) == +function ClassInstance_set_InstanceAttribute (ci: ClassInstance, attribute: string, value: Value): ClassInstanceExcept{ if ValueExcept_tag(ClassInstance_get_InstanceAttribute(ci, attribute)) == OK then ClassInstanceExcept_ok(ClassInstance_mk(ClassInstance_getClassname(ci), - ClassInstance_getInstanceAttributes(ci)[attribute:=ValueExcept_ok(v)])) - else ClassInstanceExcept_err(Error_AttributeError("Invalid instance attribute of class")); + ClassInstance_getInstanceAttributes(ci)[attribute:=ValueExcept_ok(value)])) + else ClassInstanceExcept_err(Error_AttributeError("Invalid instance attribute of class")) +} function get_ClassInstance (v: Value) : ClassInstanceExcept; axiom [get_ClassInstance_valid]: forall ci: ClassInstance :: {get_ClassInstance(Value_class(ci))} @@ -504,21 +551,21 @@ axiom [get_ClassInstance_valid]: forall ci: ClassInstance :: {get_ClassInstance( axiom [get_ClassInstance_invalid]: forall v: Value :: {get_ClassInstance(v)} !isClassInstance(v) ==> get_ClassInstance(v) == ClassInstanceExcept_err (Error_TypeError("Not of Class type")); -function get_InstanceAttribute(v: Value, attribute: string) : ValueExcept; -axiom [get_attribute_def]: forall v: Value, attribute: string ::{get_InstanceAttribute(v, attribute)} - get_InstanceAttribute(v, attribute) == if isClassInstance(v) then - ClassInstance_get_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute) - else ValueExcept_err(Error_TypeError("Not of Class type")); - -function set_InstanceAttribute(v: Value, attribute: string, v': Value) : ValueExcept; -axiom [set_attribute_def]: forall v: Value, attribute: string, v': Value ::{set_InstanceAttribute(v, attribute, v')} - set_InstanceAttribute(v, attribute, v') == if isClassInstance(v) then - if (ClassInstanceExcept_tag(ClassInstance_set_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute, v')) == OK) then - ValueExcept_ok( Value_class ( - ClassInstanceExcept_unwrap(ClassInstance_set_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute, v')) - )) - else ValueExcept_err(Error_AttributeError(("Invalid instance attribute of class"))) - else ValueExcept_err(Error_TypeError("Not of Class type")); +function get_InstanceAttribute(v: Value, attribute: string) : ValueExcept { + if isClassInstance(v) then + ClassInstance_get_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute) + else ValueExcept_err(Error_TypeError("Not of Class type")) +} + +function set_InstanceAttribute(v: Value, attribute: string, v': Value) : ValueExcept{ + if isClassInstance(v) then + if (ClassInstanceExcept_tag(ClassInstance_set_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute, v')) == OK) then + ValueExcept_ok( Value_class ( + ClassInstanceExcept_unwrap(ClassInstance_set_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute, v')) + )) + else ValueExcept_err(Error_AttributeError(("Invalid instance attribute of class"))) + else ValueExcept_err(Error_TypeError("Not of Class type")) +} function get_Classname (v: Value) : stringExcept { if isClassInstance(v) then @@ -740,131 +787,41 @@ axiom [Py_ge_unsupported]: forall v1: Value, v2: Value :: {Py_ge(v1,v2)} (isList(v1) && isList(v2))) ==> Py_ge(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not supported")); +function Py_add_unwrap (v1: Value, v2: Value) : Value { + ValueExcept_unwrap (Py_add (v1,v2)) +} +function Py_sub_unwrap (v1: Value, v2: Value) : Value { + ValueExcept_unwrap (Py_sub (v1,v2)) +} +function Py_mul_unwrap (v1: Value, v2: Value) : Value { + ValueExcept_unwrap (Py_mul (v1,v2)) +} +function Py_gt_unwrap (v1: Value, v2: Value) : bool { + boolExcept_unwrap (Py_gt (v1,v2)) +} +function Py_lt_unwrap (v1: Value, v2: Value) : bool { + boolExcept_unwrap (Py_lt (v1,v2)) +} +function Py_ge_unwrap (v1: Value, v2: Value) : bool { + boolExcept_unwrap (Py_ge (v1,v2)) +} +function Py_le_unwrap (v1: Value, v2: Value) : bool { + boolExcept_unwrap (Py_le (v1,v2)) +} + axiom [Py_eq_def]: forall v: Value, v': Value :: {Py_eq(v, v')} Py_eq(v, v') == (normalize_value(v) == normalize_value (v')); -//Testing -procedure non_contradiction_test() returns () { - assert [one_eq_two_expect_unknown]: 1 == 2; -}; - -procedure binary_op_and_types_test () returns () { - assert [int_add_ok]: forall i: int :: ValueExcept_tag(Py_add(Value_int(1), Value_int(i))) != ERR; - assert [int_add_class_except]: forall v: Value :: isClassInstance(v) ==> ValueExcept_tag(Py_add(Value_int(1), v)) == ERR; - assert [int_add_class_except']: forall v: Value :: hasAttribute(v, "a") ==> ValueExcept_tag(Py_add(Value_int(1), v)) == ERR; - assert [float_add_isInstance_int_ok]: forall v: Value :: isInstance(v,INT) ==> ValueExcept_tag(Py_add(Value_float(1.1), v)) != ERR; -}; - -procedure ValueTypeTest() returns () { - var ty1: ValueType, ty2: ValueType, tl: ValueType; - ty1 := TypeOf(Value_int(5)); - ty2 := TypeOf(Value_bool(true)); - assert [subtype1]: isSubType(ty2,ty1); - assert [subtypeList]: forall l: ListValueType :: isSubType (ValueType_List(ListType_cons(ty2, l)), ValueType_List(ListType_cons(ty1, l))); - assert [subtypeList2]: forall l1: ListValueType, l2: ListValueType :: !(isSubTypes(l1,l2)) || isSubType (ValueType_List(ListType_cons(ty2, l1)), ValueType_List(ListType_cons(ty1, l2))); -}; - -procedure simple_call(v1: Value, v2: Value) returns () - spec { - requires [v1_type]: isInstance(v1, BOOL) || isInstance(v1, STR); - requires [v2_type]: isInstance(v2, ValueType_List(ListType_cons(INT, ListType_cons(INT, ListType_nil())))); - } -{}; - -procedure test_simple_call_argument_typecheck() returns () { - var arg1: Value, arg2: Value; - arg1 := Value_bool(true); - arg2 := Value_list(ListValue_cons(Value_int(3), ListValue_cons (Value_bool(true), ListValue_nil()))); - assert [subtype_bool]: isInstance(arg1,BOOL); - call simple_call(arg1, arg2); -}; - -procedure list_functions_test() returns () -{ - var l1: ListValue, l2: ListValue; - l1 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil()))); - l2 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), - ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil())))))); - assert [index_1]: List_get(l1,1) == ValueExcept_ok(Value_int(2)); - assert [contain_true]: List_contains(l1, Value_bool(true)); - assert [ValueEq]: !(Value_int(4) == Value_int(3)); - assert [normalize_value]: !(normalize_value(Value_int(4)) == Value_int(3)); - assert [contain_3]: List_contains(l1, Value_int(2)); - assert [list_index_test1]: List_index(l1, Value_int(3)) == intExcept_ok(2); - assert [list_index_test_expect_unknown]: List_index(l1, Value_int(3)) == intExcept_ok(3); - assert [list_index_test2]: intExcept_tag(List_index(l1, Value_int(9))) == ERR; - assert [list_extend]: List_extend(l1, l1) == l2; - assert [list_repeat1]: List_repeat(l1, 2) == l2; - assert [list_repeat2]: List_repeat(l1, 6) == List_repeat(l2, 3); -}; - -procedure list_generic_test() returns () { - var l1: ListValue; - assert [contains_append]: forall l: ListValue, x: Value :: List_contains(List_append(l,x), x); - assert [len_append]: forall l: ListValue, x: Value :: List_len(List_append(l,x)) == List_len(l) + 1; - l1 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil()))); - assert [l1_contains_3]: List_contains (l1, Value_int(3)); - assert [contains_len]: forall l: ListValue, x: Value:: List_contains(l,x) ==> (List_len(l) >0); - assert [l1l2_contains_3]: forall l2: ListValue :: List_contains (List_extend(l1, l2), Value_int(3)); - assert [revl1_contain_3]: List_contains (List_reverse(l1), Value_int(3)); - assert [rev_contain]: forall l: ListValue, v: Value :: List_contains (List_reverse(l), v) == List_contains(l,v); - assert [l1r_l2_contains_3]: forall l2: ListValue :: List_contains (List_extend(List_reverse(l1), l2), Value_int(3)); - assert [l1r_l2_contains_4_expect_unknown]: forall l2: ListValue :: List_contains (List_extend(List_reverse(l1), l2), Value_int(4)); - assert [l1r_l2_contains_3']: forall l2: ListValue :: List_contains (List_reverse(List_extend(List_reverse(l1), l2)), Value_int(3)); - assert [List_cons_extend_contains_symm]: forall x: Value, l1: ListValue, l2: ListValue :: - List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x); - assert [contains_len]: forall l: ListValue, x: Value:: List_contains(l,x) ==> (List_len(l) >0); - assert [contain_remove]: forall l: ListValue, x: Value:: List_contains(l,x) ==> (List_len(l) == List_len(List_remove(l,x)) + 1); - assert [insert_len]: forall l: ListValue, i: int, v: Value :: List_len(List_insert(l, i, v)) == List_len(l) + 1; - assert [insert_contains]: forall l: ListValue, i: int, v: Value :: List_contains(List_insert(l, i, v), v); -}; - -procedure dict_functions_test () returns () { - var d1: Dict, d2: Dict, d3: Dict; - d1:= Dict_insert(Dict_empty(), Value_int(1), Value_int(1)); - d2:= Dict_insert(d1, Value_bool(true), Value_int(2)); - assert [get_1]: Dict_get(d2, Value_int(1)) == Value_int(2); -}; - -procedure test_dict_listconstructor () returns () { - var d: Dict, dl: DictList, d2: Dict, d3: Dict; - dl := DictList_cons(Value_bool(true), Value_int(10), DictList_cons(Value_int(1), Value_int(11), DictList_nil())); - d := Dict_from_DicList(dl); - assert [get_1]: Dict_get(d, Value_int(1)) == Value_int(11); - assert [get_true]: Dict_get(d, Value_bool(true)) == Value_int(11); - d2 := Dict_insert(Dict_insert(d, Value_int(10), Value_int(8)), Value_int(1), Value_str("abc")); - assert [get_true2]: Dict_get(d2, Value_bool(true)) == Value_str("abc"); - d3 := Dict_remove(d2, Value_bool(true)); - assert [get_1_d3]: Dict_get(d3, Value_int(1)) == Value_none(); - assert [ncontain]: !Dict_contains(d3, Value_bool(true)); -}; - -procedure forall_dict_test () returns () { - assert [ncontain_general]: forall d: Dict, k: Value :: !Dict_contains(Dict_remove(d,k), k); - assert [ncontain_general']: forall d: Dict, k: Value :: !Dict_contains(Dict_remove(d,normalize_value(k)), k); - assert [contain_general]: forall d: Dict, k: Value, v: Value :: (v == Value_none()) || Dict_contains(Dict_insert(d,k,v), k); - assert [remove_insert]: forall d: Dict, k: Value, v: Value, k': Value :: - !(Dict_get(d,k) == v) || Dict_get((Dict_insert(Dict_remove(d,k), k, v)), k') == Dict_get(d, k'); -}; - -procedure ClassType_test() returns () { - var civ: Value, ci: ClassInstance, v: Value; - ci := ClassInstance_init_InstanceAttribute(ClassInstance_empty("point"), "x", Value_int(1)); - ci := ClassInstance_init_InstanceAttribute(ci, "y", Value_int(2)); - civ := Value_class (ci); - assert [has_x]: hasAttribute(civ,"x"); - assert [nhas_z_expect_unknown]: hasAttribute(civ,"z"); - assert [isInstance_class]: isInstance(civ, ValueType_class("point")); - assert [get_x_empty_expect_unknown]: get_InstanceAttribute(civ, "x") == ValueExcept_ok(Value_none()); - assert [get_x]: get_InstanceAttribute(civ, "x") == ValueExcept_ok(Value_int(1)); -}; +type ExceptOrNone; +type DictStrAny; #end -#eval verify "cvc5" boogieTypePrelude +--#eval verify "cvc5" boogieTypePrelude +--#eval boogieTypePrelude.format -def Boogie.prelude : Boogie.Program := +def Boogie.Typeprelude : Boogie.Program := Boogie.getProgram Strata.boogieTypePrelude |>.fst end Strata diff --git a/Strata/Languages/Python/BoogieTypePreludeTest.lean b/Strata/Languages/Python/BoogieTypePreludeTest.lean new file mode 100644 index 000000000..a5c875a55 --- /dev/null +++ b/Strata/Languages/Python/BoogieTypePreludeTest.lean @@ -0,0 +1,922 @@ +/- + Copyright Strata Contributors + + SPDX-License-Identifier: Apache-2.0 OR MIT +-/ + +import Strata.DDM.Elab +import Strata.DDM.AST +import Strata.Languages.Boogie.DDMTransform.Parse +import Strata.Languages.Boogie.Verifier + +namespace Strata + +def boogieTypePrelude := +#strata +program Boogie; + +//Generic tag for List +type List_tag; +const CONS : List_tag; +const NIL : List_tag; +axiom [list_tag_unique]: CONS != NIL; +axiom [all_list_tag]: forall lt: List_tag :: lt == CONS || lt == NIL; + +type Error; + +// Constructors +function Error_TypeError (msg : string) : Error; +function Error_AttributeError (msg : string) : Error; +function Error_RePatternError (msg : string) : Error; +function Error_Unimplemented (msg : string) : Error; +function Error_Undefined (msg : string) : Error; + +type Error_tag; +const TYPEERR : Error_tag; +const ATRERR : Error_tag; +const REERR : Error_tag; +const UNIMPLERR : Error_tag; +const UNDEFERR : Error_tag; +axiom [error_tag_unique]: TYPEERR != ATRERR && TYPEERR != REERR && TYPEERR != UNIMPLERR && TYPEERR != UNDEFERR && + ATRERR != REERR && ATRERR != UNIMPLERR && ATRERR != UNDEFERR && + REERR != UNIMPLERR && REERR != UNDEFERR && + UNIMPLERR != UNDEFERR ; + +axiom [all_error_tag]: forall et: Error_tag :: et == TYPEERR || et == ATRERR || et == REERR || et == UNIMPLERR || et == UNDEFERR; + +function ErrorTag (e: Error) : Error_tag; +axiom [ErrorTag_def_typeerr]: forall msg: string :: {ErrorTag(Error_TypeError(msg))} ErrorTag(Error_TypeError(msg)) == TYPEERR; +axiom [ErrorTag_def_attrerr]: forall msg: string :: {ErrorTag(Error_AttributeError(msg))} ErrorTag(Error_AttributeError(msg)) == ATRERR; +axiom [ErrorTag_def_reerr]: forall msg: string :: {ErrorTag(Error_RePatternError(msg))} ErrorTag(Error_RePatternError(msg)) == REERR; +axiom [ErrorTag_def_unimplerr]: forall msg: string :: {ErrorTag(Error_Unimplemented(msg))} ErrorTag(Error_Unimplemented(msg)) == UNIMPLERR; +axiom [ErrorTag_def_undeferr]: forall msg: string :: {ErrorTag(Error_Undefined(msg))} ErrorTag(Error_Undefined(msg)) == UNDEFERR; + +type Except_tag; +const OK : Except_tag; +const ERR : Except_tag; +axiom [except_tag_unique]: OK != ERR; +axiom [all_except_tag]: forall et: Except_tag :: et == OK || et == ERR; + +type stringExcept; +function stringExcept_ok (s: string): stringExcept; +function stringExcept_err (e: Error): stringExcept; +function stringExcept_tag (ie: stringExcept) : Except_tag; +axiom [stringExcept_tag_ok_def]: forall s: string :: {stringExcept_tag(stringExcept_ok(s))} + stringExcept_tag(stringExcept_ok(s)) == OK; +axiom [stringExcept_tag_err_def]: forall e: Error :: {stringExcept_tag(stringExcept_err(e))} + stringExcept_tag(stringExcept_err(e)) == ERR; +function stringExcept_unwrap (lie: stringExcept) : string; +axiom [stringExcept_unwrap_def]: forall s: string :: {stringExcept_tag(stringExcept_ok(s))} + stringExcept_unwrap(stringExcept_ok(s)) == s; + +type boolExcept; +function boolExcept_ok (b: bool): boolExcept; +function boolExcept_err (e: Error): boolExcept; +function boolExcept_tag (be: boolExcept) : Except_tag; +axiom [boolExcept_tag_ok_def]: forall b: bool :: {boolExcept_tag(boolExcept_ok(b))} + boolExcept_tag(boolExcept_ok(b)) == OK; +axiom [boolExcept_tag_err_def]: forall e: Error :: {boolExcept_tag(boolExcept_err(e))} + boolExcept_tag(boolExcept_err(e)) == ERR; +function boolExcept_unwrap (lie: boolExcept) : bool; +axiom [boolExcept_unwrap_def]: forall b: bool :: {boolExcept_tag(boolExcept_ok(b))} + boolExcept_unwrap(boolExcept_ok(b)) == b; + +type intExcept; +function intExcept_ok (i: int): intExcept; +function intExcept_err (e: Error): intExcept; +function intExcept_tag (ie: intExcept) : Except_tag; +axiom [intExcept_tag_ok_def]: forall i: int :: {intExcept_tag(intExcept_ok(i))} + intExcept_tag(intExcept_ok(i)) == OK; +axiom [intExcept_tag_err_def]: forall e: Error :: {intExcept_tag(intExcept_err(e))} + intExcept_tag(intExcept_err(e)) == ERR; +function intExcept_unwrap (lie: intExcept) : int; +axiom [intExcept_unwrap_def]: forall i: int :: {intExcept_tag(intExcept_ok(i))} + intExcept_unwrap(intExcept_ok(i)) == i; + +type Datetime; + +// Value and ListValue types +type Value; +type ListValue; + +type ValueExcept; +function ValueExcept_ok (v: Value): ValueExcept; +function ValueExcept_err (e: Error): ValueExcept; +function ValueExcept_tag (ve: ValueExcept) : Except_tag; +axiom [ValueExcept_tag_ok_def]: forall v: Value :: {ValueExcept_tag(ValueExcept_ok(v))} + ValueExcept_tag(ValueExcept_ok(v)) == OK; +axiom [ValueExcept_tag_err_def]: forall e: Error :: {ValueExcept_tag(ValueExcept_err(e))} + ValueExcept_tag(ValueExcept_err(e)) == ERR; +function ValueExcept_unwrap (lve: ValueExcept) : Value; +axiom [ValueExcept_unwrap_def]: forall v: Value :: {ValueExcept_tag(ValueExcept_ok(v))} + ValueExcept_unwrap(ValueExcept_ok(v)) == v; + +// Class type +type InstanceAttributes := Map string ValueExcept; +type ClassInstance; + +// Constructors +function Value_bool (b : bool) : Value; +function Value_int (i : int) : Value; +function Value_float (f : real) : Value; +function Value_str (s : string) : Value; +function Value_datetime (d : Datetime) : Value; +function Value_none() : Value; +function Value_list (lv : ListValue) : Value; +function Value_class (ci: ClassInstance) : Value; + +function ListValue_nil() : ListValue; +function ListValue_cons(x0 : Value, x1 : ListValue) : ListValue; +//Tags +function ListValue_tag (l: ListValue) : List_tag; +axiom [ListValue_tag_nil_def]: ListValue_tag (ListValue_nil()) == NIL; +axiom [ListValue_tag_cons_def]: forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} ListValue_tag (ListValue_cons(v, vs)) == CONS; + +// Types of Value +type ValueType; +type ListValueType; +const BOOL : ValueType; +const INT : ValueType; +const FLOAT : ValueType; +const STR : ValueType; +const DATETIME : ValueType; +const NONE : ValueType; +function ValueType_class(classname: string): ValueType; + +function isListValueType (t: ValueType): bool; +function isClassValueType (t: ValueType): bool; +axiom [isClassType_def]: forall c: string :: {isClassValueType(ValueType_class(c))} isClassValueType(ValueType_class(c)); + +//Uniqueness axioms +axiom [unique_ValueType_DATETIME]: DATETIME != BOOL && DATETIME != INT && DATETIME != FLOAT && DATETIME != STR && DATETIME != NONE && !isListValueType(DATETIME) && !(isClassValueType(DATETIME)); +axiom [unique_ValueType_bool]: BOOL != INT && BOOL != FLOAT && BOOL != STR && BOOL != NONE && !isListValueType(BOOL) && !(isClassValueType(BOOL)); +axiom [unique_ValueType_int]: INT != STR && INT != FLOAT && INT != NONE && !isListValueType(INT) && !(isClassValueType(INT)); +axiom [unique_ValueType_float]: FLOAT != STR && FLOAT != NONE && !isListValueType(FLOAT) && !(isClassValueType(FLOAT)); +axiom [unique_ValueType_str]: STR != NONE && !isListValueType(STR) && !(isClassValueType(STR)); +axiom [unique_ValueType_none]: !isListValueType(NONE) && !(isClassValueType(NONE)); +axiom [classtype_ne_listtype]: forall t: ValueType :: {isListValueType (t), isClassValueType (t)} !(isListValueType (t) && isClassValueType (t)); +axiom [all_ValueType_cases]: forall t: ValueType :: + t == BOOL || + t == INT || + t == FLOAT || + t == STR || + t == NONE || + t == DATETIME || + isListValueType (t) || + isClassValueType (t); + +//Eq axioms +axiom [value_int_eq]: forall i: int, j: int :: {Value_int(i) == Value_int(j)} (Value_int(i) == Value_int(j)) == (i == j); +axiom [value_bool_eq]: forall b1: bool, b2: bool :: {Value_bool(b1) == Value_bool(b2)} (Value_bool(b1) == Value_bool(b2)) == (b1 == b2); +axiom [value_float_eq]: forall r1: real, r2: real :: {Value_float(r1) == Value_float(r2)} (Value_float(r1) == Value_float(r2)) == (r1 == r2); +axiom [value_str_eq]: forall s1: string, s2: string :: {Value_str(s1) == Value_str(s2)} (Value_str(s1) == Value_str(s2)) == (s1 == s2); +axiom [value_datetime_eq]: forall d1: Datetime, d2: Datetime :: {Value_datetime(d1) == Value_datetime(d2)} (Value_datetime(d1) == Value_datetime(d2)) == (d1 == d2); + +//Constructors and tag functions of ListType +function ListType_nil() : (ListValueType); +function ListType_cons(x0 : ValueType, x1 : ListValueType) : ListValueType; +function ValueType_List (l: ListValueType) : ValueType; +function ListValueType_tag (l: ListValueType) : List_tag; +axiom [ListValueType_tag_nil_def]: ListValueType_tag (ListType_nil()) == NIL; +axiom [ListValueType_tag_cons_def]: forall t: ValueType, ts: ListValueType ::{ListType_cons(t, ts)} (ListValueType_tag (ListType_cons(t, ts)) == CONS); +axiom [isListValueType_def]: forall l: ListValueType ::{isListValueType(ValueType_List (l))} isListValueType(ValueType_List (l)); + +// TypeOf and TypesOf functions +function TypeOf (v : Value) : ValueType; +function TypesOf (v: ListValue) : ListValueType; +// Definitions +axiom [TypesOf_nil_def]: TypesOf(ListValue_nil()) == ListType_nil(); +axiom [TypesOf_cons_def]: forall v: Value, vs: ListValue ::{ListValue_cons(v, vs)} TypesOf(ListValue_cons(v, vs)) == ListType_cons(TypeOf(v), TypesOf(vs)); +axiom [TypeOf_list_def]: forall l: ListValue ::{Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); +axiom [TypeOf_bool]: forall b: bool :: {TypeOf(Value_bool(b))} TypeOf(Value_bool(b)) == BOOL; +axiom [TypeOf_int]: forall i: int :: {Value_int(i)} TypeOf(Value_int(i)) == INT; +axiom [TypeOf_float]: forall f: real :: {Value_float(f)} TypeOf(Value_float(f)) == FLOAT; +axiom [TypeOf_str]: forall s: string :: {Value_str(s)} TypeOf(Value_str(s)) == STR; +axiom [TypeOf_datetime]: forall d: Datetime :: {Value_datetime(d)} TypeOf(Value_datetime(d)) == DATETIME; +axiom [TypeOf_none]: TypeOf(Value_none()) == NONE; +axiom [TypeOf_list]: forall l: ListValue :: {Value_list(l)} TypeOf(Value_list(l)) == ValueType_List(TypesOf(l)); + +axiom [TypeOf_bool_exists]: forall v: Value :: {TypeOf(v) == BOOL} TypeOf(v) == BOOL ==> exists b: bool :: v == Value_bool(b); +axiom [TypeOf_int_exists]: forall v: Value :: {TypeOf(v) == INT} TypeOf(v) == INT ==> exists i: int :: v == Value_int(i); +axiom [TypeOf_float_exists]: forall v: Value :: {TypeOf(v) == FLOAT} TypeOf(v) == FLOAT ==> exists r: real :: v == Value_float(r); +axiom [TypeOf_string_exists]: forall v: Value :: {TypeOf(v) == STR} TypeOf(v) == STR ==> exists s: string :: v == Value_str(s); +axiom [TypeOf_none']: forall v: Value :: {TypeOf(v) == NONE} (TypeOf(v) == NONE) == (v == Value_none()) ; + +function isBool (v: Value): bool { + TypeOf(v) == BOOL +} +function isInt (v: Value): bool { + TypeOf(v) == INT +} +function isStr (v: Value): bool { + TypeOf(v) == STR +} +function isFloat (v: Value): bool{ + TypeOf(v) == FLOAT +} +function isNone (v: Value): bool{ + TypeOf(v) == NONE +} +function isDatetime (v: Value): bool{ + TypeOf(v) == DATETIME +} + +function isList (v: Value): bool; +function isClassInstance (v: Value): bool; + +axiom [isList_def]: forall l: ListValue :: {Value_list(l)} isList(Value_list(l)); +axiom [isList_def']: forall v: Value :: {isListValueType(TypeOf(v))} isList(v) == isListValueType(TypeOf(v)); +axiom [isClassInstance_def]: forall ci: ClassInstance :: {Value_class(ci)} isClassInstance(Value_class(ci)); +axiom [isClassInstance_def']: forall v: Value :: {isClassValueType(TypeOf(v))} isClassInstance(v) == isClassValueType(TypeOf(v)); + +axiom [TypeOf_list_exists]: forall v: Value :: {isList(v)} isList(v) ==> exists l: ListValue :: v == Value_list(l); +axiom [TypeOf_class_exists]: forall v: Value :: {isClassInstance(v)} isClassInstance(v) ==> exists ci: ClassInstance :: v == Value_class(ci); + + +//Casting +function as_bool (v: Value) : bool; +axiom [as_bool_def]: forall b: bool :: {as_bool(Value_bool(b))} as_bool(Value_bool(b)) == b; + +// isSubType functions +function isSubType (t1: ValueType, t2: ValueType) : bool; +function isSubTypes (t1: ListValueType, t2: ListValueType) : bool; +//Definitions +axiom [isSubTypes_nil_def]: isSubTypes(ListType_nil(), ListType_nil()); +axiom [not_isSubTypes_nil]: forall ty: ValueType, l: ListValueType :: !isSubTypes(ListType_nil(), ListType_cons(ty,l)); +axiom [not_isSubTypes_nil']: forall ty: ValueType, l: ListValueType :: !isSubTypes(ListType_cons(ty,l), ListType_nil()); +axiom [isSubTypes_cons_def]:forall t: ValueType, ts: ListValueType, t': ValueType, ts': ListValueType ::{ListType_cons(t, ts), ListType_cons(t', ts')} + isSubTypes(ListType_cons(t, ts), ListType_cons(t', ts')) == (isSubType(t, t') && isSubTypes(ts, ts')); +axiom [isSubType_list_def]: forall l: ListValueType, l': ListValueType :: {ValueType_List(l), ValueType_List(l')} + isSubType(ValueType_List(l), ValueType_List(l')) == isSubTypes(l, l'); +axiom [bool_substype_int]: isSubType(BOOL, INT); +axiom [int_substype_float]: isSubType(INT, FLOAT); +axiom [not_isSubstype_string]: forall t: ValueType ::{isSubType(STR, t), isSubType(t,STR)} + t == STR || (!isSubType(STR, t) && !isSubType(t,STR)); +axiom [not_isSubstype_none]: forall t: ValueType ::{isSubType(NONE, t), isSubType(NONE, t)} + t == NONE || (!isSubType(NONE, t) && !isSubType(t,NONE)); +axiom [not_isSubstype_list]: forall t: ValueType, t': ValueType ::{isSubType(t, t')} + ((isListValueType(t) && !isListValueType(t')) || (!isListValueType(t) && isListValueType(t'))) ==> (!isSubType(t, t') && !isSubType(t', t)); +axiom [not_isSubstype_class_othertypes]: forall t: ValueType, t': ValueType ::{isSubType(t, t')} + ((isClassValueType(t) && !isClassValueType(t')) || (!isClassValueType(t) && isClassValueType(t'))) ==> (!isSubType(t, t') && !isSubType(t', t)); +axiom [not_isSubstype_class]: forall t: ValueType, c: string ::{isSubType(ValueType_class(c), t), isSubType(t,ValueType_class(c))} + t != ValueType_class(c) ==> (!isSubType(ValueType_class(c), t) && !isSubType(t,ValueType_class(c))); +// Supporting lemmas +axiom [isSubtype_rfl]: forall t: ValueType::{isSubType (t,t)} isSubType (t,t); +axiom [isSubtype_mono]: forall t1: ValueType, t2: ValueType ::{isSubType (t1,t2)} !isSubType (t1,t2) || (t1 == t2 || !isSubType(t2,t1)); +axiom [isSubtype_trans]: forall t1: ValueType, t2: ValueType, t3: ValueType::{isSubType(t1, t2)} !(isSubType(t1, t2) && isSubType(t2, t3)) || isSubType(t1, t3); + +// isInstance function: +function isInstance (v: Value, vt: ValueType) : bool; +axiom [isInstance_of_isSubtype]: forall v: Value, t: ValueType::{isInstance(v,t)} isInstance(v,t) == isSubType(TypeOf(v), t); + +function is_IntReal (v: Value) : bool; +function Value_real_to_int (v: Value) : int; +// to be extended +function normalize_value (v : Value) : Value { + if v == Value_bool(true) then Value_int(1) + else (if v == Value_bool(false) then Value_int(0) else + if TypeOf(v) == FLOAT && is_IntReal(v) then Value_int(Value_real_to_int(v)) else + v) +} + +type ListValueExcept; +function ListValueExcept_ok (l: ListValue): ListValueExcept; +function ListValueExcept_err (e: Error): ListValueExcept; +function ListValueExcept_tag (lve: ListValueExcept) : Except_tag; +axiom [ListValueExcept_tag_ok_def]: forall l: ListValue :: {ListValueExcept_tag(ListValueExcept_ok(l))} + ListValueExcept_tag(ListValueExcept_ok(l)) == OK; +axiom [ListValueExcept_tag_err_def]: forall e: Error :: {ListValueExcept_tag(ListValueExcept_err(e))} + ListValueExcept_tag(ListValueExcept_err(e)) == ERR; +function ListValueExcept_unwrap (lve: ListValueExcept) : ListValue; +axiom [ListValueExcept_unwrap_def]: forall l: ListValue :: {ListValueExcept_tag(ListValueExcept_ok(l))} + ListValueExcept_unwrap(ListValueExcept_ok(l)) == l; + +// ListValue functions +function List_contains (l : ListValue, x: Value) : bool; +function List_len (l : ListValue) : int; +function List_extend (l1 : ListValue, l2: ListValue) : ListValue; +function List_append (l: ListValue, x: Value) : ListValue; +function List_get (l : ListValue, i : int) : ValueExcept; +function List_reverse (l: ListValue) : ListValue; +function List_index! (l: ListValue, v: Value): int; +function List_index (l: ListValue, v: Value): intExcept; +function List_repeat (l: ListValue, n: int): ListValue; +function List_insert (l: ListValue, i: int, v: Value): ListValue; +function List_remove (l: ListValue, v: Value): ListValue; +//TO BE done +function List_pop (l: ListValue, i: int): ListValueExcept; + +//List function axioms +axiom [List_contains_nil_def]: forall x : Value ::{List_contains(ListValue_nil(), x)} + !List_contains(ListValue_nil(), x); +axiom [List_contains_cons_def]: forall x : Value, h : Value, t : ListValue ::{List_contains(ListValue_cons(h,t),x)} + List_contains(ListValue_cons(h,t),x) == ((normalize_value(x)==normalize_value(h)) || List_contains(t, x)); + +axiom [List_len_nil_def]: List_len (ListValue_nil()) == 0; +axiom [List_len_cons_def]: forall h : Value, t : ListValue ::{List_len (ListValue_cons(h,t))} + List_len (ListValue_cons(h,t)) == 1 + List_len(t); +axiom [List_len_nonneg]: forall l: ListValue :: {List_len(l)} List_len(l) >= 0 ; +axiom [List_nil_of_len_zero]: forall l: ListValue :: {List_len(l) == 0} + (List_len(l) == 0) == (l == ListValue_nil()); + +axiom [List_extend_nil_def]: forall l1: ListValue ::{List_extend (l1, ListValue_nil())} + List_extend (l1, ListValue_nil()) == l1; +axiom [List_nil_extend_def]: forall l1: ListValue ::{List_extend (ListValue_nil(), l1)} + List_extend (ListValue_nil(), l1) == l1; +axiom [List_cons_extend_def]: forall h: Value, t: ListValue, l2: ListValue ::{List_extend (ListValue_cons(h,t), l2)} + List_extend (ListValue_cons(h,t), l2) == ListValue_cons(h, List_extend(t,l2)); + +axiom [List_cons_extend_contains]: forall x: Value, l1: ListValue, l2: ListValue ::{List_contains (List_extend(l1,l2), x)} + List_contains (List_extend(l1,l2), x) == (List_contains (l1,x) || List_contains(l2,x)); +axiom [List_len_extend]: forall l1: ListValue, l2: ListValue ::{List_len (List_extend(l1,l2))} + List_len (List_extend(l1,l2)) == List_len (l1) + List_len(l2); +axiom [List_extend_assoc]: forall l1: ListValue, l2: ListValue, l3: ListValue :: {List_extend(List_extend(l1,l2), l3)} + List_extend(List_extend(l1,l2), l3) == List_extend(l1,List_extend(l2,l3)); + +axiom [List_get_nil]: forall i : int ::{List_get (ListValue_nil(), i)} + List_get (ListValue_nil(), i) == ValueExcept_err(Error_Undefined("index out of bound")); +axiom [List_get_zero]: forall h : Value, t : ListValue ::{List_get (ListValue_cons(h,t), 0)} + List_get (ListValue_cons(h,t), 0) == ValueExcept_ok(h); +axiom [List_get_ind]: forall h : Value, t : ListValue, i : int ::{List_get (ListValue_cons(h,t), i)} + (i > 0) ==> (List_get (ListValue_cons(h,t), i)) == List_get (t, i - 1); +axiom [List_get_contains]: forall l: ListValue, i: int, x: Value :: {List_contains(l,x), List_get(l,i)} + (List_get(l,i) == ValueExcept_ok(x)) ==> List_contains(l,x); +axiom [List_get_contains_eq]: forall l: ListValue, x: Value :: {List_contains(l,x)} + List_contains(l,x) == (exists i:int :: {} List_get(l,i) == ValueExcept_ok(x)); +axiom [List_get_ok]: forall l: ListValue, i: int:: {List_get(l,i)} + ((List_get(l,i)) != ValueExcept_err(Error_Undefined("index out of bound"))) == (i < List_len(l) && i >= 0); +axiom [List_get_ok']: forall l: ListValue, i: int:: {List_get(l,i)} + (ValueExcept_tag(List_get(l,i)) != ERR) == (i < List_len(l) && i >= 0); +axiom [List_extend_get]: forall l1: ListValue, l2: ListValue, i: int :: {List_get(List_extend(l1,l2), i)} + List_get(List_extend(l1,l2), i) == if i < List_len(l1) then List_get(l1, i) else List_get(l2, i - List_len(l1)); + +axiom [List_append_def]: forall l: ListValue, x: Value :: {List_append(l,x)} + List_append(l,x) == List_extend(l, ListValue_cons(x, ListValue_nil())); + +axiom [List_reverse_def_nil]: List_reverse(ListValue_nil()) == ListValue_nil(); +axiom [List_reverse_def_cons]: forall h: Value, t: ListValue:: {List_reverse(ListValue_cons(h,t))} + List_reverse(ListValue_cons(h,t)) == List_append(List_reverse(t), h); +axiom [List_reverse_len]: forall l: ListValue :: {List_len(List_reverse(l))} + List_len(l) == List_len(List_reverse(l)); +axiom [List_reverse_contain]: forall l: ListValue, v: Value :: {List_contains (List_reverse(l), v)} + List_contains (List_reverse(l), v) == List_contains(l,v); +axiom [List_reverse_index]: forall l: ListValue, i: int :: {List_get(List_reverse(l), i)} + List_get(List_reverse(l), i) == List_get(l, List_len(l)-1-i); +axiom [List_reverse_reverse]: forall l: ListValue :: {List_reverse(List_reverse(l))} + List_reverse(List_reverse(l)) == l; +axiom [List_reverse_extend]: forall l1: ListValue, l2: ListValue :: {List_reverse(List_extend(l1,l2))} + List_reverse(List_extend(l1,l2)) == List_extend(List_reverse(l2), List_reverse(l1)); + +axiom [List_index!_nil_def]: forall v: Value :: {List_index!(ListValue_nil(), v)} + List_index!(ListValue_nil(), v) == 0; +axiom [List_index!_cons_def_1]: forall h: Value, t: ListValue :: {List_index!(ListValue_cons(h,t), h)} + List_index!(ListValue_cons(h,t), h) == 0; +axiom [List_index!_cons_def_2]: forall v: Value, h: Value, t: ListValue :: {List_index!(ListValue_cons(h,t), v)} + !(normalize_value(v)==normalize_value(h)) ==> List_index!(ListValue_cons(h,t), v) == List_index!(t, v) + 1; +axiom [List_index_def]: forall v: Value, l: ListValue :: {List_index(l, v)} + List_index(l,v) == if (List_index!(l,v) == List_len(l)) then intExcept_err(Error_Undefined("List does not contain element")) + else intExcept_ok(List_index!(l,v)); + +axiom [List_repeat_def]: forall l: ListValue, n: int :: {List_repeat(l, n)} + List_repeat(l, n) == if (n <= 0) then ListValue_nil() else + if (n == 1) then l else List_extend(l, List_repeat(l, n-1)); +axiom [List_repeat_mul]: forall l: ListValue, n: int, m: int :: {List_repeat(List_repeat(l, n),m)} + List_repeat(List_repeat(l, n),m) == List_repeat(l, n * m); +axiom [List_repeat_len]: forall l: ListValue, n: int :: {List_len(List_repeat(l, n))} + n > 0 ==> List_len(List_repeat(l, n)) == n * List_len(l); +axiom [List_repeat_contain]: forall l: ListValue, v: Value, n: int :: {List_contains(List_repeat(l, n), v)} + n > 0 ==> (List_contains(List_repeat(l, n), v) == List_contains(l, v)); +axiom [List_repeat_get]: forall l: ListValue, v: Value, i: int, n: int, m: int :: {List_get(List_repeat(l, n), i + m * List_len(l))} + (i >= 0 && i < List_len(l) && m >= 0 && m < n) ==> (List_get(List_repeat(l, n), i + m * List_len(l)) == List_get(l, i)); + +axiom [List_insert_def0]: forall i: int, v: Value :: {List_insert(ListValue_nil(), i, v)} + List_insert(ListValue_nil(), i, v) == ListValue_cons(v, ListValue_nil()); +axiom [List_insert_def1]: forall l: ListValue, i: int, v: Value :: {List_insert(l, i, v)} + i <= 0 ==> List_insert(l, i, v) == ListValue_cons(v, l); +axiom [List_insert_def2]: forall h: Value, t: ListValue, i: int, v: Value :: {List_insert(ListValue_cons(h,t), i, v)} + (i > 0) ==> List_insert(ListValue_cons(h,t), i, v) == ListValue_cons(h, List_insert(t, i-1, v)); +axiom [List_insert_len]: forall l: ListValue, i: int, v: Value :: {List_len(List_insert(l, i, v))} + List_len(List_insert(l, i, v)) == List_len(l) + 1; +axiom [List_insert_get0]: forall l: ListValue, p: int, v: Value:: {List_get(List_insert(l, p, v), p)} + (p >= 0 && p < List_len(l)) ==> (List_get(List_insert(l, p, v), p) == ValueExcept_ok(v)); +axiom [List_insert_get1]: forall l: ListValue, p: int, v: Value:: {List_get(List_insert(l, p, v), p)} + p >= List_len(l) ==> (List_get(List_insert(l, p, v), List_len(l)) == ValueExcept_ok(v)); +axiom [List_insert_get2]: forall l: ListValue, p: int, v: Value, i: int :: {List_get(List_insert(l, p, v), i)} + (p >= List_len(l) && i < List_len(l)) ==> (List_get(List_insert(l, p, v),i) == List_get(l, i)); +axiom [List_insert_get3]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} + (p >= 0 && p < List_len(l) && i < p) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i)); +axiom [List_insert_get4]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} + (p >= 0 && p < List_len(l) && i > p) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i -1)); +axiom [List_insert_get6]: forall l: ListValue, p: int, v: Value, i: int:: {List_get(List_insert(l, p, v), i)} + (p <= 0 && i > 0) ==> (List_get(List_insert(l, p, v), i) == List_get(l,i -1)); +axiom [List_insert_contains]: forall l: ListValue, i: int, v: Value :: {List_contains(List_insert(l,i,v),v)} + List_contains(List_insert(l,i,v),v); + +axiom [List_remove_nil_def]: forall x : Value ::{List_remove(ListValue_nil(), x)} + List_remove(ListValue_nil(), x) == ListValue_nil(); +axiom [List_remove_cons_def]: forall x : Value, h : Value, t : ListValue ::{List_remove(ListValue_cons(h,t),x)} + List_remove(ListValue_cons(h,t),x) == if (normalize_value(x)==normalize_value(h)) then t + else ListValue_cons(h, List_remove(t, x)); +axiom [List_remove_len]: forall l: ListValue, x: Value :: {List_len(List_remove(l,x))} + List_len(List_remove(l,x)) == if (List_contains(l,x)) then (List_len(l) - 1) else List_len(l); +axiom [List_remove_not_contain]: forall l: ListValue, x: Value :: {List_remove(l,x)} + (!List_contains(l,x)) == (List_remove(l,x) == l); + +axiom [List_pop_def0]: forall i: int :: {List_pop(ListValue_nil(), i)} + List_pop(ListValue_nil(), i) == ListValueExcept_err(Error_Undefined("Pop from empty list")); +axiom [List_pop_def1]: forall h: Value, t: ListValue:: {List_pop(ListValue_cons(h,t), 0)} + List_pop(ListValue_cons(h,t), 0) == ListValueExcept_ok(t); +axiom [List_pop_def2]: forall h: Value, t: ListValue, i: int :: {List_pop(ListValue_cons(h,t), i)} + List_pop(ListValue_cons(h,t), i) == + if (i > 0 && i <= List_len(t)) then + ListValueExcept_ok(ListValue_cons(h, ListValueExcept_unwrap(List_pop(t, i-1)))) + else ListValueExcept_err(Error_Undefined("Pop outside of index range")); +axiom [List_pop_def3]: forall h: Value, t: ListValue, i: int :: {List_pop(ListValue_cons(h,t), i)} + (i < 0) ==> List_pop(ListValue_cons(h,t), i) == ListValueExcept_err(Error_Undefined("Pop outside of index range")); +axiom [List_pop_len]: forall l: ListValue, i: int :: {List_len(ListValueExcept_unwrap(List_pop(l, i)))} + List_len(ListValueExcept_unwrap(List_pop(l, i))) == List_len(l) - 1; +axiom [List_pop_get0]: forall l: ListValue, p: int, i :int:: {List_get(ListValueExcept_unwrap(List_pop(l, p)), i)} + (p >= 0 && p < List_len(l) && i < p) ==> + (List_get(ListValueExcept_unwrap(List_pop(l, p)), i) == List_get(l, i)); +axiom [List_pop_get2]: forall l: ListValue, p: int, i :int:: {List_get(ListValueExcept_unwrap(List_pop(l, p)), i)} + (p >= 0 && p < List_len(l) && i > p) ==> + (List_get(ListValueExcept_unwrap(List_pop(l, p)), i) == List_get(l, i + 1)); + +// Dict type +type Dict := Map Value Value; + +//Dictionary functions +function Dict_empty() : Dict; +function Dict_insert (d: Dict, k: Value, v: Value) : Dict; +function Dict_get (d: Dict, k: Value) : Value; +function Dict_remove (d: Dict, k: Value) : Dict; +function Dict_contains (d: Dict, k: Value) : bool { + Dict_get (d,k) != Value_none() +} + +//Dictionary axioms +axiom [emptydict_def]: forall k: Value :: {Dict_empty() [k]} Dict_empty() [k] == Value_none(); +axiom [Dict_get_def]: forall d: Dict, k: Value :: {Dict_get(d,k)} Dict_get(d,k) == d[normalize_value(k)]; +axiom [Dict_insert_def]: forall d: Dict, k: Value, v: Value :: {Dict_insert(d,k,v)} Dict_insert(d,k,v) == d[normalize_value(k):= v]; +axiom [Dict_remove_def]: forall d: Dict, k: Value :: {Dict_remove(d,k)} Dict_remove(d,k) == d[normalize_value(k):= Value_none()]; + +// List of pairs of Value, used to construct Dict +type DictList; +// Constructor +function DictList_nil(): DictList; +function DictList_cons(k: Value, v: Value, d: DictList): DictList; +//Tag and tag functions +function DictList_tag (dl: DictList) : List_tag; +axiom [DistListTag_nil_def]: DictList_tag (DictList_nil()) == NIL; +axiom [DistListTag_cons_def]: forall k: Value, v: Value, d: DictList ::{DictList_cons(k,v,d)} DictList_tag (DictList_cons(k,v,d)) == CONS; +// as a constructor for Dict +function Dict_from_DicList (l : DictList) : Dict; +function Dict_from_DicList_rev (l : DictList, acc: Dict) : Dict; +axiom [Dict_from_DicList_rev_nil]: forall acc: Dict :: Dict_from_DicList_rev(DictList_nil(), acc) == acc; +axiom [Dict_from_DicList_rev_cons]: forall k: Value, v: Value, d: DictList, acc: Dict :: + Dict_from_DicList_rev(DictList_cons(k,v,d), acc) == Dict_from_DicList_rev(d,Dict_insert(acc, k, v)); +axiom [Dict_from_DicList_def]: forall dl: DictList:: {Dict_from_DicList(dl)} + Dict_from_DicList(dl) == Dict_from_DicList_rev(dl, Dict_empty()); + +type ClassInstanceExcept; +function ClassInstanceExcept_ok (ci: ClassInstance): ClassInstanceExcept; +function ClassInstanceExcept_err (e: Error): ClassInstanceExcept; +function ClassInstanceExcept_tag (ie: ClassInstanceExcept) : Except_tag; +axiom [ClassInstanceExcept_tag_ok_def]: forall ci: ClassInstance :: {ClassInstanceExcept_tag(ClassInstanceExcept_ok(ci))} + ClassInstanceExcept_tag(ClassInstanceExcept_ok(ci)) == OK; +axiom [ClassInstanceExcept_tag_err_def]: forall e: Error :: {ClassInstanceExcept_tag(ClassInstanceExcept_err(e))} + ClassInstanceExcept_tag(ClassInstanceExcept_err(e)) == ERR; +function ClassInstanceExcept_unwrap (lie: ClassInstanceExcept) : ClassInstance; +axiom [ClassInstanceExcept_unwrap_def]: forall ci: ClassInstance :: {ClassInstanceExcept_tag(ClassInstanceExcept_ok(ci))} + ClassInstanceExcept_unwrap(ClassInstanceExcept_ok(ci)) == ci; + +// Class type modelling + +function ClassInstance_mk (c: string, av: InstanceAttributes) : ClassInstance; + +function ClassInstance_getInstanceAttributes (ci: ClassInstance) : InstanceAttributes; +axiom [getAttributes_def]: forall c: string, av: InstanceAttributes :: { ClassInstance_getInstanceAttributes(ClassInstance_mk (c, av))} + ClassInstance_getInstanceAttributes(ClassInstance_mk (c, av)) == av; + +function ClassInstance_getClassname (ci: ClassInstance) : string; +axiom [get_Class_def]: forall c: string, av: InstanceAttributes :: {ClassInstance_getClassname(ClassInstance_mk (c, av))} + ClassInstance_getClassname(ClassInstance_mk (c, av)) == c; + +axiom [TypeOf_class]: forall ci: ClassInstance :: {TypeOf(Value_class(ci))} TypeOf(Value_class(ci)) == ValueType_class(ClassInstance_getClassname(ci)); + +function InstanceAttributes_empty() : InstanceAttributes; +axiom [AttributeValues_empty_def]: forall a: string :: {InstanceAttributes_empty()[a]} + InstanceAttributes_empty()[a] == ValueExcept_err(Error_AttributeError("Invalid Instance attribute of Class")); + +function ClassInstance_empty (c: string) : ClassInstance { + ClassInstance_mk(c,InstanceAttributes_empty()) +} + +function ClassInstance_init_InstanceAttribute(ci: ClassInstance, attribute: string, v: Value) : ClassInstance{ + ClassInstance_mk(ClassInstance_getClassname(ci), ClassInstance_getInstanceAttributes(ci)[attribute := ValueExcept_ok(v)]) +} + +function ClassInstance_get_InstanceAttribute(ci: ClassInstance, attribute: string) : ValueExcept { + ClassInstance_getInstanceAttributes(ci)[attribute] +} + +function ClassInstance_set_InstanceAttribute (ci: ClassInstance, attribute: string, value: Value): ClassInstanceExcept{ + if ValueExcept_tag(ClassInstance_get_InstanceAttribute(ci, attribute)) == OK then + ClassInstanceExcept_ok(ClassInstance_mk(ClassInstance_getClassname(ci), + ClassInstance_getInstanceAttributes(ci)[attribute:=ValueExcept_ok(value)])) + else ClassInstanceExcept_err(Error_AttributeError("Invalid instance attribute of class")) +} + +function get_ClassInstance (v: Value) : ClassInstanceExcept; +axiom [get_ClassInstance_valid]: forall ci: ClassInstance :: {get_ClassInstance(Value_class(ci))} + get_ClassInstance(Value_class(ci)) == ClassInstanceExcept_ok(ci); +axiom [get_ClassInstance_invalid]: forall v: Value :: {get_ClassInstance(v)} + !isClassInstance(v) ==> get_ClassInstance(v) == ClassInstanceExcept_err (Error_TypeError("Not of Class type")); + +function get_InstanceAttribute(v: Value, attribute: string) : ValueExcept { + if isClassInstance(v) then + ClassInstance_get_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute) + else ValueExcept_err(Error_TypeError("Not of Class type")) +} + +function set_InstanceAttribute(v: Value, attribute: string, v': Value) : ValueExcept{ + if isClassInstance(v) then + if (ClassInstanceExcept_tag(ClassInstance_set_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute, v')) == OK) then + ValueExcept_ok( Value_class ( + ClassInstanceExcept_unwrap(ClassInstance_set_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute, v')) + )) + else ValueExcept_err(Error_AttributeError(("Invalid instance attribute of class"))) + else ValueExcept_err(Error_TypeError("Not of Class type")) +} + +function get_Classname (v: Value) : stringExcept { + if isClassInstance(v) then + stringExcept_ok(ClassInstance_getClassname(ClassInstanceExcept_unwrap(get_ClassInstance(v)))) + else stringExcept_err(Error_TypeError("Not of Class type")) +} + +function hasAttribute(v: Value, attribute: string): bool { + if isClassInstance(v) then + (ValueExcept_tag(ClassInstance_get_InstanceAttribute(ClassInstanceExcept_unwrap(get_ClassInstance(v)), attribute)) == OK) + else false +} + +//Binary op functions +function int_to_real (i: int) : real; +function str_repeat (s: string, i: int) : string; +function Py_add (v1: Value, v2: Value) : ValueExcept; +function Py_sub (v1: Value, v2: Value) : ValueExcept; +function Py_mul (v1: Value, v2: Value) : ValueExcept; +function Py_gt (v1: Value, v2: Value) : boolExcept; +function Py_lt (v1: Value, v2: Value) : boolExcept; +function Py_ge (v1: Value, v2: Value) : boolExcept; +function Py_le (v1: Value, v2: Value) : boolExcept; +function Py_eq (v1: Value, v2: Value) : bool; +inline function bool_to_int (b: bool) : int {if b then 1 else 0} +inline function bool_to_real (b: bool) : real {if b then 1.0 else 0.0} + +axiom [Py_add_ints]: forall i1: int, i2: int :: {Py_add(Value_int(i1), Value_int(i2))} + Py_add(Value_int(i1), Value_int(i2)) == ValueExcept_ok(Value_int(i1 + i2)); +axiom [Py_add_floats]: forall f1: real, f2: real :: {Py_add(Value_float(f1), Value_float(f2))} + Py_add(Value_float(f1), Value_float(f2)) == ValueExcept_ok(Value_float(f1 + f2)); +axiom [Py_add_bools]: forall b1: bool, b2: bool :: {Py_add(Value_bool(b1), Value_bool(b2))} + Py_add(Value_bool(b1), Value_bool(b2)) == ValueExcept_ok(Value_int(bool_to_int(b1) + bool_to_int(b2))); +axiom [Py_add_int_bool]: forall i: int, b: bool :: {Py_add(Value_int(i), Value_bool(b))} + Py_add(Value_int(i), Value_bool(b)) == ValueExcept_ok(Value_int(i + bool_to_int(b))); +axiom [Py_add_bool_int]: forall b: bool, i: int :: {Py_add(Value_bool(b), Value_int(i))} + Py_add(Value_bool(b), Value_int(i)) == ValueExcept_ok(Value_int(bool_to_int(b) + i)); +axiom [Py_add_int_float]: forall i: int, r: real :: {Py_add(Value_int(i), Value_float(r))} + Py_add(Value_int(i), Value_float(r)) == ValueExcept_ok(Value_float(r + int_to_real(i))); +axiom [Py_add_float_int]: forall r: real, i: int :: {Py_add(Value_float(r), Value_int(i))} + Py_add(Value_float(r), Value_int(i)) == ValueExcept_ok(Value_float(int_to_real(i) + r)); +axiom [Py_add_float_bool]: forall r: real, b: bool :: {Py_add(Value_float(r), Value_bool(b))} + Py_add(Value_float(r), Value_bool(b)) == ValueExcept_ok(Value_float(r + bool_to_real(b))); +axiom [Py_add_bool_float]: forall b: bool, r: real :: {Py_add(Value_bool(b), Value_float(r))} + Py_add(Value_bool(b), Value_float(r)) == ValueExcept_ok(Value_float(bool_to_real(b) + r)); +axiom [Py_add_strs]: forall s1: string, s2: string :: {Py_add(Value_str(s1), Value_str(s2))} + Py_add(Value_str(s1), Value_str(s2)) == ValueExcept_ok(Value_str(str.concat(s1, s2))); +axiom [Py_add_lists]: forall l1: ListValue, l2: ListValue :: {Py_add(Value_list(l1), Value_list(l2))} + Py_add(Value_list(l1), Value_list(l2)) == ValueExcept_ok(Value_list(List_extend(l1, l2))); +axiom [Py_add_undefined]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_add(v1, v2) == ValueExcept_err(Error_Undefined("Operand Type is not defined")); + +axiom [Py_sub_ints]: forall i1: int, i2: int :: {Py_sub(Value_int(i1), Value_int(i2))} + Py_sub(Value_int(i1), Value_int(i2)) == ValueExcept_ok(Value_int(i1 - i2)); +axiom [Py_sub_floats]: forall f1: real, f2: real :: {Py_sub(Value_float(f1), Value_float(f2))} + Py_sub(Value_float(f1), Value_float(f2)) == ValueExcept_ok(Value_float(f1 - f2)); +axiom [Py_sub_bools]: forall b1: bool, b2: bool :: {Py_sub(Value_bool(b1), Value_bool(b2))} + Py_sub(Value_bool(b1), Value_bool(b2)) == ValueExcept_ok(Value_int(bool_to_int(b1) - bool_to_int(b2))); +axiom [Py_sub_int_bool]: forall i: int, b: bool :: {Py_sub(Value_int(i), Value_bool(b))} + Py_sub(Value_int(i), Value_bool(b)) == ValueExcept_ok(Value_int(i - bool_to_int(b))); +axiom [Py_sub_bool_int]: forall b: bool, i: int :: {Py_sub(Value_bool(b), Value_int(i))} + Py_sub(Value_bool(b), Value_int(i)) == ValueExcept_ok(Value_int(bool_to_int(b) - i)); +axiom [Py_sub_int_float]: forall i: int, r: real :: {Py_sub(Value_int(i), Value_float(r))} + Py_sub(Value_int(i), Value_float(r)) == ValueExcept_ok(Value_float(r - int_to_real(i))); +axiom [Py_sub_float_int]: forall r: real, i: int :: {Py_sub(Value_float(r), Value_int(i))} + Py_sub(Value_float(r), Value_int(i)) == ValueExcept_ok(Value_float(int_to_real(i) - r)); +axiom [Py_sub_float_bool]: forall r: real, b: bool :: {Py_sub(Value_float(r), Value_bool(b))} + Py_sub(Value_float(r), Value_bool(b)) == ValueExcept_ok(Value_float(r - bool_to_real(b))); +axiom [Py_sub_bool_float]: forall b: bool, r: real :: {Py_sub(Value_bool(b), Value_float(r))} + Py_sub(Value_bool(b), Value_float(r)) == ValueExcept_ok(Value_float(bool_to_real(b) - r)); +axiom [Py_sub_undefined]: forall v1: Value, v2: Value :: {Py_sub(v1,v2)} + !(isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) ==> + Py_sub(v1, v2) == ValueExcept_err(Error_Undefined("Operand Type is not defined")); + +axiom [Py_mul_ints]: forall i1: int, i2: int :: {Py_mul(Value_int(i1), Value_int(i2))} + Py_mul(Value_int(i1), Value_int(i2)) == ValueExcept_ok(Value_int(i1 * i2)); +axiom [Py_mul_bools]: forall b1: bool, b2: bool :: {Py_mul(Value_bool(b1), Value_bool(b2))} + Py_mul(Value_bool(b1), Value_bool(b2)) == ValueExcept_ok(Value_int(bool_to_int(b1) * bool_to_int(b2))); +axiom [Py_mul_int_bool]: forall i: int, b: bool :: {Py_mul(Value_int(i), Value_bool(b))} + Py_mul(Value_int(i), Value_bool(b)) == ValueExcept_ok(Value_int(i * bool_to_int(b))); +axiom [Py_mul_bool_int]: forall b: bool, i: int :: {Py_mul(Value_bool(b), Value_int(i))} + Py_mul(Value_bool(b), Value_int(i)) == ValueExcept_ok(Value_int(bool_to_int(b) * i)); +axiom [Py_mul_str_int]: forall s: string, i: int :: {Py_mul(Value_str(s), Value_int(i))} + Py_mul(Value_str(s), Value_int(i)) == ValueExcept_ok(Value_str(str_repeat(s, i))); +axiom [Py_mul_int_str]: forall s: string, i: int :: {Py_mul(Value_int(i), Value_str(s))} + Py_mul(Value_int(i), Value_str(s)) == ValueExcept_ok(Value_str(str_repeat(s, i))); +axiom [Py_mul_str_bool]: forall s: string, b: bool :: {Py_mul(Value_str(s), Value_bool(b))} + Py_mul(Value_str(s), Value_bool(b)) == ValueExcept_ok(Value_str(if b then s else "")); +axiom [Py_mul_bool_str]: forall s: string, b: bool :: {Py_mul(Value_bool(b), Value_str(s)) } + Py_mul(Value_bool(b), Value_str(s)) == ValueExcept_ok(Value_str(if b then s else "")); +axiom [Py_mul_list_int]: forall l: ListValue, i: int :: {Py_mul(Value_list(l), Value_int(i))} + Py_mul(Value_list(l), Value_int(i)) == ValueExcept_ok(Value_list(List_repeat(l, i))); +axiom [Py_mul_int_list]: forall l: ListValue, i: int :: {Py_mul(Value_int(i), Value_list(l))} + Py_mul(Value_int(i), Value_list(l)) == ValueExcept_ok(Value_list(List_repeat(l, i))); +axiom [Py_mul_list_bool]: forall l: ListValue, b: bool :: {Py_mul(Value_list(l), Value_bool(b))} + Py_mul(Value_list(l), Value_bool(b)) == ValueExcept_ok(Value_list(if b then l else ListValue_nil())); +axiom [Py_mul_bool_list]: forall l: ListValue, b: bool :: {Py_mul(Value_bool(b), Value_list(l)) } + Py_mul(Value_bool(b), Value_list(l)) == ValueExcept_ok(Value_list(if b then l else ListValue_nil())); +axiom [Py_mul_undefined]: forall v1: Value, v2: Value :: {Py_add(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && isInstance(v2, INT)) || + (TypeOf(v2) == STR && isInstance(v1, INT)) || + (isList(v1) && isInstance(v2, INT)) || + (isList(v2) && isInstance(v1, INT)) ) + ==> Py_mul(v1, v2) == ValueExcept_err(Error_Undefined("Operand Type is not defined")); + +axiom [Py_lt_ints]: forall i1: int, i2: int :: {Py_lt(Value_int(i1), Value_int(i2))} + Py_lt(Value_int(i1), Value_int(i2)) == boolExcept_ok(i1 < i2); +axiom [Py_lt_floats]: forall f1: real, f2: real :: {Py_lt(Value_float(f1), Value_float(f2))} + Py_lt(Value_float(f1), Value_float(f2)) == boolExcept_ok(f1 < f2); +axiom [Py_lt_bools]: forall b1: bool, b2: bool :: {Py_lt(Value_bool(b1), Value_bool(b2))} + Py_lt(Value_bool(b1), Value_bool(b2)) == boolExcept_ok(bool_to_int(b1) < bool_to_int(b2)); +axiom [Py_lt_int_bool]: forall i: int, b: bool :: {Py_lt(Value_int(i), Value_bool(b))} + Py_lt(Value_int(i), Value_bool(b)) == boolExcept_ok(i < bool_to_int(b)); +axiom [Py_lt_bool_int]: forall b: bool, i: int :: {Py_lt(Value_bool(b), Value_int(i))} + Py_lt(Value_bool(b), Value_int(i)) == boolExcept_ok(bool_to_int(b) < i); +axiom [Py_lt_int_float]: forall i: int, r: real :: {Py_lt(Value_int(i), Value_float(r))} + Py_lt(Value_int(i), Value_float(r)) == boolExcept_ok(r < int_to_real(i)); +axiom [Py_lt_float_int]: forall r: real, i: int :: {Py_lt(Value_float(r), Value_int(i))} + Py_lt(Value_float(r), Value_int(i)) == boolExcept_ok(int_to_real(i) < r); +axiom [Py_lt_float_bool]: forall r: real, b: bool :: {Py_lt(Value_float(r), Value_bool(b))} + Py_lt(Value_float(r), Value_bool(b)) == boolExcept_ok(r < bool_to_real(b)); +axiom [Py_lt_bool_float]: forall b: bool, r: real :: {Py_lt(Value_bool(b), Value_float(r))} + Py_lt(Value_bool(b), Value_float(r)) == boolExcept_ok(bool_to_real(b) < r); +axiom [Py_lt_undefined]: forall v1: Value, v2: Value :: {Py_lt(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_lt(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not defined")); +axiom [Py_lt_unsupported]: forall v1: Value, v2: Value :: {Py_lt(v1,v2)} + ((TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_lt(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not supported")); + +axiom [Py_gt_ints]: forall i1: int, i2: int :: {Py_gt(Value_int(i1), Value_int(i2))} + Py_gt(Value_int(i1), Value_int(i2)) == boolExcept_ok(i1 > i2); +axiom [Py_gt_floats]: forall f1: real, f2: real :: {Py_gt(Value_float(f1), Value_float(f2))} + Py_gt(Value_float(f1), Value_float(f2)) == boolExcept_ok(f1 > f2); +axiom [Py_gt_bools]: forall b1: bool, b2: bool :: {Py_gt(Value_bool(b1), Value_bool(b2))} + Py_gt(Value_bool(b1), Value_bool(b2)) == boolExcept_ok(bool_to_int(b1) > bool_to_int(b2)); +axiom [Py_gt_int_bool]: forall i: int, b: bool :: {Py_gt(Value_int(i), Value_bool(b))} + Py_gt(Value_int(i), Value_bool(b)) == boolExcept_ok(i > bool_to_int(b)); +axiom [Py_gt_bool_int]: forall b: bool, i: int :: {Py_gt(Value_bool(b), Value_int(i))} + Py_gt(Value_bool(b), Value_int(i)) == boolExcept_ok(bool_to_int(b) > i); +axiom [Py_gt_int_float]: forall i: int, r: real :: {Py_gt(Value_int(i), Value_float(r))} + Py_gt(Value_int(i), Value_float(r)) == boolExcept_ok(r > int_to_real(i)); +axiom [Py_gt_float_int]: forall r: real, i: int :: {Py_gt(Value_float(r), Value_int(i))} + Py_gt(Value_float(r), Value_int(i)) == boolExcept_ok(int_to_real(i) > r); +axiom [Py_gt_float_bool]: forall r: real, b: bool :: {Py_gt(Value_float(r), Value_bool(b))} + Py_gt(Value_float(r), Value_bool(b)) == boolExcept_ok(r > bool_to_real(b)); +axiom [Py_gt_bool_float]: forall b: bool, r: real :: {Py_gt(Value_bool(b), Value_float(r))} + Py_gt(Value_bool(b), Value_float(r)) == boolExcept_ok(bool_to_real(b) > r); +axiom [Py_gt_undefined]: forall v1: Value, v2: Value :: {Py_gt(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_gt(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not defined")); +axiom [Py_gt_unsupported]: forall v1: Value, v2: Value :: {Py_gt(v1,v2)} + ((TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_gt(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not supported")); + +axiom [Py_le_ints]: forall i1: int, i2: int :: {Py_le(Value_int(i1), Value_int(i2))} + Py_le(Value_int(i1), Value_int(i2)) == boolExcept_ok(i1 <= i2); +axiom [Py_le_floats]: forall f1: real, f2: real :: {Py_le(Value_float(f1), Value_float(f2))} + Py_le(Value_float(f1), Value_float(f2)) == boolExcept_ok(f1 <= f2); +axiom [Py_le_bools]: forall b1: bool, b2: bool :: {Py_le(Value_bool(b1), Value_bool(b2))} + Py_le(Value_bool(b1), Value_bool(b2)) == boolExcept_ok(bool_to_int(b1) <= bool_to_int(b2)); +axiom [Py_le_int_bool]: forall i: int, b: bool :: {Py_le(Value_int(i), Value_bool(b))} + Py_le(Value_int(i), Value_bool(b)) == boolExcept_ok(i <= bool_to_int(b)); +axiom [Py_le_bool_int]: forall b: bool, i: int :: {Py_le(Value_bool(b), Value_int(i))} + Py_le(Value_bool(b), Value_int(i)) == boolExcept_ok(bool_to_int(b) <= i); +axiom [Py_le_int_float]: forall i: int, r: real :: {Py_le(Value_int(i), Value_float(r))} + Py_le(Value_int(i), Value_float(r)) == boolExcept_ok(r <= int_to_real(i)); +axiom [Py_le_float_int]: forall r: real, i: int :: {Py_le(Value_float(r), Value_int(i))} + Py_le(Value_float(r), Value_int(i)) == boolExcept_ok(int_to_real(i) <= r); +axiom [Py_le_float_bool]: forall r: real, b: bool :: {Py_le(Value_float(r), Value_bool(b))} + Py_le(Value_float(r), Value_bool(b)) == boolExcept_ok(r <= bool_to_real(b)); +axiom [Py_le_bool_float]: forall b: bool, r: real :: {Py_le(Value_bool(b), Value_float(r))} + Py_le(Value_bool(b), Value_float(r)) == boolExcept_ok(bool_to_real(b) <= r); +axiom [Py_le_undefined]: forall v1: Value, v2: Value :: {Py_le(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_le(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not defined")); +axiom [Py_le_unsupported]: forall v1: Value, v2: Value :: {Py_le(v1,v2)} + ((TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_le(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not supported")); + +axiom [Py_ge_ints]: forall i1: int, i2: int :: {Py_ge(Value_int(i1), Value_int(i2))} + Py_ge(Value_int(i1), Value_int(i2)) == boolExcept_ok(i1 >= i2); +axiom [Py_ge_floats]: forall f1: real, f2: real :: {Py_ge(Value_float(f1), Value_float(f2))} + Py_ge(Value_float(f1), Value_float(f2)) == boolExcept_ok(f1 >= f2); +axiom [Py_ge_bools]: forall b1: bool, b2: bool :: {Py_ge(Value_bool(b1), Value_bool(b2))} + Py_ge(Value_bool(b1), Value_bool(b2)) == boolExcept_ok(bool_to_int(b1) >= bool_to_int(b2)); +axiom [Py_ge_int_bool]: forall i: int, b: bool :: {Py_ge(Value_int(i), Value_bool(b))} + Py_ge(Value_int(i), Value_bool(b)) == boolExcept_ok(i >= bool_to_int(b)); +axiom [Py_ge_bool_int]: forall b: bool, i: int :: {Py_ge(Value_bool(b), Value_int(i))} + Py_ge(Value_bool(b), Value_int(i)) == boolExcept_ok(bool_to_int(b) >= i); +axiom [Py_ge_int_float]: forall i: int, r: real :: {Py_ge(Value_int(i), Value_float(r))} + Py_ge(Value_int(i), Value_float(r)) == boolExcept_ok(r >= int_to_real(i)); +axiom [Py_ge_float_int]: forall r: real, i: int :: {Py_ge(Value_float(r), Value_int(i))} + Py_ge(Value_float(r), Value_int(i)) == boolExcept_ok(int_to_real(i) >= r); +axiom [Py_ge_float_bool]: forall r: real, b: bool :: {Py_ge(Value_float(r), Value_bool(b))} + Py_ge(Value_float(r), Value_bool(b)) == boolExcept_ok(r >= bool_to_real(b)); +axiom [Py_ge_bool_float]: forall b: bool, r: real :: {Py_ge(Value_bool(b), Value_float(r))} + Py_ge(Value_bool(b), Value_float(r)) == boolExcept_ok(bool_to_real(b) >= r); +axiom [Py_ge_undefined]: forall v1: Value, v2: Value :: {Py_ge(v1,v2)} + !((isInstance(v1, FLOAT) && isInstance(v2, FLOAT)) || + (TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_ge(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not defined")); +axiom [Py_ge_unsupported]: forall v1: Value, v2: Value :: {Py_ge(v1,v2)} + ((TypeOf(v1) == STR && TypeOf(v2) == STR) || + (isList(v1) && isList(v2))) + ==> Py_ge(v1, v2) == boolExcept_err(Error_Undefined("Operand Type is not supported")); + +axiom [Py_eq_def]: forall v: Value, v': Value :: {Py_eq(v, v')} + Py_eq(v, v') == (normalize_value(v) == normalize_value (v')); + +function Py_add_unwrap (v1: Value, v2: Value) : Value { + ValueExcept_unwrap (Py_add (v1,v2)) +} +function Py_sub_unwrap (v1: Value, v2: Value) : Value { + ValueExcept_unwrap (Py_sub (v1,v2)) +} +function Py_mul_unwrap (v1: Value, v2: Value) : Value { + ValueExcept_unwrap (Py_mul (v1,v2)) +} +function Py_gt_unwrap (v1: Value, v2: Value) : bool { + boolExcept_unwrap (Py_gt (v1,v2)) +} +function Py_lt_unwrap (v1: Value, v2: Value) : bool { + boolExcept_unwrap (Py_lt (v1,v2)) +} +function Py_ge_unwrap (v1: Value, v2: Value) : bool { + boolExcept_unwrap (Py_ge (v1,v2)) +} +function Py_le_unwrap (v1: Value, v2: Value) : bool { + boolExcept_unwrap (Py_le (v1,v2)) +} + + +//Testing +procedure non_contradiction_test() returns () { + assert [one_eq_two_expect_unknown]: 1 == 2; +}; + +procedure binary_op_and_types_test () returns () { + assert [int_add_ok]: forall i: int :: ValueExcept_tag(Py_add(Value_int(1), Value_int(i))) != ERR; + assert [int_add_class_except]: forall v: Value :: isClassInstance(v) ==> ValueExcept_tag(Py_add(Value_int(1), v)) == ERR; + assert [int_add_class_except']: forall v: Value :: hasAttribute(v, "a") ==> ValueExcept_tag(Py_add(Value_int(1), v)) == ERR; + assert [float_add_isInstance_int_ok]: forall v: Value :: isInstance(v,INT) ==> ValueExcept_tag(Py_add(Value_float(1.1), v)) != ERR; +}; + +procedure ValueTypeTest() returns () { + var ty1: ValueType, ty2: ValueType, tl: ValueType; + ty1 := TypeOf(Value_int(5)); + ty2 := TypeOf(Value_bool(true)); + assert [subtype1]: isSubType(ty2,ty1); + assert [subtypeList]: forall l: ListValueType :: isSubType (ValueType_List(ListType_cons(ty2, l)), ValueType_List(ListType_cons(ty1, l))); + assert [subtypeList2]: forall l1: ListValueType, l2: ListValueType :: !(isSubTypes(l1,l2)) || isSubType (ValueType_List(ListType_cons(ty2, l1)), ValueType_List(ListType_cons(ty1, l2))); +}; + +procedure simple_call(v1: Value, v2: Value) returns () + spec { + requires [v1_type]: isInstance(v1, BOOL) || isInstance(v1, STR); + requires [v2_type]: isInstance(v2, ValueType_List(ListType_cons(INT, ListType_cons(INT, ListType_nil())))); + } +{}; + +procedure test_simple_call_argument_typecheck() returns () { + var arg1: Value, arg2: Value; + arg1 := Value_bool(true); + arg2 := Value_list(ListValue_cons(Value_int(3), ListValue_cons (Value_bool(true), ListValue_nil()))); + assert [subtype_bool]: isInstance(arg1,BOOL); + call simple_call(arg1, arg2); +}; + +procedure list_functions_test() returns () +{ + var l1: ListValue, l2: ListValue; + l1 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil()))); + l2 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), + ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil())))))); + assert [index_1]: List_get(l1,1) == ValueExcept_ok(Value_int(2)); + assert [contain_true]: List_contains(l1, Value_bool(true)); + assert [ValueEq]: !(Value_int(4) == Value_int(3)); + assert [normalize_value]: !(normalize_value(Value_int(4)) == Value_int(3)); + assert [contain_3]: List_contains(l1, Value_int(2)); + assert [list_index_test1]: List_index(l1, Value_int(3)) == intExcept_ok(2); + assert [list_index_test_expect_unknown]: List_index(l1, Value_int(3)) == intExcept_ok(3); + assert [list_index_test2]: intExcept_tag(List_index(l1, Value_int(9))) == ERR; + assert [list_extend]: List_extend(l1, l1) == l2; + assert [list_repeat1]: List_repeat(l1, 2) == l2; + assert [list_repeat2]: List_repeat(l1, 6) == List_repeat(l2, 3); +}; + +procedure list_generic_test() returns () { + var l1: ListValue; + assert [contains_append]: forall l: ListValue, x: Value :: List_contains(List_append(l,x), x); + assert [len_append]: forall l: ListValue, x: Value :: List_len(List_append(l,x)) == List_len(l) + 1; + l1 := ListValue_cons(Value_int(1), ListValue_cons(Value_int(2), ListValue_cons (Value_int(3), ListValue_nil()))); + assert [l1_contains_3]: List_contains (l1, Value_int(3)); + assert [contains_len]: forall l: ListValue, x: Value:: List_contains(l,x) ==> (List_len(l) >0); + assert [l1l2_contains_3]: forall l2: ListValue :: List_contains (List_extend(l1, l2), Value_int(3)); + assert [revl1_contain_3]: List_contains (List_reverse(l1), Value_int(3)); + assert [rev_contain]: forall l: ListValue, v: Value :: List_contains (List_reverse(l), v) == List_contains(l,v); + assert [l1r_l2_contains_3]: forall l2: ListValue :: List_contains (List_extend(List_reverse(l1), l2), Value_int(3)); + assert [l1r_l2_contains_4_expect_unknown]: forall l2: ListValue :: List_contains (List_extend(List_reverse(l1), l2), Value_int(4)); + assert [l1r_l2_contains_3']: forall l2: ListValue :: List_contains (List_reverse(List_extend(List_reverse(l1), l2)), Value_int(3)); + assert [List_cons_extend_contains_symm]: forall x: Value, l1: ListValue, l2: ListValue :: + List_contains (List_extend(l1,l2), x) == List_contains (List_extend(l2,l1), x); + assert [contains_len]: forall l: ListValue, x: Value:: List_contains(l,x) ==> (List_len(l) >0); + assert [contain_remove]: forall l: ListValue, x: Value:: List_contains(l,x) ==> (List_len(l) == List_len(List_remove(l,x)) + 1); + assert [insert_len]: forall l: ListValue, i: int, v: Value :: List_len(List_insert(l, i, v)) == List_len(l) + 1; + assert [insert_contains]: forall l: ListValue, i: int, v: Value :: List_contains(List_insert(l, i, v), v); +}; + +procedure dict_functions_test () returns () { + var d1: Dict, d2: Dict, d3: Dict; + d1:= Dict_insert(Dict_empty(), Value_int(1), Value_int(1)); + d2:= Dict_insert(d1, Value_bool(true), Value_int(2)); + assert [get_1]: Dict_get(d2, Value_int(1)) == Value_int(2); +}; + +procedure test_dict_listconstructor () returns () { + var d: Dict, dl: DictList, d2: Dict, d3: Dict; + dl := DictList_cons(Value_bool(true), Value_int(10), DictList_cons(Value_int(1), Value_int(11), DictList_nil())); + d := Dict_from_DicList(dl); + assert [get_1]: Dict_get(d, Value_int(1)) == Value_int(11); + assert [get_true]: Dict_get(d, Value_bool(true)) == Value_int(11); + d2 := Dict_insert(Dict_insert(d, Value_int(10), Value_int(8)), Value_int(1), Value_str("abc")); + assert [get_true2]: Dict_get(d2, Value_bool(true)) == Value_str("abc"); + d3 := Dict_remove(d2, Value_bool(true)); + assert [get_1_d3]: Dict_get(d3, Value_int(1)) == Value_none(); + assert [ncontain]: !Dict_contains(d3, Value_bool(true)); +}; + +procedure forall_dict_test () returns () { + assert [ncontain_general]: forall d: Dict, k: Value :: !Dict_contains(Dict_remove(d,k), k); + assert [ncontain_general']: forall d: Dict, k: Value :: !Dict_contains(Dict_remove(d,normalize_value(k)), k); + assert [contain_general]: forall d: Dict, k: Value, v: Value :: (v == Value_none()) || Dict_contains(Dict_insert(d,k,v), k); + assert [remove_insert]: forall d: Dict, k: Value, v: Value, k': Value :: + !(Dict_get(d,k) == v) || Dict_get((Dict_insert(Dict_remove(d,k), k, v)), k') == Dict_get(d, k'); +}; + +procedure ClassType_test() returns () { + var civ: Value, ci: ClassInstance, v: Value; + ci := ClassInstance_init_InstanceAttribute(ClassInstance_empty("point"), "x", Value_int(1)); + ci := ClassInstance_init_InstanceAttribute(ci, "y", Value_int(2)); + civ := Value_class (ci); + assert [has_x]: hasAttribute(civ,"x"); + assert [nhas_z_expect_unknown]: hasAttribute(civ,"z"); + assert [isInstance_class]: isInstance(civ, ValueType_class("point")); + assert [get_x_empty_expect_unknown]: get_InstanceAttribute(civ, "x") == ValueExcept_ok(Value_none()); + assert [get_x]: get_InstanceAttribute(civ, "x") == ValueExcept_ok(Value_int(1)); +}; + +#end + +#eval verify "cvc5" boogieTypePrelude +--#eval boogieTypePrelude.format + +def Boogie.prelude : Boogie.Program := + Boogie.getProgram Strata.boogieTypePrelude |>.fst + +end Strata diff --git a/Strata/Languages/Python/PythonToTypeBoogie.lean b/Strata/Languages/Python/PythonToTypeBoogie.lean new file mode 100644 index 000000000..b1bc510d4 --- /dev/null +++ b/Strata/Languages/Python/PythonToTypeBoogie.lean @@ -0,0 +1,962 @@ +/- + Copyright Strata Contributors + + SPDX-License-Identifier: Apache-2.0 OR MIT +-/ + +import Strata.DDM.Elab +import Strata.DDM.AST +import Lean +import Strata.Languages.Boogie.DDMTransform.Parse + +import Strata.Languages.Boogie.Boogie +import Strata.Languages.Python.PythonDialect +import Strata.Languages.Python.FunctionSignatures +import Strata.Languages.Python.Regex.ReToBoogie +import Strata.Languages.Python.PyFactory +import Strata.Languages.Python.FunctionSignatures +import Strata.Languages.Python.BoogieTypePrelude +import StrataTest.Transform.ProcedureInlining +import StrataTest.Internal.InternalBoogiePrelude +import StrataTest.Internal.InternalFunctionSignatures +import Strata.Languages.Boogie.Verifier +import Strata.DDM.Ion +import Strata.Util.IO + +namespace Strata +open Lambda.LTy.Syntax +open Rat +-- Some hard-coded things we'll need to fix later: + +def clientType : Boogie.Expression.Ty := .forAll [] (.tcons "Client" []) +def dummyClient : Boogie.Expression.Expr := .fvar () "DUMMY_CLIENT" none + +def dictStrAnyType : Boogie.Expression.Ty := .forAll [] (.tcons "DictStrAny" []) +def dummyDictStrAny : Boogie.Expression.Expr := .fvar () "DUMMY_DICT_STR_ANY" none + +def strType : Boogie.Expression.Ty := .forAll [] (.tcons "string" []) +def dummyStr : Boogie.Expression.Expr := .fvar () "DUMMY_STR" none + +def listStrType : Boogie.Expression.Ty := .forAll [] (.tcons "ListStr" []) +def dummyListStr : Boogie.Expression.Expr := .fvar () "DUMMY_LIST_STR" none + +def datetimeType : Boogie.Expression.Ty := .forAll [] (.tcons "Datetime" []) +def dummyDatetime : Boogie.Expression.Expr := .fvar () "DUMMY_DATETIME" none + +def dateType : Boogie.Expression.Ty := .forAll [] (.tcons "Date" []) +def dummyDate : Boogie.Expression.Expr := .fvar () "DUMMY_DATE" none + +def timedeltaType : Boogie.Expression.Ty := .forAll [] (.tcons "int" []) +def dummyTimedelta : Boogie.Expression.Expr := .fvar () "DUMMY_Timedelta" none + + +def ValueTy : Boogie.Expression.Ty := .forAll [] (.tcons "Value" []) +def ClassInstanceTy : Boogie.Expression.Ty := .forAll [] (.tcons "ClassInstance" []) + +------------------------------------------------------------------------------- + +-- Translating a Python expression can require Boogie statements, e.g., a function call +-- We translate these by first defining temporary variables to store the results of the stmts +-- and then using those variables in the expression. +structure PyExprTranslated where + stmts : List Boogie.Statement + expr: Boogie.Expression.Expr + post_stmts : List Boogie.Statement := [] +deriving Inhabited + +structure PythonFunctionDecl where + name : String + args : List (String × String) -- Elements are (arg_name, arg_ty) where `arg_ty` is the string representation of the type in Python + ret : String +deriving Repr, BEq, Inhabited + +structure PythonClassDecl where + name : String + --ClassAttributes: List String + --InstanceAttribute: List String +deriving Repr, BEq, Inhabited + +structure TranslationContext where + signatures : Python.Signatures + expectedType : Option (Lambda.LMonoTy) := none + variableTypes : List (String × Lambda.LMonoTy) := [] + func_infos : List PythonFunctionDecl := [] + class_infos : List PythonClassDecl := [] +deriving Inhabited + +------------------------------------------------------------------------------- +def getFunctions (decls: List Boogie.Decl) : List String := + match decls with + | [] => [] + | decl::t => match decl with + |.func f => f.name.name :: (getFunctions t) + | _ => getFunctions t + +def PreludeFunctions : List String := getFunctions Boogie.Typeprelude.decls + +def create_function_app_acc (args: List Boogie.Expression.Expr) (acc: Boogie.Expression.Expr): Boogie.Expression.Expr := + match args with + | [] => acc + | arg :: t => create_function_app_acc t (.app () acc arg) + +def create_function_app (fn: String) (args: List Boogie.Expression.Expr): Boogie.Expression.Expr := + create_function_app_acc args (.op () fn none) + +def toPyCommands (a : Array Operation) : Array (Python.Command SourceRange) := + a.map (λ op => match Python.Command.ofAst op with + | .error e => panic! s!"Failed to translate to Python.Command: {e}" + | .ok cmd => cmd) + +def unwrapModule (c : Python.Command SourceRange) : Array (Python.stmt SourceRange) := + match c with + | Python.Command.Module _ body _ => body.val + | _ => panic! "Expected module" + +def strToBoogieExpr (s: String) : Boogie.Expression.Expr := + .strConst () s + +def intToBoogieExpr (i: Int) : Boogie.Expression.Expr := + .intConst () i + +def PyIntToInt (i : Python.int SourceRange) : Int := + match i with + | .IntPos _ n => n.val + | .IntNeg _ n => -n.val + +def PyConstToBoogie (c: Python.constant SourceRange) : Boogie.Expression.Expr := + match c with + | .ConString _ s => .strConst () s.val + | .ConPos _ i => .intConst () i.val + | .ConNeg _ i => .intConst () (-i.val) + | .ConBytes _ _b => .const () (.strConst "") -- TODO: fix + | .ConFloat _ f => .strConst () (f.val) + | .ConTrue _ => .boolConst () true + | .ConFalse _ => .boolConst () false + | _ => panic! s!"Unhandled Constant: {repr c}" + +def PyAliasToBoogieExpr (a : Python.alias SourceRange) : Boogie.Expression.Expr := + match a with + | .mk_alias _ n as_n => + assert! as_n.val.isNone + .strConst () n.val + +------------------------------------------------------------------------------- + +def strToValue (s: String) : Boogie.Expression.Expr := + .app () (.op () "Value_str" none) (.strConst () s) + +def intToValue (i: Int) : Boogie.Expression.Expr := + .app () (.op () "Value_int" none) (.intConst () i) + +def boolToValue (b: Bool) : Boogie.Expression.Expr := + .app () (.op () "Value_bool" none) (.boolConst () b) + +def Value_asBool (b: Boogie.Expression.Expr) : Boogie.Expression.Expr := + .app () (.op () "as_bool" none) b + +def strVarToValue (varname: String) : Boogie.Expression.Expr := + .app () (.op () "Value_str" none) (.fvar () varname none) + +def intVarToValue (varname: String) : Boogie.Expression.Expr := + .app () (.op () "Value_int" none) (.fvar () varname none) + +def boolVarToValue (varname: String) : Boogie.Expression.Expr := + .app () (.op () "Value_bool" none) (.fvar () varname none) + +def ValueNoneExpr : Boogie.Expression.Expr := + .op () "Value_none" none + +def classVarToValue (varname: String) : Boogie.Expression.Expr := + .app () (.op () "Value_class" none) (.fvar () varname none) + +def emptyClassInstance (classname: String) : Boogie.Expression.Expr := + .app () (.op () "ClassInstance_empty" none) (.strConst () classname) + +def stringToRat (s : String) : Rat := + match s.toInt? with + | some n => n + | none => + let parts := s.splitOn "." + if parts.length == 2 then + match parts[0]!.toInt?, parts[1]!.toNat? with + | some whole, some frac => + (mkRat whole frac) + | _, _ => panic! s!"Cannot convert: {s} to Rat" + else panic! s!"Cannot convert: {s} to Rat" + +def PyConstToValue (c: Python.constant SourceRange) : Boogie.Expression.Expr := + match c with + | .ConString _ s => strToValue s.val + | .ConPos _ i => intToValue i.val + | .ConNeg _ i => intToValue (-i.val) + | .ConBytes _ _b => .const () (.strConst "") -- TODO: fix + | .ConFloat _ f => .app () (.op () "Value_float" none) (.realConst () (stringToRat f.val)) + | .ConTrue _ => boolToValue true + | .ConFalse _ => boolToValue false + | _ => panic! s!"Unhandled Constant: {repr c}" + + +------------------------------------------------------------------------------- + +def handleAdd (lhs rhs: Boogie.Expression.Expr) : Boogie.Expression.Expr := + .app () (.app () (.op () "Py_add_unwrap" none) lhs) rhs + +def handleSub (lhs rhs: Boogie.Expression.Expr) : Boogie.Expression.Expr := + .app () (.app () (.op () "Py_sub_unwrap" none) lhs) rhs + +def handleMult (lhs rhs: Boogie.Expression.Expr) : Boogie.Expression.Expr := + .app () (.app () (.op () "Py_mul_unwrap" none) lhs) rhs + +def handleFloorDiv (_translation_ctx: TranslationContext) (lhs rhs: Boogie.Expression.Expr) : Boogie.Expression.Expr := + .app () (.app () (.op () "Int.Div" mty[int → (int → int)]) lhs) rhs + +def handleNot (arg: Boogie.Expression.Expr) : Boogie.Expression.Expr := + (.app () (.op () "Py_not" none) arg) + +def handleNeg (arg: Boogie.Expression.Expr) : Boogie.Expression.Expr := + (.app () (.op () "Py_neg" none) arg) + +def handleLt (lhs rhs: Boogie.Expression.Expr) : Boogie.Expression.Expr := + .app () (.app () (.op () "Py_lt" none) lhs) rhs + +def handleLe (lhs rhs: Boogie.Expression.Expr) : Boogie.Expression.Expr := + .app () (.app () (.op () "Py_le" none) lhs) rhs + +def handleGt (lhs rhs: Boogie.Expression.Expr) : Boogie.Expression.Expr := + .app () (.app () (.op () "Py_gt" none) lhs) rhs + +def handleGe (lhs rhs: Boogie.Expression.Expr) : Boogie.Expression.Expr := + .app () (.app () (.op () "Py_ge" none) lhs) rhs + +------------------------------------------------------------------------------- + +structure SubstitutionRecord where + pyExpr : Python.expr SourceRange + boogieExpr : Boogie.Expression.Expr + +instance : Repr (List SubstitutionRecord) where + reprPrec xs _ := + let py_exprs := xs.map (λ r => r.pyExpr) + s!"{repr py_exprs}" + +def PyExprIdent (e1 e2: Python.expr SourceRange) : Bool := + match e1, e2 with + | .Call sr1 _ _ _, .Call sr2 _ _ _ => sr1 == sr2 + | _ , _ => false + +-- TODO: handle rest of names +def PyListStrToBoogie (names : Array (Python.alias SourceRange)) : Boogie.Expression.Expr := + .app () (.app () (.op () "ListStr_cons" mty[string → (ListStr → ListStr)]) (PyAliasToBoogieExpr names[0]!)) + (.op () "ListStr_nil" mty[ListStr]) + +def handleList (_elmts: Array (Python.expr SourceRange)) (expected_type : Lambda.LMonoTy): PyExprTranslated := + match expected_type with + | (.tcons "ListStr" _) => {stmts := [], expr := (.op () "ListStr_nil" expected_type)} + | (.tcons "ListDictStrAny" _) => {stmts := [], expr := (.op () "ListDictStrAny_nil" expected_type)} + | _ => panic! s!"Unexpected type : {expected_type}" + +def PyOptExprToString (e : Python.opt_expr SourceRange) : String := + match e with + | .some_expr _ (.Constant _ (.ConString _ s) _) => s.val + | _ => panic! "Expected some constant string: {e}" + +partial def PyExprToString (e : Python.expr SourceRange) : String := + match e with + | .Name _ n _ => n.val + | .Attribute _ v attr _ => s!"{PyExprToString v}_{attr.val}" + | .Subscript _ v slice _ => + let v_name := PyExprToString v + match v_name with + | "Dict" => + match slice with + | .Tuple _ elts _ => + assert! elts.val.size == 2 + s!"Dict[{PyExprToString elts.val[0]!} {PyExprToString elts.val[1]!}]" + | _ => panic! s!"Unsupported slice: {repr slice}" + | "List" => + match slice with + | .Name _ id _ => s!"List[{id.val}]" + | _ => panic! s!"Unsupported slice: {repr slice}" + | _ => panic! s!"Unsupported subscript to string: {repr e}" + | _ => panic! s!"Unhandled Expr: {repr e}" + +def PyExprToMonoTy (e : Python.expr SourceRange) : Lambda.LMonoTy := + match e with + | .Name _ n _ => + match n.val with + | "bool" => .tcons "bool" [] + | "int" => .tcons "int" [] + | "str" => .tcons "string" [] + | "float" => .tcons "string" [] + | "Dict[str Any]" => .tcons "DictStrAny" [] + | "List[str]" => .tcons "ListStr" [] + | "datetime" => .tcons "Datetime" [] + | "date" => .tcons "Date" [] + | "timedelta" => .tcons "Timedelta" [] + | "Client" => .tcons "Client" [] + | "LatencyAnalyzer" => .tcons "LatencyAnalyzer" [] + | _ => panic! s!"Unhandled name: {repr e}" + | .Subscript _ val _slice _ => + match val with + | .Name _ n _ => + match n.val with + | "Dict" => .tcons "DictStrAny" [] + | "List" => .tcons "ListStr" [] + | _ => panic! s!"Unsupported name: {repr n}" + | _ => panic! s!"Expected name: {repr e}" + | _ => panic! s!"Unhandled Expr: {repr e}" + + +-- This information should come from our prelude. For now, we use the fact that +-- these functions are exactly the ones +-- represented as `Call(Attribute(Name(...)))` in the AST (instead of `Call(Name(...))`). +def callCanThrow (func_infos : List PythonFunctionDecl) (stmt: Python.stmt SourceRange) : Bool := + match stmt with + | .Expr _ (.Call _ (.Attribute _ _ _ _) _ _) | .Assign _ _ (.Call _ (.Attribute _ _ _ _) _ _) _ => true + | .Expr _ (.Call _ f _ _) | .Assign _ _ (.Call _ f _ _) _ => match f with + | .Name _ f _ => func_infos.any (λ fi => fi.name == f.val) + | _ => false + | _ => false + +def noneOrExpr (translation_ctx : TranslationContext) (fname n : String) (e: Boogie.Expression.Expr) : Boogie.Expression.Expr := + let type_str := translation_ctx.signatures.getFuncSigType fname n + if type_str.endsWith "OrNone" then + -- Optional param. Need to wrap e.g., string into StrOrNone + match type_str with + | "IntOrNone" => .app () (.op () "IntOrNone_mk_int" none) e + | "StrOrNone" => .app () (.op () "StrOrNone_mk_str" none) e + | "BytesOrStrOrNone" => .app () (.op () "BytesOrStrOrNone_mk_str" none) e + | _ => panic! "Unsupported type_str: "++ type_str + else + e + +def handleCallThrow (jmp_target : String) : Boogie.Statement := + let cond := .eq () (.app () (.op () "ExceptOrNone_tag" none) (.fvar () "maybe_except" none)) (.op () "EN_STR_TAG" none) + .ite cond [.goto jmp_target] [] + +def deduplicateTypeAnnotations (l : List (String × Option String)) : List (String × String) := Id.run do + let mut m : Map String String := [] + for p in l do + let name := p.fst + let oty := p.snd + match oty with + | .some ty => + match m.find? name with + | .some other_ty => + if ty != other_ty then + panic! s!"Type annotation mismatch: {other_ty} vs {ty}" + | .none => m := (name, ty) :: m + | .none => () + let names := l.map (λ p => p.fst) + let unique_names := names.dedup + unique_names.map (λ n => + match m.find? n with + | .some ty => (n, ty) + | .none => panic s!"Missing type annotations for {n}") + +partial def collectVarDecls (translation_ctx : TranslationContext) (stmts: Array (Python.stmt SourceRange)) : List Boogie.Statement := + let rec go (s : Python.stmt SourceRange) : List (String × Option String) := + match s with + | .Assign _ lhs _ _ => + let names := lhs.val.toList.map PyExprToString + names.map (λ n => (n, "Value")) + | .AnnAssign _ lhs ty _ _ => + [(PyExprToString lhs, PyExprToString ty)] + | .If _ _ body _ => body.val.toList.flatMap go + | .For _ _ _ body _ _ => body.val.toList.flatMap go + | _ => [] + let dup := stmts.toList.flatMap go + let dedup := deduplicateTypeAnnotations dup + let toBoogie (p: String × String) : List Boogie.Statement := + let name := p.fst + let corename := name ++ "_coreval" + let ty_name := p.snd + match ty_name with + | "bool" => [(.init corename t[bool] (.boolConst () false)), (.havoc corename), (.init name ValueTy (boolVarToValue corename))] + | "str" => [(.init corename t[string] (.strConst () "")), (.havoc corename), (.init name ValueTy (strVarToValue corename))] + | "int" => [(.init corename t[int] (.intConst () 0)), (.havoc corename), (.init name ValueTy (intVarToValue corename))] + | "float" => [(.init name t[string] (.strConst () "0.0")), (.havoc name)] -- Floats as strs for now + | "bytes" => [(.init name t[string] (.strConst () "")), (.havoc name)] + | "Client" => [(.init name clientType dummyClient), (.havoc name)] + | "Dict[str Any]" => [(.init name dictStrAnyType dummyDictStrAny), (.havoc name)] + | "List[str]" => [(.init name listStrType dummyListStr), (.havoc name)] + | "datetime" => [(.init name datetimeType dummyDatetime), (.havoc name)] + | "date" => [(.init name dateType dummyDate), (.havoc name)] + | "timedelta" => [(.init name timedeltaType dummyTimedelta), (.havoc name)] + | "Value" => [(.init name ValueTy ValueNoneExpr), (.havoc name)] + | _ => + let user_defined_class := translation_ctx.class_infos.find? (λ i => i.name == ty_name) + match user_defined_class with + | .some i => + [(.init corename ClassInstanceTy (emptyClassInstance i.name) ), (.havoc corename), (.init name ValueTy (classVarToValue corename))] + | .none => panic! s!"Unsupported type annotation: `{ty_name}`" + let foo := dedup.map toBoogie + foo.flatten + +def isCall (e: Python.expr SourceRange) : Bool := + match e with + | .Call _ _ _ _ => true + | _ => false + +def remapFname (translation_ctx: TranslationContext) (fname: String) : String := + match translation_ctx.class_infos.find? (λ i => i.name == fname) with + | .some i => + i.name ++ "___init__" + | _ => + match fname with + | "float" => "str_to_float" + | _ => fname + +mutual + +partial def PyExprToBoogieWithSubst (translation_ctx : TranslationContext) (substitution_records : Option (List SubstitutionRecord)) (e : Python.expr SourceRange) : PyExprTranslated := + PyExprToBoogie translation_ctx e substitution_records + +partial def PyKWordsToBoogie (substitution_records : Option (List SubstitutionRecord)) (kw : Python.keyword SourceRange) : (String × PyExprTranslated) := + match kw with + | .mk_keyword _ name expr => + match name.val with + | some n => (n.val, PyExprToBoogieWithSubst default substitution_records expr) + | none => panic! "Keyword arg should have a name" + +-- TODO: we should be checking that args are right +partial def argsAndKWordsToCanonicalList (translation_ctx : TranslationContext) + (fname: String) + (args : Array (Python.expr SourceRange)) + (kwords: Array (Python.keyword SourceRange)) + (substitution_records : Option (List SubstitutionRecord) := none) : List Boogie.Expression.Expr × List Boogie.Statement := + if translation_ctx.func_infos.any (λ e => e.name == fname) || translation_ctx.class_infos.any (λ e => e.name++"___init__" == fname) then + if translation_ctx.func_infos.any (λ e => e.name == fname) then + (args.toList.map (λ a => (PyExprToBoogieWithSubst default substitution_records a).expr), []) + else + (args.toList.map (λ a => (PyExprToBoogieWithSubst default substitution_records a).expr), []) + else + let required_order := translation_ctx.signatures.getFuncSigOrder fname + assert! args.size <= required_order.length + let remaining := required_order.drop args.size + let kws_and_exprs := kwords.toList.map (PyKWordsToBoogie substitution_records) + let ordered_remaining_args := remaining.map (λ n => match kws_and_exprs.find? (λ p => p.fst == n) with + | .some p => + noneOrExpr translation_ctx fname n p.snd.expr + | .none => Strata.Python.TypeStrToBoogieExpr (translation_ctx.signatures.getFuncSigType fname n)) + let args := args.map (PyExprToBoogieWithSubst default substitution_records) + let args := (List.range required_order.length).filterMap (λ n => + if n < args.size then + let arg_name := required_order[n]! -- Guaranteed by range. Using finRange causes breaking coercions to Nat. + some (noneOrExpr translation_ctx fname arg_name args[n]!.expr) + else + none) + (args ++ ordered_remaining_args, kws_and_exprs.flatMap (λ p => p.snd.stmts)) + +partial def handleDict (keys: Array (Python.opt_expr SourceRange)) (values: Array (Python.expr SourceRange)) : PyExprTranslated := + let dict := .app () (.op () "DictStrAny_mk" none) (.strConst () "DefaultDict") -- TODO: need to generate unique dict arg + assert! keys.size == values.size + let zipped := Array.zip keys values + + let res := zipped.toList.flatMap (λ (k, v) => + let n := PyOptExprToString k + let in_dict := (.assume s!"assume_{n}_in_dict" (.app () (.app () (.op () "str_in_dict_str_any" none) (.strConst () n)) dict)) + match v with + | .Call _ f args _ => + match f with + | .Name _ {ann := _ , val := "str"} _ => + assert! args.val.size == 1 + let dt := (.app () (.op () "datetime_to_str" none) ((PyExprToBoogie default args.val[0]!).expr)) + let dict_of_v_is_k := (.assume s!"assume_{n}_key" (.eq () (.app () (.app () (.op () "dict_str_any_get_str" none) dict) (.strConst () n)) dt)) + [in_dict, dict_of_v_is_k] + | _ => panic! "Unsupported function when constructing map" + | _ => + let dict_of_v_is_k := (.assume s!"assume_{n}_key" (.eq () (.app () (.app () (.op () "dict_str_any_get_str" none) dict) (.strConst () n)) (.strConst () "DummyVal"))) + [in_dict, dict_of_v_is_k]) + + {stmts := res , expr := dict, post_stmts := []} + +partial def PyExprToBoogie (translation_ctx : TranslationContext) (e : Python.expr SourceRange) (substitution_records : Option (List SubstitutionRecord) := none) : PyExprTranslated := + if h : substitution_records.isSome && (substitution_records.get!.find? (λ r => PyExprIdent r.pyExpr e)).isSome then + have hr : (List.find? (fun r => PyExprIdent r.pyExpr e) substitution_records.get!).isSome = true := by rw [Bool.and_eq_true] at h; exact h.2 + let record := (substitution_records.get!.find? (λ r => PyExprIdent r.pyExpr e)).get hr + {stmts := [], expr := record.boogieExpr} + else + match e with + | .Call _ f args kwords => + let fn := PyExprToString f + if fn ∈ PreludeFunctions then + let trans_arg := (args.val.toList.map (λ a => (PyExprToBoogie translation_ctx a none).expr)) + {stmts:= [], expr:= create_function_app fn trans_arg} + else + panic! s!"Call should be handled at stmt level: \n(func: {repr f}) \n(Records: {repr substitution_records}) \n(AST: {repr e.toAst})" + | .Constant _ c _ => {stmts := [], expr := PyConstToValue c} + | .Name _ n _ => + match n.val with + | "AssertionError" | "Exception" => {stmts := [], expr := .strConst () n.val} + | s => + match translation_ctx.variableTypes.find? (λ p => p.fst == s) with + | .some p => + if translation_ctx.expectedType == some (.tcons "bool" []) && p.snd == (.tcons "DictStrAny" []) then + let a := .fvar () n.val none + let e := .app () (.op () "Bool.Not" none) (.eq () (.app () (.op () "dict_str_any_length" none) a) (.intConst () 0)) + {stmts := [], expr := e} + else + {stmts := [], expr := .fvar () n.val none} + | .none => {stmts := [], expr := .fvar () n.val none} + | .JoinedStr _ ss => PyExprToBoogie translation_ctx ss.val[0]! -- TODO: need to actually join strings + | .BinOp _ lhs op rhs => + let lhs := (PyExprToBoogie translation_ctx lhs) + let rhs := (PyExprToBoogie translation_ctx rhs) + match op with + | .Add _ => + {stmts := lhs.stmts ++ rhs.stmts, expr := handleAdd lhs.expr rhs.expr} + | .Sub _ => + {stmts := lhs.stmts ++ rhs.stmts, expr := handleSub lhs.expr rhs.expr} + | .Mult _ => + {stmts := lhs.stmts ++ rhs.stmts, expr := handleMult lhs.expr rhs.expr} + | _ => panic! s!"Unhandled BinOp: {repr e}" + | .Compare _ lhs op rhs => + let lhs := PyExprToBoogie translation_ctx lhs + assert! rhs.val.size == 1 + let rhs := PyExprToBoogie translation_ctx rhs.val[0]! + match op.val with + | #[v] => match v with + | Strata.Python.cmpop.Eq _ => + {stmts := lhs.stmts ++ rhs.stmts, expr := (.eq () lhs.expr rhs.expr)} + | Strata.Python.cmpop.In _ => + {stmts := lhs.stmts ++ rhs.stmts, expr := .app () (.app () (.op () "str_in_dict_str_any" none) lhs.expr) rhs.expr} + | Strata.Python.cmpop.Lt _ => + {stmts := lhs.stmts ++ rhs.stmts, expr := handleLt lhs.expr rhs.expr} + | Strata.Python.cmpop.LtE _ => + {stmts := lhs.stmts ++ rhs.stmts, expr := handleLe lhs.expr rhs.expr} + | Strata.Python.cmpop.Gt _ => + {stmts := lhs.stmts ++ rhs.stmts, expr := handleGt lhs.expr rhs.expr} + | Strata.Python.cmpop.GtE _ => + {stmts := lhs.stmts ++ rhs.stmts, expr := handleGe lhs.expr rhs.expr} + | _ => panic! s!"Unhandled comparison op: {repr op.val}" + | _ => panic! s!"Unhandled comparison op: {repr op.val}" + | .Dict _ keys values => + let res := handleDict keys.val values.val + res + | .ListComp _ keys values => panic! "ListComp must be handled at stmt level" + | .UnaryOp _ op arg => match op with + | .Not _ => {stmts := [], expr := handleNot (PyExprToBoogie translation_ctx arg).expr} + | _ => panic! "Unsupported UnaryOp: {repr e}" + | .Subscript _ v slice _ => + let l := PyExprToBoogie translation_ctx v + let k := PyExprToBoogie translation_ctx slice + -- TODO: we need to plumb the type of `v` here + match s!"{repr l.expr}" with + | "LExpr.fvar () { name := \"keys\", metadata := Boogie.Visibility.unres } none" => + -- let access_check : Boogie.Statement := .assert "subscript_bounds_check" (.app () (.app () (.op () "str_in_dict_str_any" none) k.expr) l.expr) + {stmts := l.stmts ++ k.stmts, expr := .app () (.app () (.op () "list_str_get" none) l.expr) k.expr} + | "LExpr.fvar () { name := \"blended_cost\", metadata := Boogie.Visibility.unres } none" => + -- let access_check : Boogie.Statement := .assert "subscript_bounds_check" (.app () (.app () (.op () "str_in_dict_str_any" none) k.expr) l.expr) + {stmts := l.stmts ++ k.stmts, expr := .app () (.app () (.op () "dict_str_any_get_str" none) l.expr) k.expr} + | _ => + match translation_ctx.expectedType with + | .some (.tcons "ListStr" []) => + let access_check : Boogie.Statement := .assert "subscript_bounds_check" (.app () (.app () (.op () "str_in_dict_str_any" none) k.expr) l.expr) + {stmts := l.stmts ++ k.stmts ++ [access_check], expr := .app () (.app () (.op () "dict_str_any_get_list_str" none) l.expr) k.expr} + | _ => + let access_check : Boogie.Statement := .assert "subscript_bounds_check" (.app () (.app () (.op () "str_in_dict_str_any" none) k.expr) l.expr) + {stmts := l.stmts ++ k.stmts ++ [access_check], expr := .app () (.app () (.op () "dict_str_any_get" none) l.expr) k.expr} + | .List _ elmts _ => + match elmts.val[0]! with + | .Constant _ expr _ => match expr with + | .ConString _ s => handleList elmts.val (.tcons "ListStr" []) + | _ => panic! s!"Expr: {repr expr}" + | .Dict _ _ _ => handleList elmts.val (.tcons "ListDictStrAny" []) + | _ => panic! s!"Unexpected element: {repr elmts.val[0]!}" + | _ => panic! s!"Unhandled Expr: {repr e}" + +partial def initTmpParam (p: Python.expr SourceRange × String) : List Boogie.Statement := + match p.fst with + | .Call _ f args _ => + match f with + | .Name _ n _ => + match n.val with + | "json_dumps" => [(.init p.snd t[string] (.strConst () "")), .call [p.snd, "maybe_except"] "json_dumps" [(.app () (.op () "DictStrAny_mk" none) (.strConst () "DefaultDict")), (Strata.Python.TypeStrToBoogieExpr "IntOrNone")]] + | "str" => + assert! args.val.size == 1 + [(.init p.snd t[string] (.strConst () "")), .set p.snd (.app () (.op () "datetime_to_str" none) ((PyExprToBoogie default args.val[0]!).expr))] + | "int" => [(.init p.snd t[int] (.intConst () 0)), .set p.snd (.op () "datetime_to_int" none)] + | _ => panic! s!"Unsupported name {n.val}" + | _ => panic! s!"Unsupported tmp param init call: {repr f}" + | _ => panic! "Expected Call" + +partial def exceptHandlersToBoogie (jmp_targets: List String) (translation_ctx: TranslationContext) (h : Python.excepthandler SourceRange) : List Boogie.Statement := + assert! jmp_targets.length >= 2 + match h with + | .ExceptHandler _ ex_ty _ body => + let set_ex_ty_matches := match ex_ty.val with + | .some ex_ty => + let inherits_from : Boogie.BoogieIdent := "inheritsFrom" + let get_ex_tag : Boogie.BoogieIdent := "ExceptOrNone_code_val" + let exception_ty : Boogie.Expression.Expr := .app () (.op () get_ex_tag none) (.fvar () "maybe_except" none) + let rhs_curried : Boogie.Expression.Expr := .app () (.op () inherits_from none) exception_ty + let res := PyExprToBoogie translation_ctx ex_ty + let rhs : Boogie.Expression.Expr := .app () rhs_curried (res.expr) + let call := .set "exception_ty_matches" rhs + res.stmts ++ [call] + | .none => + [.set "exception_ty_matches" (.boolConst () false)] + let cond := .fvar () "exception_ty_matches" none + let body_if_matches := body.val.toList.flatMap (λ s => (PyStmtToBoogie jmp_targets translation_ctx s).fst) ++ [.goto jmp_targets[1]!] + set_ex_ty_matches ++ [.ite cond body_if_matches []] + +partial def handleFunctionCall (lhs: List Boogie.Expression.Ident) + (fname: String) + (args: Ann (Array (Python.expr SourceRange)) SourceRange) + (kwords: Ann (Array (Python.keyword SourceRange)) SourceRange) + (_jmp_targets: List String) + (translation_ctx: TranslationContext) + (_s : Python.stmt SourceRange) : List Boogie.Statement := + + let fname := remapFname translation_ctx fname + + -- Boogie doesn't allow nested function calls, so we need to introduce temporary variables for each nested call + let nested_args_calls := args.val.filterMap (λ a => if isCall a then some a else none) + let args_calls_to_tmps := nested_args_calls.map (λ a => (a, s!"call_arg_tmp_{a.toAst.ann.start}")) + let nested_kwords_calls := kwords.val.filterMap (λ a => + let arg := match a with + | .mk_keyword _ _ f => f + if isCall arg then some arg else none) + let kwords_calls_to_tmps := nested_kwords_calls.map (λ a => (a, s!"call_kword_tmp_{a.toAst.ann.start}")) + + let substitution_records : List SubstitutionRecord := args_calls_to_tmps.toList.map (λ p => {pyExpr := p.fst, boogieExpr := .fvar () p.snd none}) ++ + kwords_calls_to_tmps.toList.map (λ p => {pyExpr := p.fst, boogieExpr := .fvar () p.snd none}) + let res := argsAndKWordsToCanonicalList translation_ctx fname args.val kwords.val substitution_records + args_calls_to_tmps.toList.flatMap initTmpParam ++ + kwords_calls_to_tmps.toList.flatMap initTmpParam ++ + res.snd ++ [.call lhs fname res.fst] + +partial def handleComprehension (lhs: Python.expr SourceRange) (gen: Array (Python.comprehension SourceRange)) : List Boogie.Statement := + assert! gen.size == 1 + match gen[0]! with + | .mk_comprehension _ _ itr _ _ => + let res := PyExprToBoogie default itr + let guard := .app () (.op () "Bool.Not" none) (.eq () (.app () (.op () "dict_str_any_length" none) res.expr) (.intConst () 0)) + let then_ss: List Boogie.Statement := [.havoc (PyExprToString lhs)] + let else_ss: List Boogie.Statement := [.set (PyExprToString lhs) (.op () "ListStr_nil" none)] + res.stmts ++ [.ite guard then_ss else_ss] + +partial def PyStmtToBoogie (jmp_targets: List String) (translation_ctx : TranslationContext) (s : Python.stmt SourceRange) : List Boogie.Statement × TranslationContext := + assert! jmp_targets.length > 0 + let non_throw : List Boogie.Statement × Option (String × Lambda.LMonoTy) := match s with + | .Import _ names => + ([.call [] "import" [PyListStrToBoogie names.val]], none) + | .ImportFrom _ s names i => + let n := match s.val with + | some s => [strToBoogieExpr s.val] + | none => [] + let i := match i.val with + | some i => [intToBoogieExpr (PyIntToInt i)] + | none => [] + ([.call [] "importFrom" (n ++ [PyListStrToBoogie names.val] ++ i)], none) + | .Expr _ (.Call _ func args kwords) => + let fname := PyExprToString func + if callCanThrow translation_ctx.func_infos s then + (handleFunctionCall ["maybe_except"] fname args kwords jmp_targets translation_ctx s, none) + else + (handleFunctionCall [] fname args kwords jmp_targets translation_ctx s, none) + | .Expr _ (.Constant _ (.ConString _ _) _) => + -- TODO: Check that it's a doc string + ([], none) -- Doc string + | .Expr _ _ => + panic! s!"Can't handle Expr statements that aren't calls: {repr s}" + | .Assign _ lhs (.Call _ func args kwords) _ => + assert! lhs.val.size == 1 + let fname := PyExprToString func + (handleFunctionCall [PyExprToString lhs.val[0]!, "maybe_except"] fname args kwords jmp_targets translation_ctx s, none) + | .Assign _ lhs rhs _ => + assert! lhs.val.size == 1 + let res := PyExprToBoogie translation_ctx rhs + (res.stmts ++ [.set (PyExprToString lhs.val[0]!) res.expr], none) + | .AnnAssign _ lhs ty { ann := _ , val := (.some (.Call _ func args kwords))} _ => + let fname := PyExprToString func + (handleFunctionCall [PyExprToString lhs, "maybe_except"] fname args kwords jmp_targets translation_ctx s, some (PyExprToString lhs, PyExprToMonoTy ty)) + | .AnnAssign _ lhs ty { ann := _ , val := (.some (.ListComp _ _ gen))} _ => + (handleComprehension lhs gen.val, some (PyExprToString lhs, PyExprToMonoTy ty)) + | .AnnAssign _ lhs ty {ann := _, val := (.some e)} _ => + let res := (PyExprToBoogie {translation_ctx with expectedType := PyExprToMonoTy ty} e) + (res.stmts ++ [.set (PyExprToString lhs) res.expr], some (PyExprToString lhs, PyExprToMonoTy ty)) + | .Try _ body handlers _orelse _finalbody => + let new_target := s!"excepthandlers_{jmp_targets[0]!}" + let entry_except_handlers := [.block new_target []] + let new_jmp_stack := new_target :: jmp_targets + let except_handlers := handlers.val.toList.flatMap (exceptHandlersToBoogie new_jmp_stack translation_ctx) + let var_decls := collectVarDecls translation_ctx body.val + ([.block "try_block" (var_decls ++ body.val.toList.flatMap (λ s => (PyStmtToBoogie new_jmp_stack translation_ctx s).fst) ++ entry_except_handlers ++ except_handlers)], none) + | .FunctionDef _ _ _ _ _ _ _ _ => panic! "Can't translate FunctionDef to Boogie statement" + | .If _ test then_b else_b => + let guard_ctx := {translation_ctx with expectedType := some (.tcons "bool" [])} + ([.ite (Value_asBool (PyExprToBoogie guard_ctx test).expr) (ArrPyStmtToBoogie translation_ctx then_b.val).fst (ArrPyStmtToBoogie translation_ctx else_b.val).fst], none) + | .Return _ v => + match v.val with + | .some v => ([.set "ret" (PyExprToBoogie translation_ctx v).expr, .goto jmp_targets[0]!], none) -- TODO: need to thread return value name here. For now, assume "ret" + | .none => ([.goto jmp_targets[0]!], none) + | .For _ tgt itr body _ _ => + -- Do one unrolling: + let guard := .app () (.op () "Bool.Not" none) (.eq () (.app () (.op () "dict_str_any_length" none) (PyExprToBoogie default itr).expr) (.intConst () 0)) + match tgt with + | .Name _ n _ => + let assign_tgt := [(.init n.val dictStrAnyType dummyDictStrAny)] + ([.ite guard (assign_tgt ++ (ArrPyStmtToBoogie translation_ctx body.val).fst) []], none) + | _ => panic! s!"tgt must be single name: {repr tgt}" + -- TODO: missing havoc + | .While _ test body _ => + -- Do one unrolling: + let guard := .app () (.op () "Bool.Not" none) (.eq () (.app () (.op () "dict_str_any_length" none) (PyExprToBoogie default test).expr) (.intConst () 0)) + ([.ite guard (ArrPyStmtToBoogie translation_ctx body.val).fst []], none) + -- TODO: missing havoc + | .Assert pos a _ => + let res := PyExprToBoogie translation_ctx a + let assertname := s!"py_assertion_{pos.start}_{pos.stop}" + ([(.assert assertname res.expr)], none) + | .AugAssign _ lhs op rhs => + match op with + | .Add _ => + match lhs with + | .Name _ n _ => + let rhs := PyExprToBoogie translation_ctx rhs + let new_lhs := (.strConst () "DUMMY_FLOAT") + (rhs.stmts ++ [.set n.val new_lhs], none) + | _ => panic! s!"Expected lhs to be name: {repr lhs}" + | .FloorDiv _ => + match lhs with + | .Name _ n _ => + let lhs := PyExprToBoogie translation_ctx lhs + let rhs := PyExprToBoogie translation_ctx rhs + let new_lhs := .app () (.app () (.op () "Int.Div" mty[int → (int → int)]) lhs.expr) rhs.expr + (rhs.stmts ++ [.set n.val new_lhs], none) + | _ => panic! s!"Expected lhs to be name: {repr lhs}" + | _ => panic! s!"Unsupported AugAssign op: {repr op}" + | _ => + panic! s!"Unsupported {repr s}" + let new_translation_ctx := match non_throw.snd with + | .some s => {translation_ctx with variableTypes := s :: translation_ctx.variableTypes} + | .none => translation_ctx + if callCanThrow translation_ctx.func_infos s then + (non_throw.fst ++ [handleCallThrow jmp_targets[0]!], new_translation_ctx) + else + (non_throw.fst, new_translation_ctx) + +partial def ArrPyStmtToBoogie (translation_ctx: TranslationContext) (a : Array (Python.stmt SourceRange)) : (List Boogie.Statement × TranslationContext) := + a.foldl (fun (stmts, ctx) stmt => + let (newStmts, newCtx) := PyStmtToBoogie ["end"] ctx stmt + (stmts ++ newStmts, newCtx) + ) ([], translation_ctx) + +end --mutual + + +def translateFunctions (a : Array (Python.stmt SourceRange)) (translation_ctx: TranslationContext) : List Boogie.Decl := + a.toList.filterMap (λ s => match s with + | .FunctionDef _ name _args body _ _ret _ _ => + + let varDecls : List Boogie.Statement := [] + let proc : Boogie.Procedure := { + header := { + name := name.val, + typeArgs := [], + inputs := [], + outputs := [("maybe_except", (.tcons "ExceptOrNone" []))]}, + spec := default, + body := varDecls ++ (ArrPyStmtToBoogie translation_ctx body.val).fst ++ [.block "end" []] + } + some (.proc proc) + | _ => none) + +def isSubstring (needle : String) (haystack : String) : Bool := + let needleLen := needle.length + let haystackLen := haystack.length + if needleLen > haystackLen then false + else + (List.range (haystackLen - needleLen + 1)).any fun i => + String.Pos.Raw.extract haystack ⟨i⟩ ⟨i + needleLen⟩ == needle + +def IsOrType (ty_str: String) : Bool := isSubstring "Or" ty_str + +def pyTyStrToLMonoTy (ty_str: String) : Lambda.LMonoTy := + match ty_str with + | "str" => mty[string] + | "int" => mty[int] + | "bool" => mty[bool] + | "datetime" => (.tcons "Datetime" []) + | _ => + if IsOrType ty_str then (.tcons "Value" []) else + panic! s!"Unsupported type: {ty_str}" + +def arg_typecheck_assertion (var: String) (ty_str: String) : Boogie.Expression.Expr := + match ty_str.toLower with + | "str" => .app () (.op () "isStr" none) (.fvar () var none) + | "int" => .app () (.op () "isInt" none) (.fvar () var none) + | "bool" => .app () (.op () "isBool" none) (.fvar () var none) + | "datetime" => .app () (.op () "isDatetime" none) (.fvar () var none) + | "none" => .app () (.op () "isNone" none) (.fvar () var none) + | _ => panic! s!"Unsupported type: {ty_str}" + +def arg_typecheck_or_expr (var: String) (ty_strs: List String) : Boogie.Expression.Expr := + match ty_strs with + | [] => panic! "ty_strs cannot be empty" + | [ty] => arg_typecheck_assertion var ty + | ty::tys => .app () (.app () (.op () "Bool.Or" none) (arg_typecheck_assertion var ty)) (arg_typecheck_or_expr var tys) + +def getArg_typecheck_assertions (var: String) (ty: String) : Boogie.Statement := + let typelist := ty.splitOn "Or" + let assertionname := var ++ "_typeconstraint" + if IsOrType ty then + .assert assertionname (arg_typecheck_or_expr var typelist) + else .assert assertionname (arg_typecheck_assertion var ty) + +def getArgs_typecheck_assertions (args: List (String × String)) : List Boogie.Statement := + match args with + | [] => [] + | (var, typ)::t => (getArg_typecheck_assertions var typ) :: (getArgs_typecheck_assertions t) + +def getArg_typecheck_precond (var: String) (ty: String) : (Boogie.BoogieLabel × Boogie.Procedure.Check) := + let typelist := ty.splitOn "Or" + let assertionname := var ++ "_typeconstraint" + if IsOrType ty then + (assertionname, {expr:=arg_typecheck_or_expr var typelist}) + else (assertionname, {expr:=arg_typecheck_assertion var ty}) + +def getArgs_typecheck_preconds (args: List (String × String)) : ListMap Boogie.BoogieLabel Boogie.Procedure.Check := + match args with + | [] => [] + | (var, typ)::t => (getArg_typecheck_precond var typ) :: (getArgs_typecheck_preconds t) + +def pythonFuncToBoogie (name : String) (args: List (String × String)) (body: Array (Python.stmt SourceRange)) + (ret : Option (Python.expr SourceRange)) (spec : Boogie.Procedure.Spec) (translation_ctx : TranslationContext) : Boogie.Procedure := + let inputs : List (Lambda.Identifier Boogie.Visibility × Lambda.LMonoTy) := args.map (λ p => (p.fst, (.tcons "Value" []))) + let varDecls := collectVarDecls translation_ctx body + --++ [(.init "exception_ty_matches" t[bool] (.boolConst () false)), (.havoc "exception_ty_matches")] + let arg_typecheck := getArgs_typecheck_preconds args + let newspec := {spec with preconditions:= arg_typecheck ++ spec.preconditions} + let stmts := (ArrPyStmtToBoogie translation_ctx body).fst + let body := varDecls ++ stmts ++ [.block "end" []] + let constructor := name.endsWith "___init__" + let outputs : Lambda.LMonoTySignature := if not constructor then + [("ret", (.tcons "Value" [])), ("maybe_except", (.tcons "ExceptOrNone" []))] + else + let class_ty_name := name.dropRight ("___init__".length) + [("ret", (.tcons s!"{class_ty_name}" [])), ("maybe_except", (.tcons "ExceptOrNone" []))] + { + header := {name, + typeArgs := [], + inputs, + outputs}, + spec:=newspec, + body + } + +def unpackPyArguments (args: Python.arguments SourceRange) : List (String × String) := +-- Python AST: +-- arguments = (arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs, +-- expr* kw_defaults, arg? kwarg, expr* defaults) + match args with -- TODO: Error if any other types of args + | .mk_arguments _ _ args _ _ _ _ _ => + let combined := args.val + combined.toList.filterMap (λ a => + match a with + | .mk_arg _ name oty _ => + if name.val == "self" then + none + else + match oty.val with + | .some ty => some (name.val, PyExprToString ty) + | _ => panic! s!"Missing type annotation on arg: {repr a} ({repr args})") + +def PyFuncDefToBoogie (s: Python.stmt SourceRange) (translation_ctx: TranslationContext) : List Boogie.Decl × PythonFunctionDecl := + match s with + | .FunctionDef _ name args body _ ret _ _ => + let args := unpackPyArguments args + ([.proc (pythonFuncToBoogie name.val args body.val ret.val default translation_ctx)], {name := name.val, args, ret := s!"{repr ret}"}) + | _ => panic! s!"Expected function def: {repr s}" + +def PyClassDefToBoogie (s: Python.stmt SourceRange) (translation_ctx: TranslationContext) : List Boogie.Decl × PythonClassDecl := + match s with + | .ClassDef _ c_name _ _ body _ _ => + let member_fn_defs := body.val.toList.filterMap (λ s => match s with + | .FunctionDef _ name args body _ ret _ _ => some (name, args, body, ret) + | _ => none) + (member_fn_defs.map (λ f => + let name := f.fst.val + let args := unpackPyArguments f.snd.fst + let body := f.snd.snd.fst.val + let ret := f.snd.snd.snd.val + .proc (pythonFuncToBoogie (c_name.val++"_"++name) args body ret default translation_ctx)), {name := c_name.val}) + | _ => panic! s!"Expected function def: {repr s}" + +def pythonToBoogie (pgm: Strata.Program): Boogie.Program := + let pyCmds := toPyCommands pgm.commands + assert! pyCmds.size == 1 + let insideMod := unwrapModule pyCmds[0]! + let func_defs := insideMod.filter (λ s => match s with + | .FunctionDef _ _ _ _ _ _ _ _ => true + | _ => false) + + let class_defs := insideMod.filter (λ s => match s with + | .ClassDef _ _ _ _ _ _ _ => true + | _ => false) + + let non_func_blocks := insideMod.filter (λ s => match s with + | .FunctionDef _ _ _ _ _ _ _ _ => false + | .ClassDef _ _ _ _ _ _ _ => false + | _ => true) + + let globals := [(.var "__name__" (.forAll [] mty[string]) (.strConst () "__main__"))] + + let rec helper {α : Type} (f : Python.stmt SourceRange → TranslationContext → List Boogie.Decl × α) + (update : TranslationContext → α → TranslationContext) + (acc : TranslationContext) : + List (Python.stmt SourceRange) → List Boogie.Decl × TranslationContext + | [] => ([], acc) + | x :: xs => + let (y, info) := f x acc + let new_acc := update acc info + let (ys, acc'') := helper f update new_acc xs + (y ++ ys, acc'') + + let func_defs_and_infos := helper PyFuncDefToBoogie (fun acc info => {acc with func_infos := info :: acc.func_infos}) default func_defs.toList + let func_defs := func_defs_and_infos.fst + let func_infos := func_defs_and_infos.snd + + let class_defs_and_infos := helper PyClassDefToBoogie (fun acc info => {acc with class_infos := info :: acc.class_infos}) func_infos class_defs.toList + let class_defs := class_defs_and_infos.fst + let class_infos := class_defs_and_infos.snd + let class_ty_decls := [(.type (.con {name := "LatencyAnalyzer", numargs := 0})) ] + + {decls := globals ++ class_ty_decls ++ func_defs ++ class_defs ++ [.proc (pythonFuncToBoogie "__main__" [] non_func_blocks none default class_infos)]} + + +def exitFailure {α} (message : String) : IO α := do + IO.eprintln (message ++ "\n\nRun strata --help for additional help.") + IO.Process.exit 1 + +def readPythonStrata (path : String) : IO Strata.Program := do + let bytes ← Strata.Util.readBinInputSource path + if ! bytes.startsWith Ion.binaryVersionMarker then + exitFailure s!"pyAnalyze expected Ion file" + match Strata.Program.fromIon Strata.Python.Python_map Strata.Python.Python.name bytes with + | .ok p => pure p + | .error msg => exitFailure msg + +def getBoogieProgram (path : String) : IO Boogie.Program := do + let pgm ← readPythonStrata path + let bpgm := Strata.pythonToBoogie pgm + return bpgm + +def verifyBoogieProgram (path : String) : IO Unit := do + let pgm ← readPythonStrata path + let preludePgm := Boogie.Typeprelude + let bpgm := Strata.pythonToBoogie pgm + let newPgm : Boogie.Program := { decls := preludePgm.decls ++ bpgm.decls } + let vcResults ← EIO.toIO (fun f => IO.Error.userError (toString f)) + (Boogie.verify "cvc5" newPgm) + let mut s := "" + for vcResult in vcResults do + s := s ++ s!"\n{vcResult.obligation.label}: {Std.format vcResult.result}\n" + IO.println s + + +end Strata + +--#eval (Strata.verifyBoogieProgram "Strata/Languages/Python/simppy.python.st.ion") From 20ccab2201dc9af318cce0e002ebaac16eca4ec5 Mon Sep 17 00:00:00 2001 From: thanhnguyen-aws Date: Tue, 6 Jan 2026 14:51:58 -0800 Subject: [PATCH 13/13] fix lint --- Strata/Languages/Python/PythonToTypeBoogie.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Strata/Languages/Python/PythonToTypeBoogie.lean b/Strata/Languages/Python/PythonToTypeBoogie.lean index b1bc510d4..5aad5487b 100644 --- a/Strata/Languages/Python/PythonToTypeBoogie.lean +++ b/Strata/Languages/Python/PythonToTypeBoogie.lean @@ -6,7 +6,6 @@ import Strata.DDM.Elab import Strata.DDM.AST -import Lean import Strata.Languages.Boogie.DDMTransform.Parse import Strata.Languages.Boogie.Boogie @@ -959,4 +958,4 @@ def verifyBoogieProgram (path : String) : IO Unit := do end Strata ---#eval (Strata.verifyBoogieProgram "Strata/Languages/Python/simppy.python.st.ion") +#eval (Strata.verifyBoogieProgram "Strata/Languages/Python/simppy.python.st.ion")