Theory VIMP_Program

theory VIMP_Program
  imports VIMP_Proc
begin

section ‹Whole programs›

text ‹
  ‹declared_global_vars› is the declared-global list in source order; a list,
  so finiteness is by type. ‹declared_global› is the derived classifier every
  program-level operation uses; procedure-level interfaces take the classifier
  as an explicit ‹vname ⇒ bool› argument instead.
›

record imp_prog =
  proc_rep :: "(pname * proc_decl) list"
  declared_global_vars :: "vname list"

definition declared_global :: "imp_prog ⇒ vname ⇒ bool" where
  "declared_global p x ⟷ x ∈ set (declared_global_vars p)"

lemma declared_global_iff [simp]:
  "declared_global p x ⟷ x ∈ set (declared_global_vars p)"
  by (simp add: declared_global_def)

text ‹The ‹program› parser fixes the entry name and rejects formals on it, so
  ‹main› is an ordinary ‹proc_rep› entry. ‹prog_main› is total through
  const‹main_body›'s aborting fallback;
  ‹wf_source_program›'s entry conjunct is what makes the lookup meaningful.›

definition prog_table :: "imp_prog ⇒ proc_table" where
  "prog_table p = map_of (proc_rep p)"

definition prog_procs :: "imp_prog ⇒ pname list" where
  "prog_procs p = filter (λn. n ≠ prog_main_name) (map fst (proc_rep p))"

definition prog_main :: "imp_prog ⇒ com" where
  "prog_main p = main_body (prog_table p)"

lemma prog_main_eq_main_body [simp]: "main_body (prog_table p) = prog_main p"
  by (simp add: prog_main_def)

text ‹‹mk_program› conses the entry onto ‹proc_rep›, so a program built through
  it satisfies ‹wf_source_program›'s entry conjunct by construction.›
definition mk_program :: "(pname * proc_decl) list ⇒ com ⇒ vname list ⇒ imp_prog" where
  "mk_program ps m gv = imp_prog.make ((prog_main_name, ⦇formals = [], body = m⦈) # ps) gv"

lemma mk_program_simps [simp]:
  "prog_table (mk_program ps m gv) = (map_of ps)(prog_main_name ↦ ⦇formals = [], body = m⦈)"
  "prog_main (mk_program ps m gv) = m"
  "declared_global_vars (mk_program ps m gv) = gv"
  "prog_main_name ∉ set (map fst ps) ⟹ prog_procs (mk_program ps m gv) = map fst ps"
  by (force simp: prog_table_def prog_main_def main_body_def prog_procs_def mk_program_def
      imp_prog.make_def filter_id_conv)+

text ‹The finite variable scope of an activation: every declared global, the
  activation's formals and body occurrences, and the reserved return location.›

definition scope_vnames :: "imp_prog ⇒ pname ⇒ vname set" where
  "scope_vnames p owner =
    set (declared_global_vars p) ∪ {ret_var} ∪
    (case prog_table p owner of
      None ⇒ {} |
      Some decl ⇒ set (formals decl) ∪ com_vnames (body decl))"

lemma finite_scope_vnames [simp]: "finite (scope_vnames p owner)"
  unfolding scope_vnames_def by (auto split: option.splits)

definition scope_vnames_list :: "imp_prog ⇒ pname ⇒ vname list" where
  "scope_vnames_list p owner = sorted_list_of_set (scope_vnames p owner)"

lemma set_scope_vnames_list [simp]:
  "set (scope_vnames_list p owner) = scope_vnames p owner"
  unfolding scope_vnames_list_def by simp

text ‹Every variable some procedure of the program declares: a program-wide
  superset of any one activation's scope.›

definition program_vars :: "imp_prog ⇒ vname list" where
  "program_vars p =
     remdups (concat (map (scope_vnames_list p) (prog_main_name # prog_procs p)))"

end