header {* \isaheader{Small Step Semantics} *}
theory SmallStep
imports Expr State
begin
fun blocks :: "vname list * ty list * val list * expr => expr"
where
"blocks(V#Vs, T#Ts, v#vs, e) = {V:T := Val v; blocks(Vs,Ts,vs,e)}"
|"blocks([],[],[],e) = e"
lemmas blocks_induct = blocks.induct[split_format (complete)]
lemma [simp]:
"[| size vs = size Vs; size Ts = size Vs |] ==> fv(blocks(Vs,Ts,vs,e)) = fv e - set Vs"
by (induct rule:blocks_induct) auto
definition assigned :: "vname => expr => bool"
where
"assigned V e ≡ ∃v e'. e = (V := Val v;; e')"
inductive_set
red :: "J_prog => ((expr × state) × (expr × state)) set"
and reds :: "J_prog => ((expr list × state) × (expr list × state)) set"
and red' :: "J_prog => expr => state => expr => state => bool"
("_ \<turnstile> ((1〈_,/_〉) ->/ (1〈_,/_〉))" [51,0,0,0,0] 81)
and reds' :: "J_prog => expr list => state => expr list => state => bool"
("_ \<turnstile> ((1〈_,/_〉) [->]/ (1〈_,/_〉))" [51,0,0,0,0] 81)
for P :: J_prog
where
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ≡ ((e,s), e',s') ∈ red P"
| "P \<turnstile> 〈es,s〉 [->] 〈es',s'〉 ≡ ((es,s), es',s') ∈ reds P"
| RedNew:
"[| new_Addr h = Some a; P \<turnstile> C has_fields FDTs; h' = h(a\<mapsto>(C,init_fields FDTs)) |]
==> P \<turnstile> 〈new C, (h,l)〉 -> 〈addr a, (h',l)〉"
| RedNewFail:
"new_Addr h = None ==>
P \<turnstile> 〈new C, (h,l)〉 -> 〈THROW OutOfMemory, (h,l)〉"
| CastRed:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈Cast C e, s〉 -> 〈Cast C e', s'〉"
| RedCastNull:
"P \<turnstile> 〈Cast C null, s〉 -> 〈null,s〉"
| RedCast:
"[| hp s a = Some(D,fs); P \<turnstile> D \<preceq>⇧* C |]
==> P \<turnstile> 〈Cast C (addr a), s〉 -> 〈addr a, s〉"
| RedCastFail:
"[| hp s a = Some(D,fs); ¬ P \<turnstile> D \<preceq>⇧* C |]
==> P \<turnstile> 〈Cast C (addr a), s〉 -> 〈THROW ClassCast, s〉"
| BinOpRed1:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈e «bop» e⇣2, s〉 -> 〈e' «bop» e⇣2, s'〉"
| BinOpRed2:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈(Val v⇣1) «bop» e, s〉 -> 〈(Val v⇣1) «bop» e', s'〉"
| RedBinOp:
"binop(bop,v⇣1,v⇣2) = Some v ==>
P \<turnstile> 〈(Val v⇣1) «bop» (Val v⇣2), s〉 -> 〈Val v,s〉"
| RedVar:
"lcl s V = Some v ==>
P \<turnstile> 〈Var V,s〉 -> 〈Val v,s〉"
| LAssRed:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈V:=e,s〉 -> 〈V:=e',s'〉"
| RedLAss:
"P \<turnstile> 〈V:=(Val v), (h,l)〉 -> 〈unit, (h,l(V\<mapsto>v))〉"
| FAccRed:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈e•F{D}, s〉 -> 〈e'•F{D}, s'〉"
| RedFAcc:
"[| hp s a = Some(C,fs); fs(F,D) = Some v |]
==> P \<turnstile> 〈(addr a)•F{D}, s〉 -> 〈Val v,s〉"
| RedFAccNull:
"P \<turnstile> 〈null•F{D}, s〉 -> 〈THROW NullPointer, s〉"
| FAssRed1:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈e•F{D}:=e⇣2, s〉 -> 〈e'•F{D}:=e⇣2, s'〉"
| FAssRed2:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈Val v•F{D}:=e, s〉 -> 〈Val v•F{D}:=e', s'〉"
| RedFAss:
"h a = Some(C,fs) ==>
P \<turnstile> 〈(addr a)•F{D}:=(Val v), (h,l)〉 -> 〈unit, (h(a \<mapsto> (C,fs((F,D) \<mapsto> v))),l)〉"
| RedFAssNull:
"P \<turnstile> 〈null•F{D}:=Val v, s〉 -> 〈THROW NullPointer, s〉"
| CallObj:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈e•M(es),s〉 -> 〈e'•M(es),s'〉"
| CallParams:
"P \<turnstile> 〈es,s〉 [->] 〈es',s'〉 ==>
P \<turnstile> 〈(Val v)•M(es),s〉 -> 〈(Val v)•M(es'),s'〉"
| RedCall:
"[| hp s a = Some(C,fs); P \<turnstile> C sees M:Ts->T = (pns,body) in D; size vs = size pns; size Ts = size pns |]
==> P \<turnstile> 〈(addr a)•M(map Val vs), s〉 -> 〈blocks(this#pns, Class D#Ts, Addr a#vs, body), s〉"
| RedCallNull:
"P \<turnstile> 〈null•M(map Val vs),s〉 -> 〈THROW NullPointer,s〉"
| BlockRedNone:
"[| P \<turnstile> 〈e, (h,l(V:=None))〉 -> 〈e', (h',l')〉; l' V = None; ¬ assigned V e |]
==> P \<turnstile> 〈{V:T; e}, (h,l)〉 -> 〈{V:T; e'}, (h',l'(V := l V))〉"
| BlockRedSome:
"[| P \<turnstile> 〈e, (h,l(V:=None))〉 -> 〈e', (h',l')〉; l' V = Some v;¬ assigned V e |]
==> P \<turnstile> 〈{V:T; e}, (h,l)〉 -> 〈{V:T := Val v; e'}, (h',l'(V := l V))〉"
| InitBlockRed:
"[| P \<turnstile> 〈e, (h,l(V\<mapsto>v))〉 -> 〈e', (h',l')〉; l' V = Some v' |]
==> P \<turnstile> 〈{V:T := Val v; e}, (h,l)〉 -> 〈{V:T := Val v'; e'}, (h',l'(V := l V))〉"
| RedBlock:
"P \<turnstile> 〈{V:T; Val u}, s〉 -> 〈Val u, s〉"
| RedInitBlock:
"P \<turnstile> 〈{V:T := Val v; Val u}, s〉 -> 〈Val u, s〉"
| SeqRed:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈e;;e⇣2, s〉 -> 〈e';;e⇣2, s'〉"
| RedSeq:
"P \<turnstile> 〈(Val v);;e⇣2, s〉 -> 〈e⇣2, s〉"
| CondRed:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈if (e) e⇣1 else e⇣2, s〉 -> 〈if (e') e⇣1 else e⇣2, s'〉"
| RedCondT:
"P \<turnstile> 〈if (true) e⇣1 else e⇣2, s〉 -> 〈e⇣1, s〉"
| RedCondF:
"P \<turnstile> 〈if (false) e⇣1 else e⇣2, s〉 -> 〈e⇣2, s〉"
| RedWhile:
"P \<turnstile> 〈while(b) c, s〉 -> 〈if(b) (c;;while(b) c) else unit, s〉"
| ThrowRed:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈throw e, s〉 -> 〈throw e', s'〉"
| RedThrowNull:
"P \<turnstile> 〈throw null, s〉 -> 〈THROW NullPointer, s〉"
| TryRed:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈try e catch(C V) e⇣2, s〉 -> 〈try e' catch(C V) e⇣2, s'〉"
| RedTry:
"P \<turnstile> 〈try (Val v) catch(C V) e⇣2, s〉 -> 〈Val v, s〉"
| RedTryCatch:
"[| hp s a = Some(D,fs); P \<turnstile> D \<preceq>⇧* C |]
==> P \<turnstile> 〈try (Throw a) catch(C V) e⇣2, s〉 -> 〈{V:Class C := addr a; e⇣2}, s〉"
| RedTryFail:
"[| hp s a = Some(D,fs); ¬ P \<turnstile> D \<preceq>⇧* C |]
==> P \<turnstile> 〈try (Throw a) catch(C V) e⇣2, s〉 -> 〈Throw a, s〉"
| ListRed1:
"P \<turnstile> 〈e,s〉 -> 〈e',s'〉 ==>
P \<turnstile> 〈e#es,s〉 [->] 〈e'#es,s'〉"
| ListRed2:
"P \<turnstile> 〈es,s〉 [->] 〈es',s'〉 ==>
P \<turnstile> 〈Val v # es,s〉 [->] 〈Val v # es',s'〉"
-- "Exception propagation"
| CastThrow: "P \<turnstile> 〈Cast C (throw e), s〉 -> 〈throw e, s〉"
| BinOpThrow1: "P \<turnstile> 〈(throw e) «bop» e⇣2, s〉 -> 〈throw e, s〉"
| BinOpThrow2: "P \<turnstile> 〈(Val v⇣1) «bop» (throw e), s〉 -> 〈throw e, s〉"
| LAssThrow: "P \<turnstile> 〈V:=(throw e), s〉 -> 〈throw e, s〉"
| FAccThrow: "P \<turnstile> 〈(throw e)•F{D}, s〉 -> 〈throw e, s〉"
| FAssThrow1: "P \<turnstile> 〈(throw e)•F{D}:=e⇣2, s〉 -> 〈throw e,s〉"
| FAssThrow2: "P \<turnstile> 〈Val v•F{D}:=(throw e), s〉 -> 〈throw e, s〉"
| CallThrowObj: "P \<turnstile> 〈(throw e)•M(es), s〉 -> 〈throw e, s〉"
| CallThrowParams: "[| es = map Val vs @ throw e # es' |] ==> P \<turnstile> 〈(Val v)•M(es), s〉 -> 〈throw e, s〉"
| BlockThrow: "P \<turnstile> 〈{V:T; Throw a}, s〉 -> 〈Throw a, s〉"
| InitBlockThrow: "P \<turnstile> 〈{V:T := Val v; Throw a}, s〉 -> 〈Throw a, s〉"
| SeqThrow: "P \<turnstile> 〈(throw e);;e⇣2, s〉 -> 〈throw e, s〉"
| CondThrow: "P \<turnstile> 〈if (throw e) e⇣1 else e⇣2, s〉 -> 〈throw e, s〉"
| ThrowThrow: "P \<turnstile> 〈throw(throw e), s〉 -> 〈throw e, s〉"
lemmas red_reds_induct = red_reds.induct [split_format (complete)]
and red_reds_inducts = red_reds.inducts [split_format (complete)]
inductive_cases [elim!]:
"P \<turnstile> 〈V:=e,s〉 -> 〈e',s'〉"
"P \<turnstile> 〈e1;;e2,s〉 -> 〈e',s'〉"
subsection{* The reflexive transitive closure *}
abbreviation
Step :: "J_prog => expr => state => expr => state => bool"
("_ \<turnstile> ((1〈_,/_〉) ->*/ (1〈_,/_〉))" [51,0,0,0,0] 81)
where "P \<turnstile> 〈e,s〉 ->* 〈e',s'〉 ≡ ((e,s), e',s') ∈ (red P)⇧*"
abbreviation
Steps :: "J_prog => expr list => state => expr list => state => bool"
("_ \<turnstile> ((1〈_,/_〉) [->]*/ (1〈_,/_〉))" [51,0,0,0,0] 81)
where "P \<turnstile> 〈es,s〉 [->]* 〈es',s'〉 ≡ ((es,s), es',s') ∈ (reds P)⇧*"
lemma converse_rtrancl_induct_red[consumes 1]:
assumes "P \<turnstile> 〈e,(h,l)〉 ->* 〈e',(h',l')〉"
and "!!e h l. R e h l e h l"
and "!!e⇣0 h⇣0 l⇣0 e⇣1 h⇣1 l⇣1 e' h' l'.
[| P \<turnstile> 〈e⇣0,(h⇣0,l⇣0)〉 -> 〈e⇣1,(h⇣1,l⇣1)〉; R e⇣1 h⇣1 l⇣1 e' h' l' |] ==> R e⇣0 h⇣0 l⇣0 e' h' l'"
shows "R e h l e' h' l'"
proof -
{ fix s s'
assume reds: "P \<turnstile> 〈e,s〉 ->* 〈e',s'〉"
and base: "!!e s. R e (hp s) (lcl s) e (hp s) (lcl s)"
and red⇣1: "!!e⇣0 s⇣0 e⇣1 s⇣1 e' s'.
[| P \<turnstile> 〈e⇣0,s⇣0〉 -> 〈e⇣1,s⇣1〉; R e⇣1 (hp s⇣1) (lcl s⇣1) e' (hp s') (lcl s') |]
==> R e⇣0 (hp s⇣0) (lcl s⇣0) e' (hp s') (lcl s')"
from reds have "R e (hp s) (lcl s) e' (hp s') (lcl s')"
proof (induct rule:converse_rtrancl_induct2)
case refl show ?case by(rule base)
next
case (step e⇣0 s⇣0 e s)
thus ?case by(blast intro:red⇣1)
qed
}
with assms show ?thesis by fastforce
qed
subsection{*Some easy lemmas*}
lemma [iff]: "¬ P \<turnstile> 〈[],s〉 [->] 〈es',s'〉"
by(blast elim: reds.cases)
lemma [iff]: "¬ P \<turnstile> 〈Val v,s〉 -> 〈e',s'〉"
by(fastforce elim: red.cases)
lemma [iff]: "¬ P \<turnstile> 〈Throw a,s〉 -> 〈e',s'〉"
by(fastforce elim: red.cases)
lemma red_hext_incr: "P \<turnstile> 〈e,(h,l)〉 -> 〈e',(h',l')〉 ==> h \<unlhd> h'"
and reds_hext_incr: "P \<turnstile> 〈es,(h,l)〉 [->] 〈es',(h',l')〉 ==> h \<unlhd> h'"
proof(induct rule:red_reds_inducts)
case RedNew thus ?case
by(fastforce dest:new_Addr_SomeD simp:hext_def split:if_splits)
next
case RedFAss thus ?case by(simp add:hext_def split:if_splits)
qed simp_all
lemma red_lcl_incr: "P \<turnstile> 〈e,(h⇣0,l⇣0)〉 -> 〈e',(h⇣1,l⇣1)〉 ==> dom l⇣0 ⊆ dom l⇣1"
and "P \<turnstile> 〈es,(h⇣0,l⇣0)〉 [->] 〈es',(h⇣1,l⇣1)〉 ==> dom l⇣0 ⊆ dom l⇣1"
by(induct rule: red_reds_inducts)(auto simp del:fun_upd_apply)
lemma red_lcl_add: "P \<turnstile> 〈e,(h,l)〉 -> 〈e',(h',l')〉 ==> (!!l⇣0. P \<turnstile> 〈e,(h,l⇣0++l)〉 -> 〈e',(h',l⇣0++l')〉)"
and "P \<turnstile> 〈es,(h,l)〉 [->] 〈es',(h',l')〉 ==> (!!l⇣0. P \<turnstile> 〈es,(h,l⇣0++l)〉 [->] 〈es',(h',l⇣0++l')〉)"
proof (induct rule:red_reds_inducts)
case RedCast thus ?case by(fastforce intro:red_reds.intros)
next
case RedCastFail thus ?case by(force intro:red_reds.intros)
next
case RedFAcc thus ?case by(fastforce intro:red_reds.intros)
next
case RedCall thus ?case by(fastforce intro:red_reds.intros)
next
case (InitBlockRed e h l V v e' h' l' v' T l⇣0)
have IH: "!!l⇣0. P \<turnstile> 〈e,(h, l⇣0 ++ l(V \<mapsto> v))〉 -> 〈e',(h', l⇣0 ++ l')〉"
and l'V: "l' V = Some v'" by fact+
from IH have IH': "P \<turnstile> 〈e,(h, (l⇣0 ++ l)(V \<mapsto> v))〉 -> 〈e',(h', l⇣0 ++ l')〉"
by simp
have "(l⇣0 ++ l')(V := (l⇣0 ++ l) V) = l⇣0 ++ l'(V := l V)"
by(rule ext)(simp add:map_add_def)
with red_reds.InitBlockRed[OF IH'] l'V show ?case by(simp del:fun_upd_apply)
next
case (BlockRedNone e h l V e' h' l' T l⇣0)
have IH: "!!l⇣0. P \<turnstile> 〈e,(h, l⇣0 ++ l(V := None))〉 -> 〈e',(h', l⇣0 ++ l')〉"
and l'V: "l' V = None" and unass: "¬ assigned V e" by fact+
have "l⇣0(V := None) ++ l(V := None) = (l⇣0 ++ l)(V := None)"
by(simp add:fun_eq_iff map_add_def)
hence IH': "P \<turnstile> 〈e,(h, (l⇣0++l)(V := None))〉 -> 〈e',(h', l⇣0(V := None) ++ l')〉"
using IH[of "l⇣0(V := None)"] by simp
have "(l⇣0(V := None) ++ l')(V := (l⇣0 ++ l) V) = l⇣0 ++ l'(V := l V)"
by(simp add:fun_eq_iff map_add_def)
with red_reds.BlockRedNone[OF IH' _ unass] l'V show ?case
by(simp add: map_add_def)
next
case (BlockRedSome e h l V e' h' l' v T l⇣0)
have IH: "!!l⇣0. P \<turnstile> 〈e,(h, l⇣0 ++ l(V := None))〉 -> 〈e',(h', l⇣0 ++ l')〉"
and l'V: "l' V = Some v" and unass: "¬ assigned V e" by fact+
have "l⇣0(V := None) ++ l(V := None) = (l⇣0 ++ l)(V := None)"
by(simp add:fun_eq_iff map_add_def)
hence IH': "P \<turnstile> 〈e,(h, (l⇣0++l)(V := None))〉 -> 〈e',(h', l⇣0(V := None) ++ l')〉"
using IH[of "l⇣0(V := None)"] by simp
have "(l⇣0(V := None) ++ l')(V := (l⇣0 ++ l) V) = l⇣0 ++ l'(V := l V)"
by(simp add:fun_eq_iff map_add_def)
with red_reds.BlockRedSome[OF IH' _ unass] l'V show ?case
by(simp add:map_add_def)
next
case RedTryCatch thus ?case by(fastforce intro:red_reds.intros)
next
case RedTryFail thus ?case by(force intro!:red_reds.intros)
qed (simp_all add:red_reds.intros)
lemma Red_lcl_add:
assumes "P \<turnstile> 〈e,(h,l)〉 ->* 〈e',(h',l')〉" shows "P \<turnstile> 〈e,(h,l⇣0++l)〉 ->* 〈e',(h',l⇣0++l')〉"
using assms
proof(induct rule:converse_rtrancl_induct_red)
case 1 thus ?case by simp
next
case 2 thus ?case
by (blast dest: red_lcl_add intro: converse_rtrancl_into_rtrancl)
qed
end