src/HOL/SMT/Tools/z3_proof_parser.ML
changeset 36898 8e55aa1306c5
parent 36897 6d1ecdb81ff0
child 36899 bcd6fce5bf06
equal deleted inserted replaced
36897:6d1ecdb81ff0 36898:8e55aa1306c5
     1 (*  Title:      HOL/SMT/Tools/z3_proof_parser.ML
       
     2     Author:     Sascha Boehme, TU Muenchen
       
     3 
       
     4 Parser for Z3 proofs.
       
     5 *)
       
     6 
       
     7 signature Z3_PROOF_PARSER =
       
     8 sig
       
     9   (* proof rules *)
       
    10   datatype rule = TrueAxiom | Asserted | Goal | ModusPonens | Reflexivity |
       
    11     Symmetry | Transitivity | TransitivityStar | Monotonicity | QuantIntro |
       
    12     Distributivity | AndElim | NotOrElim | Rewrite | RewriteStar | PullQuant |
       
    13     PullQuantStar | PushQuant | ElimUnusedVars | DestEqRes | QuantInst |
       
    14     Hypothesis | Lemma | UnitResolution | IffTrue | IffFalse | Commutativity |
       
    15     DefAxiom | IntroDef | ApplyDef | IffOeq | NnfPos | NnfNeg | NnfStar |
       
    16     CnfStar | Skolemize | ModusPonensOeq | ThLemma
       
    17   val string_of_rule: rule -> string
       
    18 
       
    19   (* proof parser *)
       
    20   datatype proof_step = Proof_Step of {
       
    21     rule: rule,
       
    22     prems: int list,
       
    23     prop: cterm }
       
    24   val parse: Proof.context -> typ Symtab.table -> term Symtab.table ->
       
    25     string list ->
       
    26     int * (proof_step Inttab.table * string list * Proof.context)
       
    27 end
       
    28 
       
    29 structure Z3_Proof_Parser: Z3_PROOF_PARSER =
       
    30 struct
       
    31 
       
    32 (** proof rules **)
       
    33 
       
    34 datatype rule = TrueAxiom | Asserted | Goal | ModusPonens | Reflexivity |
       
    35   Symmetry | Transitivity | TransitivityStar | Monotonicity | QuantIntro |
       
    36   Distributivity | AndElim | NotOrElim | Rewrite | RewriteStar | PullQuant |
       
    37   PullQuantStar | PushQuant | ElimUnusedVars | DestEqRes | QuantInst |
       
    38   Hypothesis | Lemma | UnitResolution | IffTrue | IffFalse | Commutativity |
       
    39   DefAxiom | IntroDef | ApplyDef | IffOeq | NnfPos | NnfNeg | NnfStar |
       
    40   CnfStar | Skolemize | ModusPonensOeq | ThLemma
       
    41 
       
    42 val rule_names = Symtab.make [
       
    43   ("true-axiom", TrueAxiom),
       
    44   ("asserted", Asserted),
       
    45   ("goal", Goal),
       
    46   ("mp", ModusPonens),
       
    47   ("refl", Reflexivity),
       
    48   ("symm", Symmetry),
       
    49   ("trans", Transitivity),
       
    50   ("trans*", TransitivityStar),
       
    51   ("monotonicity", Monotonicity),
       
    52   ("quant-intro", QuantIntro),
       
    53   ("distributivity", Distributivity),
       
    54   ("and-elim", AndElim),
       
    55   ("not-or-elim", NotOrElim),
       
    56   ("rewrite", Rewrite),
       
    57   ("rewrite*", RewriteStar),
       
    58   ("pull-quant", PullQuant),
       
    59   ("pull-quant*", PullQuantStar),
       
    60   ("push-quant", PushQuant),
       
    61   ("elim-unused", ElimUnusedVars),
       
    62   ("der", DestEqRes),
       
    63   ("quant-inst", QuantInst),
       
    64   ("hypothesis", Hypothesis),
       
    65   ("lemma", Lemma),
       
    66   ("unit-resolution", UnitResolution),
       
    67   ("iff-true", IffTrue),
       
    68   ("iff-false", IffFalse),
       
    69   ("commutativity", Commutativity),
       
    70   ("def-axiom", DefAxiom),
       
    71   ("intro-def", IntroDef),
       
    72   ("apply-def", ApplyDef),
       
    73   ("iff~", IffOeq),
       
    74   ("nnf-pos", NnfPos),
       
    75   ("nnf-neg", NnfNeg),
       
    76   ("nnf*", NnfStar),
       
    77   ("cnf*", CnfStar),
       
    78   ("sk", Skolemize),
       
    79   ("mp~", ModusPonensOeq),
       
    80   ("th-lemma", ThLemma)]
       
    81 
       
    82 fun string_of_rule r =
       
    83   let fun eq_rule (s, r') = if r = r' then SOME s else NONE 
       
    84   in the (Symtab.get_first eq_rule rule_names) end
       
    85 
       
    86 
       
    87 
       
    88 (** certified terms and variables **)
       
    89 
       
    90 val (var_prefix, decl_prefix) = ("v", "sk")  (* must be distinct *)
       
    91 
       
    92 fun instTs cUs (cTs, ct) = Thm.instantiate_cterm (cTs ~~ cUs, []) ct
       
    93 fun instT cU (cT, ct) = instTs [cU] ([cT], ct)
       
    94 fun mk_inst_pair destT cpat = (destT (Thm.ctyp_of_term cpat), cpat)
       
    95 val destT1 = hd o Thm.dest_ctyp
       
    96 val destT2 = hd o tl o Thm.dest_ctyp
       
    97 
       
    98 fun ctyp_of (ct, _) = Thm.ctyp_of_term ct
       
    99 fun instT' t = instT (ctyp_of t)
       
   100 
       
   101 fun certify ctxt = Thm.cterm_of (ProofContext.theory_of ctxt)
       
   102 
       
   103 val maxidx_of = #maxidx o Thm.rep_cterm
       
   104 
       
   105 fun mk_inst ctxt vars =
       
   106   let
       
   107     val max = fold (Integer.max o fst) vars 0
       
   108     val ns = fst (Variable.variant_fixes (replicate (max + 1) var_prefix) ctxt)
       
   109     fun mk (i, v) = (v, certify ctxt (Free (nth ns i, #T (Thm.rep_cterm v))))
       
   110   in map mk vars end
       
   111 
       
   112 fun close ctxt (ct, vars) =
       
   113   let
       
   114     val inst = mk_inst ctxt vars
       
   115     val mk_prop = Thm.capply @{cterm Trueprop}
       
   116     val names = fold (Term.add_free_names o Thm.term_of o snd) inst []
       
   117   in (mk_prop (Thm.instantiate_cterm ([], inst) ct), names) end
       
   118 
       
   119 
       
   120 fun mk_bound thy (i, T) =
       
   121   let val ct = Thm.cterm_of thy (Var ((Name.uu, 0), T))
       
   122   in (ct, [(i, ct)]) end
       
   123 
       
   124 local
       
   125   fun mk_quant thy q T (ct, vars) =
       
   126     let
       
   127       val cv =
       
   128         (case AList.lookup (op =) vars 0 of
       
   129           SOME cv => cv
       
   130         | _ => Thm.cterm_of thy (Var ((Name.uu, maxidx_of ct + 1), T)))
       
   131       val cq = instT (Thm.ctyp_of_term cv) q
       
   132       fun dec (i, v) = if i = 0 then NONE else SOME (i-1, v)
       
   133     in (Thm.capply cq (Thm.cabs cv ct), map_filter dec vars) end
       
   134 
       
   135   val forall = mk_inst_pair (destT1 o destT1) @{cpat All}
       
   136   val exists = mk_inst_pair (destT1 o destT1) @{cpat Ex}
       
   137 in
       
   138 fun mk_forall thy = fold_rev (mk_quant thy forall)
       
   139 fun mk_exists thy = fold_rev (mk_quant thy exists)
       
   140 end
       
   141 
       
   142 
       
   143 local
       
   144   fun equal_var cv (_, cu) = (cv aconvc cu)
       
   145 
       
   146   fun apply (ct2, vars2) (ct1, vars1) =
       
   147     let
       
   148       val incr = Thm.incr_indexes_cterm (maxidx_of ct1 + maxidx_of ct2 + 2)
       
   149 
       
   150       fun part (v as (i, cv)) =
       
   151         (case AList.lookup (op =) vars1 i of
       
   152           SOME cu => apfst (if cu aconvc cv then I else cons (cv, cu))
       
   153         | NONE =>
       
   154             if not (exists (equal_var cv) vars1) then apsnd (cons v)
       
   155             else
       
   156               let val cv' = incr cv
       
   157               in apfst (cons (cv, cv')) #> apsnd (cons (i, cv')) end)
       
   158 
       
   159       val (ct2', vars2') =
       
   160         if null vars1 then (ct2, vars2)
       
   161         else fold part vars2 ([], [])
       
   162           |>> (fn inst => Thm.instantiate_cterm ([], inst) ct2)
       
   163 
       
   164     in (Thm.capply ct1 ct2', vars1 @ vars2') end
       
   165 in
       
   166 fun mk_fun ct ts = fold apply ts (ct, [])
       
   167 fun mk_binop f t u = mk_fun f [t, u]
       
   168 fun mk_nary _ e [] = e
       
   169   | mk_nary ct _ es = uncurry (fold_rev (mk_binop ct)) (split_last es)
       
   170 end
       
   171 
       
   172 
       
   173 val mk_true = mk_fun @{cterm "~False"} []
       
   174 val mk_false = mk_fun @{cterm "False"} []
       
   175 fun mk_not t = mk_fun @{cterm Not} [t]
       
   176 val mk_imp = mk_binop @{cterm "op -->"}
       
   177 val mk_iff = mk_binop @{cterm "op = :: bool => _"}
       
   178 
       
   179 val eq = mk_inst_pair destT1 @{cpat "op ="}
       
   180 fun mk_eq t u = mk_binop (instT' t eq) t u
       
   181 
       
   182 val if_term = mk_inst_pair (destT1 o destT2) @{cpat If}
       
   183 fun mk_if c t u = mk_fun (instT' t if_term) [c, t, u]
       
   184 
       
   185 val nil_term = mk_inst_pair destT1 @{cpat Nil}
       
   186 val cons_term = mk_inst_pair destT1 @{cpat Cons}
       
   187 fun mk_list cT es =
       
   188   fold_rev (mk_binop (instT cT cons_term)) es (mk_fun (instT cT nil_term) [])
       
   189 
       
   190 val distinct = mk_inst_pair (destT1 o destT1) @{cpat distinct}
       
   191 fun mk_distinct [] = mk_true
       
   192   | mk_distinct (es as (e :: _)) =
       
   193       mk_fun (instT' e distinct) [mk_list (ctyp_of e) es]
       
   194 
       
   195 
       
   196 (* arithmetic *)
       
   197 
       
   198 fun mk_int_num i = mk_fun (Numeral.mk_cnumber @{ctyp int} i) []
       
   199 fun mk_real_num i = mk_fun (Numeral.mk_cnumber @{ctyp real} i) []
       
   200 fun mk_real_frac_num (e, NONE) = mk_real_num e
       
   201   | mk_real_frac_num (e, SOME d) =
       
   202       mk_binop @{cterm "op / :: real => _"} (mk_real_num e) (mk_real_num d)
       
   203 
       
   204 fun has_int_type e = (Thm.typ_of (ctyp_of e) = @{typ int})
       
   205 fun choose e i r = if has_int_type e then i else r
       
   206 
       
   207 val uminus_i = @{cterm "uminus :: int => _"}
       
   208 val uminus_r = @{cterm "uminus :: real => _"}
       
   209 fun mk_uminus e = mk_fun (choose e uminus_i uminus_r) [e]
       
   210 
       
   211 fun arith_op int_op real_op t u = mk_binop (choose t int_op real_op) t u
       
   212 
       
   213 val mk_add = arith_op @{cterm "op + :: int => _"} @{cterm "op + :: real => _"}
       
   214 val mk_sub = arith_op @{cterm "op - :: int => _"} @{cterm "op - :: real => _"}
       
   215 val mk_mul = arith_op @{cterm "op * :: int => _"} @{cterm "op * :: real => _"}
       
   216 val mk_int_div = mk_binop @{cterm "op div :: int => _"}
       
   217 val mk_real_div = mk_binop @{cterm "op / :: real => _"}
       
   218 val mk_mod = mk_binop @{cterm "op mod :: int => _"}
       
   219 val mk_lt = arith_op @{cterm "op < :: int => _"} @{cterm "op < :: real => _"}
       
   220 val mk_le = arith_op @{cterm "op <= :: int => _"} @{cterm "op <= :: real => _"}
       
   221 
       
   222 
       
   223 (* arrays *)
       
   224 
       
   225 val access = mk_inst_pair (Thm.dest_ctyp o destT1) @{cpat apply}
       
   226 fun mk_access array index =
       
   227   let val cTs = Thm.dest_ctyp (ctyp_of array)
       
   228   in mk_fun (instTs cTs access) [array, index] end
       
   229 
       
   230 val update = mk_inst_pair (Thm.dest_ctyp o destT1) @{cpat fun_upd}
       
   231 fun mk_update array index value =
       
   232   let val cTs = Thm.dest_ctyp (ctyp_of array)
       
   233   in mk_fun (instTs cTs update) [array, index, value] end
       
   234 
       
   235 
       
   236 (* bitvectors *)
       
   237 
       
   238 fun mk_binT size =
       
   239   let
       
   240     fun bitT i T =
       
   241       if i = 0
       
   242       then Type (@{type_name "Numeral_Type.bit0"}, [T])
       
   243       else Type (@{type_name "Numeral_Type.bit1"}, [T])
       
   244 
       
   245     fun binT i =
       
   246       if i = 0 then @{typ "Numeral_Type.num0"}
       
   247       else if i = 1 then @{typ "Numeral_Type.num1"}
       
   248       else let val (q, r) = Integer.div_mod i 2 in bitT r (binT q) end
       
   249   in
       
   250     if size >= 0 then binT size
       
   251     else raise TYPE ("mk_binT: " ^ string_of_int size, [], [])
       
   252   end
       
   253 
       
   254 fun mk_wordT size = Type (@{type_name "word"}, [mk_binT size])
       
   255 
       
   256 fun mk_bv_num thy (num, size) =
       
   257   mk_fun (Numeral.mk_cnumber (Thm.ctyp_of thy (mk_wordT size)) num) []
       
   258 
       
   259 
       
   260 
       
   261 (** proof parser **)
       
   262 
       
   263 datatype proof_step = Proof_Step of {
       
   264   rule: rule,
       
   265   prems: int list,
       
   266   prop: cterm }
       
   267 
       
   268 
       
   269 (* parser context *)
       
   270 
       
   271 fun make_context ctxt typs terms =
       
   272   let
       
   273     val ctxt' = 
       
   274       ctxt
       
   275       |> Symtab.fold (Variable.declare_typ o snd) typs
       
   276       |> Symtab.fold (Variable.declare_term o snd) terms
       
   277 
       
   278     fun cert @{term True} = @{cterm "~False"}
       
   279       | cert t = certify ctxt' t
       
   280   in (typs, Symtab.map cert terms, Inttab.empty, Inttab.empty, [], ctxt') end
       
   281 
       
   282 fun fresh_name n (typs, terms, exprs, steps, vars, ctxt) =
       
   283   let val (n', ctxt') = yield_singleton Variable.variant_fixes n ctxt
       
   284   in (n', (typs, terms, exprs, steps, vars, ctxt')) end
       
   285 
       
   286 fun theory_of (_, _, _, _, _, ctxt) = ProofContext.theory_of ctxt
       
   287 
       
   288 fun typ_of_sort n (cx as (typs, _, _, _, _, _)) =
       
   289   (case Symtab.lookup typs n of
       
   290     SOME T => (T, cx)
       
   291   | NONE => cx
       
   292       |> fresh_name ("'" ^ n) |>> TFree o rpair @{sort type}
       
   293       |> (fn (T, (typs, terms, exprs, steps, vars, ctxt)) =>
       
   294            (T, (Symtab.update (n, T) typs, terms, exprs, steps, vars, ctxt))))
       
   295 
       
   296 fun add_decl (n, T) (cx as (_, terms, _, _, _, _)) =
       
   297   (case Symtab.lookup terms n of
       
   298     SOME _ => cx
       
   299   | NONE => cx |> fresh_name (decl_prefix ^ n)
       
   300       |> (fn (m, (typs, terms, exprs, steps, vars, ctxt)) =>
       
   301            let val upd = Symtab.update (n, certify ctxt (Free (m, T)))
       
   302            in (typs, upd terms, exprs, steps, vars, ctxt) end))
       
   303 
       
   304 datatype sym = Sym of string * sym list
       
   305 
       
   306 fun mk_app _ (Sym ("true", _), _) = SOME mk_true
       
   307   | mk_app _ (Sym ("false", _), _) = SOME mk_false
       
   308   | mk_app _ (Sym ("=", _), [t, u]) = SOME (mk_eq t u)
       
   309   | mk_app _ (Sym ("distinct", _), ts) = SOME (mk_distinct ts)
       
   310   | mk_app _ (Sym ("ite", _), [s, t, u]) = SOME (mk_if s t u)
       
   311   | mk_app _ (Sym ("and", _), ts) = SOME (mk_nary @{cterm "op &"} mk_true ts)
       
   312   | mk_app _ (Sym ("or", _), ts) = SOME (mk_nary @{cterm "op |"} mk_false ts)
       
   313   | mk_app _ (Sym ("iff", _), [t, u]) = SOME (mk_iff t u)
       
   314   | mk_app _ (Sym ("xor", _), [t, u]) = SOME (mk_not (mk_iff t u))
       
   315   | mk_app _ (Sym ("not", _), [t]) = SOME (mk_not t)
       
   316   | mk_app _ (Sym ("implies", _), [t, u]) = SOME (mk_imp t u)
       
   317   | mk_app _ (Sym ("~", _), [t, u]) = SOME (mk_iff t u)
       
   318   | mk_app _ (Sym ("<", _), [t, u]) = SOME (mk_lt t u)
       
   319   | mk_app _ (Sym ("<=", _), [t, u]) = SOME (mk_le t u)
       
   320   | mk_app _ (Sym (">", _), [t, u]) = SOME (mk_lt u t)
       
   321   | mk_app _ (Sym (">=", _), [t, u]) = SOME (mk_le u t)
       
   322   | mk_app _ (Sym ("+", _), [t, u]) = SOME (mk_add t u)
       
   323   | mk_app _ (Sym ("-", _), [t, u]) = SOME (mk_sub t u)
       
   324   | mk_app _ (Sym ("-", _), [t]) = SOME (mk_uminus t)
       
   325   | mk_app _ (Sym ("*", _), [t, u]) = SOME (mk_mul t u)
       
   326   | mk_app _ (Sym ("/", _), [t, u]) = SOME (mk_real_div t u)
       
   327   | mk_app _ (Sym ("div", _), [t, u]) = SOME (mk_int_div t u)
       
   328   | mk_app _ (Sym ("mod", _), [t, u]) = SOME (mk_mod t u)
       
   329   | mk_app _ (Sym ("select", _), [m, k]) = SOME (mk_access m k)
       
   330   | mk_app _ (Sym ("store", _), [m, k, v]) = SOME (mk_update m k v)
       
   331   | mk_app _ (Sym ("pattern", _), _) = SOME mk_true
       
   332   | mk_app (_, terms, _, _, _, _) (Sym (n, _), ts) =
       
   333       Symtab.lookup terms n |> Option.map (fn ct => mk_fun ct ts)
       
   334 
       
   335 fun add_expr k t (typs, terms, exprs, steps, vars, ctxt) =
       
   336   (typs, terms, Inttab.update (k, t) exprs, steps, vars, ctxt)
       
   337 
       
   338 fun lookup_expr (_, _, exprs, _, _, _) = Inttab.lookup exprs
       
   339 
       
   340 fun add_proof_step k ((r, prems), prop) cx =
       
   341   let
       
   342     val (typs, terms, exprs, steps, vars, ctxt) = cx
       
   343     val (ct, vs) = close ctxt prop
       
   344     val step = Proof_Step {rule=r, prems=prems, prop=ct}
       
   345     val vars' = union (op =) vs vars
       
   346   in (typs, terms, exprs, Inttab.update (k, step) steps, vars', ctxt) end
       
   347 
       
   348 fun finish (_, _, _, steps, vars, ctxt) = (steps, vars, ctxt)
       
   349 
       
   350 
       
   351 (* core parser *)
       
   352 
       
   353 fun parse_exn line_no msg = raise SMT_Solver.SMT ("Z3 proof parser (line " ^
       
   354   string_of_int line_no ^ "): " ^ msg)
       
   355 
       
   356 fun scan_exn msg ((line_no, _), _) = parse_exn line_no msg
       
   357 
       
   358 fun with_info f cx =
       
   359   (case f ((NONE, 1), cx) of
       
   360     ((SOME root, _), cx') => (root, cx')
       
   361   | ((_, line_no), _) => parse_exn line_no "bad proof")
       
   362 
       
   363 fun parse_line _ _ (st as ((SOME _, _), _)) = st
       
   364   | parse_line scan line ((_, line_no), cx) =
       
   365       let val st = ((line_no, cx), explode line)
       
   366       in
       
   367         (case Scan.catch (Scan.finite' Symbol.stopper (Scan.option scan)) st of
       
   368           (SOME r, ((_, cx'), _)) => ((r, line_no+1), cx')
       
   369         | (NONE, _) => parse_exn line_no ("bad proof line: " ^ quote line))
       
   370       end
       
   371 
       
   372 fun with_context f x ((line_no, cx), st) =
       
   373   let val (y, cx') = f x cx
       
   374   in (y, ((line_no, cx'), st)) end
       
   375   
       
   376 
       
   377 fun lookup_context f x (st as ((_, cx), _)) = (f cx x, st)
       
   378 
       
   379 
       
   380 (* parser combinators and parsers for basic entities *)
       
   381 
       
   382 fun $$ s = Scan.lift (Scan.$$ s)
       
   383 fun this s = Scan.lift (Scan.this_string s)
       
   384 fun blank st = Scan.lift (Scan.many1 Symbol.is_ascii_blank) st
       
   385 fun sep scan = blank |-- scan
       
   386 fun seps scan = Scan.repeat (sep scan)
       
   387 fun seps1 scan = Scan.repeat1 (sep scan)
       
   388 fun seps_by scan_sep scan = scan ::: Scan.repeat (scan_sep |-- scan)
       
   389 
       
   390 fun par scan = $$ "(" |-- scan --| $$ ")"
       
   391 fun bra scan = $$ "[" |-- scan --| $$ "]"
       
   392 
       
   393 val digit = (fn
       
   394   "0" => SOME 0 | "1" => SOME 1 | "2" => SOME 2 | "3" => SOME 3 |
       
   395   "4" => SOME 4 | "5" => SOME 5 | "6" => SOME 6 | "7" => SOME 7 |
       
   396   "8" => SOME 8 | "9" => SOME 9 | _ => NONE)
       
   397 
       
   398 fun mk_num ds = fold (fn d => fn i => i * 10 + d) ds 0
       
   399 val nat_num = Scan.lift (Scan.repeat1 (Scan.some digit)) >> mk_num
       
   400 val int_num = Scan.optional ($$ "-" >> K (fn i => ~i)) I :|--
       
   401   (fn sign => nat_num >> sign)
       
   402 
       
   403 val is_char = Symbol.is_ascii_letter orf Symbol.is_ascii_digit orf
       
   404   member (op =) (explode "_+*-/%~=<>$&|?!.@^#")
       
   405 val name = Scan.lift (Scan.many1 is_char) >> implode
       
   406 
       
   407 fun sym st = (name -- Scan.optional (bra (seps_by ($$ ":") sym)) [] >> Sym) st
       
   408 
       
   409 fun id st = ($$ "#" |-- nat_num) st
       
   410 
       
   411 
       
   412 (* parsers for various parts of Z3 proofs *)
       
   413 
       
   414 fun sort st = Scan.first [
       
   415   this "bool" >> K @{typ bool},
       
   416   this "int" >> K @{typ int},
       
   417   this "real" >> K @{typ real},
       
   418   this "bv" |-- bra nat_num >> mk_wordT,
       
   419   this "array" |-- bra (sort --| $$ ":" -- sort) >> (op -->),
       
   420   par (this "->" |-- seps1 sort) >> ((op --->) o split_last),
       
   421   name :|-- with_context typ_of_sort] st
       
   422 
       
   423 fun bound st = (par (this ":var" |-- sep nat_num -- sep sort) :|--
       
   424   lookup_context (mk_bound o theory_of)) st
       
   425 
       
   426 fun number st = st |> (
       
   427   int_num -- Scan.option ($$ "/" |-- int_num) --| this "::" :|--
       
   428   (fn num as (n, _) =>
       
   429     this "int" >> K (mk_int_num n) ||
       
   430     this "real" >> K (mk_real_frac_num num)))
       
   431 
       
   432 fun bv_number st = (this "bv" |-- bra (nat_num --| $$ ":" -- nat_num) :|--
       
   433   lookup_context (mk_bv_num o theory_of)) st
       
   434 
       
   435 fun appl (app as (Sym (n, _), _)) = lookup_context mk_app app :|-- (fn 
       
   436     SOME app' => Scan.succeed app'
       
   437   | NONE => scan_exn ("unknown function: " ^ quote n))
       
   438 
       
   439 fun constant st = ((sym >> rpair []) :|-- appl) st
       
   440 
       
   441 fun expr_id st = (id :|-- (fn i => lookup_context lookup_expr i :|-- (fn
       
   442     SOME e => Scan.succeed e
       
   443   | NONE => scan_exn ("unknown term id: " ^ quote (string_of_int i))))) st
       
   444 
       
   445 fun arg st = Scan.first [expr_id, number, bv_number, constant] st
       
   446 
       
   447 fun application st = par ((sym -- Scan.repeat1 (sep arg)) :|-- appl) st
       
   448 
       
   449 fun variables st = par (this "vars" |-- seps1 (par (name |-- sep sort))) st
       
   450 
       
   451 fun patterns st = seps (par ((this ":pat" || this ":nopat") |-- seps1 id)) st
       
   452 
       
   453 fun quant_kind st = st |> (
       
   454   this "forall" >> K (mk_forall o theory_of) ||
       
   455   this "exists" >> K (mk_exists o theory_of))
       
   456 
       
   457 fun quantifier st =
       
   458   (par (quant_kind -- sep variables --| patterns -- sep arg) :|--
       
   459      lookup_context (fn cx => fn ((mk_q, Ts), body) => mk_q cx Ts body)) st
       
   460 
       
   461 fun expr k =
       
   462   Scan.first [bound, quantifier, application, number, bv_number, constant] :|--
       
   463   with_context (pair NONE oo add_expr k)
       
   464 
       
   465 fun rule_name st = ((name >> `(Symtab.lookup rule_names)) :|-- (fn 
       
   466     (SOME r, _) => Scan.succeed r
       
   467   | (NONE, n) => scan_exn ("unknown proof rule: " ^ quote n))) st
       
   468 
       
   469 fun rule f k =
       
   470   bra (rule_name -- seps id) --| $$ ":" -- sep arg #->
       
   471   with_context (pair (f k) oo add_proof_step k)
       
   472 
       
   473 fun decl st = (this "decl" |-- sep name --| sep (this "::") -- sep sort :|--
       
   474   with_context (pair NONE oo add_decl)) st
       
   475 
       
   476 fun def st = (id --| sep (this ":=")) st
       
   477 
       
   478 fun node st = st |> (
       
   479   decl ||
       
   480   def :|-- (fn k => sep (expr k) || sep (rule (K NONE) k)) ||
       
   481   rule SOME ~1)
       
   482 
       
   483 
       
   484 (* overall parser *)
       
   485 
       
   486 (* Currently, terms are parsed bottom-up (i.e., along with parsing the proof
       
   487    text line by line), but proofs are reconstructed top-down (i.e. by an
       
   488    in-order top-down traversal of the proof tree/graph).  The latter approach
       
   489    was taken because some proof texts comprise irrelevant proof steps which
       
   490    will thus not be reconstructed.  This approach might also be beneficial
       
   491    for constructing terms, but it would also increase the complexity of the
       
   492    (otherwise rather modular) code. *)
       
   493 
       
   494 fun parse ctxt typs terms proof_text =
       
   495   make_context ctxt typs terms
       
   496   |> with_info (fold (parse_line node) proof_text)
       
   497   ||> finish
       
   498 
       
   499 end