src/Tools/isac/BridgeJEdit/cp_spark_vcs.ML
author Walther Neuper <walther.neuper@jku.at>
Wed, 04 Nov 2020 09:59:30 +0100
changeset 60097 0aa54181d7c9
permissions -rw-r--r--
separate code for Example from spark_open, resolve name clash

notes
(1) imports HOL-SPARK.SPARK requires attention when switiching Build_Isac .. Test_Isac,
see Calculation.thy
(2) Isabelle's Specification was covered by SpecificationC
walther@60097
     1
(*/--------------------------------- cp_spark_vcs.ML -----------------------------------------\*)
walther@60097
     2
(*  Title:      src/Tools/isac/BridgeJEdit/cp_spark_vcs.ML
walther@60097
     3
    Author:     Walther Neuper, JKU Linz
walther@60097
     4
    (c) due to copyright terms
walther@60097
     5
walther@60097
     6
Preliminary file for developing Outer_Syntax.command..Example from spark_open as a model.
walther@60097
     7
walther@60097
     8
The file contains code from HOL/SPARK/Tools/set_vcs.ML, minimal for set_vcs.
walther@60097
     9
The code is separated from Calculation.thy into this file, 
walther@60097
    10
because text\<open>...\<close> and (*...*) for const_name>\<open>...\<close> etc and @{thms ...} causes errors.
walther@60097
    11
walther@60097
    12
For Test_Isac (**)ML_file "cp_set_vcs.ML"(**) must be outcommented in Calculation.thy.
walther@60097
    13
*)
walther@60097
    14
walther@60097
    15
(** theory data **)
walther@60097
    16
walther@60097
    17
fun err_unfinished () = error "An unfinished SPARK environment is still open."
walther@60097
    18
walther@60097
    19
val strip_number = apply2 implode o chop_suffix Fdl_Lexer.is_digit o raw_explode;
walther@60097
    20
walther@60097
    21
val name_ord = prod_ord string_ord (option_ord int_ord) o
walther@60097
    22
  apply2 (strip_number ##> Int.fromString);
walther@60097
    23
walther@60097
    24
structure VCtab = Table(type key = string val ord = name_ord);
walther@60097
    25
walther@60097
    26
structure VCs = Theory_Data
walther@60097
    27
(
walther@60097
    28
  type T =
walther@60097
    29
    {pfuns: ((string list * string) option * term) Symtab.table,
walther@60097
    30
     type_map: (typ * (string * string) list) Symtab.table,
walther@60097
    31
     env:
walther@60097
    32
       {ctxt: Element.context_i list,
walther@60097
    33
        defs: (binding * thm) list,
walther@60097
    34
        types: Fdl_Parser.fdl_type Fdl_Parser.tab,
walther@60097
    35
        funs: (string list * string) Fdl_Parser.tab,
walther@60097
    36
        pfuns: ((string list * string) option * term) Symtab.table,
walther@60097
    37
        ids: (term * string) Symtab.table * Name.context,
walther@60097
    38
        proving: bool,
walther@60097
    39
        vcs: (string * thm list option *
walther@60097
    40
          (string * Fdl_Parser.expr) list * (string * Fdl_Parser.expr) list) VCtab.table,
walther@60097
    41
        path: Path.T,
walther@60097
    42
        prefix: string} option}
walther@60097
    43
  val empty : T = {pfuns = Symtab.empty, type_map = Symtab.empty, env = NONE}
walther@60097
    44
  val extend = I
walther@60097
    45
  fun merge ({pfuns = pfuns1, type_map = type_map1, env = NONE},
walther@60097
    46
        {pfuns = pfuns2, type_map = type_map2, env = NONE}) =
walther@60097
    47
        {pfuns = Symtab.merge (eq_pair (op =) (op aconv)) (pfuns1, pfuns2),
walther@60097
    48
         type_map = Symtab.merge (op =) (type_map1, type_map2),
walther@60097
    49
         env = NONE}
walther@60097
    50
    | merge _ = err_unfinished ()
walther@60097
    51
)
walther@60097
    52
walther@60097
    53
(** utilities **)
walther@60097
    54
walther@60097
    55
val to_lower = raw_explode #> map Symbol.to_ascii_lower #> implode;
walther@60097
    56
walther@60097
    57
walther@60097
    58
(** set up verification conditions **)
walther@60097
    59
walther@60097
    60
fun partition_opt f =
walther@60097
    61
  let
walther@60097
    62
    fun part ys zs [] = (rev ys, rev zs)
walther@60097
    63
      | part ys zs (x :: xs) = (case f x of
walther@60097
    64
            SOME y => part (y :: ys) zs xs
walther@60097
    65
          | NONE => part ys (x :: zs) xs)
walther@60097
    66
  in part [] [] end;
walther@60097
    67
walther@60097
    68
fun dest_def (id, (Fdl_Parser.Substitution_Rule ([], Fdl_Parser.Ident s, rhs))) = SOME (id, (s, rhs))
walther@60097
    69
  | dest_def _ = NONE;
walther@60097
    70
walther@60097
    71
walther@60097
    72
val builtin = Symtab.make (map (rpair ())
walther@60097
    73
  ["->", "<->", "or", "and", "not", "=", "<>", "<", ">", "<=", ">=",
walther@60097
    74
   "+", "-", "*", "/", "div", "mod", "**"]);
walther@60097
    75
walther@60097
    76
fun complex_expr (Fdl_Parser.Number _) = false
walther@60097
    77
  | complex_expr (Fdl_Parser.Ident _) = false
walther@60097
    78
  | complex_expr (Fdl_Parser.Funct (s, es)) =
walther@60097
    79
      not (Symtab.defined builtin s) orelse exists complex_expr es
walther@60097
    80
  | complex_expr (Fdl_Parser.Quantifier (_, _, _, e)) = complex_expr e
walther@60097
    81
  | complex_expr _ = true;
walther@60097
    82
walther@60097
    83
fun complex_rule (Fdl_Parser.Inference_Rule (es, e)) =
walther@60097
    84
      complex_expr e orelse exists complex_expr es
walther@60097
    85
  | complex_rule (Fdl_Parser.Substitution_Rule (es, e, e')) =
walther@60097
    86
      complex_expr e orelse complex_expr e' orelse
walther@60097
    87
      exists complex_expr es;
walther@60097
    88
walther@60097
    89
fun is_trivial_vc ([], [(_, Fdl_Parser.Ident "true")]) = true
walther@60097
    90
  | is_trivial_vc _ = false;
walther@60097
    91
walther@60097
    92
walther@60097
    93
fun rulenames rules = commas
walther@60097
    94
  (map (fn ((s, i), _) => s ^ "(" ^ string_of_int i ^ ")") rules);
walther@60097
    95
walther@60097
    96
walther@60097
    97
val is_pfun =
walther@60097
    98
  Symtab.defined builtin orf
walther@60097
    99
  can (unprefix "fld_") orf can (unprefix "upf_") orf
walther@60097
   100
  can (unsuffix "__pos") orf can (unsuffix "__val") orf
walther@60097
   101
  equal "succ" orf equal "pred";
walther@60097
   102
walther@60097
   103
fun fold_opt f = the_default I o Option.map f;
walther@60097
   104
fun fold_pair f g (x, y) = f x #> g y;
walther@60097
   105
walther@60097
   106
fun fold_expr f g (Fdl_Parser.Funct (s, es)) = f s #> fold (fold_expr f g) es
walther@60097
   107
  | fold_expr f g (Fdl_Parser.Ident s) = g s
walther@60097
   108
  | fold_expr f g (Fdl_Parser.Number _) = I
walther@60097
   109
  | fold_expr f g (Fdl_Parser.Quantifier (_, _, _, e)) = fold_expr f g e
walther@60097
   110
  | fold_expr f g (Fdl_Parser.Element (e, es)) =
walther@60097
   111
      fold_expr f g e #> fold (fold_expr f g) es
walther@60097
   112
  | fold_expr f g (Fdl_Parser.Update (e, es, e')) =
walther@60097
   113
      fold_expr f g e #> fold (fold_expr f g) es #> fold_expr f g e'
walther@60097
   114
  | fold_expr f g (Fdl_Parser.Record (_, flds)) = fold (fold_expr f g o snd) flds
walther@60097
   115
  | fold_expr f g (Fdl_Parser.Array (_, default, assocs)) =
walther@60097
   116
      fold_opt (fold_expr f g) default #>
walther@60097
   117
      fold (fold_pair
walther@60097
   118
        (fold (fold (fold_pair
walther@60097
   119
          (fold_expr f g) (fold_opt (fold_expr f g)))))
walther@60097
   120
        (fold_expr f g)) assocs;
walther@60097
   121
walther@60097
   122
walther@60097
   123
fun add_expr_pfuns funs = fold_expr
walther@60097
   124
  (fn s => if is_pfun s then I else insert (op =) s)
walther@60097
   125
  (fn s => if is_none (Fdl_Parser.lookup funs s) then I else insert (op =) s);
walther@60097
   126
walther@60097
   127
fun lookup_prfx "" tab s = Symtab.lookup tab s
walther@60097
   128
  | lookup_prfx prfx tab s = (case Symtab.lookup tab s of
walther@60097
   129
        NONE => Symtab.lookup tab (prfx ^ "__" ^ s)
walther@60097
   130
      | x => x);
walther@60097
   131
walther@60097
   132
fun fold_vcs f vcs =
walther@60097
   133
  VCtab.fold (fn (_, (_, _, ps, cs)) => fold f ps #> fold f cs) vcs;
walther@60097
   134
walther@60097
   135
fun pfuns_of_vcs prfx funs pfuns vcs =
walther@60097
   136
  fold_vcs (add_expr_pfuns funs o snd) vcs [] |>
walther@60097
   137
  filter (is_none o lookup_prfx prfx pfuns);
walther@60097
   138
walther@60097
   139
val booleanN = "boolean";
walther@60097
   140
val integerN = "integer";
walther@60097
   141
walther@60097
   142
walther@60097
   143
fun get_type thy prfx ty =
walther@60097
   144
  let val {type_map, ...} = VCs.get thy
walther@60097
   145
  in lookup_prfx prfx type_map ty end;
walther@60097
   146
walther@60097
   147
fun mk_type' _ _ "integer" = (HOLogic.intT, [])
walther@60097
   148
  | mk_type' _ _ "boolean" = (HOLogic.boolT, [])
walther@60097
   149
  | mk_type' thy prfx ty =
walther@60097
   150
      (case get_type thy prfx ty of
walther@60097
   151
         NONE =>
walther@60097
   152
           (Syntax.check_typ (Proof_Context.init_global thy)
walther@60097
   153
              (Type (Sign.full_name thy (Binding.name ty), [])),
walther@60097
   154
            [])
walther@60097
   155
       | SOME p => p);
walther@60097
   156
walther@60097
   157
fun mk_type thy prfx ty = fst (mk_type' thy prfx ty);
walther@60097
   158
walther@60097
   159
fun check_no_assoc thy prfx s = case get_type thy prfx s of
walther@60097
   160
    NONE => ()
walther@60097
   161
  | SOME _ => error ("Cannot associate a type with " ^ s ^
walther@60097
   162
      "\nsince it is no record or enumeration type");
walther@60097
   163
walther@60097
   164
walther@60097
   165
fun define_overloaded (def_name, eq) lthy =
walther@60097
   166
  let
walther@60097
   167
    val ((c, _), rhs) = eq |> Syntax.check_term lthy |>
walther@60097
   168
      Logic.dest_equals |>> dest_Free;
walther@60097
   169
    val ((_, (_, thm)), lthy') = Local_Theory.define
walther@60097
   170
      ((Binding.name c, NoSyn), ((Binding.name def_name, []), rhs)) lthy
walther@60097
   171
    val ctxt_thy = Proof_Context.init_global (Proof_Context.theory_of lthy');
walther@60097
   172
    val thm' = singleton (Proof_Context.export lthy' ctxt_thy) thm
walther@60097
   173
  in (thm', lthy') end;
walther@60097
   174
walther@60097
   175
(** generate properties of enumeration types **)
walther@60097
   176
walther@60097
   177
fun add_enum_type tyname tyname' thy =
walther@60097
   178
  let
walther@60097
   179
    val {case_name, ...} = the (BNF_LFP_Compat.get_info thy [BNF_LFP_Compat.Keep_Nesting] tyname');
walther@60097
   180
    val cs = map Const (the (BNF_LFP_Compat.get_constrs thy tyname'));
walther@60097
   181
    val k = length cs;
walther@60097
   182
    val T = Type (tyname', []);
walther@60097
   183
    val p = Const (\<^const_name>\<open>pos\<close>, T --> HOLogic.intT);
walther@60097
   184
    val v = Const (\<^const_name>\<open>val\<close>, HOLogic.intT --> T);
walther@60097
   185
    val card = Const (\<^const_name>\<open>card\<close>,
walther@60097
   186
      HOLogic.mk_setT T --> HOLogic.natT) $ HOLogic.mk_UNIV T;
walther@60097
   187
walther@60097
   188
    fun mk_binrel_def s f = Logic.mk_equals
walther@60097
   189
      (Const (s, T --> T --> HOLogic.boolT),
walther@60097
   190
       Abs ("x", T, Abs ("y", T,
walther@60097
   191
         Const (s, HOLogic.intT --> HOLogic.intT --> HOLogic.boolT) $
walther@60097
   192
           (f $ Bound 1) $ (f $ Bound 0))));
walther@60097
   193
walther@60097
   194
    val (((def1, def2), def3), lthy) = thy |>
walther@60097
   195
walther@60097
   196
      Class.instantiation ([tyname'], [], \<^sort>\<open>spark_enum\<close>) |>
walther@60097
   197
walther@60097
   198
      define_overloaded ("pos_" ^ tyname ^ "_def", Logic.mk_equals
walther@60097
   199
        (p,
walther@60097
   200
         list_comb (Const (case_name, replicate k HOLogic.intT @
walther@60097
   201
             [T] ---> HOLogic.intT),
walther@60097
   202
           map (HOLogic.mk_number HOLogic.intT) (0 upto k - 1)))) ||>>
walther@60097
   203
walther@60097
   204
      define_overloaded ("less_eq_" ^ tyname ^ "_def",
walther@60097
   205
        mk_binrel_def \<^const_name>\<open>less_eq\<close> p) ||>>
walther@60097
   206
      define_overloaded ("less_" ^ tyname ^ "_def",
walther@60097
   207
        mk_binrel_def \<^const_name>\<open>less\<close> p);
walther@60097
   208
walther@60097
   209
    val UNIV_eq = Goal.prove lthy [] []
walther@60097
   210
      (HOLogic.mk_Trueprop (HOLogic.mk_eq
walther@60097
   211
         (HOLogic.mk_UNIV T, HOLogic.mk_set T cs)))
walther@60097
   212
      (fn {context = ctxt, ...} =>
walther@60097
   213
         resolve_tac ctxt @{thms subset_antisym} 1 THEN
walther@60097
   214
         resolve_tac ctxt @{thms subsetI} 1 THEN
walther@60097
   215
         Old_Datatype_Aux.exh_tac ctxt (K (#exhaust (BNF_LFP_Compat.the_info
walther@60097
   216
           (Proof_Context.theory_of ctxt) [BNF_LFP_Compat.Keep_Nesting] tyname'))) 1 THEN
walther@60097
   217
         ALLGOALS (asm_full_simp_tac ctxt));
walther@60097
   218
walther@60097
   219
    val finite_UNIV = Goal.prove lthy [] []
walther@60097
   220
      (HOLogic.mk_Trueprop (Const (\<^const_name>\<open>finite\<close>,
walther@60097
   221
         HOLogic.mk_setT T --> HOLogic.boolT) $ HOLogic.mk_UNIV T))
walther@60097
   222
      (fn {context = ctxt, ...} => simp_tac (ctxt addsimps [UNIV_eq]) 1);
walther@60097
   223
walther@60097
   224
    val card_UNIV = Goal.prove lthy [] []
walther@60097
   225
      (HOLogic.mk_Trueprop (HOLogic.mk_eq
walther@60097
   226
         (card, HOLogic.mk_number HOLogic.natT k)))
walther@60097
   227
      (fn {context = ctxt, ...} => simp_tac (ctxt addsimps [UNIV_eq]) 1);
walther@60097
   228
walther@60097
   229
    val range_pos = Goal.prove lthy [] []
walther@60097
   230
      (HOLogic.mk_Trueprop (HOLogic.mk_eq
walther@60097
   231
         (Const (\<^const_name>\<open>image\<close>, (T --> HOLogic.intT) -->
walther@60097
   232
            HOLogic.mk_setT T --> HOLogic.mk_setT HOLogic.intT) $
walther@60097
   233
              p $ HOLogic.mk_UNIV T,
walther@60097
   234
          Const (\<^const_name>\<open>atLeastLessThan\<close>, HOLogic.intT -->
walther@60097
   235
            HOLogic.intT --> HOLogic.mk_setT HOLogic.intT) $
walther@60097
   236
              HOLogic.mk_number HOLogic.intT 0 $
walther@60097
   237
              (\<^term>\<open>int\<close> $ card))))
walther@60097
   238
      (fn {context = ctxt, ...} =>
walther@60097
   239
         simp_tac (ctxt addsimps [card_UNIV]) 1 THEN
walther@60097
   240
         simp_tac (ctxt addsimps [UNIV_eq, def1]) 1 THEN
walther@60097
   241
         resolve_tac ctxt @{thms subset_antisym} 1 THEN
walther@60097
   242
         simp_tac ctxt 1 THEN
walther@60097
   243
         resolve_tac ctxt @{thms subsetI} 1 THEN
walther@60097
   244
         asm_full_simp_tac (ctxt addsimps @{thms interval_expand}
walther@60097
   245
           delsimps @{thms atLeastLessThan_iff}) 1);
walther@60097
   246
walther@60097
   247
    val lthy' =
walther@60097
   248
      Class.prove_instantiation_instance (fn ctxt =>
walther@60097
   249
        Class.intro_classes_tac ctxt [] THEN
walther@60097
   250
        resolve_tac ctxt [finite_UNIV] 1 THEN
walther@60097
   251
        resolve_tac ctxt [range_pos] 1 THEN
walther@60097
   252
        simp_tac (put_simpset HOL_basic_ss ctxt addsimps [def3]) 1 THEN
walther@60097
   253
        simp_tac (put_simpset HOL_basic_ss ctxt addsimps [def2]) 1) lthy;
walther@60097
   254
walther@60097
   255
    val (pos_eqs, val_eqs) = split_list (map_index (fn (i, c) =>
walther@60097
   256
      let
walther@60097
   257
        val n = HOLogic.mk_number HOLogic.intT i;
walther@60097
   258
        val th = Goal.prove lthy' [] []
walther@60097
   259
          (HOLogic.mk_Trueprop (HOLogic.mk_eq (p $ c, n)))
walther@60097
   260
          (fn {context = ctxt, ...} => simp_tac (ctxt addsimps [def1]) 1);
walther@60097
   261
        val th' = Goal.prove lthy' [] []
walther@60097
   262
          (HOLogic.mk_Trueprop (HOLogic.mk_eq (v $ n, c)))
walther@60097
   263
          (fn {context = ctxt, ...} =>
walther@60097
   264
             resolve_tac ctxt [@{thm inj_pos} RS @{thm injD}] 1 THEN
walther@60097
   265
             simp_tac (ctxt addsimps [@{thm pos_val}, range_pos, card_UNIV, th]) 1)
walther@60097
   266
      in (th, th') end) cs);
walther@60097
   267
walther@60097
   268
    val first_el = Goal.prove lthy' [] []
walther@60097
   269
      (HOLogic.mk_Trueprop (HOLogic.mk_eq
walther@60097
   270
         (Const (\<^const_name>\<open>first_el\<close>, T), hd cs)))
walther@60097
   271
      (fn {context = ctxt, ...} => simp_tac (ctxt addsimps [@{thm first_el_def}, hd val_eqs]) 1);
walther@60097
   272
walther@60097
   273
    val last_el = Goal.prove lthy' [] []
walther@60097
   274
      (HOLogic.mk_Trueprop (HOLogic.mk_eq
walther@60097
   275
         (Const (\<^const_name>\<open>last_el\<close>, T), List.last cs)))
walther@60097
   276
      (fn {context = ctxt, ...} =>
walther@60097
   277
        simp_tac (ctxt addsimps [@{thm last_el_def}, List.last val_eqs, card_UNIV]) 1);
walther@60097
   278
  in
walther@60097
   279
    lthy' |>
walther@60097
   280
    Local_Theory.note
walther@60097
   281
      ((Binding.name (tyname ^ "_card"), @{attributes [simp]}), [card_UNIV]) ||>>
walther@60097
   282
    Local_Theory.note
walther@60097
   283
      ((Binding.name (tyname ^ "_pos"), @{attributes [simp]}), pos_eqs) ||>>
walther@60097
   284
    Local_Theory.note
walther@60097
   285
      ((Binding.name (tyname ^ "_val"), @{attributes [simp]}), val_eqs) ||>>
walther@60097
   286
    Local_Theory.note
walther@60097
   287
      ((Binding.name (tyname ^ "_first_el"), @{attributes [simp]}), [first_el]) ||>>
walther@60097
   288
    Local_Theory.note
walther@60097
   289
      ((Binding.name (tyname ^ "_last_el"), @{attributes [simp]}), [last_el]) |> snd |>
walther@60097
   290
    Local_Theory.exit_global
walther@60097
   291
  end;
walther@60097
   292
walther@60097
   293
walther@60097
   294
val lcase_eq = (op =) o apply2 (to_lower o Long_Name.base_name);
walther@60097
   295
walther@60097
   296
fun check_enum [] [] = NONE
walther@60097
   297
  | check_enum els [] = SOME ("has no element(s) " ^ commas els)
walther@60097
   298
  | check_enum [] cs = SOME ("has extra element(s) " ^
walther@60097
   299
      commas (map (Long_Name.base_name o fst) cs))
walther@60097
   300
  | check_enum (el :: els) ((cname, _) :: cs) =
walther@60097
   301
      if lcase_eq (el, cname) then check_enum els cs
walther@60097
   302
      else SOME ("either has no element " ^ el ^
walther@60097
   303
        " or it is at the wrong position");
walther@60097
   304
walther@60097
   305
fun strip_prfx s =
walther@60097
   306
  let
walther@60097
   307
    fun strip ys [] = ("", implode ys)
walther@60097
   308
      | strip ys ("_" :: "_" :: xs) = (implode (rev xs), implode ys)
walther@60097
   309
      | strip ys (x :: xs) = strip (x :: ys) xs
walther@60097
   310
  in strip [] (rev (raw_explode s)) end;
walther@60097
   311
walther@60097
   312
fun assoc_ty_err thy T s msg =
walther@60097
   313
  error ("Type " ^ Syntax.string_of_typ_global thy T ^
walther@60097
   314
    " associated with SPARK type " ^ s ^ "\n" ^ msg);
walther@60097
   315
walther@60097
   316
fun check_enum [] [] = NONE
walther@60097
   317
  | check_enum els [] = SOME ("has no element(s) " ^ commas els)
walther@60097
   318
  | check_enum [] cs = SOME ("has extra element(s) " ^
walther@60097
   319
      commas (map (Long_Name.base_name o fst) cs))
walther@60097
   320
  | check_enum (el :: els) ((cname, _) :: cs) =
walther@60097
   321
      if lcase_eq (el, cname) then check_enum els cs
walther@60097
   322
      else SOME ("either has no element " ^ el ^
walther@60097
   323
        " or it is at the wrong position");
walther@60097
   324
walther@60097
   325
fun unprefix_pfun "" s = s
walther@60097
   326
  | unprefix_pfun prfx s =
walther@60097
   327
      let val (prfx', s') = strip_prfx s
walther@60097
   328
      in if prfx = prfx' then s' else s end;
walther@60097
   329
walther@60097
   330
fun invert_map [] = I
walther@60097
   331
  | invert_map cmap =
walther@60097
   332
      map (apfst (the o AList.lookup (op =) (map swap cmap)));
walther@60097
   333
walther@60097
   334
fun get_record_info thy T = (case Record.dest_recTs T of
walther@60097
   335
    [(tyname, [\<^typ>\<open>unit\<close>])] =>
walther@60097
   336
      Record.get_info thy (Long_Name.qualifier tyname)
walther@60097
   337
  | _ => NONE);
walther@60097
   338
walther@60097
   339
walther@60097
   340
walther@60097
   341
fun add_type_def prfx (s, Fdl_Parser.Basic_Type ty) (ids, thy) =
walther@60097
   342
      (check_no_assoc thy prfx s;
walther@60097
   343
       (ids,
walther@60097
   344
        Typedecl.abbrev_global (Binding.name s, [], NoSyn)
walther@60097
   345
          (mk_type thy prfx ty) thy |> snd))
walther@60097
   346
walther@60097
   347
  | add_type_def prfx (s, Fdl_Parser.Enum_Type els) ((tab, ctxt), thy) =
walther@60097
   348
      let
walther@60097
   349
        val (thy', tyname) = (case get_type thy prfx s of
walther@60097
   350
            NONE =>
walther@60097
   351
              let
walther@60097
   352
                val tyb = Binding.name s;
walther@60097
   353
                val tyname = Sign.full_name thy tyb
walther@60097
   354
              in
walther@60097
   355
                (thy |>
walther@60097
   356
                 BNF_LFP_Compat.add_datatype [BNF_LFP_Compat.Keep_Nesting]
walther@60097
   357
                   [((tyb, [], NoSyn),
walther@60097
   358
                     map (fn s => (Binding.name s, [], NoSyn)) els)] |> snd |>
walther@60097
   359
                 add_enum_type s tyname,
walther@60097
   360
                 tyname)
walther@60097
   361
              end
walther@60097
   362
          | SOME (T as Type (tyname, []), cmap) =>
walther@60097
   363
              (case BNF_LFP_Compat.get_constrs thy tyname of
walther@60097
   364
                 NONE => assoc_ty_err thy T s "is not a datatype"
walther@60097
   365
               | SOME cs =>
walther@60097
   366
                   let val (prfx', _) = strip_prfx s
walther@60097
   367
                   in
walther@60097
   368
                     case check_enum (map (unprefix_pfun prfx') els)
walther@60097
   369
                         (invert_map cmap cs) of
walther@60097
   370
                       NONE => (thy, tyname)
walther@60097
   371
                     | SOME msg => assoc_ty_err thy T s msg
walther@60097
   372
                   end)
walther@60097
   373
          | SOME (T, _) => assoc_ty_err thy T s "is not a datatype");
walther@60097
   374
        val cs = map Const (the (BNF_LFP_Compat.get_constrs thy' tyname));
walther@60097
   375
      in
walther@60097
   376
        ((fold (Symtab.update_new o apsnd (rpair s)) (els ~~ cs) tab,
walther@60097
   377
          fold Name.declare els ctxt),
walther@60097
   378
         thy')
walther@60097
   379
      end
walther@60097
   380
walther@60097
   381
  | add_type_def prfx (s, Fdl_Parser.Array_Type (argtys, resty)) (ids, thy) =
walther@60097
   382
      (check_no_assoc thy prfx s;
walther@60097
   383
       (ids,
walther@60097
   384
        Typedecl.abbrev_global (Binding.name s, [], NoSyn)
walther@60097
   385
          (foldr1 HOLogic.mk_prodT (map (mk_type thy prfx) argtys) -->
walther@60097
   386
             mk_type thy prfx resty) thy |> snd))
walther@60097
   387
walther@60097
   388
  | add_type_def prfx (s, Fdl_Parser.Record_Type fldtys) (ids, thy) =
walther@60097
   389
      (ids,
walther@60097
   390
       let val fldTs = maps (fn (flds, ty) =>
walther@60097
   391
         map (rpair (mk_type thy prfx ty)) flds) fldtys
walther@60097
   392
       in case get_type thy prfx s of
walther@60097
   393
           NONE =>
walther@60097
   394
             Record.add_record {overloaded = false} ([], Binding.name s) NONE
walther@60097
   395
               (map (fn (fld, T) => (Binding.name fld, T, NoSyn)) fldTs) thy
walther@60097
   396
         | SOME (rT, cmap) =>
walther@60097
   397
             (case get_record_info thy rT of
walther@60097
   398
                NONE => assoc_ty_err thy rT s "is not a record type"
walther@60097
   399
              | SOME {fields, ...} =>
walther@60097
   400
                  let val fields' = invert_map cmap fields
walther@60097
   401
                  in
walther@60097
   402
                    (case subtract (lcase_eq o apply2 fst) fldTs fields' of
walther@60097
   403
                       [] => ()
walther@60097
   404
                     | flds => assoc_ty_err thy rT s ("has extra field(s) " ^
walther@60097
   405
                         commas (map (Long_Name.base_name o fst) flds));
walther@60097
   406
                     map (fn (fld, T) =>
walther@60097
   407
                       case AList.lookup lcase_eq fields' fld of
walther@60097
   408
                         NONE => assoc_ty_err thy rT s ("has no field " ^ fld)
walther@60097
   409
                       | SOME U => T = U orelse assoc_ty_err thy rT s
walther@60097
   410
                           ("has field " ^
walther@60097
   411
                            fld ^ " whose type\n" ^
walther@60097
   412
                            Syntax.string_of_typ_global thy U ^
walther@60097
   413
                            "\ndoes not match declared type\n" ^
walther@60097
   414
                            Syntax.string_of_typ_global thy T)) fldTs;
walther@60097
   415
                     thy)
walther@60097
   416
                  end)
walther@60097
   417
       end)
walther@60097
   418
walther@60097
   419
  | add_type_def prfx (s, Fdl_Parser.Pending_Type) (ids, thy) =
walther@60097
   420
      (ids,
walther@60097
   421
       case get_type thy prfx s of
walther@60097
   422
         SOME _ => thy
walther@60097
   423
       | NONE => Typedecl.typedecl_global {final = true} (Binding.name s, [], NoSyn) thy |> snd);
walther@60097
   424
walther@60097
   425
fun add_type_def prfx (s, Fdl_Parser.Basic_Type ty) (ids, thy) =
walther@60097
   426
      (check_no_assoc thy prfx s;
walther@60097
   427
       (ids,
walther@60097
   428
        Typedecl.abbrev_global (Binding.name s, [], NoSyn)
walther@60097
   429
          (mk_type thy prfx ty) thy |> snd))
walther@60097
   430
walther@60097
   431
  | add_type_def prfx (s, Fdl_Parser.Enum_Type els) ((tab, ctxt), thy) =
walther@60097
   432
      let
walther@60097
   433
        val (thy', tyname) = (case get_type thy prfx s of
walther@60097
   434
            NONE =>
walther@60097
   435
              let
walther@60097
   436
                val tyb = Binding.name s;
walther@60097
   437
                val tyname = Sign.full_name thy tyb
walther@60097
   438
              in
walther@60097
   439
                (thy |>
walther@60097
   440
                 BNF_LFP_Compat.add_datatype [BNF_LFP_Compat.Keep_Nesting]
walther@60097
   441
                   [((tyb, [], NoSyn),
walther@60097
   442
                     map (fn s => (Binding.name s, [], NoSyn)) els)] |> snd |>
walther@60097
   443
                 add_enum_type s tyname,
walther@60097
   444
                 tyname)
walther@60097
   445
              end
walther@60097
   446
          | SOME (T as Type (tyname, []), cmap) =>
walther@60097
   447
              (case BNF_LFP_Compat.get_constrs thy tyname of
walther@60097
   448
                 NONE => assoc_ty_err thy T s "is not a datatype"
walther@60097
   449
               | SOME cs =>
walther@60097
   450
                   let val (prfx', _) = strip_prfx s
walther@60097
   451
                   in
walther@60097
   452
                     case check_enum (map (unprefix_pfun prfx') els)
walther@60097
   453
                         (invert_map cmap cs) of
walther@60097
   454
                       NONE => (thy, tyname)
walther@60097
   455
                     | SOME msg => assoc_ty_err thy T s msg
walther@60097
   456
                   end)
walther@60097
   457
          | SOME (T, _) => assoc_ty_err thy T s "is not a datatype");
walther@60097
   458
        val cs = map Const (the (BNF_LFP_Compat.get_constrs thy' tyname));
walther@60097
   459
      in
walther@60097
   460
        ((fold (Symtab.update_new o apsnd (rpair s)) (els ~~ cs) tab,
walther@60097
   461
          fold Name.declare els ctxt),
walther@60097
   462
         thy')
walther@60097
   463
      end
walther@60097
   464
walther@60097
   465
  | add_type_def prfx (s, Fdl_Parser.Array_Type (argtys, resty)) (ids, thy) =
walther@60097
   466
      (check_no_assoc thy prfx s;
walther@60097
   467
       (ids,
walther@60097
   468
        Typedecl.abbrev_global (Binding.name s, [], NoSyn)
walther@60097
   469
          (foldr1 HOLogic.mk_prodT (map (mk_type thy prfx) argtys) -->
walther@60097
   470
             mk_type thy prfx resty) thy |> snd))
walther@60097
   471
walther@60097
   472
  | add_type_def prfx (s, Fdl_Parser.Record_Type fldtys) (ids, thy) =
walther@60097
   473
      (ids,
walther@60097
   474
       let val fldTs = maps (fn (flds, ty) =>
walther@60097
   475
         map (rpair (mk_type thy prfx ty)) flds) fldtys
walther@60097
   476
       in case get_type thy prfx s of
walther@60097
   477
           NONE =>
walther@60097
   478
             Record.add_record {overloaded = false} ([], Binding.name s) NONE
walther@60097
   479
               (map (fn (fld, T) => (Binding.name fld, T, NoSyn)) fldTs) thy
walther@60097
   480
         | SOME (rT, cmap) =>
walther@60097
   481
             (case get_record_info thy rT of
walther@60097
   482
                NONE => assoc_ty_err thy rT s "is not a record type"
walther@60097
   483
              | SOME {fields, ...} =>
walther@60097
   484
                  let val fields' = invert_map cmap fields
walther@60097
   485
                  in
walther@60097
   486
                    (case subtract (lcase_eq o apply2 fst) fldTs fields' of
walther@60097
   487
                       [] => ()
walther@60097
   488
                     | flds => assoc_ty_err thy rT s ("has extra field(s) " ^
walther@60097
   489
                         commas (map (Long_Name.base_name o fst) flds));
walther@60097
   490
                     map (fn (fld, T) =>
walther@60097
   491
                       case AList.lookup lcase_eq fields' fld of
walther@60097
   492
                         NONE => assoc_ty_err thy rT s ("has no field " ^ fld)
walther@60097
   493
                       | SOME U => T = U orelse assoc_ty_err thy rT s
walther@60097
   494
                           ("has field " ^
walther@60097
   495
                            fld ^ " whose type\n" ^
walther@60097
   496
                            Syntax.string_of_typ_global thy U ^
walther@60097
   497
                            "\ndoes not match declared type\n" ^
walther@60097
   498
                            Syntax.string_of_typ_global thy T)) fldTs;
walther@60097
   499
                     thy)
walther@60097
   500
                  end)
walther@60097
   501
       end)
walther@60097
   502
walther@60097
   503
  | add_type_def prfx (s, Fdl_Parser.Pending_Type) (ids, thy) =
walther@60097
   504
      (ids,
walther@60097
   505
       case get_type thy prfx s of
walther@60097
   506
         SOME _ => thy
walther@60097
   507
       | NONE => Typedecl.typedecl_global {final = true} (Binding.name s, [], NoSyn) thy |> snd);
walther@60097
   508
walther@60097
   509
fun add_const prfx (s, ty) ((tab, ctxt), thy) =
walther@60097
   510
  let
walther@60097
   511
    val T = mk_type thy prfx ty;
walther@60097
   512
    val b = Binding.name s;
walther@60097
   513
    val c = Const (Sign.full_name thy b, T)
walther@60097
   514
  in
walther@60097
   515
    (c,
walther@60097
   516
     ((Symtab.update (s, (c, ty)) tab, Name.declare s ctxt),
walther@60097
   517
      Sign.add_consts [(b, T, NoSyn)] thy))
walther@60097
   518
  end;
walther@60097
   519
walther@60097
   520
fun mk_unop s t =
walther@60097
   521
  let val T = fastype_of t
walther@60097
   522
  in Const (s, T --> T) $ t end;
walther@60097
   523
walther@60097
   524
fun strip_underscores s =
walther@60097
   525
  strip_underscores (unsuffix "_" s) handle Fail _ => s;
walther@60097
   526
walther@60097
   527
fun strip_tilde s =
walther@60097
   528
  unsuffix "~" s ^ "_init" handle Fail _ => s;
walther@60097
   529
walther@60097
   530
val mangle_name = strip_underscores #> strip_tilde;
walther@60097
   531
walther@60097
   532
fun mk_variables thy prfx xs ty (tab, ctxt) =
walther@60097
   533
  let
walther@60097
   534
    val T = mk_type thy prfx ty;
walther@60097
   535
    val (ys, ctxt') = fold_map Name.variant (map mangle_name xs) ctxt;
walther@60097
   536
    val zs = map (Free o rpair T) ys;
walther@60097
   537
  in (zs, (fold (Symtab.update o apsnd (rpair ty)) (xs ~~ zs) tab, ctxt')) end;
walther@60097
   538
walther@60097
   539
fun find_field [] fname fields =
walther@60097
   540
      find_first (curry lcase_eq fname o fst) fields
walther@60097
   541
  | find_field cmap fname fields =
walther@60097
   542
      (case AList.lookup (op =) cmap fname of
walther@60097
   543
         NONE => NONE
walther@60097
   544
       | SOME fname' => SOME (fname', the (AList.lookup (op =) fields fname')));
walther@60097
   545
walther@60097
   546
fun find_field' fname = get_first (fn (flds, fldty) =>
walther@60097
   547
  if member (op =) flds fname then SOME fldty else NONE);
walther@60097
   548
walther@60097
   549
fun mk_times (t, u) =
walther@60097
   550
  let
walther@60097
   551
    val setT = fastype_of t;
walther@60097
   552
    val T = HOLogic.dest_setT setT;
walther@60097
   553
    val U = HOLogic.dest_setT (fastype_of u)
walther@60097
   554
  in
walther@60097
   555
    Const (\<^const_name>\<open>Sigma\<close>, setT --> (T --> HOLogic.mk_setT U) -->
walther@60097
   556
      HOLogic.mk_setT (HOLogic.mk_prodT (T, U))) $ t $ Abs ("", T, u)
walther@60097
   557
  end;
walther@60097
   558
walther@60097
   559
walther@60097
   560
fun term_of_expr thy prfx types pfuns =
walther@60097
   561
  let
walther@60097
   562
    fun tm_of vs (Fdl_Parser.Funct ("->", [e, e'])) =
walther@60097
   563
          (HOLogic.mk_imp (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
walther@60097
   564
walther@60097
   565
      | tm_of vs (Fdl_Parser.Funct ("<->", [e, e'])) =
walther@60097
   566
          (HOLogic.mk_eq (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
walther@60097
   567
walther@60097
   568
      | tm_of vs (Fdl_Parser.Funct ("or", [e, e'])) =
walther@60097
   569
          (HOLogic.mk_disj (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
walther@60097
   570
walther@60097
   571
      | tm_of vs (Fdl_Parser.Funct ("and", [e, e'])) =
walther@60097
   572
          (HOLogic.mk_conj (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
walther@60097
   573
walther@60097
   574
      | tm_of vs (Fdl_Parser.Funct ("not", [e])) =
walther@60097
   575
          (HOLogic.mk_not (fst (tm_of vs e)), booleanN)
walther@60097
   576
walther@60097
   577
      | tm_of vs (Fdl_Parser.Funct ("=", [e, e'])) =
walther@60097
   578
          (HOLogic.mk_eq (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
walther@60097
   579
walther@60097
   580
      | tm_of vs (Fdl_Parser.Funct ("<>", [e, e'])) = (HOLogic.mk_not
walther@60097
   581
          (HOLogic.mk_eq (fst (tm_of vs e), fst (tm_of vs e'))), booleanN)
walther@60097
   582
walther@60097
   583
      | tm_of vs (Fdl_Parser.Funct ("<", [e, e'])) = (HOLogic.mk_binrel \<^const_name>\<open>less\<close>
walther@60097
   584
          (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
walther@60097
   585
walther@60097
   586
      | tm_of vs (Fdl_Parser.Funct (">", [e, e'])) = (HOLogic.mk_binrel \<^const_name>\<open>less\<close>
walther@60097
   587
          (fst (tm_of vs e'), fst (tm_of vs e)), booleanN)
walther@60097
   588
walther@60097
   589
      | tm_of vs (Fdl_Parser.Funct ("<=", [e, e'])) = (HOLogic.mk_binrel \<^const_name>\<open>less_eq\<close>
walther@60097
   590
          (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
walther@60097
   591
walther@60097
   592
      | tm_of vs (Fdl_Parser.Funct (">=", [e, e'])) = (HOLogic.mk_binrel \<^const_name>\<open>less_eq\<close>
walther@60097
   593
          (fst (tm_of vs e'), fst (tm_of vs e)), booleanN)
walther@60097
   594
walther@60097
   595
      | tm_of vs (Fdl_Parser.Funct ("+", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>plus\<close>
walther@60097
   596
          (fst (tm_of vs e), fst (tm_of vs e')), integerN)
walther@60097
   597
walther@60097
   598
      | tm_of vs (Fdl_Parser.Funct ("-", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>minus\<close>
walther@60097
   599
          (fst (tm_of vs e), fst (tm_of vs e')), integerN)
walther@60097
   600
walther@60097
   601
      | tm_of vs (Fdl_Parser.Funct ("*", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>times\<close>
walther@60097
   602
          (fst (tm_of vs e), fst (tm_of vs e')), integerN)
walther@60097
   603
walther@60097
   604
      | tm_of vs (Fdl_Parser.Funct ("/", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>divide\<close>
walther@60097
   605
          (fst (tm_of vs e), fst (tm_of vs e')), integerN)
walther@60097
   606
walther@60097
   607
      | tm_of vs (Fdl_Parser.Funct ("div", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>sdiv\<close>
walther@60097
   608
          (fst (tm_of vs e), fst (tm_of vs e')), integerN)
walther@60097
   609
walther@60097
   610
      | tm_of vs (Fdl_Parser.Funct ("mod", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>modulo\<close>
walther@60097
   611
          (fst (tm_of vs e), fst (tm_of vs e')), integerN)
walther@60097
   612
walther@60097
   613
      | tm_of vs (Fdl_Parser.Funct ("-", [e])) =
walther@60097
   614
          (mk_unop \<^const_name>\<open>uminus\<close> (fst (tm_of vs e)), integerN)
walther@60097
   615
walther@60097
   616
      | tm_of vs (Fdl_Parser.Funct ("**", [e, e'])) =
walther@60097
   617
          (Const (\<^const_name>\<open>power\<close>, HOLogic.intT --> HOLogic.natT -->
walther@60097
   618
             HOLogic.intT) $ fst (tm_of vs e) $
walther@60097
   619
               (\<^const>\<open>nat\<close> $ fst (tm_of vs e')), integerN)
walther@60097
   620
walther@60097
   621
      | tm_of (tab, _) (Fdl_Parser.Ident s) =
walther@60097
   622
          (case Symtab.lookup tab s of
walther@60097
   623
             SOME t_ty => t_ty
walther@60097
   624
           | NONE => (case lookup_prfx prfx pfuns s of
walther@60097
   625
               SOME (SOME ([], resty), t) => (t, resty)
walther@60097
   626
             | _ => error ("Undeclared identifier " ^ s)))
walther@60097
   627
walther@60097
   628
      | tm_of _ (Fdl_Parser.Number i) = (HOLogic.mk_number HOLogic.intT i, integerN)
walther@60097
   629
walther@60097
   630
      | tm_of vs (Fdl_Parser.Quantifier (s, xs, ty, e)) =
walther@60097
   631
          let
walther@60097
   632
            val (ys, vs') = mk_variables thy prfx xs ty vs;
walther@60097
   633
            val q = (case s of
walther@60097
   634
                "for_all" => HOLogic.mk_all
walther@60097
   635
              | "for_some" => HOLogic.mk_exists)
walther@60097
   636
          in
walther@60097
   637
            (fold_rev (fn Free (x, T) => fn t => q (x, T, t))
walther@60097
   638
               ys (fst (tm_of vs' e)),
walther@60097
   639
             booleanN)
walther@60097
   640
          end
walther@60097
   641
walther@60097
   642
      | tm_of vs (Fdl_Parser.Funct (s, es)) =
walther@60097
   643
walther@60097
   644
          (* record field selection *)
walther@60097
   645
          (case try (unprefix "fld_") s of
walther@60097
   646
             SOME fname => (case es of
walther@60097
   647
               [e] =>
walther@60097
   648
                 let
walther@60097
   649
                   val (t, rcdty) = tm_of vs e;
walther@60097
   650
                   val (rT, cmap) = mk_type' thy prfx rcdty
walther@60097
   651
                 in case (get_record_info thy rT, Fdl_Parser.lookup types rcdty) of
walther@60097
   652
                     (SOME {fields, ...}, SOME (Fdl_Parser.Record_Type fldtys)) =>
walther@60097
   653
                       (case (find_field cmap fname fields,
walther@60097
   654
                            find_field' fname fldtys) of
walther@60097
   655
                          (SOME (fname', fT), SOME fldty) =>
walther@60097
   656
                            (Const (fname', rT --> fT) $ t, fldty)
walther@60097
   657
                        | _ => error ("Record " ^ rcdty ^
walther@60097
   658
                            " has no field named " ^ fname))
walther@60097
   659
                   | _ => error (rcdty ^ " is not a record type")
walther@60097
   660
                 end
walther@60097
   661
             | _ => error ("Function " ^ s ^ " expects one argument"))
walther@60097
   662
           | NONE =>
walther@60097
   663
walther@60097
   664
          (* record field update *)
walther@60097
   665
          (case try (unprefix "upf_") s of
walther@60097
   666
             SOME fname => (case es of
walther@60097
   667
               [e, e'] =>
walther@60097
   668
                 let
walther@60097
   669
                   val (t, rcdty) = tm_of vs e;
walther@60097
   670
                   val (rT, cmap) = mk_type' thy prfx rcdty;
walther@60097
   671
                   val (u, fldty) = tm_of vs e';
walther@60097
   672
                   val fT = mk_type thy prfx fldty
walther@60097
   673
                 in case get_record_info thy rT of
walther@60097
   674
                     SOME {fields, ...} =>
walther@60097
   675
                       (case find_field cmap fname fields of
walther@60097
   676
                          SOME (fname', fU) =>
walther@60097
   677
                            if fT = fU then
walther@60097
   678
                              (Const (fname' ^ "_update",
walther@60097
   679
                                 (fT --> fT) --> rT --> rT) $
walther@60097
   680
                                   Abs ("x", fT, u) $ t,
walther@60097
   681
                               rcdty)
walther@60097
   682
                            else error ("Type\n" ^
walther@60097
   683
                              Syntax.string_of_typ_global thy fT ^
walther@60097
   684
                              "\ndoes not match type\n" ^
walther@60097
   685
                              Syntax.string_of_typ_global thy fU ^
walther@60097
   686
                              "\nof field " ^ fname)
walther@60097
   687
                        | NONE => error ("Record " ^ rcdty ^
walther@60097
   688
                            " has no field named " ^ fname))
walther@60097
   689
                   | _ => error (rcdty ^ " is not a record type")
walther@60097
   690
                 end
walther@60097
   691
             | _ => error ("Function " ^ s ^ " expects two arguments"))
walther@60097
   692
           | NONE =>
walther@60097
   693
walther@60097
   694
          (* enumeration type to integer *)
walther@60097
   695
          (case try (unsuffix "__pos") s of
walther@60097
   696
             SOME tyname => (case es of
walther@60097
   697
               [e] => (Const (\<^const_name>\<open>pos\<close>,
walther@60097
   698
                   mk_type thy prfx tyname --> HOLogic.intT) $ fst (tm_of vs e),
walther@60097
   699
                 integerN)
walther@60097
   700
             | _ => error ("Function " ^ s ^ " expects one argument"))
walther@60097
   701
           | NONE =>
walther@60097
   702
walther@60097
   703
          (* integer to enumeration type *)
walther@60097
   704
          (case try (unsuffix "__val") s of
walther@60097
   705
             SOME tyname => (case es of
walther@60097
   706
               [e] => (Const (\<^const_name>\<open>val\<close>,
walther@60097
   707
                   HOLogic.intT --> mk_type thy prfx tyname) $ fst (tm_of vs e),
walther@60097
   708
                 tyname)
walther@60097
   709
             | _ => error ("Function " ^ s ^ " expects one argument"))
walther@60097
   710
           | NONE =>
walther@60097
   711
walther@60097
   712
          (* successor / predecessor of enumeration type element *)
walther@60097
   713
          if s = "succ" orelse s = "pred" then (case es of
walther@60097
   714
              [e] =>
walther@60097
   715
                let
walther@60097
   716
                  val (t, tyname) = tm_of vs e;
walther@60097
   717
                  val T = mk_type thy prfx tyname
walther@60097
   718
                in (Const
walther@60097
   719
                  (if s = "succ" then \<^const_name>\<open>succ\<close>
walther@60097
   720
                   else \<^const_name>\<open>pred\<close>, T --> T) $ t, tyname)
walther@60097
   721
                end
walther@60097
   722
            | _ => error ("Function " ^ s ^ " expects one argument"))
walther@60097
   723
walther@60097
   724
          (* user-defined proof function *)
walther@60097
   725
          else
walther@60097
   726
            (case lookup_prfx prfx pfuns s of
walther@60097
   727
               SOME (SOME (_, resty), t) =>
walther@60097
   728
                 (list_comb (t, map (fst o tm_of vs) es), resty)
walther@60097
   729
             | _ => error ("Undeclared proof function " ^ s))))))
walther@60097
   730
walther@60097
   731
      | tm_of vs (Fdl_Parser.Element (e, es)) =
walther@60097
   732
          let val (t, ty) = tm_of vs e
walther@60097
   733
          in case Fdl_Parser.lookup types ty of
walther@60097
   734
              SOME (Fdl_Parser.Array_Type (_, elty)) =>
walther@60097
   735
                (t $ foldr1 HOLogic.mk_prod (map (fst o tm_of vs) es), elty)
walther@60097
   736
            | _ => error (ty ^ " is not an array type")
walther@60097
   737
          end
walther@60097
   738
walther@60097
   739
      | tm_of vs (Fdl_Parser.Update (e, es, e')) =
walther@60097
   740
          let val (t, ty) = tm_of vs e
walther@60097
   741
          in case Fdl_Parser.lookup types ty of
walther@60097
   742
              SOME (Fdl_Parser.Array_Type (idxtys, elty)) =>
walther@60097
   743
                let
walther@60097
   744
                  val T = foldr1 HOLogic.mk_prodT
walther@60097
   745
                    (map (mk_type thy prfx) idxtys);
walther@60097
   746
                  val U = mk_type thy prfx elty;
walther@60097
   747
                  val fT = T --> U
walther@60097
   748
                in
walther@60097
   749
                  (Const (\<^const_name>\<open>fun_upd\<close>, fT --> T --> U --> fT) $
walther@60097
   750
                     t $ foldr1 HOLogic.mk_prod (map (fst o tm_of vs) es) $
walther@60097
   751
                       fst (tm_of vs e'),
walther@60097
   752
                   ty)
walther@60097
   753
                end
walther@60097
   754
            | _ => error (ty ^ " is not an array type")
walther@60097
   755
          end
walther@60097
   756
walther@60097
   757
      | tm_of vs (Fdl_Parser.Record (s, flds)) =
walther@60097
   758
          let
walther@60097
   759
            val (T, cmap) = mk_type' thy prfx s;
walther@60097
   760
            val {extension = (ext_name, _), fields, ...} =
walther@60097
   761
              (case get_record_info thy T of
walther@60097
   762
                 NONE => error (s ^ " is not a record type")
walther@60097
   763
               | SOME info => info);
walther@60097
   764
            val flds' = map (apsnd (tm_of vs)) flds;
walther@60097
   765
            val fnames = fields |> invert_map cmap |>
walther@60097
   766
              map (Long_Name.base_name o fst);
walther@60097
   767
            val fnames' = map fst flds;
walther@60097
   768
            val (fvals, ftys) = split_list (map (fn s' =>
walther@60097
   769
              case AList.lookup lcase_eq flds' s' of
walther@60097
   770
                SOME fval_ty => fval_ty
walther@60097
   771
              | NONE => error ("Field " ^ s' ^ " missing in record " ^ s))
walther@60097
   772
                  fnames);
walther@60097
   773
            val _ = (case subtract lcase_eq fnames fnames' of
walther@60097
   774
                [] => ()
walther@60097
   775
              | xs => error ("Extra field(s) " ^ commas xs ^
walther@60097
   776
                  " in record " ^ s));
walther@60097
   777
            val _ = (case duplicates (op =) fnames' of
walther@60097
   778
                [] => ()
walther@60097
   779
              | xs => error ("Duplicate field(s) " ^ commas xs ^
walther@60097
   780
                  " in record " ^ s))
walther@60097
   781
          in
walther@60097
   782
            (list_comb
walther@60097
   783
               (Const (ext_name,
walther@60097
   784
                  map (mk_type thy prfx) ftys @ [HOLogic.unitT] ---> T),
walther@60097
   785
                fvals @ [HOLogic.unit]),
walther@60097
   786
             s)
walther@60097
   787
          end
walther@60097
   788
walther@60097
   789
      | tm_of vs (Fdl_Parser.Array (s, default, assocs)) =
walther@60097
   790
          (case Fdl_Parser.lookup types s of
walther@60097
   791
             SOME (Fdl_Parser.Array_Type (idxtys, elty)) =>
walther@60097
   792
               let
walther@60097
   793
                 val Ts = map (mk_type thy prfx) idxtys;
walther@60097
   794
                 val T = foldr1 HOLogic.mk_prodT Ts;
walther@60097
   795
                 val U = mk_type thy prfx elty;
walther@60097
   796
                 fun mk_idx' T (e, NONE) = HOLogic.mk_set T [fst (tm_of vs e)]
walther@60097
   797
                   | mk_idx' T (e, SOME e') = Const (\<^const_name>\<open>atLeastAtMost\<close>,
walther@60097
   798
                       T --> T --> HOLogic.mk_setT T) $
walther@60097
   799
                         fst (tm_of vs e) $ fst (tm_of vs e');
walther@60097
   800
                 fun mk_idx idx =
walther@60097
   801
                   if length Ts <> length idx then
walther@60097
   802
                     error ("Arity mismatch in construction of array " ^ s)
walther@60097
   803
                   else foldr1 mk_times (map2 mk_idx' Ts idx);
walther@60097
   804
                 fun mk_upd (idxs, e) t =
walther@60097
   805
                   if length idxs = 1 andalso forall (is_none o snd) (hd idxs)
walther@60097
   806
                   then
walther@60097
   807
                     Const (\<^const_name>\<open>fun_upd\<close>, (T --> U) -->
walther@60097
   808
                         T --> U --> T --> U) $ t $
walther@60097
   809
                       foldl1 HOLogic.mk_prod
walther@60097
   810
                         (map (fst o tm_of vs o fst) (hd idxs)) $
walther@60097
   811
                       fst (tm_of vs e)
walther@60097
   812
                   else
walther@60097
   813
                     Const (\<^const_name>\<open>fun_upds\<close>, (T --> U) -->
walther@60097
   814
                         HOLogic.mk_setT T --> U --> T --> U) $ t $
walther@60097
   815
                       foldl1 (HOLogic.mk_binop \<^const_name>\<open>sup\<close>)
walther@60097
   816
                         (map mk_idx idxs) $
walther@60097
   817
                       fst (tm_of vs e)
walther@60097
   818
               in
walther@60097
   819
                 (fold mk_upd assocs
walther@60097
   820
                    (case default of
walther@60097
   821
                       SOME e => Abs ("x", T, fst (tm_of vs e))
walther@60097
   822
                     | NONE => Const (\<^const_name>\<open>undefined\<close>, T --> U)),
walther@60097
   823
                  s)
walther@60097
   824
               end
walther@60097
   825
           | _ => error (s ^ " is not an array type"))
walther@60097
   826
walther@60097
   827
  in tm_of end;
walther@60097
   828
walther@60097
   829
walther@60097
   830
fun mk_rulename (s, i) = Binding.name (s ^ string_of_int i);
walther@60097
   831
walther@60097
   832
walther@60097
   833
fun add_def prfx types pfuns consts (id, (s, e)) (ids as (tab, ctxt), thy) =
walther@60097
   834
  (case Fdl_Parser.lookup consts s of
walther@60097
   835
    SOME ty =>
walther@60097
   836
      let
walther@60097
   837
        val (t, ty') = term_of_expr thy prfx types pfuns ids e;
walther@60097
   838
        val T = mk_type thy prfx ty;
walther@60097
   839
        val T' = mk_type thy prfx ty';
walther@60097
   840
        val _ = T = T' orelse
walther@60097
   841
          error ("Declared type " ^ ty ^ " of " ^ s ^
walther@60097
   842
            "\ndoes not match type " ^ ty' ^ " in definition");
walther@60097
   843
        val id' = mk_rulename id;
walther@60097
   844
        val ((t', (_, th)), lthy') = Named_Target.theory_init thy
walther@60097
   845
          |> Specification.definition NONE [] []
walther@60097
   846
            ((id', []), HOLogic.mk_Trueprop (HOLogic.mk_eq (Free (s, T), t)));
walther@60097
   847
        val phi =
walther@60097
   848
          Proof_Context.export_morphism lthy'
walther@60097
   849
            (Proof_Context.init_global (Proof_Context.theory_of lthy'));
walther@60097
   850
      in
walther@60097
   851
        ((id', Morphism.thm phi th),
walther@60097
   852
          ((Symtab.update (s, (Morphism.term phi t', ty)) tab, Name.declare s ctxt),
walther@60097
   853
            Local_Theory.exit_global lthy'))
walther@60097
   854
       end
walther@60097
   855
  | NONE => error ("Undeclared constant " ^ s));
walther@60097
   856
walther@60097
   857
walther@60097
   858
walther@60097
   859
val add_expr_idents = fold_expr (K I) (insert (op =));
walther@60097
   860
walther@60097
   861
(* sort definitions according to their dependency *)
walther@60097
   862
fun sort_defs _ _ _ _ [] sdefs = rev sdefs
walther@60097
   863
  | sort_defs prfx funs pfuns consts defs sdefs =
walther@60097
   864
      (case find_first (fn (_, (_, e)) =>
walther@60097
   865
         forall (is_some o lookup_prfx prfx pfuns)
walther@60097
   866
           (add_expr_pfuns funs e []) andalso
walther@60097
   867
         forall (fn id =>
walther@60097
   868
           member (fn (s, (_, (s', _))) => s = s') sdefs id orelse
walther@60097
   869
           consts id)
walther@60097
   870
             (add_expr_idents e [])) defs of
walther@60097
   871
         SOME d => sort_defs prfx funs pfuns consts
walther@60097
   872
           (remove (op =) d defs) (d :: sdefs)
walther@60097
   873
       | NONE => error ("Bad definitions: " ^ rulenames defs));
walther@60097
   874
walther@60097
   875
fun add_var prfx (s, ty) (ids, thy) =
walther@60097
   876
  let val ([Free p], ids') = mk_variables thy prfx [s] ty ids
walther@60097
   877
  in (p, (ids', thy)) end;
walther@60097
   878
walther@60097
   879
fun add_init_vars prfx vcs (ids_thy as ((tab, _), _)) =
walther@60097
   880
  fold_map (add_var prfx)
walther@60097
   881
    (map_filter
walther@60097
   882
       (fn s => case try (unsuffix "~") s of
walther@60097
   883
          SOME s' => (case Symtab.lookup tab s' of
walther@60097
   884
            SOME (_, ty) => SOME (s, ty)
walther@60097
   885
          | NONE => error ("Undeclared identifier " ^ s'))
walther@60097
   886
        | NONE => NONE)
walther@60097
   887
       (fold_vcs (add_expr_idents o snd) vcs []))
walther@60097
   888
    ids_thy;
walther@60097
   889
walther@60097
   890
fun term_of_rule thy prfx types pfuns ids rule =
walther@60097
   891
  let val tm_of = fst o term_of_expr thy prfx types pfuns ids
walther@60097
   892
  in case rule of
walther@60097
   893
      Fdl_Parser.Inference_Rule (es, e) => Logic.list_implies
walther@60097
   894
        (map (HOLogic.mk_Trueprop o tm_of) es, HOLogic.mk_Trueprop (tm_of e))
walther@60097
   895
    | Fdl_Parser.Substitution_Rule (es, e, e') => Logic.list_implies
walther@60097
   896
        (map (HOLogic.mk_Trueprop o tm_of) es,
walther@60097
   897
         HOLogic.mk_Trueprop (HOLogic.mk_eq (tm_of e, tm_of e')))
walther@60097
   898
  end;
walther@60097
   899
walther@60097
   900
walther@60097
   901
fun pfun_type thy prfx (argtys, resty) =
walther@60097
   902
  map (mk_type thy prfx) argtys ---> mk_type thy prfx resty;
walther@60097
   903
walther@60097
   904
fun check_pfun_type thy prfx s t optty1 optty2 =
walther@60097
   905
  let
walther@60097
   906
    val T = fastype_of t;
walther@60097
   907
    fun check ty =
walther@60097
   908
      let val U = pfun_type thy prfx ty
walther@60097
   909
      in
walther@60097
   910
        T = U orelse
walther@60097
   911
        error ("Type\n" ^
walther@60097
   912
          Syntax.string_of_typ_global thy T ^
walther@60097
   913
          "\nof function " ^
walther@60097
   914
          Syntax.string_of_term_global thy t ^
walther@60097
   915
          " associated with proof function " ^ s ^
walther@60097
   916
          "\ndoes not match declared type\n" ^
walther@60097
   917
          Syntax.string_of_typ_global thy U)
walther@60097
   918
      end
walther@60097
   919
  in (Option.map check optty1; Option.map check optty2; ()) end;
walther@60097
   920
walther@60097
   921
fun upd_option x y = if is_some x then x else y;
walther@60097
   922
walther@60097
   923
fun check_pfuns_types thy prfx funs =
walther@60097
   924
  Symtab.map (fn s => fn (optty, t) =>
walther@60097
   925
   let val optty' = Fdl_Parser.lookup funs (unprefix_pfun prfx s)
walther@60097
   926
   in
walther@60097
   927
     (check_pfun_type thy prfx s t optty optty';
walther@60097
   928
      (NONE |> upd_option optty |> upd_option optty', t))
walther@60097
   929
   end);
walther@60097
   930
walther@60097
   931
walther@60097
   932
walther@60097
   933
walther@60097
   934
fun pp_vcs msg vcs = Pretty.big_list msg (map (Pretty.str o fst) vcs);
walther@60097
   935
walther@60097
   936
fun pp_open_vcs [] = Pretty.str "All verification conditions have been proved."
walther@60097
   937
  | pp_open_vcs vcs = pp_vcs
walther@60097
   938
      "The following verification conditions remain to be proved:" vcs;
walther@60097
   939
walther@60097
   940
fun partition_vcs vcs = VCtab.fold_rev
walther@60097
   941
  (fn (name, (trace, SOME thms, ps, cs)) =>
walther@60097
   942
        apfst (cons (name, (trace, thms, ps, cs)))
walther@60097
   943
    | (name, (trace, NONE, ps, cs)) =>
walther@60097
   944
        apsnd (cons (name, (trace, ps, cs))))
walther@60097
   945
  vcs ([], []);
walther@60097
   946
walther@60097
   947
fun print_open_vcs f vcs =
walther@60097
   948
  (Pretty.writeln (f (pp_open_vcs (snd (partition_vcs vcs)))); vcs);
walther@60097
   949
walther@60097
   950
fun set_env ctxt defs types funs ids vcs path prefix thy = VCs.map (fn
walther@60097
   951
    {pfuns, type_map, env = NONE} =>
walther@60097
   952
      {pfuns = pfuns,
walther@60097
   953
       type_map = type_map,
walther@60097
   954
       env = SOME
walther@60097
   955
         {ctxt = ctxt, defs = defs, types = types, funs = funs,
walther@60097
   956
          pfuns = check_pfuns_types thy prefix funs pfuns,
walther@60097
   957
          ids = ids, proving = false, vcs = print_open_vcs I vcs, path = path,
walther@60097
   958
          prefix = prefix}}
walther@60097
   959
  | _ => err_unfinished ()) thy;
walther@60097
   960
walther@60097
   961
fun set_vcs ({types, vars, consts, funs} : Fdl_Parser.decls)
walther@60097
   962
      (rules, _) ((_, ident), vcs) path opt_prfx thy =
walther@60097
   963
  let
walther@60097
   964
    val prfx' =
walther@60097
   965
      if opt_prfx = "" then
walther@60097
   966
        space_implode "__" (Long_Name.explode (Long_Name.qualifier ident))
walther@60097
   967
      else opt_prfx;
walther@60097
   968
    val prfx = to_lower prfx';
walther@60097
   969
    val {pfuns, ...} = VCs.get thy;
walther@60097
   970
    val (defs, rules') = partition_opt dest_def rules;
walther@60097
   971
    val consts' =
walther@60097
   972
      subtract (fn ((_, (s, _)), (s', _)) => s = s') defs (Fdl_Parser.items consts);
walther@60097
   973
    (* ignore all complex rules in rls files *)
walther@60097
   974
    val (rules'', other_rules) =
walther@60097
   975
      List.partition (complex_rule o snd) rules';
walther@60097
   976
    val _ = if null rules'' then ()
walther@60097
   977
      else warning ("Ignoring rules: " ^ rulenames rules'');
walther@60097
   978
walther@60097
   979
    val vcs' = VCtab.make (maps (fn (tr, vcs) =>
walther@60097
   980
      map (fn (s, (ps, cs)) => (s, (tr, NONE, ps, cs)))
walther@60097
   981
        (filter_out (is_trivial_vc o snd) vcs)) vcs);
walther@60097
   982
walther@60097
   983
    val _ = (case filter_out (is_some o Fdl_Parser.lookup funs)
walther@60097
   984
        (pfuns_of_vcs prfx funs pfuns vcs') of
walther@60097
   985
        [] => ()
walther@60097
   986
      | fs => error ("Undeclared proof function(s) " ^ commas fs));
walther@60097
   987
walther@60097
   988
    val (((defs', vars''), ivars), (ids, thy')) =
walther@60097
   989
      ((Symtab.empty |>
walther@60097
   990
        Symtab.update ("false", (\<^term>\<open>False\<close>, booleanN)) |>
walther@60097
   991
        Symtab.update ("true", (\<^term>\<open>True\<close>, booleanN)),
walther@60097
   992
        Name.context),
walther@60097
   993
       thy |> Sign.add_path
walther@60097
   994
         ((if prfx' = "" then "" else prfx' ^ "__") ^ Long_Name.base_name ident)) |>
walther@60097
   995
      fold (add_type_def prfx) (Fdl_Parser.items types) |>
walther@60097
   996
      fold (snd oo add_const prfx) consts' |> (fn ids_thy as ((tab, _), _) =>
walther@60097
   997
        ids_thy |>
walther@60097
   998
        fold_map (add_def prfx types pfuns consts)
walther@60097
   999
          (sort_defs prfx funs pfuns (Symtab.defined tab) defs []) ||>>
walther@60097
  1000
        fold_map (add_var prfx) (Fdl_Parser.items vars) ||>>
walther@60097
  1001
        add_init_vars prfx vcs');
walther@60097
  1002
walther@60097
  1003
    val ctxt =
walther@60097
  1004
      [Element.Fixes (map (fn (s, T) =>
walther@60097
  1005
         (Binding.name s, SOME T, NoSyn)) (vars'' @ ivars)),
walther@60097
  1006
       Element.Assumes (map (fn (id, rl) =>
walther@60097
  1007
         ((mk_rulename id, []),
walther@60097
  1008
          [(term_of_rule thy' prfx types pfuns ids rl, [])]))
walther@60097
  1009
           other_rules),
walther@60097
  1010
       Element.Notes ("", [((Binding.name "defns", []), map (rpair [] o single o snd) defs')])]
walther@60097
  1011
walther@60097
  1012
  in
walther@60097
  1013
    set_env ctxt defs' types funs ids vcs' path prfx thy'
walther@60097
  1014
  end;
walther@60097
  1015
(*\--------------------------------- cp_spark_vcs.ML -----------------------------------------/*)