Added command for associating user-defined types with SPARK types.
authorberghofe
Fri, 15 Apr 2011 15:33:57 +0200
changeset 43227e8777e3ea6ef
parent 43226 ce00462fe8aa
child 43228 3305f573294e
Added command for associating user-defined types with SPARK types.
etc/isar-keywords.el
src/HOL/SPARK/Tools/spark_commands.ML
src/HOL/SPARK/Tools/spark_vcs.ML
     1.1 --- a/etc/isar-keywords.el	Thu Apr 14 15:04:42 2011 +0200
     1.2 +++ b/etc/isar-keywords.el	Fri Apr 15 15:33:57 2011 +0200
     1.3 @@ -227,6 +227,7 @@
     1.4      "spark_open"
     1.5      "spark_proof_functions"
     1.6      "spark_status"
     1.7 +    "spark_types"
     1.8      "spark_vc"
     1.9      "specification"
    1.10      "statespace"
    1.11 @@ -520,6 +521,7 @@
    1.12      "spark_end"
    1.13      "spark_open"
    1.14      "spark_proof_functions"
    1.15 +    "spark_types"
    1.16      "statespace"
    1.17      "syntax"
    1.18      "syntax_declaration"
     2.1 --- a/src/HOL/SPARK/Tools/spark_commands.ML	Thu Apr 14 15:04:42 2011 +0200
     2.2 +++ b/src/HOL/SPARK/Tools/spark_commands.ML	Fri Apr 15 15:33:57 2011 +0200
     2.3 @@ -27,7 +27,7 @@
     2.4      SPARK_VCs.set_vcs
     2.5        (snd (Fdl_Parser.parse_declarations (Path.position fdl_path) (File.read fdl_path)))
     2.6        (Fdl_Parser.parse_rules (Path.position rls_path) (File.read rls_path))
     2.7 -      (snd (snd (Fdl_Parser.parse_vcs header (Path.position vc_path) (File.read vc_path))))
     2.8 +      (snd (Fdl_Parser.parse_vcs header (Path.position vc_path) (File.read vc_path)))
     2.9        base thy
    2.10    end;
    2.11  
    2.12 @@ -39,6 +39,9 @@
    2.13         Syntax.check_term ctxt) pf thy
    2.14    end;
    2.15  
    2.16 +fun add_spark_type_cmd (s, raw_typ) thy =
    2.17 +  SPARK_VCs.add_type (s, Syntax.read_typ_global thy raw_typ) thy;
    2.18 +
    2.19  fun get_vc thy vc_name =
    2.20    (case SPARK_VCs.lookup_vc thy vc_name of
    2.21      SOME (ctxt, (_, proved, ctxt', stmt)) =>
    2.22 @@ -117,6 +120,13 @@
    2.23         (Toplevel.theory o fold add_proof_fun_cmd));
    2.24  
    2.25  val _ =
    2.26 +  Outer_Syntax.command "spark_types"
    2.27 +    "associate SPARK types with types"
    2.28 +    Keyword.thy_decl
    2.29 +    (Scan.repeat1 (Parse.name --| Args.$$$ "=" -- Parse.typ) >>
    2.30 +       (Toplevel.theory o fold add_spark_type_cmd));
    2.31 +
    2.32 +val _ =
    2.33    Outer_Syntax.command "spark_vc"
    2.34      "enter into proof mode for a specific verification condition"
    2.35      Keyword.thy_goal
     3.1 --- a/src/HOL/SPARK/Tools/spark_vcs.ML	Thu Apr 14 15:04:42 2011 +0200
     3.2 +++ b/src/HOL/SPARK/Tools/spark_vcs.ML	Fri Apr 15 15:33:57 2011 +0200
     3.3 @@ -7,11 +7,12 @@
     3.4  
     3.5  signature SPARK_VCS =
     3.6  sig
     3.7 -  val set_vcs: Fdl_Parser.decls -> Fdl_Parser.rules -> Fdl_Parser.vcs ->
     3.8 -    Path.T -> theory -> theory
     3.9 +  val set_vcs: Fdl_Parser.decls -> Fdl_Parser.rules ->
    3.10 +    (string * string) * Fdl_Parser.vcs -> Path.T -> theory -> theory
    3.11    val add_proof_fun: (typ option -> 'a -> term) ->
    3.12      string * ((string list * string) option * 'a) ->
    3.13      theory -> theory
    3.14 +  val add_type: string * typ -> theory -> theory
    3.15    val lookup_vc: theory -> string -> (Element.context_i list *
    3.16      (string * thm list option * Element.context_i * Element.statement_i)) option
    3.17    val get_vcs: theory ->
    3.18 @@ -28,8 +29,49 @@
    3.19  open Fdl_Parser;
    3.20  
    3.21  
    3.22 +(** theory data **)
    3.23 +
    3.24 +fun err_unfinished () = error "An unfinished SPARK environment is still open."
    3.25 +
    3.26 +val strip_number = pairself implode o take_suffix Fdl_Lexer.is_digit o raw_explode;
    3.27 +
    3.28 +val name_ord = prod_ord string_ord (option_ord int_ord) o
    3.29 +  pairself (strip_number ##> Int.fromString);
    3.30 +
    3.31 +structure VCtab = Table(type key = string val ord = name_ord);
    3.32 +
    3.33 +structure VCs = Theory_Data
    3.34 +(
    3.35 +  type T =
    3.36 +    {pfuns: ((string list * string) option * term) Symtab.table,
    3.37 +     type_map: typ Symtab.table,
    3.38 +     env:
    3.39 +       {ctxt: Element.context_i list,
    3.40 +        defs: (binding * thm) list,
    3.41 +        types: fdl_type tab,
    3.42 +        funs: (string list * string) tab,
    3.43 +        ids: (term * string) Symtab.table * Name.context,
    3.44 +        proving: bool,
    3.45 +        vcs: (string * thm list option *
    3.46 +          (string * expr) list * (string * expr) list) VCtab.table,
    3.47 +        path: Path.T} option}
    3.48 +  val empty : T = {pfuns = Symtab.empty, type_map = Symtab.empty, env = NONE}
    3.49 +  val extend = I
    3.50 +  fun merge ({pfuns = pfuns1, type_map = type_map1, env = NONE},
    3.51 +        {pfuns = pfuns2, type_map = type_map2, env = NONE}) =
    3.52 +        {pfuns = Symtab.merge (eq_pair (op =) (op aconv)) (pfuns1, pfuns2),
    3.53 +         type_map = Symtab.merge (op =) (type_map1, type_map2),
    3.54 +         env = NONE}
    3.55 +    | merge _ = err_unfinished ()
    3.56 +)
    3.57 +
    3.58 +
    3.59  (** utilities **)
    3.60  
    3.61 +val to_lower = raw_explode #> map Symbol.to_ascii_lower #> implode;
    3.62 +
    3.63 +val lcase_eq = (op =) o pairself (to_lower o Long_Name.base_name);
    3.64 +
    3.65  fun mk_unop s t =
    3.66    let val T = fastype_of t
    3.67    in Const (s, T --> T) $ t end;
    3.68 @@ -44,17 +86,22 @@
    3.69        HOLogic.mk_setT (HOLogic.mk_prodT (T, U))) $ t $ Abs ("", T, u)
    3.70    end;
    3.71  
    3.72 +fun get_type thy ty =
    3.73 +  let val {type_map, ...} = VCs.get thy
    3.74 +  in Symtab.lookup type_map ty end;
    3.75 +
    3.76  fun mk_type _ "integer" = HOLogic.intT
    3.77    | mk_type _ "boolean" = HOLogic.boolT
    3.78 -  | mk_type thy ty = Syntax.check_typ (ProofContext.init_global thy)
    3.79 -      (Type (Sign.full_name thy (Binding.name ty), []));
    3.80 +  | mk_type thy ty =
    3.81 +      (case get_type thy ty of
    3.82 +         NONE =>
    3.83 +           Syntax.check_typ (ProofContext.init_global thy)
    3.84 +             (Type (Sign.full_name thy (Binding.name ty), []))
    3.85 +       | SOME T => T);
    3.86  
    3.87  val booleanN = "boolean";
    3.88  val integerN = "integer";
    3.89  
    3.90 -fun mk_qual_name thy s s' =
    3.91 -  Sign.full_name thy (Binding.qualify true s (Binding.name s'));
    3.92 -
    3.93  fun define_overloaded (def_name, eq) lthy =
    3.94    let
    3.95      val ((c, _), rhs) = eq |> Syntax.check_term lthy |>
    3.96 @@ -80,17 +127,29 @@
    3.97      val zs = map (Free o rpair T) ys;
    3.98    in (zs, (fold (Symtab.update o apsnd (rpair ty)) (xs ~~ zs) tab, ctxt')) end;
    3.99  
   3.100 +fun get_record_info thy T = (case Record.dest_recTs T of
   3.101 +    [(tyname, [@{typ unit}])] =>
   3.102 +      Record.get_info thy (Long_Name.qualifier tyname)
   3.103 +  | _ => NONE);
   3.104 +
   3.105 +fun find_field fname = find_first (curry lcase_eq fname o fst);
   3.106 +
   3.107 +fun find_field' fname = get_first (fn (flds, fldty) =>
   3.108 +  if member (op =) flds fname then SOME fldty else NONE);
   3.109 +
   3.110 +fun assoc_ty_err thy T s msg =
   3.111 +  error ("Type " ^ Syntax.string_of_typ_global thy T ^
   3.112 +    " associated with SPARK type " ^ s ^ "\n" ^ msg);
   3.113 +
   3.114  
   3.115  (** generate properties of enumeration types **)
   3.116  
   3.117 -fun add_enum_type tyname els (tab, ctxt) thy =
   3.118 +fun add_enum_type tyname tyname' thy =
   3.119    let
   3.120 -    val tyb = Binding.name tyname;
   3.121 -    val tyname' = Sign.full_name thy tyb;
   3.122 +    val {case_name, ...} = the (Datatype_Data.get_info thy tyname');
   3.123 +    val cs = map Const (the (Datatype_Data.get_constrs thy tyname'));
   3.124 +    val k = length cs;
   3.125      val T = Type (tyname', []);
   3.126 -    val case_name = mk_qual_name thy tyname (tyname ^ "_case");
   3.127 -    val cs = map (fn s => Const (mk_qual_name thy tyname s, T)) els;
   3.128 -    val k = length els;
   3.129      val p = Const (@{const_name pos}, T --> HOLogic.intT);
   3.130      val v = Const (@{const_name val}, HOLogic.intT --> T);
   3.131      val card = Const (@{const_name card},
   3.132 @@ -103,9 +162,6 @@
   3.133             (f $ Bound 1) $ (f $ Bound 0))));
   3.134  
   3.135      val (((def1, def2), def3), lthy) = thy |>
   3.136 -      Datatype.add_datatype {strict = true, quiet = true} [tyname]
   3.137 -        [([], tyb, NoSyn,
   3.138 -          map (fn s => (Binding.name s, [], NoSyn)) els)] |> snd |>
   3.139  
   3.140        Class.instantiation ([tyname'], [], @{sort enum}) |>
   3.141  
   3.142 @@ -195,46 +251,107 @@
   3.143      val simp_att = [Attrib.internal (K Simplifier.simp_add)]
   3.144  
   3.145    in
   3.146 -    ((fold (Symtab.update_new o apsnd (rpair tyname)) (els ~~ cs) tab,
   3.147 -      fold Name.declare els ctxt),
   3.148 -     lthy' |>
   3.149 -     Local_Theory.note
   3.150 -       ((Binding.name (tyname ^ "_card_UNIV"), simp_att), [card_UNIV]) ||>>
   3.151 -     Local_Theory.note
   3.152 -       ((Binding.name (tyname ^ "_pos"), simp_att), pos_eqs) ||>>
   3.153 -     Local_Theory.note
   3.154 -       ((Binding.name (tyname ^ "_val"), simp_att), val_eqs) ||>>
   3.155 -     Local_Theory.note
   3.156 -       ((Binding.name (tyname ^ "_first_el"), simp_att), [first_el]) ||>>
   3.157 -     Local_Theory.note
   3.158 -       ((Binding.name (tyname ^ "_last_el"), simp_att), [last_el]) |> snd |>
   3.159 -     Local_Theory.exit_global)
   3.160 +    lthy' |>
   3.161 +    Local_Theory.note
   3.162 +      ((Binding.name (tyname ^ "_card_UNIV"), simp_att), [card_UNIV]) ||>>
   3.163 +    Local_Theory.note
   3.164 +      ((Binding.name (tyname ^ "_pos"), simp_att), pos_eqs) ||>>
   3.165 +    Local_Theory.note
   3.166 +      ((Binding.name (tyname ^ "_val"), simp_att), val_eqs) ||>>
   3.167 +    Local_Theory.note
   3.168 +      ((Binding.name (tyname ^ "_first_el"), simp_att), [first_el]) ||>>
   3.169 +    Local_Theory.note
   3.170 +      ((Binding.name (tyname ^ "_last_el"), simp_att), [last_el]) |> snd |>
   3.171 +    Local_Theory.exit_global
   3.172    end;
   3.173  
   3.174  
   3.175 +fun check_no_assoc thy s = case get_type thy s of
   3.176 +    NONE => ()
   3.177 +  | SOME _ => error ("Cannot associate a type with " ^ s ^
   3.178 +      "\nsince it is no record or enumeration type");
   3.179 +
   3.180 +fun check_enum [] [] = NONE 
   3.181 +  | check_enum els [] = SOME ("has no element(s) " ^ commas els)
   3.182 +  | check_enum [] cs = SOME ("has extra element(s) " ^
   3.183 +      commas (map (Long_Name.base_name o fst) cs))
   3.184 +  | check_enum (el :: els) ((cname, _) :: cs) =
   3.185 +      if lcase_eq (el, cname) then check_enum els cs
   3.186 +      else SOME ("either has no element " ^ el ^
   3.187 +        " or it is at the wrong position");
   3.188 +
   3.189  fun add_type_def (s, Basic_Type ty) (ids, thy) =
   3.190 -      (ids,
   3.191 -       Typedecl.abbrev_global (Binding.name s, [], NoSyn)
   3.192 -         (mk_type thy ty) thy |> snd)
   3.193 +      (check_no_assoc thy s;
   3.194 +       (ids,
   3.195 +        Typedecl.abbrev_global (Binding.name s, [], NoSyn)
   3.196 +          (mk_type thy ty) thy |> snd))
   3.197  
   3.198 -  | add_type_def (s, Enum_Type els) (ids, thy) = add_enum_type s els ids thy
   3.199 +  | add_type_def (s, Enum_Type els) ((tab, ctxt), thy) =
   3.200 +      let
   3.201 +        val (thy', tyname) = (case get_type thy s of
   3.202 +            NONE =>
   3.203 +              let
   3.204 +                val tyb = Binding.name s;
   3.205 +                val tyname = Sign.full_name thy tyb
   3.206 +              in
   3.207 +                (thy |>
   3.208 +                 Datatype.add_datatype {strict = true, quiet = true} [s]
   3.209 +                   [([], tyb, NoSyn,
   3.210 +                     map (fn s => (Binding.name s, [], NoSyn)) els)] |> snd |>
   3.211 +                 add_enum_type s tyname,
   3.212 +                 tyname)
   3.213 +              end
   3.214 +          | SOME (T as Type (tyname, [])) =>
   3.215 +              (case Datatype_Data.get_constrs thy tyname of
   3.216 +                 NONE => assoc_ty_err thy T s "is not a datatype"
   3.217 +               | SOME cs => (case check_enum els cs of
   3.218 +                   NONE => (thy, tyname)
   3.219 +                 | SOME msg => assoc_ty_err thy T s msg)));
   3.220 +        val cs = map Const (the (Datatype_Data.get_constrs thy' tyname))
   3.221 +      in
   3.222 +        ((fold (Symtab.update_new o apsnd (rpair s)) (els ~~ cs) tab,
   3.223 +          fold Name.declare els ctxt),
   3.224 +         thy')
   3.225 +      end
   3.226  
   3.227    | add_type_def (s, Array_Type (argtys, resty)) (ids, thy) =
   3.228 -      (ids,
   3.229 -       Typedecl.abbrev_global (Binding.name s, [], NoSyn)
   3.230 -         (foldr1 HOLogic.mk_prodT (map (mk_type thy) argtys) -->
   3.231 -            mk_type thy resty) thy |> snd)
   3.232 +      (check_no_assoc thy s;
   3.233 +       (ids,
   3.234 +        Typedecl.abbrev_global (Binding.name s, [], NoSyn)
   3.235 +          (foldr1 HOLogic.mk_prodT (map (mk_type thy) argtys) -->
   3.236 +             mk_type thy resty) thy |> snd))
   3.237  
   3.238    | add_type_def (s, Record_Type fldtys) (ids, thy) =
   3.239        (ids,
   3.240 -       Record.add_record true ([], Binding.name s) NONE
   3.241 -         (maps (fn (flds, ty) =>
   3.242 -            let val T = mk_type thy ty
   3.243 -            in map (fn fld => (Binding.name fld, T, NoSyn)) flds
   3.244 -            end) fldtys) thy)
   3.245 +       let val fldTs = maps (fn (flds, ty) =>
   3.246 +         map (rpair (mk_type thy ty)) flds) fldtys
   3.247 +       in case get_type thy s of
   3.248 +           NONE =>
   3.249 +             Record.add_record true ([], Binding.name s) NONE
   3.250 +               (map (fn (fld, T) => (Binding.name fld, T, NoSyn)) fldTs) thy
   3.251 +         | SOME rT =>
   3.252 +             (case get_record_info thy rT of
   3.253 +                NONE => assoc_ty_err thy rT s "is not a record type"
   3.254 +              | SOME {fields, ...} =>
   3.255 +                  (case subtract (lcase_eq o pairself fst) fldTs fields of
   3.256 +                     [] => ()
   3.257 +                   | flds => assoc_ty_err thy rT s ("has extra field(s) " ^
   3.258 +                       commas (map (Long_Name.base_name o fst) flds));
   3.259 +                   map (fn (fld, T) =>
   3.260 +                     case AList.lookup lcase_eq fields fld of
   3.261 +                       NONE => assoc_ty_err thy rT s ("has no field " ^ fld)
   3.262 +                     | SOME U => T = U orelse assoc_ty_err thy rT s
   3.263 +                         ("has field " ^
   3.264 +                          fld ^ " whose type\n" ^
   3.265 +                          Syntax.string_of_typ_global thy U ^
   3.266 +                          "\ndoes not match declared type\n" ^
   3.267 +                          Syntax.string_of_typ_global thy T)) fldTs;
   3.268 +                   thy))
   3.269 +       end)
   3.270  
   3.271    | add_type_def (s, Pending_Type) (ids, thy) =
   3.272 -      (ids, Typedecl.typedecl_global (Binding.name s, [], NoSyn) thy |> snd);
   3.273 +      (check_no_assoc thy s;
   3.274 +       (ids, Typedecl.typedecl_global (Binding.name s, [], NoSyn) thy |> snd));
   3.275  
   3.276  
   3.277  fun term_of_expr thy types funs pfuns =
   3.278 @@ -323,17 +440,16 @@
   3.279            (case try (unprefix "fld_") s of
   3.280               SOME fname => (case es of
   3.281                 [e] =>
   3.282 -                 let val (t, rcdty) = tm_of vs e
   3.283 -                 in case lookup types rcdty of
   3.284 -                     SOME (Record_Type fldtys) =>
   3.285 -                       (case get_first (fn (flds, fldty) =>
   3.286 -                            if member (op =) flds fname then SOME fldty
   3.287 -                            else NONE) fldtys of
   3.288 -                          SOME fldty =>
   3.289 -                            (Const (mk_qual_name thy rcdty fname,
   3.290 -                               mk_type thy rcdty --> mk_type thy fldty) $ t,
   3.291 -                             fldty)
   3.292 -                        | NONE => error ("Record " ^ rcdty ^
   3.293 +                 let
   3.294 +                   val (t, rcdty) = tm_of vs e;
   3.295 +                   val rT = mk_type thy rcdty
   3.296 +                 in case (get_record_info thy rT, lookup types rcdty) of
   3.297 +                     (SOME {fields, ...}, SOME (Record_Type fldtys)) =>
   3.298 +                       (case (find_field fname fields,
   3.299 +                            find_field' fname fldtys) of
   3.300 +                          (SOME (fname', fT), SOME fldty) =>
   3.301 +                            (Const (fname', rT --> fT) $ t, fldty)
   3.302 +                        | _ => error ("Record " ^ rcdty ^
   3.303                              " has no field named " ^ fname))
   3.304                     | _ => error (rcdty ^ " is not a record type")
   3.305                   end
   3.306 @@ -349,20 +465,20 @@
   3.307                     val rT = mk_type thy rcdty;
   3.308                     val (u, fldty) = tm_of vs e';
   3.309                     val fT = mk_type thy fldty
   3.310 -                 in case lookup types rcdty of
   3.311 -                     SOME (Record_Type fldtys) =>
   3.312 -                       (case get_first (fn (flds, fldty) =>
   3.313 -                            if member (op =) flds fname then SOME fldty
   3.314 -                            else NONE) fldtys of
   3.315 -                          SOME fldty' =>
   3.316 -                            if fldty = fldty' then
   3.317 -                              (Const (mk_qual_name thy rcdty (fname ^ "_update"),
   3.318 +                 in case get_record_info thy rT of
   3.319 +                     SOME {fields, ...} =>
   3.320 +                       (case find_field fname fields of
   3.321 +                          SOME (fname', fU) =>
   3.322 +                            if fT = fU then
   3.323 +                              (Const (fname' ^ "_update",
   3.324                                   (fT --> fT) --> rT --> rT) $
   3.325                                     Abs ("x", fT, u) $ t,
   3.326                                 rcdty)
   3.327 -                            else error ("Type " ^ fldty ^
   3.328 -                              " does not match type " ^ fldty' ^ " of field " ^
   3.329 -                              fname)
   3.330 +                            else error ("Type\n" ^
   3.331 +                              Syntax.string_of_typ_global thy fT ^
   3.332 +                              "\ndoes not match type\n" ^
   3.333 +                              Syntax.string_of_typ_global thy fU ^
   3.334 +                              "\nof field " ^ fname)
   3.335                          | NONE => error ("Record " ^ rcdty ^
   3.336                              " has no field named " ^ fname))
   3.337                     | _ => error (rcdty ^ " is not a record type")
   3.338 @@ -431,34 +547,35 @@
   3.339            end
   3.340  
   3.341        | tm_of vs (Record (s, flds)) =
   3.342 -          (case lookup types s of
   3.343 -             SOME (Record_Type fldtys) =>
   3.344 -               let
   3.345 -                 val flds' = map (apsnd (tm_of vs)) flds;
   3.346 -                 val fnames = maps fst fldtys;
   3.347 -                 val fnames' = map fst flds;
   3.348 -                 val (fvals, ftys) = split_list (map (fn s' =>
   3.349 -                   case AList.lookup (op =) flds' s' of
   3.350 -                     SOME fval_ty => fval_ty
   3.351 -                   | NONE => error ("Field " ^ s' ^ " missing in record " ^ s))
   3.352 -                       fnames);
   3.353 -                 val _ = (case subtract (op =) fnames fnames' of
   3.354 -                     [] => ()
   3.355 -                   | xs => error ("Extra field(s) " ^ commas xs ^
   3.356 -                       " in record " ^ s));
   3.357 -                 val _ = (case duplicates (op =) fnames' of
   3.358 -                     [] => ()
   3.359 -                   | xs => error ("Duplicate field(s) " ^ commas xs ^
   3.360 -                       " in record " ^ s))
   3.361 -               in
   3.362 -                 (list_comb
   3.363 -                    (Const (mk_qual_name thy s (s ^ "_ext"),
   3.364 -                       map (mk_type thy) ftys @ [HOLogic.unitT] --->
   3.365 -                         mk_type thy s),
   3.366 -                     fvals @ [HOLogic.unit]),
   3.367 -                  s)
   3.368 -               end
   3.369 -           | _ => error (s ^ " is not a record type"))
   3.370 +          let
   3.371 +            val T = mk_type thy s;
   3.372 +            val {extension = (ext_name, _), fields, ...} =
   3.373 +              (case get_record_info thy T of
   3.374 +                 NONE => error (s ^ " is not a record type")
   3.375 +               | SOME info => info);
   3.376 +            val flds' = map (apsnd (tm_of vs)) flds;
   3.377 +            val fnames = map (Long_Name.base_name o fst) fields;
   3.378 +            val fnames' = map fst flds;
   3.379 +            val (fvals, ftys) = split_list (map (fn s' =>
   3.380 +              case AList.lookup lcase_eq flds' s' of
   3.381 +                SOME fval_ty => fval_ty
   3.382 +              | NONE => error ("Field " ^ s' ^ " missing in record " ^ s))
   3.383 +                  fnames);
   3.384 +            val _ = (case subtract lcase_eq fnames fnames' of
   3.385 +                [] => ()
   3.386 +              | xs => error ("Extra field(s) " ^ commas xs ^
   3.387 +                  " in record " ^ s));
   3.388 +            val _ = (case duplicates (op =) fnames' of
   3.389 +                [] => ()
   3.390 +              | xs => error ("Duplicate field(s) " ^ commas xs ^
   3.391 +                  " in record " ^ s))
   3.392 +          in
   3.393 +            (list_comb
   3.394 +               (Const (ext_name,
   3.395 +                  map (mk_type thy) ftys @ [HOLogic.unitT] ---> T),
   3.396 +                fvals @ [HOLogic.unit]),
   3.397 +             s)
   3.398 +          end
   3.399  
   3.400        | tm_of vs (Array (s, default, assocs)) =
   3.401            (case lookup types s of
   3.402 @@ -592,44 +709,15 @@
   3.403  
   3.404  (** the VC store **)
   3.405  
   3.406 -fun err_unfinished () = error "An unfinished SPARK environment is still open."
   3.407 -
   3.408  fun err_vcs names = error (Pretty.string_of
   3.409    (Pretty.big_list "The following verification conditions have not been proved:"
   3.410      (map Pretty.str names)))
   3.411  
   3.412 -val strip_number = pairself implode o take_suffix Fdl_Lexer.is_digit o raw_explode;
   3.413 -
   3.414 -val name_ord = prod_ord string_ord (option_ord int_ord) o
   3.415 -  pairself (strip_number ##> Int.fromString);
   3.416 -
   3.417 -structure VCtab = Table(type key = string val ord = name_ord);
   3.418 -
   3.419 -structure VCs = Theory_Data
   3.420 -(
   3.421 -  type T =
   3.422 -    {pfuns: ((string list * string) option * term) Symtab.table,
   3.423 -     env:
   3.424 -       {ctxt: Element.context_i list,
   3.425 -        defs: (binding * thm) list,
   3.426 -        types: fdl_type tab,
   3.427 -        funs: (string list * string) tab,
   3.428 -        ids: (term * string) Symtab.table * Name.context,
   3.429 -        proving: bool,
   3.430 -        vcs: (string * thm list option *
   3.431 -          (string * expr) list * (string * expr) list) VCtab.table,
   3.432 -        path: Path.T} option}
   3.433 -  val empty : T = {pfuns = Symtab.empty, env = NONE}
   3.434 -  val extend = I
   3.435 -  fun merge ({pfuns = pfuns1, env = NONE}, {pfuns = pfuns2, env = NONE}) =
   3.436 -        {pfuns = Symtab.merge (eq_pair (op =) (op aconv)) (pfuns1, pfuns2),
   3.437 -         env = NONE}
   3.438 -    | merge _ = err_unfinished ()
   3.439 -)
   3.440 -
   3.441  fun set_env (env as {funs, ...}) thy = VCs.map (fn
   3.442 -    {pfuns, env = NONE} =>
   3.443 -      {pfuns = check_pfuns_types thy funs pfuns, env = SOME env}
   3.444 +    {pfuns, type_map, env = NONE} =>
   3.445 +      {pfuns = check_pfuns_types thy funs pfuns,
   3.446 +       type_map = type_map,
   3.447 +       env = SOME env}
   3.448    | _ => err_unfinished ()) thy;
   3.449  
   3.450  fun mk_pat s = (case Int.fromString s of
   3.451 @@ -672,28 +760,60 @@
   3.452  fun add_proof_fun prep (s, (optty, raw_t)) thy =
   3.453    VCs.map (fn
   3.454        {env = SOME {proving = true, ...}, ...} => err_unfinished ()
   3.455 -    | {pfuns, env} =>
   3.456 +    | {pfuns, type_map, env} =>
   3.457          let
   3.458            val optty' = (case env of
   3.459                SOME {funs, ...} => lookup funs s
   3.460              | NONE => NONE);
   3.461            val optty'' = NONE |> upd_option optty |> upd_option optty';
   3.462 -          val t = prep (Option.map (pfun_type thy) optty'') raw_t
   3.463 +          val t = prep (Option.map (pfun_type thy) optty'') raw_t;
   3.464 +          val _ = (case fold_aterms (fn u =>
   3.465 +              if is_Var u orelse is_Free u then insert (op =) u else I) t [] of
   3.466 +              [] => ()
   3.467 +            | ts => error ("Term\n" ^ Syntax.string_of_term_global thy t ^
   3.468 +                "\nto be associated with proof function " ^ s ^
   3.469 +                " contains free variable(s) " ^
   3.470 +                commas (map (Syntax.string_of_term_global thy) ts)));
   3.471          in
   3.472            (check_pfun_type thy s t optty optty';
   3.473             if is_some optty'' orelse is_none env then
   3.474               {pfuns = Symtab.update_new (s, (optty'', t)) pfuns,
   3.475 +              type_map = type_map,
   3.476                env = env}
   3.477                 handle Symtab.DUP _ => error ("Proof function " ^ s ^
   3.478                   " already associated with function")
   3.479             else error ("Undeclared proof function " ^ s))
   3.480          end) thy;
   3.481  
   3.482 +fun add_type (s, T as Type (tyname, Ts)) thy =
   3.483 +      thy |>
   3.484 +      VCs.map (fn
   3.485 +          {env = SOME _, ...} => err_unfinished ()
   3.486 +        | {pfuns, type_map, env} =>
   3.487 +            {pfuns = pfuns,
   3.488 +             type_map = Symtab.update_new (s, T) type_map,
   3.489 +             env = env}
   3.490 +              handle Symtab.DUP _ => error ("SPARK type " ^ s ^
   3.491 +                " already associated with type")) |>
   3.492 +      (fn thy' =>
   3.493 +         case Datatype_Data.get_constrs thy' tyname of
   3.494 +           NONE => thy'
   3.495 +         | SOME cs =>
   3.496 +             if null Ts then
   3.497 +               (map
   3.498 +                  (fn (_, Type (_, [])) => ()
   3.499 +                    | (cname, _) => assoc_ty_err thy T s
   3.500 +                        ("has illegal constructor " ^
   3.501 +                         Long_Name.base_name cname)) cs;
   3.502 +                add_enum_type s tyname thy')
   3.503 +             else assoc_ty_err thy T s "is illegal")
   3.504 +  | add_type (s, T) thy = assoc_ty_err thy T s "is illegal";
   3.505 +
   3.506  val is_closed = is_none o #env o VCs.get;
   3.507  
   3.508  fun lookup_vc thy name =
   3.509    (case VCs.get thy of
   3.510 -    {env = SOME {vcs, types, funs, ids, ctxt, ...}, pfuns} =>
   3.511 +    {env = SOME {vcs, types, funs, ids, ctxt, ...}, pfuns, ...} =>
   3.512        (case VCtab.lookup vcs name of
   3.513           SOME vc =>           
   3.514             let val (pfuns', ctxt', ids') =
   3.515 @@ -703,7 +823,7 @@
   3.516    | _ => NONE);
   3.517  
   3.518  fun get_vcs thy = (case VCs.get thy of
   3.519 -    {env = SOME {vcs, types, funs, ids, ctxt, defs, ...}, pfuns} =>
   3.520 +    {env = SOME {vcs, types, funs, ids, ctxt, defs, ...}, pfuns, ...} =>
   3.521        let val (pfuns', ctxt', ids') =
   3.522          declare_missing_pfuns thy funs pfuns vcs ids
   3.523        in
   3.524 @@ -714,8 +834,10 @@
   3.525    | _ => ([], [], []));
   3.526  
   3.527  fun mark_proved name thms = VCs.map (fn
   3.528 -    {pfuns, env = SOME {ctxt, defs, types, funs, ids, vcs, path, ...}} =>
   3.529 +    {pfuns, type_map,
   3.530 +     env = SOME {ctxt, defs, types, funs, ids, vcs, path, ...}} =>
   3.531        {pfuns = pfuns,
   3.532 +       type_map = type_map,
   3.533         env = SOME {ctxt = ctxt, defs = defs,
   3.534           types = types, funs = funs, ids = ids,
   3.535           proving = true,
   3.536 @@ -724,18 +846,21 @@
   3.537           path = path}}
   3.538    | x => x);
   3.539  
   3.540 -fun close thy = VCs.map (fn
   3.541 -    {pfuns, env = SOME {vcs, path, ...}} =>
   3.542 -      (case VCtab.fold_rev (fn vc as (_, (_, p, _, _)) =>
   3.543 -           (if is_some p then apfst else apsnd) (cons vc)) vcs ([], []) of
   3.544 -         (proved, []) =>
   3.545 -           (Thm.join_proofs (maps (the o #2 o snd) proved);
   3.546 -            File.write (Path.ext "prv" path)
   3.547 -              (concat (map (fn (s, _) => snd (strip_number s) ^
   3.548 -                 " -- proved by " ^ Distribution.version ^ "\n") proved));
   3.549 -            {pfuns = pfuns, env = NONE})
   3.550 -       | (_, unproved) => err_vcs (map fst unproved))
   3.551 -  | x => x) thy;
   3.552 +fun close thy =
   3.553 +  thy |>
   3.554 +  VCs.map (fn
   3.555 +      {pfuns, type_map, env = SOME {vcs, path, ...}} =>
   3.556 +        (case VCtab.fold_rev (fn vc as (_, (_, p, _, _)) =>
   3.557 +             (if is_some p then apfst else apsnd) (cons vc)) vcs ([], []) of
   3.558 +           (proved, []) =>
   3.559 +             (Thm.join_proofs (maps (the o #2 o snd) proved);
   3.560 +              File.write (Path.ext "prv" path)
   3.561 +                (concat (map (fn (s, _) => snd (strip_number s) ^
   3.562 +                   " -- proved by " ^ Distribution.version ^ "\n") proved));
   3.563 +              {pfuns = pfuns, type_map = type_map, env = NONE})
   3.564 +         | (_, unproved) => err_vcs (map fst unproved))
   3.565 +    | _ => error "No SPARK environment is currently open") |>
   3.566 +  Sign.parent_path;
   3.567  
   3.568  
   3.569  (** set up verification conditions **)
   3.570 @@ -822,7 +947,8 @@
   3.571             (remove (op =) d defs) (d :: sdefs)
   3.572         | NONE => error ("Bad definitions: " ^ rulenames defs));
   3.573  
   3.574 -fun set_vcs ({types, vars, consts, funs} : decls) (rules, _) vcs path thy =
   3.575 +fun set_vcs ({types, vars, consts, funs} : decls)
   3.576 +      (rules, _) ((_, ident), vcs) path thy =
   3.577    let
   3.578      val {pfuns, ...} = VCs.get thy;
   3.579      val (defs, rules') = partition_opt dest_def rules;
   3.580 @@ -847,7 +973,8 @@
   3.581        ((Symtab.empty |>
   3.582          Symtab.update ("false", (HOLogic.false_const, booleanN)) |>
   3.583          Symtab.update ("true", (HOLogic.true_const, booleanN)),
   3.584 -        Name.context), thy) |>
   3.585 +        Name.context),
   3.586 +       thy |> Sign.add_path (Long_Name.base_name ident)) |>
   3.587        fold add_type_def (items types) |>
   3.588        fold (snd oo add_const) consts' |> (fn ids_thy as ((tab, _), _) =>
   3.589          ids_thy |>