theory CFGExit imports CFG begin
subsection {* Adds an exit node to the abstract CFG *}
locale CFGExit = CFG sourcenode targetnode kind valid_edge Entry
  for sourcenode :: "'edge => 'node" and targetnode :: "'edge => 'node"
  and kind :: "'edge => 'state edge_kind" and valid_edge :: "'edge => bool"
  and Entry :: "'node" ("'('_Entry'_')") + 
  fixes Exit::"'node"  ("'('_Exit'_')")
  assumes Exit_source [dest]: "[|valid_edge a; sourcenode a = (_Exit_)|] ==> False"
  and Entry_Exit_edge: "∃a. valid_edge a ∧ sourcenode a = (_Entry_) ∧
    targetnode a = (_Exit_) ∧ kind a = (λs. False)⇣\<surd>"
  
begin
lemma Entry_noteq_Exit [dest]:
  assumes eq:"(_Entry_) = (_Exit_)" shows "False"
proof -
  from Entry_Exit_edge obtain a where "sourcenode a = (_Entry_)" 
    and "valid_edge a" by blast
  with eq show False by simp(erule Exit_source)
qed
lemma Exit_noteq_Entry [dest]:"(_Exit_) = (_Entry_) ==> False"
  by(rule Entry_noteq_Exit[OF sym],simp)
lemma [simp]: "valid_node (_Entry_)"
proof -
  from Entry_Exit_edge obtain a where "sourcenode a = (_Entry_)" 
    and "valid_edge a" by blast
  thus ?thesis by(fastforce simp:valid_node_def)
qed
lemma [simp]: "valid_node (_Exit_)"
proof -
  from Entry_Exit_edge obtain a where "targetnode a = (_Exit_)"
    and "valid_edge a" by blast
  thus ?thesis by(fastforce simp:valid_node_def)
qed
definition inner_node :: "'node => bool"
  where inner_node_def: 
  "inner_node n ≡ valid_node n ∧ n ≠ (_Entry_) ∧ n ≠ (_Exit_)"
lemma inner_is_valid:
  "inner_node n ==> valid_node n"
by(simp add:inner_node_def valid_node_def)
lemma [dest]:
  "inner_node (_Entry_) ==> False"
by(simp add:inner_node_def)
lemma [dest]:
  "inner_node (_Exit_) ==> False" 
by(simp add:inner_node_def)
lemma [simp]:"[|valid_edge a; targetnode a ≠ (_Exit_)|] 
  ==> inner_node (targetnode a)"
  by(simp add:inner_node_def,rule ccontr,simp,erule Entry_target)
lemma [simp]:"[|valid_edge a; sourcenode a ≠ (_Entry_)|]
  ==> inner_node (sourcenode a)"
  by(simp add:inner_node_def,rule ccontr,simp,erule Exit_source)
lemma valid_node_cases [consumes 1, case_names "Entry" "Exit" "inner"]:
  "[|valid_node n; n = (_Entry_) ==> Q; n = (_Exit_) ==> Q;
    inner_node n ==> Q|] ==> Q"
apply(auto simp:valid_node_def)
 apply(case_tac "sourcenode a = (_Entry_)") apply auto
apply(case_tac "targetnode a = (_Exit_)") apply auto
done
lemma path_Exit_source [dest]:
  assumes "(_Exit_) -as->* n'" shows "n' = (_Exit_)" and "as = []"
  using `(_Exit_) -as->* n'`
proof(induct n≡"(_Exit_)" as n' rule:path.induct)
  case (Cons_path n'' as n' a)
  from `sourcenode a = (_Exit_)` `valid_edge a` have False 
    by -(rule Exit_source,simp_all)
  { case 1 with `False` show ?case ..
  next
    case 2 with `False` show ?case ..
  }
qed simp_all
lemma Exit_no_sourcenode[dest]:
  assumes isin:"(_Exit_) ∈ set (sourcenodes as)" and path:"n -as->* n'"
  shows False
proof -
  from isin obtain ns' ns'' where "sourcenodes as = ns'@(_Exit_)#ns''"
    by(auto dest:split_list simp:sourcenodes_def)
  then obtain as' as'' a where "as = as'@a#as''"
    and source:"sourcenode a = (_Exit_)"
    by(fastforce elim:map_append_append_maps simp:sourcenodes_def)
  with path have "valid_edge a" by(fastforce dest:path_split)
  with source show ?thesis by -(erule Exit_source)
qed
end 
end