src/Tools/isac/BridgeJEdit/Calculation.thy
author Walther Neuper <walther.neuper@jku.at>
Fri, 27 Nov 2020 16:53:08 +0100
changeset 60114 307fe00bbfc9
parent 60113 2fdf32b16c44
child 60115 1613406ad3f3
permissions -rw-r--r--
integration 3: push new code down to storing by Theory_Data
     1 (*  Title:      src/Tools/isac/BridgeJEdit/Calculation.thy
     2     Author:     Walther Neuper, JKU Linz
     3     (c) due to copyright terms
     4 
     5 Outer syntax for Isabelle/Isac. Compare src/Pure/Pure.thy
     6 *)
     7 
     8 theory Calculation
     9   imports "~~/src/Tools/isac/MathEngine/MathEngine" "HOL-SPARK.SPARK"
    10 keywords
    11   "Example" :: thy_load ("str") and (* "spark_vc" :: thy_goal *)
    12   "Problem" and (* root-problem + recursively in Solution *)
    13   "Specification" "Model" "References" "Solution" and (* structure only *)
    14   "Given" "Find" "Relate" "Where" and (* await input of term *)
    15   "RTheory" (* await input of string; "R" distingues "Problem".."RProblem" *)
    16   "RProblem" "RMethod" and (* await input of string list *)
    17   "Tactic" (* optional for each step 0..end of calculation *)
    18 begin
    19 
    20 ML_file parseC.sml
    21 ML_file "~~/test/HOL/SPARK/test-data.sml" (*..:*)ML \<open>g_c_d_siv_content\<close>
    22 
    23 ML \<open>
    24 \<close> ML \<open>
    25 \<close> ML \<open>
    26 \<close> ML \<open>
    27 \<close>
    28 
    29 section \<open>code for spark_open: cp.to cp_spark_vcs.ML, cp_spark_vcs.ML\<close>
    30 text \<open>
    31   We minimally change code for Example, until all works.
    32 
    33   The code is separated from Calculation.thy into files cp_spark_vcs.ML and cp_spark_commands.ML, 
    34   because text\<open>...\<close> and (*...*) for const_name>\<open>...\<close> etc and @ {thms ...} causes errors.
    35 
    36   Thus for Test_Isac (**)ML_file "cp_spark_vcs.ML", ""(*cp_spark_commands.ML*), "HOL-SPARK.SPARK"
    37   must be outcommented.
    38 \<close>
    39 
    40 subsection \<open>cp. HOL/SPARK/Tools/spark_vcs.ML\<close>
    41 ML \<open>
    42 \<close> ML \<open>
    43 (*  Title:      src/Tools/isac/BridgeJEdit/cp_spark_vcs.ML
    44     Author:     Walther Neuper, JKU Linz
    45     (c) due to copyright terms
    46 
    47 Preliminary code for developing Outer_Syntax.command..Example from spark_open as a model.
    48 The original signatures from this subsection are:
    49 *)
    50 signature SPARK_VCS_PARTIALLY =
    51 sig
    52   val err_unfinished: unit -> 'a
    53   val strip_number: string -> string * string
    54   val name_ord: string * string -> order
    55   structure VCtab: TABLE
    56   structure VCs: THEORY_DATA
    57   val to_lower: string -> string
    58   val partition_opt: ('a -> 'b option) -> 'a list -> 'b list * 'a list
    59   val dest_def: 'a * Fdl_Parser.fdl_rule -> ('a * (string * Fdl_Parser.expr)) option
    60   val builtin: unit Symtab.table
    61   val complex_expr: Fdl_Parser.expr -> bool
    62   val complex_rule: Fdl_Parser.fdl_rule -> bool
    63   val is_trivial_vc: 'a list * ('b * Fdl_Parser.expr) list -> bool
    64   val rulenames: ((string * int) * 'a) list -> string
    65   val is_pfun: Symtab.key -> bool
    66   val fold_opt: ('a -> 'b -> 'b) -> 'a option -> 'b -> 'b
    67   val fold_pair: ('a -> 'b -> 'c) -> ('d -> 'c -> 'e) -> 'a * 'd -> 'b -> 'e
    68   val fold_expr: (string -> 'a -> 'a) -> (string -> 'a -> 'a) -> Fdl_Parser.expr -> 'a -> 'a
    69   val add_expr_pfuns: 'a Fdl_Parser.tab -> Fdl_Parser.expr -> Symtab.key list -> Symtab.key list
    70   val lookup_prfx: string -> 'a Symtab.table -> Symtab.key -> 'a option
    71   val fold_vcs: ('a -> 'b -> 'b) -> ('c * 'd * 'a list * 'a list) VCtab.table -> 'b -> 'b
    72   val pfuns_of_vcs: string -> 'a Fdl_Parser.tab -> 'b Symtab.table -> ('c * 'd * ('e * Fdl_Parser.expr) list * ('e * Fdl_Parser.expr) list) VCtab.table -> Symtab.key list
    73   val booleanN: string
    74   val integerN: string
    75   val get_type: theory -> string -> Symtab.key -> (typ * (string * string) list) option
    76   val mk_type': theory -> string -> string -> typ * (string * string) list
    77   val mk_type: theory -> string -> string -> typ
    78   val check_no_assoc: theory -> string -> string -> unit
    79   val define_overloaded: bstring * term -> Proof.context -> thm * local_theory
    80   val add_enum_type: string -> string -> theory -> theory
    81   val lcase_eq: string * string -> bool
    82   val check_enum: string list -> (string * 'a) list -> string option
    83   val strip_prfx: string -> string * string
    84   val assoc_ty_err: theory -> typ -> string -> string -> 'a
    85   val unprefix_pfun: string -> string -> string
    86   val invert_map: (''a * ''a) list -> (''a * 'b) list -> (''a * 'b) list
    87   val get_record_info: theory -> typ -> Record.info option
    88   val add_type_def: string -> string * Fdl_Parser.fdl_type -> ((term * bstring) Symtab.table * Name.context) * theory -> ((term * bstring) Symtab.table * Name.context) * theory
    89   val add_const: string -> bstring * string -> ((term * string) Symtab.table * Name.context) * theory -> term * (((term * string) Symtab.table * Name.context) * theory)
    90   val mk_unop: string -> term -> term
    91   val strip_underscores: string -> string
    92   val strip_tilde: string -> string
    93   val mangle_name: string -> string
    94   val mk_variables: theory -> string -> string list -> string -> (term * string) Symtab.table * Name.context -> term list * ((term * string) Symtab.table * Name.context)
    95   val find_field: (string * string) list -> string -> (string * 'a) list -> (string * 'a) option
    96   val find_field': ''a -> (''a list * 'b) list -> 'b option
    97   val mk_times: term * term -> term
    98   val term_of_expr: theory -> string -> Fdl_Parser.fdl_type Fdl_Parser.tab -> (('a list * string) option * term) Symtab.table -> (term * string) Symtab.table * Name.context -> Fdl_Parser.expr -> term * string
    99   val mk_rulename: string * int -> binding
   100   val add_def:
   101      string ->
   102        Fdl_Parser.fdl_type Fdl_Parser.tab ->
   103          (('a list * string) option * term) Symtab.table ->
   104            string Fdl_Parser.tab -> (string * int) * (string * Fdl_Parser.expr) -> ((term * string) Symtab.table * Name.context) * theory -> (binding * thm) * (((term * string) Symtab.table * Name.context) * theory)
   105   val add_expr_idents: Fdl_Parser.expr -> string list -> string list
   106   val sort_defs:
   107      string ->
   108        'a Fdl_Parser.tab ->
   109          'b Symtab.table -> (string -> bool) -> ((string * int) * (string * Fdl_Parser.expr)) list -> ((string * int) * (string * Fdl_Parser.expr)) list -> ((string * int) * (string * Fdl_Parser.expr)) list
   110   val add_var: string -> string * string -> ((term * string) Symtab.table * Name.context) * theory -> (string * typ) * (((term * string) Symtab.table * Name.context) * theory)
   111   val add_init_vars:
   112      string ->
   113        ('a * 'b * ('c * Fdl_Parser.expr) list * ('c * Fdl_Parser.expr) list) VCtab.table ->
   114          ((term * string) Symtab.table * Name.context) * theory -> (string * typ) list * (((term * string) Symtab.table * Name.context) * theory)
   115   val term_of_rule: theory -> string -> Fdl_Parser.fdl_type Fdl_Parser.tab -> (('a list * string) option * term) Symtab.table -> (term * string) Symtab.table * Name.context -> Fdl_Parser.fdl_rule -> term
   116   val pfun_type: theory -> string -> string list * string -> typ
   117   val check_pfun_type: theory -> string -> string -> term -> (string list * string) option -> (string list * string) option -> unit
   118   val upd_option: 'a option -> 'a option -> 'a option
   119   val check_pfuns_types: theory -> string -> (string list * string) Fdl_Parser.tab -> ((string list * string) option * term) Symtab.table -> ((string list * string) option * term) Symtab.table
   120   val pp_vcs: string -> (string * 'a) list -> Pretty.T
   121   val pp_open_vcs: (string * 'a) list -> Pretty.T
   122   val partition_vcs: ('a * 'b option * 'c * 'd) VCtab.table -> (VCtab.key * ('a * 'b * 'c * 'd)) list * (VCtab.key * ('a * 'c * 'd)) list
   123   val print_open_vcs: (Pretty.T -> Pretty.T) -> ('a * 'b option * 'c * 'd) VCtab.table -> ('a * 'b option * 'c * 'd) VCtab.table
   124 end
   125 
   126 (** theory data **)
   127 
   128 fun err_unfinished () = error "An unfinished SPARK environment is still open."
   129 
   130 val strip_number = apply2 implode o chop_suffix Fdl_Lexer.is_digit o raw_explode;
   131 
   132 val name_ord = prod_ord string_ord (option_ord int_ord) o
   133   apply2 (strip_number ##> Int.fromString);
   134 
   135 structure VCtab = Table(type key = string val ord = name_ord);
   136 
   137 structure VCs = Theory_Data
   138 (
   139   (*/----------------------------- this is stored in thy --------------------------------\*)
   140   type T = (*Pure/General/table.ML:             'a *)
   141     {pfuns: ((string list * string) option * term) Symtab.table,
   142      type_map: (typ * (string * string) list) Symtab.table,
   143      env:
   144        {ctxt: Element.context_i list,
   145         defs: (binding * thm) list,
   146         types: Fdl_Parser.fdl_type Fdl_Parser.tab,
   147         funs: (string list * string) Fdl_Parser.tab,
   148         pfuns: ((string list * string) option * term) Symtab.table,
   149         ids: (term * string) Symtab.table * Name.context,
   150         proving: bool,
   151         vcs: (string * thm list option *
   152           (string * Fdl_Parser.expr) list * (string * Fdl_Parser.expr) list) VCtab.table,
   153         path: Path.T,
   154         prefix: string} option}
   155   (*\----------------------------- this is stored in thy --------------------------------/*)
   156   val empty : T = {pfuns = Symtab.empty, type_map = Symtab.empty, env = NONE}
   157   val extend = I
   158   fun merge ({pfuns = pfuns1, type_map = type_map1, env = NONE},
   159         {pfuns = pfuns2, type_map = type_map2, env = NONE}) =
   160         {pfuns = Symtab.merge (eq_pair (op =) (op aconv)) (pfuns1, pfuns2),
   161          type_map = Symtab.merge (op =) (type_map1, type_map2),
   162          env = NONE}
   163     | merge _ = err_unfinished ()
   164 )
   165 
   166 (** utilities **)
   167 
   168 val to_lower = raw_explode #> map Symbol.to_ascii_lower #> implode;
   169 
   170 
   171 (** set up verification conditions **)
   172 
   173 fun partition_opt f =
   174   let
   175     fun part ys zs [] = (rev ys, rev zs)
   176       | part ys zs (x :: xs) = (case f x of
   177             SOME y => part (y :: ys) zs xs
   178           | NONE => part ys (x :: zs) xs)
   179   in part [] [] end;
   180 
   181 fun dest_def (id, (Fdl_Parser.Substitution_Rule ([], Fdl_Parser.Ident s, rhs))) = SOME (id, (s, rhs))
   182   | dest_def _ = NONE;
   183 
   184 
   185 val builtin = Symtab.make (map (rpair ())
   186   ["->", "<->", "or", "and", "not", "=", "<>", "<", ">", "<=", ">=",
   187    "+", "-", "*", "/", "div", "mod", "**"]);
   188 
   189 fun complex_expr (Fdl_Parser.Number _) = false
   190   | complex_expr (Fdl_Parser.Ident _) = false
   191   | complex_expr (Fdl_Parser.Funct (s, es)) =
   192       not (Symtab.defined builtin s) orelse exists complex_expr es
   193   | complex_expr (Fdl_Parser.Quantifier (_, _, _, e)) = complex_expr e
   194   | complex_expr _ = true;
   195 
   196 fun complex_rule (Fdl_Parser.Inference_Rule (es, e)) =
   197       complex_expr e orelse exists complex_expr es
   198   | complex_rule (Fdl_Parser.Substitution_Rule (es, e, e')) =
   199       complex_expr e orelse complex_expr e' orelse
   200       exists complex_expr es;
   201 
   202 fun is_trivial_vc ([], [(_, Fdl_Parser.Ident "true")]) = true
   203   | is_trivial_vc _ = false;
   204 
   205 
   206 fun rulenames rules = commas
   207   (map (fn ((s, i), _) => s ^ "(" ^ string_of_int i ^ ")") rules);
   208 
   209 
   210 val is_pfun =
   211   Symtab.defined builtin orf
   212   can (unprefix "fld_") orf can (unprefix "upf_") orf
   213   can (unsuffix "__pos") orf can (unsuffix "__val") orf
   214   equal "succ" orf equal "pred";
   215 
   216 fun fold_opt f = the_default I o Option.map f;
   217 fun fold_pair f g (x, y) = f x #> g y;
   218 
   219 fun fold_expr f g (Fdl_Parser.Funct (s, es)) = f s #> fold (fold_expr f g) es
   220   | fold_expr f g (Fdl_Parser.Ident s) = g s
   221   | fold_expr f g (Fdl_Parser.Number _) = I
   222   | fold_expr f g (Fdl_Parser.Quantifier (_, _, _, e)) = fold_expr f g e
   223   | fold_expr f g (Fdl_Parser.Element (e, es)) =
   224       fold_expr f g e #> fold (fold_expr f g) es
   225   | fold_expr f g (Fdl_Parser.Update (e, es, e')) =
   226       fold_expr f g e #> fold (fold_expr f g) es #> fold_expr f g e'
   227   | fold_expr f g (Fdl_Parser.Record (_, flds)) = fold (fold_expr f g o snd) flds
   228   | fold_expr f g (Fdl_Parser.Array (_, default, assocs)) =
   229       fold_opt (fold_expr f g) default #>
   230       fold (fold_pair
   231         (fold (fold (fold_pair
   232           (fold_expr f g) (fold_opt (fold_expr f g)))))
   233         (fold_expr f g)) assocs;
   234 
   235 
   236 fun add_expr_pfuns funs = fold_expr
   237   (fn s => if is_pfun s then I else insert (op =) s)
   238   (fn s => if is_none (Fdl_Parser.lookup funs s) then I else insert (op =) s);
   239 
   240 fun lookup_prfx "" tab s = Symtab.lookup tab s
   241   | lookup_prfx prfx tab s = (case Symtab.lookup tab s of
   242         NONE => Symtab.lookup tab (prfx ^ "__" ^ s)
   243       | x => x);
   244 
   245 fun fold_vcs f vcs =
   246   VCtab.fold (fn (_, (_, _, ps, cs)) => fold f ps #> fold f cs) vcs;
   247 
   248 fun pfuns_of_vcs prfx funs pfuns vcs =
   249   fold_vcs (add_expr_pfuns funs o snd) vcs [] |>
   250   filter (is_none o lookup_prfx prfx pfuns);
   251 
   252 val booleanN = "boolean";
   253 val integerN = "integer";
   254 
   255 
   256 fun get_type thy prfx ty =
   257   let val {type_map, ...} = VCs.get thy
   258   in lookup_prfx prfx type_map ty end;
   259 
   260 fun mk_type' _ _ "integer" = (HOLogic.intT, [])
   261   | mk_type' _ _ "boolean" = (HOLogic.boolT, [])
   262   | mk_type' thy prfx ty =
   263       (case get_type thy prfx ty of
   264          NONE =>
   265            (Syntax.check_typ (Proof_Context.init_global thy)
   266               (Type (Sign.full_name thy (Binding.name ty), [])),
   267             [])
   268        | SOME p => p);
   269 
   270 fun mk_type thy prfx ty = fst (mk_type' thy prfx ty);
   271 
   272 fun check_no_assoc thy prfx s = case get_type thy prfx s of
   273     NONE => ()
   274   | SOME _ => error ("Cannot associate a type with " ^ s ^
   275       "\nsince it is no record or enumeration type");
   276 
   277 
   278 fun define_overloaded (def_name, eq) lthy =
   279   let
   280     val ((c, _), rhs) = eq |> Syntax.check_term lthy |>
   281       Logic.dest_equals |>> dest_Free;
   282     val ((_, (_, thm)), lthy') = Local_Theory.define
   283       ((Binding.name c, NoSyn), ((Binding.name def_name, []), rhs)) lthy
   284     val ctxt_thy = Proof_Context.init_global (Proof_Context.theory_of lthy');
   285     val thm' = singleton (Proof_Context.export lthy' ctxt_thy) thm
   286   in (thm', lthy') end;
   287 
   288 (** generate properties of enumeration types **)
   289 
   290 fun add_enum_type tyname tyname' thy =
   291   let
   292     val {case_name, ...} = the (BNF_LFP_Compat.get_info thy [BNF_LFP_Compat.Keep_Nesting] tyname');
   293     val cs = map Const (the (BNF_LFP_Compat.get_constrs thy tyname'));
   294     val k = length cs;
   295     val T = Type (tyname', []);
   296     val p = Const (\<^const_name>\<open>pos\<close>, T --> HOLogic.intT);
   297     val v = Const (\<^const_name>\<open>val\<close>, HOLogic.intT --> T);
   298     val card = Const (\<^const_name>\<open>card\<close>,
   299       HOLogic.mk_setT T --> HOLogic.natT) $ HOLogic.mk_UNIV T;
   300 
   301     fun mk_binrel_def s f = Logic.mk_equals
   302       (Const (s, T --> T --> HOLogic.boolT),
   303        Abs ("x", T, Abs ("y", T,
   304          Const (s, HOLogic.intT --> HOLogic.intT --> HOLogic.boolT) $
   305            (f $ Bound 1) $ (f $ Bound 0))));
   306 
   307     val (((def1, def2), def3), lthy) = thy |>
   308 
   309       Class.instantiation ([tyname'], [], \<^sort>\<open>spark_enum\<close>) |>
   310 
   311       define_overloaded ("pos_" ^ tyname ^ "_def", Logic.mk_equals
   312         (p,
   313          list_comb (Const (case_name, replicate k HOLogic.intT @
   314              [T] ---> HOLogic.intT),
   315            map (HOLogic.mk_number HOLogic.intT) (0 upto k - 1)))) ||>>
   316 
   317       define_overloaded ("less_eq_" ^ tyname ^ "_def",
   318         mk_binrel_def \<^const_name>\<open>less_eq\<close> p) ||>>
   319       define_overloaded ("less_" ^ tyname ^ "_def",
   320         mk_binrel_def \<^const_name>\<open>less\<close> p);
   321 
   322     val UNIV_eq = Goal.prove lthy [] []
   323       (HOLogic.mk_Trueprop (HOLogic.mk_eq
   324          (HOLogic.mk_UNIV T, HOLogic.mk_set T cs)))
   325       (fn {context = ctxt, ...} =>
   326          resolve_tac ctxt @{thms subset_antisym} 1 THEN
   327          resolve_tac ctxt @{thms subsetI} 1 THEN
   328          Old_Datatype_Aux.exh_tac ctxt (K (#exhaust (BNF_LFP_Compat.the_info
   329            (Proof_Context.theory_of ctxt) [BNF_LFP_Compat.Keep_Nesting] tyname'))) 1 THEN
   330          ALLGOALS (asm_full_simp_tac ctxt));
   331 
   332     val finite_UNIV = Goal.prove lthy [] []
   333       (HOLogic.mk_Trueprop (Const (\<^const_name>\<open>finite\<close>,
   334          HOLogic.mk_setT T --> HOLogic.boolT) $ HOLogic.mk_UNIV T))
   335       (fn {context = ctxt, ...} => simp_tac (ctxt addsimps [UNIV_eq]) 1);
   336 
   337     val card_UNIV = Goal.prove lthy [] []
   338       (HOLogic.mk_Trueprop (HOLogic.mk_eq
   339          (card, HOLogic.mk_number HOLogic.natT k)))
   340       (fn {context = ctxt, ...} => simp_tac (ctxt addsimps [UNIV_eq]) 1);
   341 
   342     val range_pos = Goal.prove lthy [] []
   343       (HOLogic.mk_Trueprop (HOLogic.mk_eq
   344          (Const (\<^const_name>\<open>image\<close>, (T --> HOLogic.intT) -->
   345             HOLogic.mk_setT T --> HOLogic.mk_setT HOLogic.intT) $
   346               p $ HOLogic.mk_UNIV T,
   347           Const (\<^const_name>\<open>atLeastLessThan\<close>, HOLogic.intT -->
   348             HOLogic.intT --> HOLogic.mk_setT HOLogic.intT) $
   349               HOLogic.mk_number HOLogic.intT 0 $
   350               (\<^term>\<open>int\<close> $ card))))
   351       (fn {context = ctxt, ...} =>
   352          simp_tac (ctxt addsimps [card_UNIV]) 1 THEN
   353          simp_tac (ctxt addsimps [UNIV_eq, def1]) 1 THEN
   354          resolve_tac ctxt @{thms subset_antisym} 1 THEN
   355          simp_tac ctxt 1 THEN
   356          resolve_tac ctxt @{thms subsetI} 1 THEN
   357          asm_full_simp_tac (ctxt addsimps @{thms interval_expand}
   358            delsimps @{thms atLeastLessThan_iff}) 1);
   359 
   360     val lthy' =
   361       Class.prove_instantiation_instance (fn ctxt =>
   362         Class.intro_classes_tac ctxt [] THEN
   363         resolve_tac ctxt [finite_UNIV] 1 THEN
   364         resolve_tac ctxt [range_pos] 1 THEN
   365         simp_tac (put_simpset HOL_basic_ss ctxt addsimps [def3]) 1 THEN
   366         simp_tac (put_simpset HOL_basic_ss ctxt addsimps [def2]) 1) lthy;
   367 
   368     val (pos_eqs, val_eqs) = split_list (map_index (fn (i, c) =>
   369       let
   370         val n = HOLogic.mk_number HOLogic.intT i;
   371         val th = Goal.prove lthy' [] []
   372           (HOLogic.mk_Trueprop (HOLogic.mk_eq (p $ c, n)))
   373           (fn {context = ctxt, ...} => simp_tac (ctxt addsimps [def1]) 1);
   374         val th' = Goal.prove lthy' [] []
   375           (HOLogic.mk_Trueprop (HOLogic.mk_eq (v $ n, c)))
   376           (fn {context = ctxt, ...} =>
   377              resolve_tac ctxt [@{thm inj_pos} RS @{thm injD}] 1 THEN
   378              simp_tac (ctxt addsimps [@{thm pos_val}, range_pos, card_UNIV, th]) 1)
   379       in (th, th') end) cs);
   380 
   381     val first_el = Goal.prove lthy' [] []
   382       (HOLogic.mk_Trueprop (HOLogic.mk_eq
   383          (Const (\<^const_name>\<open>first_el\<close>, T), hd cs)))
   384       (fn {context = ctxt, ...} => simp_tac (ctxt addsimps [@{thm first_el_def}, hd val_eqs]) 1);
   385 
   386     val last_el = Goal.prove lthy' [] []
   387       (HOLogic.mk_Trueprop (HOLogic.mk_eq
   388          (Const (\<^const_name>\<open>last_el\<close>, T), List.last cs)))
   389       (fn {context = ctxt, ...} =>
   390         simp_tac (ctxt addsimps [@{thm last_el_def}, List.last val_eqs, card_UNIV]) 1);
   391   in
   392     lthy' |>
   393     Local_Theory.note
   394       ((Binding.name (tyname ^ "_card"), @{attributes [simp]}), [card_UNIV]) ||>>
   395     Local_Theory.note
   396       ((Binding.name (tyname ^ "_pos"), @{attributes [simp]}), pos_eqs) ||>>
   397     Local_Theory.note
   398       ((Binding.name (tyname ^ "_val"), @{attributes [simp]}), val_eqs) ||>>
   399     Local_Theory.note
   400       ((Binding.name (tyname ^ "_first_el"), @{attributes [simp]}), [first_el]) ||>>
   401     Local_Theory.note
   402       ((Binding.name (tyname ^ "_last_el"), @{attributes [simp]}), [last_el]) |> snd |>
   403     Local_Theory.exit_global
   404   end;
   405 
   406 
   407 val lcase_eq = (op =) o apply2 (to_lower o Long_Name.base_name);
   408 
   409 fun check_enum [] [] = NONE
   410   | check_enum els [] = SOME ("has no element(s) " ^ commas els)
   411   | check_enum [] cs = SOME ("has extra element(s) " ^
   412       commas (map (Long_Name.base_name o fst) cs))
   413   | check_enum (el :: els) ((cname, _) :: cs) =
   414       if lcase_eq (el, cname) then check_enum els cs
   415       else SOME ("either has no element " ^ el ^
   416         " or it is at the wrong position");
   417 
   418 fun strip_prfx s =
   419   let
   420     fun strip ys [] = ("", implode ys)
   421       | strip ys ("_" :: "_" :: xs) = (implode (rev xs), implode ys)
   422       | strip ys (x :: xs) = strip (x :: ys) xs
   423   in strip [] (rev (raw_explode s)) end;
   424 
   425 fun assoc_ty_err thy T s msg =
   426   error ("Type " ^ Syntax.string_of_typ_global thy T ^
   427     " associated with SPARK type " ^ s ^ "\n" ^ msg);
   428 
   429 fun check_enum [] [] = NONE
   430   | check_enum els [] = SOME ("has no element(s) " ^ commas els)
   431   | check_enum [] cs = SOME ("has extra element(s) " ^
   432       commas (map (Long_Name.base_name o fst) cs))
   433   | check_enum (el :: els) ((cname, _) :: cs) =
   434       if lcase_eq (el, cname) then check_enum els cs
   435       else SOME ("either has no element " ^ el ^
   436         " or it is at the wrong position");
   437 
   438 fun unprefix_pfun "" s = s
   439   | unprefix_pfun prfx s =
   440       let val (prfx', s') = strip_prfx s
   441       in if prfx = prfx' then s' else s end;
   442 
   443 fun invert_map [] = I
   444   | invert_map cmap =
   445       map (apfst (the o AList.lookup (op =) (map swap cmap)));
   446 
   447 fun get_record_info thy T = (case Record.dest_recTs T of
   448     [(tyname, [\<^typ>\<open>unit\<close>])] =>
   449       Record.get_info thy (Long_Name.qualifier tyname)
   450   | _ => NONE);
   451 
   452 
   453 
   454 fun add_type_def prfx (s, Fdl_Parser.Basic_Type ty) (ids, thy) =
   455       (check_no_assoc thy prfx s;
   456        (ids,
   457         Typedecl.abbrev_global (Binding.name s, [], NoSyn)
   458           (mk_type thy prfx ty) thy |> snd))
   459 
   460   | add_type_def prfx (s, Fdl_Parser.Enum_Type els) ((tab, ctxt), thy) =
   461       let
   462         val (thy', tyname) = (case get_type thy prfx s of
   463             NONE =>
   464               let
   465                 val tyb = Binding.name s;
   466                 val tyname = Sign.full_name thy tyb
   467               in
   468                 (thy |>
   469                  BNF_LFP_Compat.add_datatype [BNF_LFP_Compat.Keep_Nesting]
   470                    [((tyb, [], NoSyn),
   471                      map (fn s => (Binding.name s, [], NoSyn)) els)] |> snd |>
   472                  add_enum_type s tyname,
   473                  tyname)
   474               end
   475           | SOME (T as Type (tyname, []), cmap) =>
   476               (case BNF_LFP_Compat.get_constrs thy tyname of
   477                  NONE => assoc_ty_err thy T s "is not a datatype"
   478                | SOME cs =>
   479                    let val (prfx', _) = strip_prfx s
   480                    in
   481                      case check_enum (map (unprefix_pfun prfx') els)
   482                          (invert_map cmap cs) of
   483                        NONE => (thy, tyname)
   484                      | SOME msg => assoc_ty_err thy T s msg
   485                    end)
   486           | SOME (T, _) => assoc_ty_err thy T s "is not a datatype");
   487         val cs = map Const (the (BNF_LFP_Compat.get_constrs thy' tyname));
   488       in
   489         ((fold (Symtab.update_new o apsnd (rpair s)) (els ~~ cs) tab,
   490           fold Name.declare els ctxt),
   491          thy')
   492       end
   493 
   494   | add_type_def prfx (s, Fdl_Parser.Array_Type (argtys, resty)) (ids, thy) =
   495       (check_no_assoc thy prfx s;
   496        (ids,
   497         Typedecl.abbrev_global (Binding.name s, [], NoSyn)
   498           (foldr1 HOLogic.mk_prodT (map (mk_type thy prfx) argtys) -->
   499              mk_type thy prfx resty) thy |> snd))
   500 
   501   | add_type_def prfx (s, Fdl_Parser.Record_Type fldtys) (ids, thy) =
   502       (ids,
   503        let val fldTs = maps (fn (flds, ty) =>
   504          map (rpair (mk_type thy prfx ty)) flds) fldtys
   505        in case get_type thy prfx s of
   506            NONE =>
   507              Record.add_record {overloaded = false} ([], Binding.name s) NONE
   508                (map (fn (fld, T) => (Binding.name fld, T, NoSyn)) fldTs) thy
   509          | SOME (rT, cmap) =>
   510              (case get_record_info thy rT of
   511                 NONE => assoc_ty_err thy rT s "is not a record type"
   512               | SOME {fields, ...} =>
   513                   let val fields' = invert_map cmap fields
   514                   in
   515                     (case subtract (lcase_eq o apply2 fst) fldTs fields' of
   516                        [] => ()
   517                      | flds => assoc_ty_err thy rT s ("has extra field(s) " ^
   518                          commas (map (Long_Name.base_name o fst) flds));
   519                      map (fn (fld, T) =>
   520                        case AList.lookup lcase_eq fields' fld of
   521                          NONE => assoc_ty_err thy rT s ("has no field " ^ fld)
   522                        | SOME U => T = U orelse assoc_ty_err thy rT s
   523                            ("has field " ^
   524                             fld ^ " whose type\n" ^
   525                             Syntax.string_of_typ_global thy U ^
   526                             "\ndoes not match declared type\n" ^
   527                             Syntax.string_of_typ_global thy T)) fldTs;
   528                      thy)
   529                   end)
   530        end)
   531 
   532   | add_type_def prfx (s, Fdl_Parser.Pending_Type) (ids, thy) =
   533       (ids,
   534        case get_type thy prfx s of
   535          SOME _ => thy
   536        | NONE => Typedecl.typedecl_global {final = true} (Binding.name s, [], NoSyn) thy |> snd);
   537 
   538 fun add_type_def prfx (s, Fdl_Parser.Basic_Type ty) (ids, thy) =
   539       (check_no_assoc thy prfx s;
   540        (ids,
   541         Typedecl.abbrev_global (Binding.name s, [], NoSyn)
   542           (mk_type thy prfx ty) thy |> snd))
   543 
   544   | add_type_def prfx (s, Fdl_Parser.Enum_Type els) ((tab, ctxt), thy) =
   545       let
   546         val (thy', tyname) = (case get_type thy prfx s of
   547             NONE =>
   548               let
   549                 val tyb = Binding.name s;
   550                 val tyname = Sign.full_name thy tyb
   551               in
   552                 (thy |>
   553                  BNF_LFP_Compat.add_datatype [BNF_LFP_Compat.Keep_Nesting]
   554                    [((tyb, [], NoSyn),
   555                      map (fn s => (Binding.name s, [], NoSyn)) els)] |> snd |>
   556                  add_enum_type s tyname,
   557                  tyname)
   558               end
   559           | SOME (T as Type (tyname, []), cmap) =>
   560               (case BNF_LFP_Compat.get_constrs thy tyname of
   561                  NONE => assoc_ty_err thy T s "is not a datatype"
   562                | SOME cs =>
   563                    let val (prfx', _) = strip_prfx s
   564                    in
   565                      case check_enum (map (unprefix_pfun prfx') els)
   566                          (invert_map cmap cs) of
   567                        NONE => (thy, tyname)
   568                      | SOME msg => assoc_ty_err thy T s msg
   569                    end)
   570           | SOME (T, _) => assoc_ty_err thy T s "is not a datatype");
   571         val cs = map Const (the (BNF_LFP_Compat.get_constrs thy' tyname));
   572       in
   573         ((fold (Symtab.update_new o apsnd (rpair s)) (els ~~ cs) tab,
   574           fold Name.declare els ctxt),
   575          thy')
   576       end
   577 
   578   | add_type_def prfx (s, Fdl_Parser.Array_Type (argtys, resty)) (ids, thy) =
   579       (check_no_assoc thy prfx s;
   580        (ids,
   581         Typedecl.abbrev_global (Binding.name s, [], NoSyn)
   582           (foldr1 HOLogic.mk_prodT (map (mk_type thy prfx) argtys) -->
   583              mk_type thy prfx resty) thy |> snd))
   584 
   585   | add_type_def prfx (s, Fdl_Parser.Record_Type fldtys) (ids, thy) =
   586       (ids,
   587        let val fldTs = maps (fn (flds, ty) =>
   588          map (rpair (mk_type thy prfx ty)) flds) fldtys
   589        in case get_type thy prfx s of
   590            NONE =>
   591              Record.add_record {overloaded = false} ([], Binding.name s) NONE
   592                (map (fn (fld, T) => (Binding.name fld, T, NoSyn)) fldTs) thy
   593          | SOME (rT, cmap) =>
   594              (case get_record_info thy rT of
   595                 NONE => assoc_ty_err thy rT s "is not a record type"
   596               | SOME {fields, ...} =>
   597                   let val fields' = invert_map cmap fields
   598                   in
   599                     (case subtract (lcase_eq o apply2 fst) fldTs fields' of
   600                        [] => ()
   601                      | flds => assoc_ty_err thy rT s ("has extra field(s) " ^
   602                          commas (map (Long_Name.base_name o fst) flds));
   603                      map (fn (fld, T) =>
   604                        case AList.lookup lcase_eq fields' fld of
   605                          NONE => assoc_ty_err thy rT s ("has no field " ^ fld)
   606                        | SOME U => T = U orelse assoc_ty_err thy rT s
   607                            ("has field " ^
   608                             fld ^ " whose type\n" ^
   609                             Syntax.string_of_typ_global thy U ^
   610                             "\ndoes not match declared type\n" ^
   611                             Syntax.string_of_typ_global thy T)) fldTs;
   612                      thy)
   613                   end)
   614        end)
   615 
   616   | add_type_def prfx (s, Fdl_Parser.Pending_Type) (ids, thy) =
   617       (ids,
   618        case get_type thy prfx s of
   619          SOME _ => thy
   620        | NONE => Typedecl.typedecl_global {final = true} (Binding.name s, [], NoSyn) thy |> snd);
   621 
   622 fun add_const prfx (s, ty) ((tab, ctxt), thy) =
   623   let
   624     val T = mk_type thy prfx ty;
   625     val b = Binding.name s;
   626     val c = Const (Sign.full_name thy b, T)
   627   in
   628     (c,
   629      ((Symtab.update (s, (c, ty)) tab, Name.declare s ctxt),
   630       Sign.add_consts [(b, T, NoSyn)] thy))
   631   end;
   632 
   633 fun mk_unop s t =
   634   let val T = fastype_of t
   635   in Const (s, T --> T) $ t end;
   636 
   637 fun strip_underscores s =
   638   strip_underscores (unsuffix "_" s) handle Fail _ => s;
   639 
   640 fun strip_tilde s =
   641   unsuffix "~" s ^ "_init" handle Fail _ => s;
   642 
   643 val mangle_name = strip_underscores #> strip_tilde;
   644 
   645 fun mk_variables thy prfx xs ty (tab, ctxt) =
   646   let
   647     val T = mk_type thy prfx ty;
   648     val (ys, ctxt') = fold_map Name.variant (map mangle_name xs) ctxt;
   649     val zs = map (Free o rpair T) ys;
   650   in (zs, (fold (Symtab.update o apsnd (rpair ty)) (xs ~~ zs) tab, ctxt')) end;
   651 
   652 fun find_field [] fname fields =
   653       find_first (curry lcase_eq fname o fst) fields
   654   | find_field cmap fname fields =
   655       (case AList.lookup (op =) cmap fname of
   656          NONE => NONE
   657        | SOME fname' => SOME (fname', the (AList.lookup (op =) fields fname')));
   658 
   659 fun find_field' fname = get_first (fn (flds, fldty) =>
   660   if member (op =) flds fname then SOME fldty else NONE);
   661 
   662 fun mk_times (t, u) =
   663   let
   664     val setT = fastype_of t;
   665     val T = HOLogic.dest_setT setT;
   666     val U = HOLogic.dest_setT (fastype_of u)
   667   in
   668     Const (\<^const_name>\<open>Sigma\<close>, setT --> (T --> HOLogic.mk_setT U) -->
   669       HOLogic.mk_setT (HOLogic.mk_prodT (T, U))) $ t $ Abs ("", T, u)
   670   end;
   671 
   672 
   673 fun term_of_expr thy prfx types pfuns =
   674   let
   675     fun tm_of vs (Fdl_Parser.Funct ("->", [e, e'])) =
   676           (HOLogic.mk_imp (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
   677 
   678       | tm_of vs (Fdl_Parser.Funct ("<->", [e, e'])) =
   679           (HOLogic.mk_eq (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
   680 
   681       | tm_of vs (Fdl_Parser.Funct ("or", [e, e'])) =
   682           (HOLogic.mk_disj (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
   683 
   684       | tm_of vs (Fdl_Parser.Funct ("and", [e, e'])) =
   685           (HOLogic.mk_conj (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
   686 
   687       | tm_of vs (Fdl_Parser.Funct ("not", [e])) =
   688           (HOLogic.mk_not (fst (tm_of vs e)), booleanN)
   689 
   690       | tm_of vs (Fdl_Parser.Funct ("=", [e, e'])) =
   691           (HOLogic.mk_eq (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
   692 
   693       | tm_of vs (Fdl_Parser.Funct ("<>", [e, e'])) = (HOLogic.mk_not
   694           (HOLogic.mk_eq (fst (tm_of vs e), fst (tm_of vs e'))), booleanN)
   695 
   696       | tm_of vs (Fdl_Parser.Funct ("<", [e, e'])) = (HOLogic.mk_binrel \<^const_name>\<open>less\<close>
   697           (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
   698 
   699       | tm_of vs (Fdl_Parser.Funct (">", [e, e'])) = (HOLogic.mk_binrel \<^const_name>\<open>less\<close>
   700           (fst (tm_of vs e'), fst (tm_of vs e)), booleanN)
   701 
   702       | tm_of vs (Fdl_Parser.Funct ("<=", [e, e'])) = (HOLogic.mk_binrel \<^const_name>\<open>less_eq\<close>
   703           (fst (tm_of vs e), fst (tm_of vs e')), booleanN)
   704 
   705       | tm_of vs (Fdl_Parser.Funct (">=", [e, e'])) = (HOLogic.mk_binrel \<^const_name>\<open>less_eq\<close>
   706           (fst (tm_of vs e'), fst (tm_of vs e)), booleanN)
   707 
   708       | tm_of vs (Fdl_Parser.Funct ("+", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>plus\<close>
   709           (fst (tm_of vs e), fst (tm_of vs e')), integerN)
   710 
   711       | tm_of vs (Fdl_Parser.Funct ("-", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>minus\<close>
   712           (fst (tm_of vs e), fst (tm_of vs e')), integerN)
   713 
   714       | tm_of vs (Fdl_Parser.Funct ("*", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>times\<close>
   715           (fst (tm_of vs e), fst (tm_of vs e')), integerN)
   716 
   717       | tm_of vs (Fdl_Parser.Funct ("/", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>divide\<close>
   718           (fst (tm_of vs e), fst (tm_of vs e')), integerN)
   719 
   720       | tm_of vs (Fdl_Parser.Funct ("div", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>sdiv\<close>
   721           (fst (tm_of vs e), fst (tm_of vs e')), integerN)
   722 
   723       | tm_of vs (Fdl_Parser.Funct ("mod", [e, e'])) = (HOLogic.mk_binop \<^const_name>\<open>modulo\<close>
   724           (fst (tm_of vs e), fst (tm_of vs e')), integerN)
   725 
   726       | tm_of vs (Fdl_Parser.Funct ("-", [e])) =
   727           (mk_unop \<^const_name>\<open>uminus\<close> (fst (tm_of vs e)), integerN)
   728 
   729       | tm_of vs (Fdl_Parser.Funct ("**", [e, e'])) =
   730           (Const (\<^const_name>\<open>power\<close>, HOLogic.intT --> HOLogic.natT -->
   731              HOLogic.intT) $ fst (tm_of vs e) $
   732                (\<^const>\<open>nat\<close> $ fst (tm_of vs e')), integerN)
   733 
   734       | tm_of (tab, _) (Fdl_Parser.Ident s) =
   735           (case Symtab.lookup tab s of
   736              SOME t_ty => t_ty
   737            | NONE => (case lookup_prfx prfx pfuns s of
   738                SOME (SOME ([], resty), t) => (t, resty)
   739              | _ => error ("Undeclared identifier " ^ s)))
   740 
   741       | tm_of _ (Fdl_Parser.Number i) = (HOLogic.mk_number HOLogic.intT i, integerN)
   742 
   743       | tm_of vs (Fdl_Parser.Quantifier (s, xs, ty, e)) =
   744           let
   745             val (ys, vs') = mk_variables thy prfx xs ty vs;
   746             val q = (case s of
   747                 "for_all" => HOLogic.mk_all
   748               | "for_some" => HOLogic.mk_exists)
   749           in
   750             (fold_rev (fn Free (x, T) => fn t => q (x, T, t))
   751                ys (fst (tm_of vs' e)),
   752              booleanN)
   753           end
   754 
   755       | tm_of vs (Fdl_Parser.Funct (s, es)) =
   756 
   757           (* record field selection *)
   758           (case try (unprefix "fld_") s of
   759              SOME fname => (case es of
   760                [e] =>
   761                  let
   762                    val (t, rcdty) = tm_of vs e;
   763                    val (rT, cmap) = mk_type' thy prfx rcdty
   764                  in case (get_record_info thy rT, Fdl_Parser.lookup types rcdty) of
   765                      (SOME {fields, ...}, SOME (Fdl_Parser.Record_Type fldtys)) =>
   766                        (case (find_field cmap fname fields,
   767                             find_field' fname fldtys) of
   768                           (SOME (fname', fT), SOME fldty) =>
   769                             (Const (fname', rT --> fT) $ t, fldty)
   770                         | _ => error ("Record " ^ rcdty ^
   771                             " has no field named " ^ fname))
   772                    | _ => error (rcdty ^ " is not a record type")
   773                  end
   774              | _ => error ("Function " ^ s ^ " expects one argument"))
   775            | NONE =>
   776 
   777           (* record field update *)
   778           (case try (unprefix "upf_") s of
   779              SOME fname => (case es of
   780                [e, e'] =>
   781                  let
   782                    val (t, rcdty) = tm_of vs e;
   783                    val (rT, cmap) = mk_type' thy prfx rcdty;
   784                    val (u, fldty) = tm_of vs e';
   785                    val fT = mk_type thy prfx fldty
   786                  in case get_record_info thy rT of
   787                      SOME {fields, ...} =>
   788                        (case find_field cmap fname fields of
   789                           SOME (fname', fU) =>
   790                             if fT = fU then
   791                               (Const (fname' ^ "_update",
   792                                  (fT --> fT) --> rT --> rT) $
   793                                    Abs ("x", fT, u) $ t,
   794                                rcdty)
   795                             else error ("Type\n" ^
   796                               Syntax.string_of_typ_global thy fT ^
   797                               "\ndoes not match type\n" ^
   798                               Syntax.string_of_typ_global thy fU ^
   799                               "\nof field " ^ fname)
   800                         | NONE => error ("Record " ^ rcdty ^
   801                             " has no field named " ^ fname))
   802                    | _ => error (rcdty ^ " is not a record type")
   803                  end
   804              | _ => error ("Function " ^ s ^ " expects two arguments"))
   805            | NONE =>
   806 
   807           (* enumeration type to integer *)
   808           (case try (unsuffix "__pos") s of
   809              SOME tyname => (case es of
   810                [e] => (Const (\<^const_name>\<open>pos\<close>,
   811                    mk_type thy prfx tyname --> HOLogic.intT) $ fst (tm_of vs e),
   812                  integerN)
   813              | _ => error ("Function " ^ s ^ " expects one argument"))
   814            | NONE =>
   815 
   816           (* integer to enumeration type *)
   817           (case try (unsuffix "__val") s of
   818              SOME tyname => (case es of
   819                [e] => (Const (\<^const_name>\<open>val\<close>,
   820                    HOLogic.intT --> mk_type thy prfx tyname) $ fst (tm_of vs e),
   821                  tyname)
   822              | _ => error ("Function " ^ s ^ " expects one argument"))
   823            | NONE =>
   824 
   825           (* successor / predecessor of enumeration type element *)
   826           if s = "succ" orelse s = "pred" then (case es of
   827               [e] =>
   828                 let
   829                   val (t, tyname) = tm_of vs e;
   830                   val T = mk_type thy prfx tyname
   831                 in (Const
   832                   (if s = "succ" then \<^const_name>\<open>succ\<close>
   833                    else \<^const_name>\<open>pred\<close>, T --> T) $ t, tyname)
   834                 end
   835             | _ => error ("Function " ^ s ^ " expects one argument"))
   836 
   837           (* user-defined proof function *)
   838           else
   839             (case lookup_prfx prfx pfuns s of
   840                SOME (SOME (_, resty), t) =>
   841                  (list_comb (t, map (fst o tm_of vs) es), resty)
   842              | _ => error ("Undeclared proof function " ^ s))))))
   843 
   844       | tm_of vs (Fdl_Parser.Element (e, es)) =
   845           let val (t, ty) = tm_of vs e
   846           in case Fdl_Parser.lookup types ty of
   847               SOME (Fdl_Parser.Array_Type (_, elty)) =>
   848                 (t $ foldr1 HOLogic.mk_prod (map (fst o tm_of vs) es), elty)
   849             | _ => error (ty ^ " is not an array type")
   850           end
   851 
   852       | tm_of vs (Fdl_Parser.Update (e, es, e')) =
   853           let val (t, ty) = tm_of vs e
   854           in case Fdl_Parser.lookup types ty of
   855               SOME (Fdl_Parser.Array_Type (idxtys, elty)) =>
   856                 let
   857                   val T = foldr1 HOLogic.mk_prodT
   858                     (map (mk_type thy prfx) idxtys);
   859                   val U = mk_type thy prfx elty;
   860                   val fT = T --> U
   861                 in
   862                   (Const (\<^const_name>\<open>fun_upd\<close>, fT --> T --> U --> fT) $
   863                      t $ foldr1 HOLogic.mk_prod (map (fst o tm_of vs) es) $
   864                        fst (tm_of vs e'),
   865                    ty)
   866                 end
   867             | _ => error (ty ^ " is not an array type")
   868           end
   869 
   870       | tm_of vs (Fdl_Parser.Record (s, flds)) =
   871           let
   872             val (T, cmap) = mk_type' thy prfx s;
   873             val {extension = (ext_name, _), fields, ...} =
   874               (case get_record_info thy T of
   875                  NONE => error (s ^ " is not a record type")
   876                | SOME info => info);
   877             val flds' = map (apsnd (tm_of vs)) flds;
   878             val fnames = fields |> invert_map cmap |>
   879               map (Long_Name.base_name o fst);
   880             val fnames' = map fst flds;
   881             val (fvals, ftys) = split_list (map (fn s' =>
   882               case AList.lookup lcase_eq flds' s' of
   883                 SOME fval_ty => fval_ty
   884               | NONE => error ("Field " ^ s' ^ " missing in record " ^ s))
   885                   fnames);
   886             val _ = (case subtract lcase_eq fnames fnames' of
   887                 [] => ()
   888               | xs => error ("Extra field(s) " ^ commas xs ^
   889                   " in record " ^ s));
   890             val _ = (case duplicates (op =) fnames' of
   891                 [] => ()
   892               | xs => error ("Duplicate field(s) " ^ commas xs ^
   893                   " in record " ^ s))
   894           in
   895             (list_comb
   896                (Const (ext_name,
   897                   map (mk_type thy prfx) ftys @ [HOLogic.unitT] ---> T),
   898                 fvals @ [HOLogic.unit]),
   899              s)
   900           end
   901 
   902       | tm_of vs (Fdl_Parser.Array (s, default, assocs)) =
   903           (case Fdl_Parser.lookup types s of
   904              SOME (Fdl_Parser.Array_Type (idxtys, elty)) =>
   905                let
   906                  val Ts = map (mk_type thy prfx) idxtys;
   907                  val T = foldr1 HOLogic.mk_prodT Ts;
   908                  val U = mk_type thy prfx elty;
   909                  fun mk_idx' T (e, NONE) = HOLogic.mk_set T [fst (tm_of vs e)]
   910                    | mk_idx' T (e, SOME e') = Const (\<^const_name>\<open>atLeastAtMost\<close>,
   911                        T --> T --> HOLogic.mk_setT T) $
   912                          fst (tm_of vs e) $ fst (tm_of vs e');
   913                  fun mk_idx idx =
   914                    if length Ts <> length idx then
   915                      error ("Arity mismatch in construction of array " ^ s)
   916                    else foldr1 mk_times (map2 mk_idx' Ts idx);
   917                  fun mk_upd (idxs, e) t =
   918                    if length idxs = 1 andalso forall (is_none o snd) (hd idxs)
   919                    then
   920                      Const (\<^const_name>\<open>fun_upd\<close>, (T --> U) -->
   921                          T --> U --> T --> U) $ t $
   922                        foldl1 HOLogic.mk_prod
   923                          (map (fst o tm_of vs o fst) (hd idxs)) $
   924                        fst (tm_of vs e)
   925                    else
   926                      Const (\<^const_name>\<open>fun_upds\<close>, (T --> U) -->
   927                          HOLogic.mk_setT T --> U --> T --> U) $ t $
   928                        foldl1 (HOLogic.mk_binop \<^const_name>\<open>sup\<close>)
   929                          (map mk_idx idxs) $
   930                        fst (tm_of vs e)
   931                in
   932                  (fold mk_upd assocs
   933                     (case default of
   934                        SOME e => Abs ("x", T, fst (tm_of vs e))
   935                      | NONE => Const (\<^const_name>\<open>undefined\<close>, T --> U)),
   936                   s)
   937                end
   938            | _ => error (s ^ " is not an array type"))
   939 
   940   in tm_of end;
   941 
   942 
   943 fun mk_rulename (s, i) = Binding.name (s ^ string_of_int i);
   944 
   945 
   946 fun add_def prfx types pfuns consts (id, (s, e)) (ids as (tab, ctxt), thy) =
   947   (case Fdl_Parser.lookup consts s of
   948     SOME ty =>
   949       let
   950         val (t, ty') = term_of_expr thy prfx types pfuns ids e;
   951         val T = mk_type thy prfx ty;
   952         val T' = mk_type thy prfx ty';
   953         val _ = T = T' orelse
   954           error ("Declared type " ^ ty ^ " of " ^ s ^
   955             "\ndoes not match type " ^ ty' ^ " in definition");
   956         val id' = mk_rulename id;
   957         val ((t', (_, th)), lthy') = Named_Target.theory_init thy
   958           |> Specification.definition NONE [] []
   959             ((id', []), HOLogic.mk_Trueprop (HOLogic.mk_eq (Free (s, T), t)));
   960         val phi =
   961           Proof_Context.export_morphism lthy'
   962             (Proof_Context.init_global (Proof_Context.theory_of lthy'));
   963       in
   964         ((id', Morphism.thm phi th),
   965           ((Symtab.update (s, (Morphism.term phi t', ty)) tab, Name.declare s ctxt),
   966             Local_Theory.exit_global lthy'))
   967        end
   968   | NONE => error ("Undeclared constant " ^ s));
   969 
   970 
   971 
   972 val add_expr_idents = fold_expr (K I) (insert (op =));
   973 
   974 (* sort definitions according to their dependency *)
   975 fun sort_defs _ _ _ _ [] sdefs = rev sdefs
   976   | sort_defs prfx funs pfuns consts defs sdefs =
   977       (case find_first (fn (_, (_, e)) =>
   978          forall (is_some o lookup_prfx prfx pfuns)
   979            (add_expr_pfuns funs e []) andalso
   980          forall (fn id =>
   981            member (fn (s, (_, (s', _))) => s = s') sdefs id orelse
   982            consts id)
   983              (add_expr_idents e [])) defs of
   984          SOME d => sort_defs prfx funs pfuns consts
   985            (remove (op =) d defs) (d :: sdefs)
   986        | NONE => error ("Bad definitions: " ^ rulenames defs));
   987 
   988 fun add_var prfx (s, ty) (ids, thy) =
   989   let val ([Free p], ids') = mk_variables thy prfx [s] ty ids
   990   in (p, (ids', thy)) end;
   991 
   992 fun add_init_vars prfx vcs (ids_thy as ((tab, _), _)) =
   993   fold_map (add_var prfx)
   994     (map_filter
   995        (fn s => case try (unsuffix "~") s of
   996           SOME s' => (case Symtab.lookup tab s' of
   997             SOME (_, ty) => SOME (s, ty)
   998           | NONE => error ("Undeclared identifier " ^ s'))
   999         | NONE => NONE)
  1000        (fold_vcs (add_expr_idents o snd) vcs []))
  1001     ids_thy;
  1002 
  1003 fun term_of_rule thy prfx types pfuns ids rule =
  1004   let val tm_of = fst o term_of_expr thy prfx types pfuns ids
  1005   in case rule of
  1006       Fdl_Parser.Inference_Rule (es, e) => Logic.list_implies
  1007         (map (HOLogic.mk_Trueprop o tm_of) es, HOLogic.mk_Trueprop (tm_of e))
  1008     | Fdl_Parser.Substitution_Rule (es, e, e') => Logic.list_implies
  1009         (map (HOLogic.mk_Trueprop o tm_of) es,
  1010          HOLogic.mk_Trueprop (HOLogic.mk_eq (tm_of e, tm_of e')))
  1011   end;
  1012 
  1013 
  1014 fun pfun_type thy prfx (argtys, resty) =
  1015   map (mk_type thy prfx) argtys ---> mk_type thy prfx resty;
  1016 
  1017 fun check_pfun_type thy prfx s t optty1 optty2 =
  1018   let
  1019     val T = fastype_of t;
  1020     fun check ty =
  1021       let val U = pfun_type thy prfx ty
  1022       in
  1023         T = U orelse
  1024         error ("Type\n" ^
  1025           Syntax.string_of_typ_global thy T ^
  1026           "\nof function " ^
  1027           Syntax.string_of_term_global thy t ^
  1028           " associated with proof function " ^ s ^
  1029           "\ndoes not match declared type\n" ^
  1030           Syntax.string_of_typ_global thy U)
  1031       end
  1032   in (Option.map check optty1; Option.map check optty2; ()) end;
  1033 
  1034 fun upd_option x y = if is_some x then x else y;
  1035 
  1036 fun check_pfuns_types thy prfx funs =
  1037   Symtab.map (fn s => fn (optty, t) =>
  1038    let val optty' = Fdl_Parser.lookup funs (unprefix_pfun prfx s)
  1039    in
  1040      (check_pfun_type thy prfx s t optty optty';
  1041       (NONE |> upd_option optty |> upd_option optty', t))
  1042    end);
  1043 
  1044 
  1045 
  1046 
  1047 fun pp_vcs msg vcs = Pretty.big_list msg (map (Pretty.str o fst) vcs);
  1048 
  1049 fun pp_open_vcs [] = Pretty.str "All verification conditions have been proved."
  1050   | pp_open_vcs vcs = pp_vcs
  1051       "The following verification conditions remain to be proved:" vcs;
  1052 
  1053 fun partition_vcs vcs = VCtab.fold_rev
  1054   (fn (name, (trace, SOME thms, ps, cs)) =>
  1055         apfst (cons (name, (trace, thms, ps, cs)))
  1056     | (name, (trace, NONE, ps, cs)) =>
  1057         apsnd (cons (name, (trace, ps, cs))))
  1058   vcs ([], []);
  1059 
  1060 fun print_open_vcs f vcs =
  1061   (Pretty.writeln (f (pp_open_vcs (snd (partition_vcs vcs)))); vcs);
  1062 
  1063 (*   set_env: Element.context_i list -> (binding * thm) list -> fdl_type tab ->
  1064        (string list * string) tab -> term * string) Symtab.table * Name.context ->
  1065          (string * thm list option * (string * expr) list * (string * expr) list) VCtab.table ->
  1066            Path.T -> string -> theory -> theory 
  1067   Context --vvvv is made Theory_Data by -------------------vvvvvvv, see.def. above *)
  1068 fun set_env ctxt defs types funs ids vcs path prefix thy = VCs.map (fn
  1069     {pfuns, type_map, env = NONE} =>
  1070       {pfuns = pfuns,
  1071        type_map = type_map,
  1072        env = SOME
  1073          {ctxt = ctxt, defs = defs, types = types, funs = funs,
  1074           pfuns = check_pfuns_types thy prefix funs pfuns,
  1075           ids = ids, proving = false, vcs = print_open_vcs I vcs, path = path,
  1076           prefix = prefix}}
  1077   | _ => err_unfinished ()) thy;
  1078 VCs.map: (VCs.T -> VCs.T) -> theory -> theory;
  1079 (* Pure/context.ML
  1080 signature THEORY_DATA =
  1081 sig
  1082   type T                                  (*..VCs.T*)
  1083   val get: theory -> T
  1084   val put: T -> theory -> theory
  1085   val map: (T -> T) -> theory -> theory   (*..(VCs.T -> VCs.T)*)
  1086 end;
  1087 *)
  1088 \<close> ML \<open>
  1089 structure Refs_Data = Theory_Data
  1090 (
  1091   type T = References.T
  1092   val empty : T = References.empty
  1093   val extend = I
  1094   fun merge (_, refs) = refs
  1095 );
  1096 (*
  1097 Refs_Data.empty;                                    (*in Refs_Data defined workers are hidden*)
  1098 Refs_Data.extend;                                   (*in Refs_Data defined workers are hidden*)
  1099 Refs_Data.merge;                                    (*in Refs_Data defined workers are hidden*)
  1100 ML error\<^here>:
  1101 Value or constructor (empty) has not been declared in structure Refs *)
  1102 
  1103 Refs_Data.get: theory -> Refs_Data.T;                            (*from signature THEORY_DATA*)
  1104 Refs_Data.put: Refs_Data.T -> theory -> theory;                  (*from signature THEORY_DATA*)
  1105 Refs_Data.map: (Refs_Data.T -> Refs_Data.T) -> theory -> theory; (*from signature THEORY_DATA*)
  1106 \<close> ML \<open>
  1107 structure OMod_Data = Theory_Data
  1108 (
  1109   type T = O_Model.T
  1110   val empty : T = []
  1111   val extend = I
  1112   fun merge (_, o_model) = o_model
  1113 )
  1114 \<close> ML \<open>
  1115 structure Ctxt_Data = Theory_Data
  1116 (
  1117   type T = Proof.context
  1118   val empty : T = ContextC.empty
  1119   val extend = I
  1120   fun merge (_, ctxt) = ctxt
  1121 )
  1122 \<close> ML \<open>
  1123 \<close> ML \<open>
  1124 fun set_vcs _(*{types, vars, consts, funs} : Fdl_Parser.decls*)
  1125       _(*rules, _*) _(*(_, ident), vcs*) header path opt_prfx thy =
  1126   let
  1127   (*/----- keep running from spark_open \<open>greatest_common_divisor/g_c_d\<close> -----\*)
  1128     val ({types, vars, consts, funs} : Fdl_Parser.decls) = 
  1129       snd (Fdl_Parser.parse_declarations Position.start g_c_d_fdl_content)
  1130     val (rules, _) = Fdl_Parser.parse_rules Position.start g_c_d_rls_content
  1131     val ((_, ident), vcs) =
  1132       snd (Fdl_Parser.parse_vcs Fdl_Lexer.siv_header Position.start g_c_d_siv_content)
  1133   (*------ new argument:  ParseC.vcs = ParseC.formalise ----------------------*)
  1134     val formalise = case header of xxx as
  1135       [(["Traegerlaenge L", "Streckenlast q_0", "Biegelinie y", "Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]", "FunktionsVariable x", "GleichungsVariablen [c, c_2, c_3, c_4]", "AbleitungBiegelinie dy"],
  1136         ("Biegelinie", ["Biegelinien"], ["IntegrierenUndKonstanteBestimmen2"]))] => hd xxx
  1137       | _ => error "magic failed: handling file exp_Statics_Biegel_Timischl_7-70.str failed"
  1138   (*\----- keep running from spark_open \<open>greatest_common_divisor/g_c_d\<close> -----/*)
  1139     val (hdlPIDE, _, refs, o_model, var_type_ctxt) = Step_Specify.initialisePIDE formalise
  1140   (*     ^^^^^^^ goes to PIDE as "Problem hdlPIDE"                            *)
  1141 
  1142     val prfx' =
  1143       if opt_prfx = "" then
  1144         space_implode "__" (Long_Name.explode (Long_Name.qualifier ident))
  1145       else opt_prfx;
  1146     val prfx = to_lower prfx';
  1147     val {pfuns, ...} = VCs.get thy;                                                       (*..thy*)
  1148     val (defs, rules') = partition_opt dest_def rules;
  1149     val consts' =
  1150       subtract (fn ((_, (s, _)), (s', _)) => s = s') defs (Fdl_Parser.items consts);
  1151     (* ignore all complex rules in rls files *)
  1152     val (rules'', other_rules) =
  1153       List.partition (complex_rule o snd) rules';
  1154     val _ = if null rules'' then ()
  1155       else warning ("Ignoring rules: " ^ rulenames rules'');
  1156 
  1157     val vcs' = VCtab.make (maps (fn (tr, vcs) =>
  1158       map (fn (s, (ps, cs)) => (s, (tr, NONE, ps, cs)))
  1159         (filter_out (is_trivial_vc o snd) vcs)) vcs);
  1160 
  1161     val _ = (case filter_out (is_some o Fdl_Parser.lookup funs)
  1162         (pfuns_of_vcs prfx funs pfuns vcs') of
  1163         [] => ()
  1164       | fs => error ("Undeclared proof function(s) " ^ commas fs));
  1165 
  1166     val (((defs', vars''), ivars)(*->*),(*<-*) (ids, thy')) =                            (*..thy'*)
  1167       ((Symtab.empty |>
  1168         Symtab.update ("false", (\<^term>\<open>False\<close>, booleanN)) |>
  1169         Symtab.update ("true", (\<^term>\<open>True\<close>, booleanN)),     (*..(defs', vars'')*)
  1170         Name.context)(*->*),(*<-*)                           (*..ivars*)
  1171        thy |> Sign.add_path                                                               (*..thy*)
  1172          ((if prfx' = "" then "" else prfx' ^ "__") ^ Long_Name.base_name ident)) |>
  1173       fold (add_type_def prfx) (Fdl_Parser.items types) |>
  1174       fold (snd oo add_const prfx) consts' |> (fn ids_thy as ((tab, _), _) =>
  1175         ids_thy |>
  1176         fold_map (add_def prfx types pfuns consts)
  1177           (sort_defs prfx funs pfuns (Symtab.defined tab) defs []) ||>>
  1178         fold_map (add_var prfx) (Fdl_Parser.items vars) ||>>
  1179         add_init_vars prfx vcs');                            (*..(ids,                      thy')*)
  1180 
  1181     val ctxt =
  1182       [Element.Fixes (map (fn (s, T) =>
  1183          (Binding.name s, SOME T, NoSyn)) (vars'' @ ivars)),
  1184        Element.Assumes (map (fn (id, rl) =>
  1185          ((mk_rulename id, []),
  1186           [(term_of_rule thy' prfx types pfuns ids rl, [])]))                            (*..thy'*)
  1187            other_rules),
  1188        Element.Notes ("", [((Binding.name "defns", []), map (rpair [] o single o snd) defs')])]
  1189 
  1190   in
  1191     set_env ctxt defs' types funs ids vcs' path prfx thy'
  1192       |> Refs_Data.put refs
  1193       |> OMod_Data.put o_model
  1194       |> Ctxt_Data.put var_type_ctxt
  1195   end;
  1196 \<close> ML \<open>
  1197 \<close>
  1198 
  1199 subsection \<open>cp. HOL/SPARK/Tools/fdl_lexer.ML\<close>
  1200 ML \<open>
  1201 \<close> ML \<open>
  1202 type chars = (string * Position.T) list;
  1203 val e_chars = []: (string * Position.T) list;               
  1204 
  1205 type banner = string * string * string;               val e_banner = ("b1", "b2", "b3")
  1206 type date = string * string * string;                 val e_date = ("d1", "d2", "d3")
  1207 type time = string * string * string * string option; val e_time = ("t1", "t2", "t3", SOME "t4")
  1208 
  1209 fun siv_header (_: chars) = 
  1210   ((e_banner, (e_date, e_time), (e_date, e_time), ("", "")), e_chars);
  1211 \<close> ML \<open>
  1212 \<close> 
  1213 
  1214 subsection \<open>cp. HOL/SPARK/Tools/spark_commands.ML\<close>
  1215 ML \<open>
  1216 \<close> ML \<open>
  1217 (*  Title:      src/Tools/isac/BridgeJEdit/cp_spark_commands.ML
  1218     Author:     Walther Neuper, JKU Linz
  1219     (c) due to copyright terms
  1220 
  1221 Preliminary code for developing Outer_Syntax.command..Example from spark_open as a model.
  1222 *)
  1223 
  1224 fun spark_open header (files, prfx) thy =
  1225 (*Fdl_Lexer.siv_header*)
  1226   let
  1227 (** )val _ = @{print} {a = "//--- ###C spark_open", files = files, prfx = prfx};( **)
  1228     val xxx as ([{src_path, lines = vc_lines, pos = vc_pos, ...}: Token.file (*,.siv*)
  1229 (** )  {lines = fdl_lines, pos = fdl_pos, ...},                              ( *.fld*)
  1230 (** )  {lines = rls_lines, pos = rls_pos, ...}                               ( *.rls*)
  1231       ], thy') = 
  1232     ((** @{print} {a = "###C spark_open: before call <files thy>, files = siv_header !"};( **)
  1233       files thy);
  1234 (*                                                                                    ^^^^^ arg!*)
  1235     val path = fst (Path.split_ext src_path);
  1236   in
  1237 (** )@{print} {a = "###C spark_open: result from siv_header, without thy'", fst_xxx = fst xxx};( **)
  1238 (** )@{print} {a = "###C spark_open: 1 arg for SPARK_VCs.set_vcs",
  1239 (** ) arg1 = (snd (Fdl_Parser.parse_declarations fdl_pos (cat_lines fdl_lines))),
  1240       arg2 = (Fdl_Parser.parse_rules rls_pos (cat_lines rls_lines)),            ( **)
  1241 (** ) arg3 = (snd (Fdl_Parser.parse_vcs header vc_pos (cat_lines vc_lines))), ( **)
  1242 (*                                                     !^^^^^^^!*)
  1243       z = "\\--- ###C spark_open"};( **)
  1244     (*SPARK_VCs.*)set_vcs
  1245 (*ADDED*) (**)
  1246 (** )  (snd (Fdl_Parser.parse_declarations fdl_pos (cat_lines fdl_lines)))( **)Fdl_Parser.empty_decls(**)
  1247 (** )  (Fdl_Parser.parse_rules rls_pos (cat_lines rls_lines))             ( **)Fdl_Parser.empty_rules(**)
  1248 (** )  (snd (Fdl_Parser.parse_vcs header vc_pos (cat_lines vc_lines)))    ( **)Fdl_Parser.empty_vcs(**)
  1249 (**)   (ParseC.read_out_formalise (fst (header     (fst (ParseC.scan' vc_pos (cat_lines vc_lines))))))(**)
  1250       path prfx thy'
  1251   end;
  1252 \<close> ML \<open>
  1253 \<close> ML \<open> (* compose NEW argument "header"                               ^v^v^v^v^v^v^v^v^v^v^v^v^v^v*)
  1254        (ParseC.read_out_formalise (fst (ParseC.vcs (fst (ParseC.scan' Position.start formalise_str)))))
  1255 \<close> ML \<open>
  1256 \<close> ML \<open>
  1257 \<close> ML \<open> (* generate the arguments directly for: spark_open \<open>greatest_common_divisor/g_c_d\<close>*)
  1258 (*     (snd (Fdl_Parser.parse_declarations fdl_pos (cat_lines fdl_lines))) *)
  1259         snd (Fdl_Parser.parse_declarations Position.start g_c_d_fdl_content)
  1260 \<close> ML \<open>
  1261 (*     (Fdl_Parser.parse_rules rls_pos (cat_lines rls_lines)) *)
  1262         Fdl_Parser.parse_rules Position.start g_c_d_rls_content
  1263 \<close> ML \<open>
  1264 val (("procedure", "Greatest_Common_Divisor.G_C_D"), vcs) =
  1265 (*     (snd (Fdl_Parser.parse_vcs header vc_pos (cat_lines vc_lines))) *)
  1266         snd (Fdl_Parser.parse_vcs Fdl_Lexer.siv_header Position.start g_c_d_siv_content);
  1267 length vcs = 11;
  1268 vcs;
  1269 \<close> ML \<open>
  1270 \<close> ML \<open>
  1271 \<close>
  1272 
  1273 section \<open>setup command_keyword \<close>
  1274 subsection \<open>hide for development, use for Test_Isac\<close>
  1275 text \<open>
  1276 (*HIDE for development, activate for Test_Isac*)
  1277 type chars = (string * Position.T) list;
  1278 val e_chars = []: (string * Position.T) list;
  1279 
  1280 fun spark_open (_: ((*Fdl_Lexer.*)chars -> 'a * (*Fdl_Lexer.*)chars)) 
  1281     (_: ('b -> Token.file list * theory) * string) (_: 'b) = @ {theory}
  1282 
  1283 type banner = string * string * string;               val e_banner = ("b1", "b2", "b3")
  1284 type date = string * string * string;                 val e_date = ("d1", "d2", "d3")
  1285 type time = string * string * string * string option; val e_time = ("t1", "t2", "t3", SOME "t4")
  1286 
  1287 fun siv_header (_: chars) = 
  1288   ((e_banner, (e_date, e_time), (e_date, e_time), ("", "")), e_chars);
  1289 (*HIDE for development, activate for Test_Isac*)
  1290 \<close> ML \<open>
  1291 \<close> 
  1292 subsection \<open>def.for Build_Isac; for Test_Isac outcomment SPARK_Commands, Fdl_Lexer below\<close>
  1293 ML \<open>
  1294 \<close> ML \<open>
  1295 val siv_header = ParseC.vcs; (*---------------------------------------------vvvvvvvvv*)
  1296 \<close> ML \<open>
  1297 val _ =                                                  
  1298   Outer_Syntax.command \<^command_keyword>\<open>Example\<close> "start Isac Calculation from a Formalise-file"
  1299     (Resources.provide_parse_files "spark_open" -- Parse.parname
  1300       >> (Toplevel.theory o ((*SPARK_Commands.*)spark_open (*Fdl_Lexer.( **)siv_header)));
  1301 (*--------------------------------------------------------------------------^^^^^^^^^^*)
  1302 \<close> ML \<open>
  1303 \<close> ML \<open>
  1304 \<close>
  1305 
  1306 subsection \<open>test runs with Example and spark_open\<close>
  1307 (*======= vv-- Example =================================================================*)
  1308 (** Test_Isac finds exp_Statics_Biegel_Timischl_7-70.siv ?!?* )
  1309 Example \<open>/usr/local/isabisac/src/Tools/isac/Examples/exp_Statics_Biegel_Timischl_7-70\<close>(*.str*)
  1310 ( ***Output:
  1311 
  1312 *)
  1313 (*====== ^^-- Example, spark_open--vv ==================================================*)
  1314 (* DO THAT IN ..................... HOL/SPARK/Examples/Gcd/Greatest_Common_Divisor.thy)
  1315 spark_open \<open>/usr/local/isabisac/src/HOL/SPARK/Examples/Gcd/greatest_common_divisor/g_c_d\<close>
  1316 ( ***Output:
  1317 
  1318 *)
  1319 (*==================== spark_open--^^ ==================================================*)
  1320 
  1321 section \<open>Adapt SPARK's parser -> parse Formalise.T\<close>
  1322 text \<open>
  1323   Possible models, where a file is read and parsed:
  1324   * for *.bib see usage of Resources.provide_parse_files     .. parsed by LaTeX
  1325   * Outer_Syntax.command \ <command_keyword>\<open>external_file\<close>  .. ?!?
  1326   * Outer_Syntax.command \<command_keyword>\<open>spark_open\<close>
  1327   We pursue the latter.
  1328   From c.f.2b9b4b38ab96 we have found Fdl_Lexer.scan as the very model
  1329   for scanning/parsing Formalise.T.
  1330 \<close>
  1331 
  1332 subsection \<open>testbed separates Fdl_Lexer.scan + Fdl_Parser from SPARK code\<close>
  1333 declare [[ML_print_depth = 7]] (* 3 7 10 20 999999999 *)
  1334 ML \<open>
  1335 open Fdl_Lexer
  1336 (** )open Fdl_Parser( *conflict with some of Fdl_Lexer.* *)
  1337 (*
  1338   step 1: go top down and keep respective results according to trace from
  1339           spark_open \<open>greatest_common_divisor/g_c_d\<close> SPARK/../Greatest_Common_Divisor.thy.
  1340           (in the example this is simple: just watch the bottom of Output
  1341            The following verification conditions remain to be proved:
  1342              procedure_g_c_d_4
  1343              procedure_g_c_d_11)
  1344         ! remove @~{print} from calling functions (higher level) 
  1345           once you go down to the called functions (lower level)
  1346           in order to reduce noise and to focus the code under actual consideration.
  1347   step 2: at bottom gather the most elementary funs for transformation
  1348            of g_c_d_siv_content to args of Fdl_Lexer.scan
  1349   step 3: parse the tokens created by  Fdl_Lexer.scan
  1350 *)
  1351 \<close> ML \<open>
  1352 \<close> ML \<open> (** high start level: parsing to header + VCs **)
  1353 val parsed = Fdl_Parser.parse_vcs Fdl_Lexer.siv_header Position.start g_c_d_siv_content;
  1354 \<close> ML \<open> (*               ^^^^^^^^^ <<<<<------------------------------------------------------*)
  1355 val ((banner, (date, time), (date2, time2), (string, string2)), ((str, str2), vcss)) = parsed;
  1356 
  1357 if banner = ("Semantic Analysis of SPARK Text",
  1358     "Examiner Pro Edition, Version 9.1.0, Build Date 20101119, Build 19039",
  1359     "Copyright (C) 2010 Altran Praxis Limited, Bath, U.K.")  andalso
  1360   (date, time) = (("29", "NOV", "2010"), ("14", "30", "10", NONE)) andalso
  1361   (date2, time2) = (("29", "NOV", "2010"), ("14", "30", "11", NONE)) andalso
  1362   (string, string2) =
  1363     ("SPARK Simplifier Pro Edition, Version 9.1.0, Build Date 20101119, Build 19039",
  1364     "Copyright (C) 2010 Altran Praxis Limited, Bath, U.K.") andalso
  1365   (str, str2) = ("procedure", "Greatest_Common_Divisor.G_C_D")
  1366   then () else error "Fdl_Parser.parse_vcs header CHANGED";
  1367 if length vcss = 11 (* verification conditions (VCs) from g_c_d_siv_content *) then
  1368   case vcss of
  1369     ("path(s) from start to run-time check associated with statement of line 8", 
  1370       [("procedure_g_c_d_1", ([], [("1", Fdl_Parser.Ident "true")]))]) ::
  1371     ("path(s) from start to run-time check associated with statement of line 8", 
  1372       [("procedure_g_c_d_2", ([], [("1", Fdl_Parser.Ident "true")]))]) ::
  1373     ("path(s) from start to assertion of line 10", 
  1374       [("procedure_g_c_d_3", ([], [("1", Fdl_Parser.Ident "true")]))]) :: 
  1375     ("path(s) from assertion of line 10 to assertion of line 10",
  1376       [("procedure_g_c_d_4",
  1377         (("1", Fdl_Parser.Funct (">=", [Fdl_Parser.Ident "c", Fdl_Parser.Number 0])) :: 
  1378          ("2", Fdl_Parser.Funct (">", [Fdl_Parser.Ident "d", Fdl_Parser.Number 0])) :: _,
  1379          _))]) :: _ => ()
  1380   | _ => error "Fdl_Parser.parse_vcs vcss CHANGED 1"
  1381 else error "Fdl_Parser.parse_vcs vcss CHANGED 2";
  1382 \<close> ML \<open>
  1383 \<close> ML \<open>
  1384 \<close> ML \<open> (* lower level 1: tokenize string to header + VCs *)
  1385 val level1_header_toks =
  1386 (* tokenize to header + VCs is NON-standard ..
  1387             vvvvvvvv--- parses vvvvvvvvvv     +     vvvvvvvvv, but leaves vcsss as Token list*)
  1388   Fdl_Lexer.tokenize Fdl_Lexer.siv_header Fdl_Lexer.c_comment Position.start g_c_d_siv_content;
  1389 \<close> ML \<open> (*   ^^^^^^^^ <<<<<-------------------------------------------------------------------*)
  1390 val ((banner, (date, time), (date2, time2), (string, string2)), toks ) = level1_header_toks;
  1391 
  1392 if banner = ("Semantic Analysis of SPARK Text",
  1393     "Examiner Pro Edition, Version 9.1.0, Build Date 20101119, Build 19039",
  1394     "Copyright (C) 2010 Altran Praxis Limited, Bath, U.K.")  andalso
  1395   (date, time) = (("29", "NOV", "2010"), ("14", "30", "10", NONE)) andalso
  1396   (date2, time2) = (("29", "NOV", "2010"), ("14", "30", "11", NONE)) andalso
  1397   (string, string2) =
  1398     ("SPARK Simplifier Pro Edition, Version 9.1.0, Build Date 20101119, Build 19039",
  1399     "Copyright (C) 2010 Altran Praxis Limited, Bath, U.K.")
  1400   then () else error "Fdl_Lexer.tokenize header CHANGED";
  1401 if length toks = 319 (* tokens for str :: str :: verification conditions from g_c_d_siv_content *) then
  1402   case toks of
  1403     Token (Keyword, "procedure", _(*Position.T*)) :: 
  1404     Token (Long_Ident, "Greatest_Common_Divisor.G_C_D", _(*Position.T*)) :: _  => ()
  1405   | _ => error "Fdl_Lexer.tokenize tokens CHANGED 1"
  1406 else error "Fdl_Lexer.tokenize header CHANGED 2";
  1407 \<close> ML \<open>
  1408 \<close> ML \<open>
  1409 \<close> ML \<open> (* lower level 2: tokenize the string *)
  1410 val chars = Fdl_Lexer.explode_pos g_c_d_siv_content(*_content*) Position.start;
  1411 if length chars = 2886 then () else error "Fdl_Lexer.explode_pos g_c_d_siv_content CHANGED";
  1412 val level2_header_toks = (Scan.finite char_stopper (*..from tokenize..*)
  1413   (Scan.error (Fdl_Lexer.scan Fdl_Lexer.siv_header Fdl_Lexer.c_comment)) chars);
  1414 (* ---------------------------------------------------------------------------\
  1415                Fdl_Lexer.scan Fdl_Lexer.siv_header Fdl_Lexer.c_comment chars
  1416 exception MORE () raised (line 176 of "General/scan.ML") ---------------------/ *)
  1417 
  1418 case level2_header_toks of
  1419   (((("Semantic Analysis of SPARK Text", 
  1420        "Examiner Pro Edition, Version 9.1.0, Build Date 20101119, Build 19039", 
  1421        "Copyright (C) 2010 Altran Praxis Limited, Bath, U.K."), 
  1422        (("29", "NOV", "2010"), ("14", "30", "10", NONE)),
  1423        (("29", "NOV", "2010"), ("14", "30", "11", NONE)), 
  1424        ("SPARK Simplifier Pro Edition, Version 9.1.0, Build Date 20101119, Build 19039", 
  1425          "Copyright (C) 2010 Altran Praxis Limited, Bath, U.K.")),
  1426      Token (Keyword, "procedure", _) :: Token (Long_Ident, "Greatest_Common_Divisor.G_C_D", _) ::
  1427      Token (Traceability, 
  1428        "path(s) from start to run-time check associated with statement of line 8", _) ::
  1429      _ ),
  1430    []) => ()
  1431 | _ => error "Fdl_Lexer.scan level2 CHANGED";
  1432 \<close> ML \<open>
  1433 \<close> ML \<open>
  1434 \<close> ML \<open> (* lower level 2: parse the tokens *)
  1435 val ((_, tokens), _) = level2_header_toks;
  1436 \<close> ML \<open>
  1437 Fdl_Parser.vcs: T list ->
  1438   ((string * string) * (string * (string * ((string * Fdl_Parser.expr) list * (string * Fdl_Parser.expr) list)) list) list)
  1439   * T list;
  1440 (filter Fdl_Lexer.is_proper): T list -> T list;
  1441 \<close> ML \<open>
  1442 val (parsed', _) =
  1443   Scan.finite Fdl_Lexer.stopper (Scan.error (Fdl_Parser.!!! Fdl_Parser.vcs))
  1444     (filter Fdl_Lexer.is_proper (*|*)tokens(*|*))
  1445 (* ---------------------------------------------------------------------------\
  1446                  Fdl_Parser.vcs (*|*)tokens(*|*)
  1447 exception ABORT fn raised (line 109 of "General/scan.ML") --------------------/ *)
  1448 \<close> ML \<open>
  1449 if parsed' = ((str, str2), vcss) then () else error "Fdl_Parser.parse_vcs level 2 CHANGED 2";
  1450 \<close> ML \<open>
  1451 \<close>
  1452 
  1453 subsection \<open>test data for Isac's Formalise.T parser\<close>
  1454 ML \<open>
  1455 \<close> ML \<open>
  1456 val form_single_str = (
  1457   "(\n" ^
  1458 (* Formalise.model: *)
  1459   "  [\"Traegerlaenge L\", \"Streckenlast q_0\", \"Biegelinie y\",\n" ^
  1460 	"    \"Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]\",\n" ^
  1461 	"    \"FunktionsVariable x\", \"GleichungsVariablen [c, c_2, c_3, c_4]\",\n" ^
  1462   "    \"AbleitungBiegelinie dy\"],\n" ^
  1463 (* Formalise.spec: *)
  1464   "  (\"Biegelinie\", [\"Biegelinien\"], [\"IntegrierenUndKonstanteBestimmen2\"])\n" ^
  1465   ")")
  1466 \<close> ML \<open>
  1467 val formalise_str = "[" ^ form_single_str ^ "]"; (*..we assume one element ONLY *)
  1468 \<close> ML \<open>
  1469 val form_spec_str =
  1470 (* Formalise.spec: *)
  1471   "  (\"Biegelinie\", [\"Biegelinien\"], [\"IntegrierenUndKonstanteBestimmen2\"])";
  1472 val form_spec_str' =
  1473   "(\"Biegelinie\",[\"Biegelinien\"],[\"IntegrierenUndKonstanteBestimmen2\"])";
  1474 \<close> ML \<open>
  1475 val form_model_str = (
  1476 (* Formalise.model: *)
  1477   "  [\"Traegerlaenge L\", \"Streckenlast q_0\", \"Biegelinie y\",\n" ^
  1478 	"    \"Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]\",\n" ^
  1479 	"    \"FunktionsVariable x\", \"GleichungsVariablen [c, c_2, c_3, c_4]\",\n" ^
  1480   "    \"AbleitungBiegelinie dy\"],\n")
  1481 val form_model_str' = ( (* NO whitespace *)
  1482   "[\"Traegerlaenge L\",\"Streckenlast q_0\",\"Biegelinie y\",\"Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]\",\"FunktionsVariable x\", \"GleichungsVariablen [c, c_2, c_3, c_4]\",\"AbleitungBiegelinie dy\"]")
  1483 \<close> ML \<open>
  1484 val form_model_str'' = ( (* NO whitespace, NO [ ] *)
  1485   "\"Traegerlaenge L\",\"Streckenlast q_0\",\"Biegelinie y\",\"Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]\",\"FunktionsVariable x\", \"GleichungsVariablen [c, c_2, c_3, c_4]\",\"AbleitungBiegelinie dy\"]")
  1486 \<close> ML \<open>
  1487 val form_model_str''' = ( (* NO whitespace, NO [ ], NO "," *)
  1488   "[\"Traegerlaenge L\"\"Streckenlast q_0\"\"Biegelinie y\"\"Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]\"\"FunktionsVariable x\"\"GleichungsVariablen [c, c_2, c_3, c_4]\"\"AbleitungBiegelinie dy\"]")
  1489 \<close> ML \<open>
  1490 \<close>
  1491 
  1492 subsection \<open>Adapt SPARK's code for parsing Formalise.T\<close>
  1493 text \<open>
  1494 \<close> ML \<open> (* equip the string -----vvvvvvvvvvvvvvv with Positions..*)
  1495 val chars = Fdl_Lexer.explode_pos form_single_str Position.start: Fdl_Lexer.chars;
  1496 if length chars = 306 then () else error "Fdl_Lexer.explode_pos g_c_d_siv CHANGED";
  1497 \<close> 
  1498 
  1499 subsubsection \<open>identify various code that might serve as model\<close>
  1500 ML \<open>
  1501 \<close> ML \<open> (* gen_comment adapted for a single string (*1*) on simplified form_model_str'' *)
  1502 val tokenize_string = $$$ "\"" |-- !!! "unclosed string" (*2*)
  1503   (Scan.repeat (Scan.unless ($$$ "\"") any) --| $$$ "\"") >> make_token Comment(*!!!*);
  1504 tokenize_string: chars -> T * chars
  1505 \<close> ML \<open>
  1506 val chars = Fdl_Lexer.explode_pos form_model_str'' Position.start: Fdl_Lexer.chars;
  1507 tokenize_string chars; (*3*) (* = WE ONLY GET THE FIRST ELEMENT tokenized, WHY?..
  1508    (Token (Comment, "Traegerlaenge L", {line=1, offset=2}),
  1509     [(",", {line=1, offset=18}), ("\"", {line=1, offset=19}), ("S", {line=1, offset=20}), ("t", {line=1, offset=21}), ("r", {line=1, offset=22}), ("e", {line=1, offset=23}), ("c", {line=1, offset=24}),
  1510      ("k", {line=1, offset=25}), ("...", {line=1, offset=26}), ...])*)
  1511 \<close> ML \<open>
  1512 \<close> ML \<open> (* gen_comment adapted for several strings (*4*) on simplified form_model_str''' *)
  1513 val tokenize_strings =
  1514   Fdl_Lexer.keyword "[" |-- !!! "unclosed list"
  1515     (Scan.repeat (Scan.unless (Fdl_Lexer.keyword "]") tokenize_string) --|
  1516   Fdl_Lexer.keyword "]");
  1517 tokenize_strings: chars -> T(*Token of kind * string * Position.T*) list * chars
  1518 \<close> ML \<open>
  1519 val chars = Fdl_Lexer.explode_pos form_model_str''' Position.start;
  1520 tokenize_strings chars;(* =       THIS LOOKS PROMISING..
  1521    ([Token (Comment, "Traegerlaenge L", {line=1, offset=3}), Token (Comment, "Streckenlast q_0", {line=1, offset=20}), Token (Comment, "Biegelinie y", {line=1, offset=38}),
  1522      Token (Comment, "Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]", {line=1, offset=52}), Token (Comment, "FunktionsVariable x", {line=1, offset=118}),
  1523      Token (Comment, "GleichungsVariablen [c, c_2, c_3, c_4]", {line=1, offset=139}), Token (Comment, "AbleitungBiegelinie dy", {line=1, offset=179})],
  1524     [])*)
  1525 \<close> ML \<open>
  1526 \<close> ML \<open> (*.. BUT THAT DOESN'T WORK FOR MORE REALISTIC DATA..*)
  1527 val chars = Fdl_Lexer.explode_pos form_model_str' Position.start;
  1528 (* (*6*)
  1529 tokenize_strings chars;
  1530 exception ABORT fn raised (line 109 of "General/scan.ML")*)
  1531 \<close> ML \<open>
  1532 \<close> ML \<open>
  1533 \<close> ML \<open> (*A NEW IDEA: postpone list-structure to Fld_Parser, now just make reasonable tokens *)
  1534 val chars = Fdl_Lexer.explode_pos "\"GleichungsVariablen [c, c_2, c_3, c_4]\"" Position.start;
  1535 tokenize_string chars; (* = (Token (Comment, "GleichungsVariablen [c, c_2, c_3, c_4]"*)
  1536 \<close> ML \<open>
  1537 \<close> ML \<open> (*..what about delimiters of lists?..*)
  1538 \<close> ML \<open> (*let's go bottom up..*)
  1539 val xxx =
  1540   whitespace --
  1541     keyword "(" --
  1542       keyword "[";
  1543 xxx: chars -> ((chars * chars) * chars) * chars;
  1544 \<close> ML \<open>
  1545 val xxx =
  1546                                       whitespace --
  1547     keyword "(" --
  1548       keyword "[" -- tokenize_string;
  1549 xxx: chars -> (((chars * chars) * chars) * T) * chars
  1550 \<close> ML \<open> (*                                 ^^^ list ?!*)
  1551 \<close> ML \<open>
  1552 val xxx =
  1553                                       whitespace --
  1554     keyword "(" --                    whitespace --
  1555       keyword "[" --                  whitespace --
  1556         tokenize_string;
  1557 xxx: chars -> (((((chars * chars) * chars) * chars) * chars) * T) * chars;
  1558 \<close> ML \<open> (* how can we drop  ^^^^^    ^^^^^    ^^ and make here ^^^ a list ?!
  1559           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*)
  1560 val chars = Fdl_Lexer.explode_pos "(\n  [\"Traegerlaenge L\""  Position.start;
  1561 \<close> ML \<open>
  1562 xxx chars; (* =  WE GET AN UNPLEASANT MIXTURE OF Fld_Lexer.T  AND Fld_Lexer.char ..
  1563    (((((([], [("(", {line=1, offset=1})]), [("\n", {line=1, offset=2}), (" ", {line=2, offset=3}), (" ", {line=2, offset=4})]), [("[", {line=2, offset=5})]), []),
  1564      Token (Comment, "Traegerlaenge L", {line=2, offset=7})),
  1565     [])*)
  1566 \<close> ML \<open>
  1567 tokenize_string: chars -> T * chars;
  1568 whitespace: chars -> chars * chars;
  1569 tokenize: (chars -> 'a * chars) -> (chars -> T * chars) -> Position.T -> string -> 'a * T list;
  1570 Scan.repeat: ('a -> 'b * 'a) -> 'a -> 'b list * 'a
  1571 (*                  ^^                ^^^^^^^                                           ^^^^^^*)
  1572 \<close> ML \<open>
  1573 \<close>  
  1574 
  1575 subsubsection \<open>have a closer look at SPARKs main tokenizer\<close>
  1576 ML \<open>
  1577 \<close> ML \<open> Fdl_Lexer.scan; (*7*) (*.. <ctrl><mouse> leads to the source *)
  1578 \<close> ML \<open>
  1579 val aaa = (*remove code specific for SPARK..*)
  1580   Scan.repeat (Scan.unless (Scan.one is_char_eof)
  1581     ( (*comment *)
  1582         (keyword "For" -- whitespace1) |--
  1583            Scan.repeat1 (Scan.unless (keyword ":") any) --|
  1584            keyword ":" >> make_token Traceability             
  1585      || Scan.max leq_token
  1586           (Scan.literal lexicon >> make_token Keyword)
  1587           (   long_identifier >> make_token Long_Ident
  1588            || identifier >> make_token Ident
  1589           )
  1590      || number >> make_token Number
  1591     )
  1592   );
  1593 \<close> ML \<open> (* we investigate the alternatives || and confirm observations from tracing:
  1594           EACH ROUND OF LEXING CREATES one TOKEN ----------------------vvv *)
  1595 (*fun scan header comment = ...                                                      (*8*)
  1596    (    comment *)
  1597   (*||*)(keyword "For" -- whitespace1) |--
  1598            Scan.repeat1 (Scan.unless (keyword ":") any) --|
  1599            keyword ":" >> make_token Traceability            : chars -> T * chars;
  1600   (*||*)Scan.max leq_token
  1601           (Scan.literal lexicon >> make_token Keyword)
  1602           (   long_identifier >> make_token Long_Ident
  1603            || identifier >> make_token Ident
  1604           )                                                  : chars -> T * chars;
  1605   (*||*)number >> make_token Number                          : chars -> T * chars;
  1606 (*                                               ----------------------^^^ *)
  1607 \<close> ML \<open>
  1608 val aaa = 
  1609   Scan.repeat (Scan.unless (Scan.one is_char_eof) (*8b*)
  1610     ((**)   (tokenize_string (**)-- whitespace(**))      (* reads a first string including , ]  *)
  1611      (**)|| (keyword "," >> tokenize_string)             (* further element of string list ?" " *)
  1612      (**)|| ((Scan.max leq_token                         (* *)
  1613      (**)    (Scan.literal lexicon >> make_token Keyword)(**)
  1614      (**)    (   long_identifier >> make_token Long_Ident(**)
  1615      (**)     || identifier >> make_token Ident)         (**)
  1616      (**)    )  -- whitespace)                           (**)
  1617     )
  1618   );
  1619 \<close> ML \<open>
  1620 val chars = Fdl_Lexer.explode_pos "\"aa\",\"bb\"] ##" Position.start;
  1621 \<close> ML \<open>
  1622 aaa chars; (* --------vvvv here we get both as Tokens, list elements AND list delimiters
  1623    ([(Token (Comment, "aa", {line=1, offset=2}), []),                            (*6a*)
  1624      (Token (Keyword, ",", {line=1, offset=5}), []), 
  1625      (Token (Comment, "bb", {line=1, offset=7}), []), 
  1626      (Token (Keyword, "]", {line=1, offset=10}), 
  1627      [(" ", {line=1, offset=11})])],
  1628     [("#", {line=1, offset=12}), ("#", {line=1, offset=13})])*)
  1629 \<close> ML \<open>
  1630 \<close> ML \<open>
  1631 \<close> ML \<open> (* what is this part of scan doing ..*)                    (*8*)
  1632 val yyy = Scan.max leq_token
  1633              (Scan.literal lexicon >> make_token Keyword)
  1634              (   long_identifier >> make_token Long_Ident
  1635               || identifier >> make_token Ident);
  1636 yyy: chars -> T * chars;
  1637 \<close> ML \<open>
  1638 val chars = Fdl_Lexer.explode_pos "For " Position.start;
  1639 (**)yyy chars;(* = (Token (Keyword, "For", {line=1, offset=1}), [(" ", ..*)
  1640 \<close> ML \<open>
  1641 val chars = Fdl_Lexer.explode_pos ", " Position.start;
  1642 (**)yyy chars;(* = (Token (Keyword, ",", {line=1, offset=1}), [(" ", ..*)
  1643 \<close> ML \<open>
  1644 val chars = Fdl_Lexer.explode_pos " , " Position.start;
  1645 (** )yyy chars;( * exception FAIL NONE raised (line 204 of "General/scan.ML") *)
  1646 \<close> ML \<open>
  1647 val chars = Fdl_Lexer.explode_pos "id " Position.start;
  1648 (**)yyy chars;(* = (Token (Ident, "id", {line=1, offset=1}), [(" ", ..*)
  1649 \<close> ML \<open>
  1650 val chars = Fdl_Lexer.explode_pos "spec.id " Position.start;
  1651 (**)yyy chars;(* = (Token (Long_Ident, "spec.id", {line=1, offset=1}), [(" ", ..*)
  1652 \<close> ML \<open> (*..we see: this part of scan handles whitespace perfectly! *)
  1653 \<close> ML \<open>
  1654 \<close>  
  1655 
  1656 subsubsection \<open>play with function types and construct them systematically\<close>
  1657 ML \<open>
  1658 \<close> ML \<open> (* string list is a string || keyword "," || whitespace*)            (*10*)
  1659 tokenize_string                  : chars -> T * chars;
  1660 keyword "," >> make_token Keyword: chars -> T * chars;
  1661 whitespace                       : chars -> chars * chars; (*? ? ? how make this of equal type *)
  1662 \<close> ML \<open>
  1663 val chars = Fdl_Lexer.explode_pos ",  " Position.start;                                     (*11*)
  1664 whitespace chars;
  1665 (* = ([], [(",", {line=1, offset=1}), (" ", {line=1, offset=2}), (" ", {line=1, offset=3})])*)
  1666 \<close> ML \<open>
  1667 val chars = Fdl_Lexer.explode_pos "  ," Position.start;                                     (*11*)
  1668 whitespace chars;
  1669 (* = ([(" ", {line=1, offset=1}), (" ", {line=1, offset=2})], [(",", {line=1, offset=3})])*)
  1670 \<close> ML \<open>
  1671 val chars = Fdl_Lexer.explode_pos " , " Position.start;                                     (*11*)
  1672 whitespace chars;
  1673 (* = ([(" ", {line=1, offset=1})], [(",", {line=1, offset=2}), (" ", {line=1, offset=3})])*)
  1674 \<close> ML \<open>
  1675 \<close> ML \<open>
  1676 \<close> ML \<open> (* investigate (whitespace -- keyword "," -- whitespace) >> make_token Keyword*)
  1677 \<close> ML \<open>
  1678 val xxx = (* this nicely separates whitespace from "," *)                                   (*12*)
  1679   (whitespace -- keyword "," -- whitespace): chars -> ((chars * chars) * chars) * chars;
  1680 val chars = Fdl_Lexer.explode_pos "   ,   ." Position.start;
  1681 xxx chars;
  1682 (* = (((
  1683     [(" ", {line=1, offset=1}), (" ", {line=1, offset=2}), (" ", {line=1, offset=3})], 
  1684 \<longrightarrow> [(",", {line=1, offset=4})]), 
  1685     [(" ", {line=1, offset=5}), (" ", {line=1, offset=6}), (" ", {line=1, offset=7})]),
  1686     [(".", {line=1, offset=8})])
  1687 ^^^^^^^^^^^^^^^^^^^^^^ this nicely separates whitespace from "," ^^^^^^^^^^^^^^^^^^^^^*)
  1688 \<close> ML \<open>
  1689 tokenize_string                                                            : chars -> T * chars;
  1690 (*whitespace*)keyword ","(*whitespace*) >> make_token Keyword              : chars -> T * chars;
  1691 (* we want this type uniformly for ||                                      ^^^^^^^^^^^^^^^^^^^^^ *)
  1692 \<close> ML \<open>
  1693 val eee = (fn (((_, chs1), _), chs2) => (chs1, chs2)) : (('a * 'b) * 'c) * 'd -> 'b * 'd;  (*14*)
  1694 \<close> text \<open> HOW CORRECT THIS...
  1695 (whitespace -- keyword "," -- whitespace) >> (fn (((_, chs1), _), chs2) => (chs1, chs2));
  1696 ERROR Can't unify (string * Position.T) list to 'a * 'b
  1697 \<close> ML \<open>
  1698 val fff = (fn (((_, chars), _), _) => chars)                :       (('a * 'b) * 'c) * 'd -> 'b;(*14*)
  1699 val ggg = (fn _ => (fn (((_, chars), _), _) => chars))      : 'a -> (('b * 'c) * 'd) * 'e -> 'c;
  1700 val hhh = (fn xxx => (fn (((_, chars), _), _) => chars) xxx):       (('a * 'b) * 'c) * 'd -> 'b;
  1701 val iii = (fn ((_, chars), _) => make_token Keyword chars)
  1702                                                             :      ('a * chars) * 'b -> T
  1703 \<close> ML \<open>
  1704 \<close> ML \<open> (*after above trials we use this pattern for building comma_spaced *)                   (*11a*)
  1705 keyword ","                        : chars -> chars                          * chars;
  1706 make_token Keyword                 :          chars                     -> T        ; 
  1707 keyword "," >> make_token Keyword  : chars ->                              T * chars;
  1708                                                                         
  1709 tokenize_string                    : chars ->                              T * chars;
  1710 whitespace                         : chars -> chars                          * chars;
  1711 \<close> ML \<open>
  1712 \<close> ML \<open>
  1713 val space_comma_space = xxx;
  1714 val make_token_comma = iii;
  1715 val comma_spaced = space_comma_space >> make_token_comma
  1716 \<close> ML \<open>
  1717 xxx  : chars -> ((chars * chars) * chars) * chars;
  1718 (**)
  1719 space_comma_space                  : chars -> ((chars * chars) * chars)      * chars;
  1720 make_token_comma                   :          ((chars * chars) * chars) -> T        ;
  1721 comma_spaced                       : chars ->                              T * chars; (**)
  1722 \<close> ML \<open>
  1723 val chars = Fdl_Lexer.explode_pos "   ,   ." Position.start;
  1724 comma_spaced chars; (*(Token (Keyword, ",", {line=1, offset=4}), [(".", {line=1, offset=8})])*)
  1725 (*\--------- found right type for arguments of Scan.repeat ---------------------------------/*)
  1726 \<close> ML \<open>
  1727 \<close> ML \<open>
  1728 \<close> ML \<open> (*we use that for a list tokenizer..*) (*13*)
  1729 val string_list = 
  1730   Scan.repeat (tokenize_string || comma_spaced);
  1731 string_list: chars -> T list * chars
  1732 \<close> ML \<open>
  1733 val chars = Fdl_Lexer.explode_pos form_model_str'' Position.start;
  1734 \<close> ML \<open> (* tokenize_string_list works..*)
  1735 string_list chars; (* =
  1736    ([Token (Comment, "Traegerlaenge L", {line=1, offset=2})  , Token (Keyword, ",", {line=1, offset=18}), 
  1737      Token (Comment, "Streckenlast q_0", {line=1, offset=20}), Token (Keyword, ",", {line=1, offset=37}),
  1738      Token (Comment, "Biegelinie y", {line=1, offset=39})    , Token (Keyword, ",", {line=1, offset=52}), 
  1739      Token (Comment, "Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]", {line=1, offset=54}), 
  1740                                                                Token (Keyword, ",", {line=1, offset=119}), 
  1741      Token (Comment, "FunktionsVariable x", {line=1, offset=121}), 
  1742                                                                Token (Keyword, ",", {line=1, offset=141}),
  1743      Token (Comment, "GleichungsVariablen [c, c_2, c_3, c_4]", {line=1, offset=144}), 
  1744                                                                Token (Keyword, ",", {line=1, offset=183}), 
  1745      Token (Comment, "AbleitungBiegelinie dy", {line=1, offset=185})],
  1746     [("]", {line=1, offset=208})])*)
  1747 \<close> ML \<open>
  1748 \<close> ML \<open>
  1749 \<close> ML \<open> (*but how connect with tokenizing other parts?..*)
  1750 string_list :                          chars ->  T list * chars;
  1751 Scan.repeat1: ('a    -> 'b * 'a   ) -> 'a    -> 'b list * 'a;
  1752 Scan.repeat1: (chars -> 'b * chars) -> chars -> 'b list * chars;
  1753 \<close> ML \<open>
  1754 op @@@ : ('a -> 'b list * 'c) * ('c -> 'b list * 'd) -> 'a -> 'b list * 'd;
  1755 op ::: : ('a -> 'b * 'c) * ('c -> 'b list * 'd) -> 'a -> 'b list * 'd;
  1756 op --  : ('a -> 'b * 'c) * ('c -> 'd * 'e) -> 'a -> ('b * 'd) * 'e
  1757 \<close> ML \<open>
  1758 \<close> 
  1759 
  1760 subsubsection \<open>adapt Fdl_Lexer.scan to a tokenizer\<close>
  1761 ML \<open>
  1762 \<close> ML \<open> Fdl_Lexer.scan; (*<ctrl><mouse-click> jumps to the code*) (*14*) 
  1763 \<close> ML \<open> (*the first top down trial fails..*)
  1764 val xxx =
  1765 (*fun scan (*header comment*) =
  1766 ( *!!! "bad header" header --| whitespace --*)
  1767   Scan.repeat (Scan.unless (Scan.one is_char_eof)
  1768     (!!! "bad input"
  1769        ( (*comment
  1770         ||*)(keyword "For" -- whitespace1) |--
  1771               Scan.repeat1 (Scan.unless (keyword ":") any) --|
  1772               keyword ":" >> make_token Traceability             
  1773         || Scan.max leq_token
  1774              (Scan.literal lexicon >> make_token Keyword)
  1775              (   long_identifier >> make_token Long_Ident
  1776               || identifier >> make_token Ident)
  1777         (*|| number >> make_token Number*)) --|
  1778      whitespace) );
  1779 xxx: chars -> T list * chars;
  1780 \<close> ML \<open> (*.. but we see, that the scanner delivers a token per call..*)
  1781 \<close> ML \<open>
  1782 \<close> ML \<open> (*we want a string like "GleichungsVariablen [c, c_2, c_3, c_4]" in ONE token*)
  1783 val chars = Fdl_Lexer.explode_pos (form_single_str ^ ",") Position.start;
  1784 (** )
  1785 xxx chars;
  1786 ( ** )ERROR exception ABORT fn raised (line 109 of "General/scan.ML")( **)
  1787 \<close> ML \<open>
  1788 \<close> ML \<open>
  1789 \<close> ML \<open> (*we have to tokenize [ and ] and , explicitly..*)
  1790 val xxx =
  1791   keyword "[" -- whitespace --
  1792   Scan.repeat (tokenize_string || comma_spaced) --
  1793   keyword "]"
  1794 \<close> ML \<open>
  1795 val chars = Fdl_Lexer.explode_pos (form_model_str' ^ ".") Position.start;
  1796 xxx chars; (* =    AGAIN WE GET AN UNPLEASANT MIXTURE..
  1797    (((([("[", {line=1, offset=1})], []),
  1798       [Token (Comment, "Traegerlaenge L", {line=1, offset=3}), Token (Keyword, ",", {line=1, offset=19}), Token (Comment, "Streckenlast q_0", {line=1, offset=21}), Token (Keyword, ",", {line=1, offset=38}),
  1799        Token (Comment, "Biegelinie y", {line=1, offset=40}), Token (Keyword, ",", {line=1, offset=53}), Token (Comment, "Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]", {line=1, offset=55}),
  1800        Token (Keyword, ",", {line=1, offset=120}), Token (Comment, "FunktionsVariable x", {line=1, offset=122}), Token (Keyword, ",", {line=1, offset=142}),
  1801        Token (Comment, "GleichungsVariablen [c, c_2, c_3, c_4]", {line=1, offset=145}), Token (Keyword, ",", {line=1, offset=184}), Token (Comment, "AbleitungBiegelinie dy", {line=1, offset=186})]),
  1802      [("]", {line=1, offset=209})]),
  1803     [(".", {line=1, offset=210})])*)
  1804 \<close> ML \<open>
  1805 \<close> ML \<open>
  1806 \<close> ML \<open> (* IDEA COMBINING (*8*) and (*13*) for (*15*):
  1807           we do NOT tokenize the whole (string) list, but tokenize_string FIRST *)
  1808 val scan =
  1809 (*fun scan (*header comment*) =
  1810 ( *!!! "bad header" header --| whitespace --*)
  1811   Scan.repeat (Scan.unless (Scan.one is_char_eof)
  1812     (!!! "bad input"
  1813        (   tokenize_string                              (*.. THIS MUST BE FIRST *)
  1814            (*comment
  1815         ||(keyword "For" -- whitespace1) |--
  1816               Scan.repeat1 (Scan.unless (keyword ":") any) --|
  1817               keyword ":" >> make_token Traceability*)
  1818         ||Scan.max leq_token
  1819              (Scan.literal lexicon >> make_token Keyword)
  1820              (   long_identifier >> make_token Long_Ident
  1821               || identifier >> make_token Ident)
  1822       (*|| number >> make_token Number*) ) --|
  1823      whitespace) );
  1824 scan: chars -> T list * chars;
  1825 \<close> ML \<open>
  1826 val chars = Fdl_Lexer.explode_pos (form_single_str ^ ",") Position.start;
  1827 (** )
  1828 xxx chars;
  1829 ( ** )ERROR exception ABORT fn raised (line 109 of "General/scan.ML")( **)
  1830 \<close> ML \<open> (*BUT WITH THE WRAPPER IN tokenize THAT WORKS..*)
  1831 (*fun tokenize_formalise pos str =   KEEP IDENTIFIERS CLOSE TO SPARK..*)
  1832 fun scan' pos str =
  1833 (Scan.finite char_stopper
  1834     (Scan.error scan) (explode_pos str pos));
  1835 \<close> ML \<open>
  1836 val (toks, _) = scan' Position.start formalise_str
  1837 \<close> ML \<open>
  1838 (*it =       ----------------------------------------------------------------- IS PEFECT ! ! ! !
  1839    ([Token (Keyword, "[", {line=1, offset=1}), 
  1840        Token (Keyword, "(", {line=1, offset=2}), 
  1841          Token (Keyword, "[", {line=2, offset=6}), 
  1842            Token (Comment, "Traegerlaenge L", {line=2, offset=8}), Token (Keyword, ",", {line=2, offset=24}), Token (Comment, "Streckenlast q_0", {line=2, offset=27}), Token (Keyword, ",", {line=2, offset=44}), Token (Comment, "Biegelinie y", {line=2, offset=47}), Token (Keyword, ",", {line=2, offset=60}), Token (Comment, "Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]", {line=3, offset=67}), Token (Keyword, ",", {line=3, offset=132}), Token (Comment, "FunktionsVariable x", {line=4, offset=139}), Token (Keyword, ",", {line=4, offset=159}), Token (Comment, "GleichungsVariablen [c, c_2, c_3, c_4]", {line=4, offset=162}), Token (Keyword, ",", {line=4, offset=201}), Token (Comment, "AbleitungBiegelinie dy", {line=5, offset=208}), 
  1843          Token (Keyword, "]", {line=5, offset=231}), 
  1844        Token (Keyword, ",", {line=5, offset=232}),
  1845          Token (Keyword, "(", {line=6, offset=236}), 
  1846            Token (Comment, "Biegelinie", {line=6, offset=238}), 
  1847          Token (Keyword, ",", {line=6, offset=249}), 
  1848            Token (Keyword, "[", {line=6, offset=251}),
  1849              Token (Comment, "Biegelinien", {line=6, offset=253}), 
  1850            Token (Keyword, "]", {line=6, offset=265}), 
  1851          Token (Keyword, ",", {line=6, offset=266}), 
  1852            Token (Keyword, "[", {line=6, offset=268}),
  1853              Token (Comment, "IntegrierenUndKonstanteBestimmen2", {line=6, offset=270}), 
  1854            Token (Keyword, "]", {line=6, offset=304}), 
  1855          Token (Keyword, ")", {line=6, offset=305}), 
  1856        Token (Keyword, ")", {line=7, offset=307}),
  1857      Token (Keyword, "]", {line=7, offset=308})],
  1858     [])
  1859 \-- ^^ chars EXHAUSTED, PEFECT *)
  1860 \<close> ML \<open>
  1861 \<close> ML \<open>
  1862 \<close>
  1863 
  1864 subsubsection \<open>Implement the parser\<close>
  1865 ML \<open>
  1866 \<close> ML \<open> (*the only difference between Parse and Fdl_Parser is Token.T versus Fdl_Lexer.T *)
  1867 Parse.enum1: 
  1868   string ->                      'a parser                                  -> 'a list parser;
  1869 Parse.enum1: 
  1870   string -> (Token.T     list -> 'a * Token.T     list) -> Token.T list     -> 'a list * Token.T     list;
  1871 Fdl_Parser.enum1: 
  1872   string -> (Fdl_Lexer.T list -> 'a * Fdl_Lexer.T list) -> Fdl_Lexer.T list -> 'a list * Fdl_Lexer.T list;
  1873 \<close> ML \<open>
  1874 \<close> ML \<open> (*we start with the initial parentheses..*)
  1875 val xxx =
  1876   Fdl_Parser.$$$ "[" --
  1877     Fdl_Parser.$$$ "(" --
  1878       Fdl_Parser.$$$ "[" |-- 
  1879         Fdl_Parser.!!! (Fdl_Parser.list1 Fdl_Parser.identifier --| 
  1880       Fdl_Parser.$$$ "]")
  1881 \<close> ML \<open> (*need string_list_parser instead ^^^^^^^^^^^^^^^^^^^^^*)
  1882 \<close> ML \<open> (*..vvvvvvvvvv is our model..*)
  1883 Fdl_Parser.identifier: T list -> string * T list;
  1884 \<close> ML \<open> (*we have..*)
  1885 tokenize_string      : chars -> T * chars; (*we need:
  1886 parse_string         : T list -> string * T list;    *)
  1887 \<close> ML \<open>
  1888 \<close> ML \<open> (*in analogy to Fdl_Parser ..*)
  1889 val identifier = Fdl_Parser.group "identifier"
  1890   (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Ident) >>
  1891      Fdl_Lexer.content_of);
  1892 \<close> ML \<open> (*.. we implement..*)
  1893 val parse_string = Fdl_Parser.group "string"
  1894   (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Comment) >>
  1895      Fdl_Lexer.content_of);
  1896 parse_string         : T list -> string * T list;
  1897 \<close> ML \<open> (*we copy the structure from *101* *)
  1898 val xxx =
  1899   Fdl_Parser.$$$ "[" --
  1900     Fdl_Parser.$$$ "(" --
  1901       (Fdl_Parser.$$$ "[" |-- Fdl_Parser.!!! (
  1902         Fdl_Parser.list1 parse_string --| 
  1903       Fdl_Parser.$$$ "]")) --
  1904     Fdl_Parser.$$$ "," --
  1905       Fdl_Parser.$$$ "(" --
  1906         parse_string --                     (* "Biegelinie" *)
  1907       Fdl_Parser.$$$ "," --
  1908         (Fdl_Parser.$$$ "[" |-- Fdl_Parser.!!! (
  1909           Fdl_Parser.list1 parse_string --| (* ["Biegelinien"] *)
  1910         Fdl_Parser.$$$ "]")) --
  1911       Fdl_Parser.$$$ "," --
  1912         (Fdl_Parser.$$$ "[" |-- Fdl_Parser.!!! (
  1913           Fdl_Parser.list1 parse_string --| (* ["IntegrierenUndKonstanteBestimmen2"] *)
  1914         Fdl_Parser.$$$ "]")) --
  1915       Fdl_Parser.$$$ ")" --
  1916     Fdl_Parser.$$$ ")" --
  1917   Fdl_Parser.$$$ "]"
  1918 \<close> ML \<open> (*.. this compiles correctly, but we modularise into parse_form_model..*)
  1919 val parse_form_model =
  1920   (Fdl_Parser.$$$ "[" |-- Fdl_Parser.!!! (
  1921     Fdl_Parser.list1 parse_string --| 
  1922   Fdl_Parser.$$$ "]"));
  1923 parse_form_model: T list -> string list * T list;
  1924 \<close> ML \<open>
  1925 type form_model =           string list;
  1926 parse_form_model: T list -> form_model   * T list
  1927 \<close> ML \<open>
  1928 \<close> ML \<open> (*.. and into parse_form_refs..*)
  1929 val parse_form_refs = 
  1930   Fdl_Parser.$$$ "(" --
  1931     parse_string --                     (* "Biegelinie" *)
  1932   Fdl_Parser.$$$ "," --
  1933     (Fdl_Parser.$$$ "[" |-- Fdl_Parser.!!! (
  1934       Fdl_Parser.list1 parse_string --| (* ["Biegelinien"] *)
  1935     Fdl_Parser.$$$ "]")) --
  1936   Fdl_Parser.$$$ "," --
  1937     (Fdl_Parser.$$$ "[" |-- Fdl_Parser.!!! (
  1938       Fdl_Parser.list1 parse_string --| (* ["IntegrierenUndKonstanteBestimmen2"] *)
  1939     Fdl_Parser.$$$ "]")) --
  1940   Fdl_Parser.$$$ ")";
  1941 parse_form_refs: T list -> ((((((string * string) * string) * string list) * string) * string list) * string) * T list;
  1942 \<close> ML \<open>
  1943 type form_refs = (((((string * string) * string) * string list) * string) * string list) * string;
  1944 parse_form_refs: T list -> form_refs * T list; (*..how can we use this type --------------vvvvv*)
  1945 \<close> ML \<open>
  1946 \<close> ML \<open> (*we combinge parse_form_model and parse_form_refs..*)
  1947 (*val parse_formalise =   KEEP IDENTIFIERS CLOSE TO SPARK..*)
  1948 val vcs =
  1949   Fdl_Parser.!!! (
  1950     Fdl_Parser.$$$ "[" --
  1951       Fdl_Parser.$$$ "(" --
  1952         parse_form_model --
  1953       Fdl_Parser.$$$ "," --
  1954         parse_form_refs --
  1955       Fdl_Parser.$$$ ")" --
  1956     Fdl_Parser.$$$ "]");
  1957 (*                                      vvvvvvvvvv*)
  1958 vcs: T list -> ((((((string * string) * form_model) * string) * (*------------refs..*)
  1959   ((((((string * string) * string) * string list) * string) * string list) * string)) * string) * string) * T list;
  1960 \<close> ML \<open>
  1961 \<close> ML \<open> (*we use code from the parser..*)
  1962 val (parsed', []) = (*TODO *##* *)
  1963 Scan.finite Fdl_Lexer.stopper (Scan.error (Fdl_Parser.!!! vcs)) toks;
  1964 (*see SPARK 99, but ..^^^^^^^ we don't need that ---------vvv   vvvv*)
  1965 \<close> ML \<open>
  1966 val (parsed', []) =                                       vcs   toks;
  1967 \<close> ML \<open> (*..however, we adopt   vvvvvvvvvvvvvvvvvvvvvvvvvv error handling*)
  1968 val (parsed', []) =           (Scan.error (Fdl_Parser.!!! vcs)) toks;
  1969 \<close> ML \<open>
  1970 case parsed' of
  1971  ((((( (
  1972   "[", 
  1973     "("),
  1974       [ "Traegerlaenge L", "Streckenlast q_0", "Biegelinie y", 
  1975         "Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]", "FunktionsVariable x", 
  1976         "GleichungsVariablen [c, c_2, c_3, c_4]", "AbleitungBiegelinie dy"
  1977       ]),
  1978     ","), ((((((
  1979       "(", 
  1980         "Biegelinie"), 
  1981       ","), 
  1982         ["Biegelinien"]), 
  1983       ","), 
  1984         ["IntegrierenUndKonstanteBestimmen2"]), 
  1985       ")")),
  1986     ")"),
  1987   "]") => ()
  1988 | _ => error "parse_formalise CHANGED";
  1989 \<close> ML \<open>
  1990 \<close> ML \<open> (*we read out Formalisation.T from the parser's result..*)
  1991 fun read_out_formalise ((((( (
  1992   "[", 
  1993     "("),
  1994       form_model: TermC.as_string list),
  1995     ","), ((((((
  1996       "(", 
  1997         thy_id: ThyC.id), 
  1998       ","), 
  1999         probl_id: Problem.id), 
  2000       ","), 
  2001         meth_id: Method.id), 
  2002       ")")),
  2003     ")"),
  2004   "]") = [(form_model, (thy_id, probl_id, meth_id))]
  2005 | read_out_formalise _ =
  2006   raise ERROR "read_out_formalise: WRONGLY parsed";
  2007 read_out_formalise:
  2008   (((((string * string) * TermC.as_string list) * string) * 
  2009       ((((((string * ThyC.id) * string) * Problem.id) * string) * Method.id) * string)) * string) * string ->
  2010     (TermC.as_string list * (ThyC.id * Problem.id * Method.id)) list;
  2011 \<close> ML \<open>
  2012 type formalise = (((((string * string) * TermC.as_string list) * string) *
  2013   ((((((string * ThyC.id) * string) * Problem.id) * string) * Method.id) * string)) * string) * string;
  2014 read_out_formalise: formalise -> Formalise.T list
  2015 \<close> ML \<open>
  2016 if (read_out_formalise parsed' : Formalise.T list ) =
  2017   [(["Traegerlaenge L", "Streckenlast q_0", "Biegelinie y",
  2018      "Randbedingungen [y 0 = (0::real), y L = 0, M_b 0 = 0, M_b L = 0]", "FunktionsVariable x", 
  2019      "GleichungsVariablen [c, c_2, c_3, c_4]", "AbleitungBiegelinie dy"],
  2020    ("Biegelinie", ["Biegelinien"], ["IntegrierenUndKonstanteBestimmen2"]))]
  2021 then () else error "read_out_formalise CHANGED";
  2022 \<close> ML \<open>
  2023 \<close>
  2024 
  2025 end