src/HOL/Boogie/Tools/boogie_loader.ML
author wenzelm
Sun, 07 Mar 2010 12:19:47 +0100
changeset 35625 9c818cab0dd0
parent 35391 34d8e0a9bfa7
child 35626 06197484c6ad
permissions -rw-r--r--
modernized structure Object_Logic;
boehmes@33408
     1
(*  Title:      HOL/Boogie/Tools/boogie_loader.ML
boehmes@33408
     2
    Author:     Sascha Boehme, TU Muenchen
boehmes@33408
     3
boehmes@33408
     4
Loading and interpreting Boogie-generated files.
boehmes@33408
     5
*)
boehmes@33408
     6
boehmes@33408
     7
signature BOOGIE_LOADER =
boehmes@33408
     8
sig
boehmes@35125
     9
  val load_b2i: bool -> (string * int) list -> Path.T -> theory -> theory
boehmes@33408
    10
end
boehmes@33408
    11
boehmes@33408
    12
structure Boogie_Loader: BOOGIE_LOADER =
boehmes@33408
    13
struct
boehmes@33408
    14
boehmes@34002
    15
fun log verbose text args x =
boehmes@34002
    16
  if verbose andalso not (null args)
boehmes@34002
    17
  then (Pretty.writeln (Pretty.big_list text (map Pretty.str args)); x)
boehmes@34002
    18
  else x
boehmes@33408
    19
boehmes@33408
    20
val isabelle_name =
boehmes@33408
    21
  let 
boehmes@33441
    22
    fun purge s = if Symbol.is_letter s orelse Symbol.is_digit s then s else
boehmes@33408
    23
      (case s of
boehmes@33408
    24
        "." => "_o_"
boehmes@33408
    25
      | "_" => "_n_"
boehmes@33408
    26
      | "$" => "_S_"
boehmes@33408
    27
      | "@" => "_G_"
boehmes@33408
    28
      | "#" => "_H_"
boehmes@33408
    29
      | "^" => "_T_"
boehmes@33408
    30
      | _   => ("_" ^ string_of_int (ord s) ^ "_"))
boehmes@33408
    31
  in prefix "b_" o translate_string purge end
boehmes@33408
    32
boehmes@34946
    33
fun drop_underscore s =
boehmes@34946
    34
  try (unsuffix "_") s
boehmes@34946
    35
  |> Option.map drop_underscore
boehmes@34946
    36
  |> the_default s
boehmes@34946
    37
boehmes@33441
    38
val short_name =
boehmes@34946
    39
  translate_string (fn s => if Symbol.is_letdig s then s else "") #>
boehmes@34946
    40
  drop_underscore
boehmes@33441
    41
boehmes@34068
    42
(* these prefixes must be distinct: *)
boehmes@34068
    43
val var_prefix = "V_"
boehmes@34068
    44
val label_prefix = "L_"
boehmes@34068
    45
val position_prefix = "P_"
boehmes@34068
    46
boehmes@34068
    47
val no_label_name = label_prefix ^ "unknown"
boehmes@34068
    48
fun label_name line col =
boehmes@34068
    49
  if line = 0 orelse col = 0 then no_label_name
boehmes@34068
    50
  else label_prefix ^ string_of_int line ^ "_" ^ string_of_int col
boehmes@34068
    51
boehmes@35358
    52
fun mk_syntax name i =
boehmes@35358
    53
  let
wenzelm@35390
    54
    val syn = Syntax.escape name
wenzelm@35391
    55
    val args = space_implode ",/ " (replicate i "_")
boehmes@35358
    56
  in
boehmes@35358
    57
    if i = 0 then Mixfix (syn, [], 1000)
boehmes@35358
    58
    else Mixfix (syn ^ "()'(/" ^ args ^ "')", replicate i 0, 1000)
boehmes@35358
    59
  end
boehmes@35358
    60
boehmes@33441
    61
boehmes@34002
    62
datatype attribute_value = StringValue of string | TermValue of term
boehmes@33408
    63
boehmes@33408
    64
boehmes@33408
    65
boehmes@33408
    66
local
boehmes@33408
    67
  fun lookup_type_name thy name arity =
boehmes@33408
    68
    let val intern = Sign.intern_type thy name
boehmes@33408
    69
    in
boehmes@33408
    70
      if Sign.declared_tyname thy intern
boehmes@33408
    71
      then
boehmes@33408
    72
        if Sign.arity_number thy intern = arity then SOME intern
boehmes@33408
    73
        else error ("Boogie: type already declared with different arity: " ^
boehmes@33408
    74
          quote name)
boehmes@33408
    75
      else NONE
boehmes@33408
    76
    end
boehmes@33408
    77
boehmes@34002
    78
  fun log_new bname name = bname ^ " (as " ^ name ^ ")"
boehmes@34002
    79
  fun log_ex bname name = "[" ^ bname ^ " has already been declared as " ^
boehmes@34002
    80
    name ^ "]"
boehmes@34002
    81
boehmes@33408
    82
  fun declare (name, arity) thy =
boehmes@33408
    83
    let val isa_name = isabelle_name name
boehmes@33408
    84
    in
boehmes@33408
    85
      (case lookup_type_name thy isa_name arity of
boehmes@34002
    86
        SOME type_name => (((name, type_name), log_ex name type_name), thy)
boehmes@33408
    87
      | NONE =>
boehmes@33408
    88
          let
boehmes@33408
    89
            val args = Name.variant_list [] (replicate arity "'")
wenzelm@35625
    90
            val (T, thy') =
wenzelm@35625
    91
              Object_Logic.typedecl (Binding.name isa_name, args, mk_syntax name arity) thy
boehmes@33408
    92
            val type_name = fst (Term.dest_Type T)
boehmes@34002
    93
          in (((name, type_name), log_new name type_name), thy') end)
boehmes@33408
    94
    end
boehmes@33408
    95
in
boehmes@33408
    96
fun declare_types verbose tys =
boehmes@34002
    97
  fold_map declare tys #>> split_list #-> (fn (tds, logs) =>
boehmes@34002
    98
  log verbose "Declared types:" logs #>
boehmes@34002
    99
  rpair (Symtab.make tds))
boehmes@33408
   100
end
boehmes@33408
   101
boehmes@33408
   102
boehmes@33408
   103
boehmes@33408
   104
local
boehmes@33893
   105
  fun maybe_builtin T =
boehmes@33408
   106
    let
boehmes@33408
   107
      fun const name = SOME (Const (name, T))
boehmes@34068
   108
      fun const2_abs name =
boehmes@34181
   109
        let val U = Term.domain_type T
boehmes@34068
   110
        in
boehmes@34068
   111
          SOME (Abs (Name.uu, U, Abs (Name.uu, U,
boehmes@34068
   112
            Const (name, T) $ Bound 0 $ Bound 1)))
boehmes@34068
   113
        end
boehmes@33408
   114
boehmes@33408
   115
      fun choose builtin =
boehmes@33408
   116
        (case builtin of
boehmes@34068
   117
          "bvnot" => const @{const_name bitNOT}
boehmes@34068
   118
        | "bvand" => const @{const_name bitAND}
boehmes@34068
   119
        | "bvor" => const @{const_name bitOR}
boehmes@34068
   120
        | "bvxor" => const @{const_name bitXOR}
boehmes@34068
   121
        | "bvadd" => const @{const_name plus}
boehmes@34068
   122
        | "bvneg" => const @{const_name uminus}
boehmes@34068
   123
        | "bvsub" => const @{const_name minus}
boehmes@34068
   124
        | "bvmul" => const @{const_name times}
boehmes@34068
   125
        | "bvudiv" => const @{const_name div}
boehmes@34068
   126
        | "bvurem" => const @{const_name mod}
boehmes@34068
   127
        | "bvsdiv" => const @{const_name sdiv}
boehmes@34068
   128
        | "bvsrem" => const @{const_name srem}
boehmes@34068
   129
        | "bvshl" => const @{const_name bv_shl}
boehmes@34068
   130
        | "bvlshr" => const @{const_name bv_lshr}
boehmes@34068
   131
        | "bvashr" => const @{const_name bv_ashr}
boehmes@34068
   132
        | "bvult" => const @{const_name less}
boehmes@34068
   133
        | "bvule" => const @{const_name less_eq}
boehmes@34068
   134
        | "bvugt" => const2_abs @{const_name less}
boehmes@34068
   135
        | "bvuge" => const2_abs @{const_name less_eq}
boehmes@34068
   136
        | "bvslt" => const @{const_name word_sless}
boehmes@34068
   137
        | "bvsle" => const @{const_name word_sle}
boehmes@34068
   138
        | "bvsgt" => const2_abs @{const_name word_sless}
boehmes@34068
   139
        | "bvsge" => const2_abs @{const_name word_sle}
boehmes@34068
   140
        | "zero_extend" => const @{const_name ucast}
boehmes@34068
   141
        | "sign_extend" => const @{const_name scast}
boehmes@33408
   142
        | _ => NONE)
boehmes@33408
   143
boehmes@33408
   144
      fun is_builtin att =
boehmes@33408
   145
        (case att of
boehmes@33408
   146
          ("bvbuiltin", [StringValue builtin]) => choose builtin
boehmes@33408
   147
        | ("bvint", [StringValue "ITE"]) => const @{const_name If}
boehmes@33408
   148
        | _ => NONE)
boehmes@33408
   149
    in get_first is_builtin end
boehmes@33408
   150
boehmes@33408
   151
  fun lookup_const thy name T =
boehmes@33458
   152
    let val intern = Sign.intern_const thy name
boehmes@33408
   153
    in
boehmes@33408
   154
      if Sign.declared_const thy intern
boehmes@33408
   155
      then
boehmes@33458
   156
        if Sign.typ_instance thy (T, Sign.the_const_type thy intern)
boehmes@33408
   157
        then SOME (Const (intern, T))
boehmes@33408
   158
        else error ("Boogie: function already declared with different type: " ^
boehmes@33408
   159
          quote name)
boehmes@33408
   160
      else NONE
boehmes@33408
   161
    end
boehmes@33408
   162
boehmes@34002
   163
  fun log_term thy t = Syntax.string_of_term_global thy t
boehmes@34002
   164
  fun log_new thy name t = name ^ " (as " ^ log_term thy t ^ ")"
boehmes@34002
   165
  fun log_ex thy name t = "[" ^ name ^ " has already been declared as " ^
boehmes@34002
   166
    log_term thy t ^ "]"
boehmes@34002
   167
  fun log_builtin thy name t = "[" ^ name ^ " has been identified as " ^
boehmes@34002
   168
    log_term thy t ^ "]"
boehmes@33408
   169
boehmes@34002
   170
  fun declare' name isa_name T arity atts thy =
boehmes@34002
   171
    (case lookup_const thy isa_name T of
boehmes@34002
   172
      SOME t => (((name, t), log_ex thy name t), thy)
boehmes@34002
   173
    | NONE =>
boehmes@34002
   174
        (case maybe_builtin T atts of
boehmes@34002
   175
          SOME t => (((name, t), log_builtin thy name t), thy)
boehmes@34002
   176
        | NONE =>
boehmes@34002
   177
            thy
boehmes@34002
   178
            |> Sign.declare_const ((Binding.name isa_name, T),
boehmes@34002
   179
                 mk_syntax name arity)
boehmes@34002
   180
            |> (fn (t, thy') => (((name, t), log_new thy' name t), thy'))))
boehmes@34002
   181
  fun declare (name, ((Ts, T), atts)) =
boehmes@34002
   182
    declare' name (isabelle_name name) (Ts ---> T) (length Ts) atts
boehmes@33893
   183
boehmes@33893
   184
  fun uniques fns fds =
boehmes@33893
   185
    let
boehmes@34068
   186
      fun is_unique (name, (([], _), atts)) =
boehmes@33893
   187
            (case AList.lookup (op =) atts "unique" of
boehmes@33893
   188
              SOME _ => Symtab.lookup fds name
boehmes@33893
   189
            | NONE => NONE)
boehmes@33893
   190
        | is_unique _ = NONE
boehmes@33893
   191
      fun mk_unique_axiom T ts =
boehmes@33893
   192
        Const (@{const_name distinct}, HOLogic.listT T --> @{typ bool}) $
boehmes@33893
   193
          HOLogic.mk_list T ts
boehmes@33893
   194
    in
boehmes@33893
   195
      map_filter is_unique fns
boehmes@33893
   196
      |> map (swap o Term.dest_Const)
boehmes@33893
   197
      |> AList.group (op =)
boehmes@33893
   198
      |> map (fn (T, ns) => mk_unique_axiom T (map (Const o rpair T) ns))
boehmes@33893
   199
    end
boehmes@33408
   200
in
boehmes@33408
   201
fun declare_functions verbose fns =
boehmes@34002
   202
  fold_map declare fns #>> split_list #-> (fn (fds, logs) =>
boehmes@34002
   203
  log verbose "Loaded constants:" logs #>
boehmes@34002
   204
  rpair (` (uniques fns) (Symtab.make fds)))
boehmes@33408
   205
end
boehmes@33408
   206
boehmes@33408
   207
boehmes@33408
   208
boehmes@33408
   209
local
boehmes@33408
   210
  fun name_axioms axs =
boehmes@33408
   211
    let fun mk_name idx = "axiom_" ^ string_of_int (idx + 1)
boehmes@33408
   212
    in map_index (fn (idx, t) => (mk_name idx, HOLogic.mk_Trueprop t)) axs end
boehmes@33408
   213
boehmes@34002
   214
  datatype kind = Unused of thm | Used of thm | New of string
boehmes@34002
   215
boehmes@34002
   216
  fun mark (name, t) axs =
boehmes@34002
   217
    (case Termtab.lookup axs t of
boehmes@34002
   218
      SOME (Unused thm) => Termtab.update (t, Used thm) axs
boehmes@34002
   219
    | NONE => Termtab.update (t, New name) axs
boehmes@34002
   220
    | SOME _ => axs)
boehmes@34002
   221
boehmes@34002
   222
  val sort_fst_str = sort (prod_ord fast_string_ord (K EQUAL)) 
boehmes@34002
   223
  fun split_list_kind thy axs =
boehmes@34002
   224
    let
boehmes@34002
   225
      fun split (_, Used thm) (used, new) = (thm :: used, new)
boehmes@34002
   226
        | split (t, New name) (used, new) = (used, (name, t) :: new)
boehmes@34068
   227
        | split (_, Unused thm) (used, new) =
boehmes@34002
   228
           (warning (Pretty.str_of
boehmes@34002
   229
             (Pretty.big_list "This background axiom has not been loaded:"
boehmes@34002
   230
               [Display.pretty_thm_global thy thm]));
boehmes@34002
   231
            (used, new))
boehmes@34002
   232
    in apsnd sort_fst_str (fold split axs ([], [])) end
boehmes@34002
   233
boehmes@34002
   234
  fun mark_axioms thy axs =
boehmes@34002
   235
    Boogie_Axioms.get (ProofContext.init thy)
boehmes@34002
   236
    |> Termtab.make o map (fn thm => (Thm.prop_of thm, Unused thm))
boehmes@34002
   237
    |> fold mark axs
boehmes@34002
   238
    |> split_list_kind thy o Termtab.dest
boehmes@33408
   239
in
boehmes@33408
   240
fun add_axioms verbose axs thy =
boehmes@34002
   241
  let val (used, new) = mark_axioms thy (name_axioms axs)
boehmes@33408
   242
  in
boehmes@33408
   243
    thy
boehmes@34002
   244
    |> PureThy.add_axioms (map (rpair [] o apfst Binding.name) new)
boehmes@33408
   245
    |-> Context.theory_map o fold Boogie_Axioms.add_thm
boehmes@34002
   246
    |> log verbose "The following axioms were added:" (map fst new)
boehmes@34002
   247
    |> (fn thy' => log verbose "The following axioms already existed:"
boehmes@34002
   248
         (map (Display.string_of_thm_global thy') used) thy')
boehmes@33408
   249
  end
boehmes@33408
   250
end
boehmes@33408
   251
boehmes@33408
   252
boehmes@33408
   253
boehmes@33441
   254
local
boehmes@33441
   255
  fun burrow_distinct eq f xs =
boehmes@33441
   256
    let
boehmes@33441
   257
      val ys = distinct eq xs
boehmes@33441
   258
      val tab = ys ~~ f ys
boehmes@33441
   259
    in map (the o AList.lookup eq tab) xs end
boehmes@33441
   260
boehmes@33441
   261
  fun indexed names =
boehmes@33441
   262
    let
boehmes@33441
   263
      val dup = member (op =) (duplicates (op =) (map fst names))
boehmes@33441
   264
      fun make_name (n, i) = n ^ (if dup n then "_" ^ string_of_int i else "")
boehmes@33441
   265
    in map make_name names end
boehmes@33441
   266
boehmes@33441
   267
  fun rename idx_names =
boehmes@33441
   268
    idx_names
boehmes@33441
   269
    |> burrow_fst (burrow_distinct (op =)
boehmes@33441
   270
         (map short_name #> ` (duplicates (op =)) #-> Name.variant_list))
boehmes@33441
   271
    |> indexed
boehmes@33441
   272
in
boehmes@33408
   273
fun add_vcs verbose vcs thy =
boehmes@34068
   274
  let val vcs' = burrow_fst rename vcs
boehmes@33408
   275
  in
boehmes@33408
   276
    thy
boehmes@33408
   277
    |> Boogie_VCs.set vcs'
boehmes@33408
   278
    |> log verbose "The following verification conditions were loaded:"
boehmes@33408
   279
         (map fst vcs')
boehmes@33408
   280
  end
boehmes@33441
   281
end
boehmes@33408
   282
boehmes@33408
   283
boehmes@33408
   284
boehmes@33408
   285
local
boehmes@33408
   286
  fun mk_bitT i T =
boehmes@33408
   287
    if i = 0
boehmes@33408
   288
    then Type (@{type_name "Numeral_Type.bit0"}, [T])
boehmes@33408
   289
    else Type (@{type_name "Numeral_Type.bit1"}, [T])
boehmes@33408
   290
boehmes@33408
   291
  fun mk_binT size = 
boehmes@33408
   292
    if size = 0 then @{typ "Numeral_Type.num0"}
boehmes@33408
   293
    else if size = 1 then @{typ "Numeral_Type.num1"}
boehmes@33408
   294
    else let val (q, r) = Integer.div_mod size 2 in mk_bitT r (mk_binT q) end
boehmes@33408
   295
in
boehmes@33408
   296
fun mk_wordT size =
boehmes@33408
   297
  if size >= 0 then Type (@{type_name "word"}, [mk_binT size])
boehmes@33408
   298
  else raise TYPE ("mk_wordT: " ^ quote (string_of_int size), [], [])
boehmes@33408
   299
end
boehmes@33408
   300
boehmes@33408
   301
local
boehmes@33408
   302
  fun dest_binT T =
boehmes@33408
   303
    (case T of
boehmes@33408
   304
      Type (@{type_name "Numeral_Type.num0"}, _) => 0
boehmes@33408
   305
    | Type (@{type_name "Numeral_Type.num1"}, _) => 1
boehmes@33408
   306
    | Type (@{type_name "Numeral_Type.bit0"}, [T]) => 2 * dest_binT T
boehmes@33408
   307
    | Type (@{type_name "Numeral_Type.bit1"}, [T]) => 1 + 2 * dest_binT T
boehmes@33408
   308
    | _ => raise TYPE ("dest_binT", [T], []))
boehmes@33408
   309
in
boehmes@33408
   310
val dest_wordT = (fn
boehmes@33408
   311
    Type (@{type_name "word"}, [T]) => dest_binT T
boehmes@33408
   312
  | T => raise TYPE ("dest_wordT", [T], []))
boehmes@33408
   313
end
boehmes@33408
   314
boehmes@33408
   315
fun mk_arrayT (Ts, T) = Type (@{type_name "fun"}, [HOLogic.mk_tupleT Ts, T])
boehmes@33408
   316
boehmes@33408
   317
boehmes@33408
   318
boehmes@33408
   319
datatype token = Token of string | Newline | EOF
boehmes@33408
   320
boehmes@33408
   321
fun tokenize path =
boehmes@33408
   322
  let
boehmes@33408
   323
    fun blank c = (c = #" " orelse c = #"\t" orelse c = #"\n" orelse c = #"\r")
boehmes@33408
   324
    fun split line (i, tss) = (i + 1,
boehmes@33408
   325
      map (pair i) (map Token (String.tokens blank line) @ [Newline]) :: tss)
boehmes@33408
   326
  in apsnd (flat o rev) (File.fold_lines split path (1, [])) end
boehmes@33408
   327
boehmes@33408
   328
fun stopper i = Scan.stopper (K (i, EOF)) (fn (_, EOF) => true | _ => false)
boehmes@33408
   329
boehmes@33408
   330
fun scan_err msg [] = "Boogie (at end of input): " ^ msg
boehmes@33408
   331
  | scan_err msg ((i, _) :: _) = "Boogie (at line " ^ string_of_int i ^ "): " ^
boehmes@33408
   332
      msg
boehmes@33408
   333
boehmes@33408
   334
fun scan_fail msg = Scan.fail_with (scan_err msg)
boehmes@33408
   335
boehmes@33408
   336
fun finite scan path =
boehmes@33408
   337
  let val (i, ts) = tokenize path
boehmes@33408
   338
  in
boehmes@33408
   339
    (case Scan.error (Scan.finite (stopper i) scan) ts of
boehmes@33408
   340
      (x, []) => x
boehmes@33408
   341
    | (_, ts) => error (scan_err "unparsed input" ts))
boehmes@33408
   342
  end
boehmes@33408
   343
boehmes@33408
   344
fun read_int' s = (case read_int (explode s) of (i, []) => SOME i | _ => NONE)
boehmes@33408
   345
boehmes@33408
   346
fun $$$ s = Scan.one (fn (_, Token s') => s = s' | _ => false)
boehmes@33497
   347
fun str st = Scan.some (fn (_, Token s) => SOME s | _ => NONE) st
boehmes@33497
   348
fun num st = Scan.some (fn (_, Token s) => read_int' s | _ => NONE) st
boehmes@33408
   349
boehmes@33408
   350
fun scan_line key scan =
boehmes@33408
   351
  $$$ key |-- scan --| Scan.one (fn (_, Newline) => true | _ => false)
boehmes@33408
   352
fun scan_line' key = scan_line key (Scan.succeed ())
boehmes@33408
   353
boehmes@33408
   354
fun scan_count scan i =
boehmes@33408
   355
  if i > 0 then scan ::: scan_count scan (i - 1) else Scan.succeed []
boehmes@33408
   356
boehmes@33408
   357
fun scan_lookup kind tab key =
boehmes@33408
   358
  (case Symtab.lookup tab key of
boehmes@33408
   359
    SOME value => Scan.succeed value
boehmes@33408
   360
  | NONE => scan_fail ("undefined " ^ kind ^ ": " ^ quote key))
boehmes@33408
   361
boehmes@33408
   362
fun typ tds =
boehmes@33408
   363
  let
boehmes@33408
   364
    fun tp st =
boehmes@33408
   365
     (scan_line' "bool" >> K @{typ bool} ||
boehmes@33408
   366
      scan_line' "int" >> K @{typ int} ||
boehmes@33408
   367
      scan_line "bv" num >> mk_wordT ||
boehmes@33408
   368
      scan_line "type-con" (str -- num) :|-- (fn (name, arity) =>
boehmes@33408
   369
        scan_lookup "type constructor" tds name -- scan_count tp arity >>
boehmes@33408
   370
        Type) ||
boehmes@33408
   371
      scan_line "array" num :|-- (fn arity =>
boehmes@33408
   372
        scan_count tp (arity - 1) -- tp >> mk_arrayT) ||
boehmes@33408
   373
      scan_fail "illegal type") st
boehmes@33408
   374
  in tp end
boehmes@33408
   375
boehmes@33408
   376
local
boehmes@33408
   377
  fun mk_nary _ t [] = t
boehmes@33661
   378
    | mk_nary f _ ts = uncurry (fold_rev f) (split_last ts)
boehmes@33408
   379
boehmes@33408
   380
  fun mk_distinct T ts =
boehmes@33408
   381
    Const (@{const_name distinct}, HOLogic.listT T --> @{typ bool}) $ 
boehmes@33408
   382
      HOLogic.mk_list T ts
boehmes@33408
   383
boehmes@33408
   384
  fun quant name f = scan_line name (num -- num -- num) >> pair f
boehmes@33408
   385
  val quants =
boehmes@33408
   386
    quant "forall" HOLogic.all_const ||
boehmes@33408
   387
    quant "exists" HOLogic.exists_const ||
boehmes@33408
   388
    scan_fail "illegal quantifier kind"
boehmes@33441
   389
  fun mk_quant q (n, T) t = q T $ Term.absfree (n, T, t)
boehmes@33408
   390
boehmes@33408
   391
  val patternT = @{typ pattern}
boehmes@33408
   392
  fun mk_pattern _ [] = raise TERM ("mk_pattern", [])
boehmes@33408
   393
    | mk_pattern n [t] = Const (n, Term.fastype_of t --> patternT) $ t
boehmes@33408
   394
    | mk_pattern n (t :: ts) =
boehmes@33408
   395
        let val T = patternT --> Term.fastype_of t --> patternT
boehmes@33408
   396
        in Const (@{const_name andpat}, T) $ mk_pattern n ts $ t end
boehmes@33408
   397
  fun patt n c scan =
boehmes@33408
   398
    scan_line n num :|-- scan_count scan >> (mk_pattern c)
boehmes@33408
   399
  fun pattern scan =
boehmes@33408
   400
    patt "pat" @{const_name pat} scan ||
boehmes@33408
   401
    patt "nopat" @{const_name nopat} scan ||
boehmes@33408
   402
    scan_fail "illegal pattern kind"
boehmes@33408
   403
  fun mk_trigger [] t = t
boehmes@33408
   404
    | mk_trigger ps t = @{term trigger} $ HOLogic.mk_list patternT ps $ t
boehmes@33408
   405
boehmes@34068
   406
  fun make_label (line, col) = Free (label_name line col, @{typ bool})
boehmes@34068
   407
  fun labelled_by kind pos t = kind $ make_label pos $ t
boehmes@35125
   408
  fun label offset =
boehmes@35125
   409
    $$$ "pos" |-- num -- num >> (fn (line, col) =>
boehmes@34068
   410
      if label_name line col = no_label_name then I
boehmes@35125
   411
      else labelled_by @{term block_at} (line - offset, col)) ||
boehmes@35125
   412
    $$$ "neg" |-- num -- num >> (fn (line, col) =>
boehmes@35125
   413
      labelled_by @{term assert_at} (line - offset, col)) ||
boehmes@33408
   414
    scan_fail "illegal label kind"
boehmes@33408
   415
boehmes@33408
   416
  fun mk_store ((m, k), v) =
boehmes@33408
   417
    let
boehmes@33408
   418
      val mT = Term.fastype_of m and kT = Term.fastype_of k
boehmes@33408
   419
      val vT = Term.fastype_of v
boehmes@34068
   420
    in Const (@{const_name fun_upd}, mT --> kT --> vT --> mT) $ m $ k $ v end
boehmes@33408
   421
  
boehmes@33408
   422
  fun mk_extract ((msb, lsb), t) =
boehmes@33408
   423
    let
boehmes@33408
   424
      val dT = Term.fastype_of t and rT = mk_wordT (msb - lsb)
boehmes@33408
   425
      val nT = @{typ nat}
boehmes@33408
   426
      val mk_nat_num = HOLogic.mk_number @{typ nat}
boehmes@34068
   427
    in Const (@{const_name slice}, [nT, dT] ---> rT) $ mk_nat_num lsb $ t end
boehmes@33408
   428
boehmes@33408
   429
  fun mk_concat (t1, t2) =
boehmes@33408
   430
    let
boehmes@33408
   431
      val T1 = Term.fastype_of t1 and T2 = Term.fastype_of t2
boehmes@33408
   432
      val U = mk_wordT (dest_wordT T1 + dest_wordT T2)
boehmes@34068
   433
    in Const (@{const_name word_cat}, [T1, T2] ---> U) $ t1 $ t2 end
boehmes@33441
   434
boehmes@34068
   435
  fun unique_labels t =
boehmes@34068
   436
    let
boehmes@34068
   437
      fun names_of (@{term assert_at} $ Free (n, _) $ t) = cons n #> names_of t
boehmes@34068
   438
        | names_of (t $ u) = names_of t #> names_of u
boehmes@34068
   439
        | names_of (Abs (_, _, t)) = names_of t
boehmes@34068
   440
        | names_of _ = I
boehmes@34068
   441
      val nctxt = Name.make_context (duplicates (op =) (names_of t []))
boehmes@34068
   442
boehmes@34068
   443
      fun fresh (i, nctxt) = (position_prefix ^ string_of_int i, (i+1, nctxt))
boehmes@34068
   444
      fun renamed n (i, nctxt) =
boehmes@34068
   445
        yield_singleton Name.variants n nctxt ||> pair i
boehmes@34068
   446
      fun mk_label (name, t) = @{term assert_at} $ Free (name, @{typ bool}) $ t
boehmes@34068
   447
boehmes@34068
   448
      fun unique t =
boehmes@34068
   449
        (case t of
boehmes@34068
   450
          @{term assert_at} $ Free (n, _) $ u =>
boehmes@34068
   451
            if n = no_label_name
boehmes@34068
   452
            then fresh ##>> unique u #>> mk_label
boehmes@34068
   453
            else renamed n ##>> unique u #>> mk_label
boehmes@34068
   454
        | u1 $ u2 => unique u1 ##>> unique u2 #>> (op $)
boehmes@34068
   455
        | Abs (n, T, u) => unique u #>> (fn u' => Abs (n, T, u'))
boehmes@34068
   456
        | _ => pair t)
boehmes@34068
   457
    in fst (unique t (1, nctxt)) end
boehmes@34068
   458
boehmes@34068
   459
  val var_name = str >> prefix var_prefix
boehmes@34068
   460
  val dest_var_name = unprefix var_prefix
boehmes@33441
   461
  fun rename_variables t =
boehmes@33441
   462
    let
boehmes@33441
   463
      fun short_var_name n = short_name (dest_var_name n)
boehmes@33441
   464
boehmes@34068
   465
      val all_names = Term.add_free_names t []
boehmes@33441
   466
      val (names, nctxt) =
boehmes@34068
   467
        all_names
boehmes@33441
   468
        |> map_filter (try (fn n => (n, short_var_name n)))
boehmes@33441
   469
        |> split_list
boehmes@34068
   470
        ||>> (fn names => Name.variants names (Name.make_context all_names))
boehmes@33441
   471
        |>> Symtab.make o (op ~~)
boehmes@33441
   472
boehmes@33441
   473
      fun rename_free n = the_default n (Symtab.lookup names n)
boehmes@33441
   474
      fun rename_abs n = yield_singleton Name.variants (short_var_name n)
boehmes@33441
   475
boehmes@33441
   476
      fun rename _ (Free (n, T)) = Free (rename_free n, T)
boehmes@33441
   477
        | rename nctxt (Abs (n, T, t)) =
boehmes@33441
   478
            let val (n', nctxt') = rename_abs n nctxt
boehmes@33441
   479
            in Abs (n', T, rename nctxt' t) end
boehmes@33441
   480
        | rename nctxt (t $ u) = rename nctxt t $ rename nctxt u
boehmes@33441
   481
        | rename _ t = t
boehmes@33441
   482
    in rename nctxt t end
boehmes@33408
   483
in
boehmes@35125
   484
fun expr offset tds fds =
boehmes@33408
   485
  let
boehmes@33408
   486
    fun binop t (u1, u2) = t $ u1 $ u2
boehmes@33408
   487
    fun binexp s f = scan_line' s |-- exp -- exp >> f
boehmes@33408
   488
boehmes@33408
   489
    and exp st =
boehmes@33408
   490
     (scan_line' "true" >> K @{term True} ||
boehmes@33408
   491
      scan_line' "false" >> K @{term False} ||
boehmes@33408
   492
      scan_line' "not" |-- exp >> HOLogic.mk_not ||
boehmes@33408
   493
      scan_line "and" num :|-- scan_count exp >> 
boehmes@33408
   494
        mk_nary (curry HOLogic.mk_conj) @{term True} ||
boehmes@33408
   495
      scan_line "or" num :|-- scan_count exp >>
boehmes@33408
   496
        mk_nary (curry HOLogic.mk_disj) @{term False} ||
boehmes@33408
   497
      binexp "implies" (binop @{term "op -->"}) ||
boehmes@33408
   498
      scan_line "distinct" num :|-- scan_count exp >>
boehmes@33408
   499
        (fn [] => @{term True}
boehmes@33408
   500
          | ts as (t :: _) => mk_distinct (Term.fastype_of t) ts) ||
boehmes@33408
   501
      binexp "=" HOLogic.mk_eq ||
boehmes@33441
   502
      scan_line "var" var_name -- typ tds >> Free ||
boehmes@33408
   503
      scan_line "fun" (str -- num) :|-- (fn (name, arity) =>
boehmes@33408
   504
        scan_lookup "constant" fds name -- scan_count exp arity >>
boehmes@33408
   505
        Term.list_comb) ||
boehmes@33408
   506
      quants :|-- (fn (q, ((n, k), i)) =>
boehmes@33441
   507
        scan_count (scan_line "var" var_name -- typ tds) n --
boehmes@33408
   508
        scan_count (pattern exp) k --
boehmes@35125
   509
        scan_count (attribute offset tds fds) i --
boehmes@33408
   510
        exp >> (fn (((vs, ps), _), t) =>
boehmes@33408
   511
          fold_rev (mk_quant q) vs (mk_trigger ps t))) ||
boehmes@35125
   512
      scan_line "label" (label offset) -- exp >> (fn (mk, t) => mk t) ||
boehmes@33408
   513
      scan_line "int-num" num >> HOLogic.mk_number @{typ int} ||
boehmes@33408
   514
      binexp "<" (binop @{term "op < :: int => _"}) ||
boehmes@33408
   515
      binexp "<=" (binop @{term "op <= :: int => _"}) ||
boehmes@33408
   516
      binexp ">" (binop @{term "op < :: int => _"} o swap) ||
boehmes@33408
   517
      binexp ">=" (binop @{term "op <= :: int => _"} o swap) ||
boehmes@33408
   518
      binexp "+" (binop @{term "op + :: int => _"}) ||
boehmes@33661
   519
      binexp "-" (binop @{term "op - :: int => _"}) ||
boehmes@33661
   520
      binexp "*" (binop @{term "op * :: int => _"}) ||
boehmes@33408
   521
      binexp "/" (binop @{term boogie_div}) ||
boehmes@33408
   522
      binexp "%" (binop @{term boogie_mod}) ||
boehmes@33408
   523
      scan_line "select" num :|-- (fn arity =>
boehmes@34068
   524
        exp -- (scan_count exp (arity - 1) >> HOLogic.mk_tuple) >> (op $)) ||
boehmes@33408
   525
      scan_line "store" num :|-- (fn arity =>
boehmes@33408
   526
        exp -- (scan_count exp (arity - 2) >> HOLogic.mk_tuple) -- exp >> 
boehmes@33408
   527
          mk_store) ||
boehmes@33408
   528
      scan_line "bv-num" (num -- num) >> (fn (size, i) =>
boehmes@33408
   529
        HOLogic.mk_number (mk_wordT size) i) ||
boehmes@33408
   530
      scan_line "bv-extract" (num -- num) -- exp >> mk_extract ||
boehmes@33408
   531
      binexp "bv-concat" mk_concat ||
boehmes@33408
   532
      scan_fail "illegal expression") st
boehmes@34068
   533
  in exp >> (rename_variables o unique_labels) end
boehmes@33408
   534
boehmes@35125
   535
and attribute offset tds fds =
boehmes@33408
   536
  let
boehmes@33408
   537
    val attr_val = 
boehmes@35125
   538
      scan_line' "expr-attr" |-- expr offset tds fds >> TermValue ||
boehmes@33408
   539
      scan_line "string-attr" (Scan.repeat1 str) >>
boehmes@33408
   540
        (StringValue o space_implode " ") ||
boehmes@33408
   541
      scan_fail "illegal attribute value"
boehmes@33408
   542
  in
boehmes@33408
   543
    scan_line "attribute" (str -- num) :|-- (fn (name, i) =>
boehmes@33408
   544
      scan_count attr_val i >> pair name) ||
boehmes@33408
   545
    scan_fail "illegal attribute"
boehmes@33408
   546
  end
boehmes@33408
   547
end
boehmes@33408
   548
boehmes@33408
   549
fun type_decls verbose = Scan.depend (fn thy => 
boehmes@33408
   550
  Scan.repeat (scan_line "type-decl" (str -- num -- num) :|-- (fn (ty, i) =>
boehmes@35125
   551
    scan_count (attribute 0 Symtab.empty Symtab.empty) i >> K ty)) >>
boehmes@33408
   552
    (fn tys => declare_types verbose tys thy))
boehmes@33408
   553
boehmes@33408
   554
fun fun_decls verbose tds = Scan.depend (fn thy =>
boehmes@33408
   555
  Scan.repeat (scan_line "fun-decl" (str -- num -- num) :|--
boehmes@33408
   556
    (fn ((name, arity), i) =>
boehmes@33408
   557
      scan_count (typ tds) (arity - 1) -- typ tds --
boehmes@35125
   558
      scan_count (attribute 0 tds Symtab.empty) i >> pair name)) >>
boehmes@33408
   559
    (fn fns => declare_functions verbose fns thy))
boehmes@33408
   560
boehmes@33893
   561
fun axioms verbose tds fds unique_axs = Scan.depend (fn thy =>
boehmes@33408
   562
  Scan.repeat (scan_line "axiom" num :|-- (fn i =>
boehmes@35125
   563
    expr 0 tds fds --| scan_count (attribute 0 tds fds) i)) >>
boehmes@33893
   564
    (fn axs => (add_axioms verbose (unique_axs @ axs) thy, ())))
boehmes@33408
   565
boehmes@33408
   566
fun var_decls tds fds = Scan.depend (fn thy =>
boehmes@33408
   567
  Scan.repeat (scan_line "var-decl" (str -- num) :|-- (fn (_, i) =>
boehmes@35125
   568
    typ tds -- scan_count (attribute 0 tds fds) i >> K ())) >> K (thy, ()))
boehmes@33408
   569
boehmes@35125
   570
fun local_vc_offset offsets vc_name =
boehmes@35125
   571
   Integer.add ~1 (the_default 1 (AList.lookup (op =) offsets vc_name))
boehmes@33408
   572
boehmes@35125
   573
fun vcs verbose offsets tds fds = Scan.depend (fn thy =>
boehmes@35125
   574
  Scan.repeat (scan_line "vc" (str -- num) :-- (fn (name, _) =>
boehmes@35125
   575
    (expr (local_vc_offset offsets name) tds fds))) >> 
boehmes@35125
   576
    (fn vcs => ((), add_vcs verbose vcs thy)))
boehmes@35125
   577
boehmes@35125
   578
fun parse verbose offsets thy = Scan.pass thy
boehmes@33408
   579
 (type_decls verbose :|-- (fn tds =>
boehmes@33893
   580
  fun_decls verbose tds :|-- (fn (unique_axs, fds) =>
boehmes@33893
   581
  axioms verbose tds fds unique_axs |--
boehmes@33408
   582
  var_decls tds fds |--
boehmes@35125
   583
  vcs verbose offsets tds fds)))
boehmes@33408
   584
boehmes@35125
   585
fun load_b2i verbose offsets path thy = finite (parse verbose offsets thy) path
boehmes@33408
   586
boehmes@33408
   587
end