(************************************************************************) (* * The Rocq Prover / The Rocq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* <O___,, * (see version control and CREDITS file for authors & dates) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************)
open Util open Pp open CErrors open Names open Proofview.Notations open Tac2expr open Tac2val open Tac2bt
let empty_environment = {
env_ist = Id.Map.empty;
}
type closure = {
mutable clos_env : valexpr Id.Map.t; (** Mutable so that we can implement recursive functions imperatively *)
clos_var : Name.t list; (** Bound variables *)
clos_exp : glb_tacexpr; (** Body *)
clos_ref : ltac_constant option; (** Global constant from which the closure originates *)
}
let push_id ist id v = { env_ist = Id.Map.add id v ist.env_ist }
let push_name ist id v = match id with
| Anonymous -> ist
| Name id -> push_id ist id v
let get_var ist id = try Id.Map.find id ist.env_ist with Not_found ->
anomaly (str "Unbound variable " ++ Id.print id)
let return = Proofview.tclUNIT
exception NoMatch
let match_ctor_against ctor v = match ctor, v with
| { cindx = Open ctor }, ValOpn (ctor', vs) -> if KerName.equal ctor ctor' then vs elseraise NoMatch
| { cindx = Open _ }, _ -> assert false
| { cnargs = 0; cindx = Closed i }, ValInt i' -> if Int.equal i i' then [| |] elseraise NoMatch
| { cnargs = 0; cindx = Closed _ }, ValBlk _ -> raise NoMatch
| _, ValInt _ -> raise NoMatch
| { cindx = Closed i }, ValBlk (i', vs) -> if Int.equal i i' then vs elseraise NoMatch
| { cindx = Closed _ }, ValOpn _ -> assert false
| _, (ValStr _ | ValCls _ | ValExt _) -> assert false
let check_atom_against atm v = match atm, v with
| AtmInt n, ValInt n' -> if not (Int.equal n n') thenraise NoMatch
| AtmStr s, ValStr s' -> if not (String.equal s (Bytes.unsafe_to_string s')) thenraise NoMatch
| (AtmInt _ | AtmStr _), _ -> assert false
let rec match_pattern_against ist pat v = match pat with
| GPatVar x -> push_name ist x v
| GPatAtm atm -> check_atom_against atm v; ist
| GPatAs (p,x) -> match_pattern_against (push_name ist (Name x) v) p v
| GPatRef (ctor,pats) -> let vs = match_ctor_against ctor v in List.fold_left_i (fun i ist pat -> match_pattern_against ist pat vs.(i)) 0 ist pats
| GPatOr pats -> match_pattern_against_or ist pats v
and match_pattern_against_or ist pats v = match pats with
| [] -> raise NoMatch
| pat :: pats -> try match_pattern_against ist pat v with NoMatch -> match_pattern_against_or ist pats v
let eval_glb_ext ist (Tac2dyn.Arg.Glb (tag,e)) = let tpe = Tac2env.interp_ml_object tag in
with_frame (FrExtn (tag, e)) (tpe.Tac2env.ml_interp ist e)
let rec interp (ist : environment) = function
| GTacAtm (AtmInt n) -> return (Tac2ffi.of_int n)
| GTacAtm (AtmStr s) -> return (Tac2ffi.of_string s)
| GTacVar id -> return (get_var ist id)
| GTacRef kn -> return (eval_global kn)
| GTacFun (ids, e) -> let cls = { clos_ref = None; clos_env = ist.env_ist; clos_var = ids; clos_exp = e } in let f = interp_closure cls in
return f
| GTacApp (f, args) ->
interp ist f >>= fun f ->
Proofview.Monad.List.map (fun e -> interp ist e) args >>= fun args ->
Tac2val.apply_val f args
| GTacLet (false, el, e) -> let fold accu (na, e) =
interp ist e >>= fun e ->
return (push_name accu na e) in
Proofview.Monad.List.fold_left fold ist el >>= fun ist ->
interp ist e
| GTacLet (true, el, e) -> let ist = push_let_rec ist.env_ist el in
interp { env_ist = ist } e
| GTacCst (_, n, []) -> return (Valexpr.make_int n)
| GTacCst (_, n, el) ->
Proofview.Monad.List.map (fun e -> interp ist e) el >>= fun el ->
return (Valexpr.make_block n (Array.of_list el))
| GTacCse (e, _, cse0, cse1) ->
interp ist e >>= fun e -> interp_case ist e cse0 cse1
| GTacWth { opn_match = e; opn_branch = cse; opn_default = def } ->
interp ist e >>= fun e -> interp_with ist e cse def
| GTacFullMatch (e,brs) ->
interp ist e >>= fun e -> interp_full_match ist e brs
| GTacPrj (_, e, p) ->
interp ist e >>= fun e -> interp_proj ist e p
| GTacSet (_, e, p, r) ->
interp ist e >>= fun e ->
interp ist r >>= fun r ->
interp_set ist e p r
| GTacOpn (kn, el) ->
Proofview.Monad.List.map (fun e -> interp ist e) el >>= fun el ->
return (Tac2ffi.of_open (kn, Array.of_list el))
| GTacPrm ml ->
return (Tac2env.interp_primitive ml)
| GTacExt (tag, e) -> eval_glb_ext ist (Glb (tag,e))
and push_let_rec ist el = letmap (na, e) = match e with
| GTacFun (ids, e) -> let cls = { clos_ref = None; clos_env = ist; clos_var = ids; clos_exp = e } in let f = interp_closure cls in
na, cls, f
| _ -> anomaly (str "Ill-formed recursive function") in let fixs = List.mapmap el in let fold accu (na, _, cls) =match na with
| Anonymous -> accu
| Name id -> Id.Map.add id cls accu in let ist = List.fold_left fold ist fixs in (* Hack to make a cycle imperatively in the environment *) let iter (_, e, _) = e.clos_env <- ist in let () = List.iter iter fixs in
ist
and interp_closure f = let ans = fun args -> let { clos_env = ist; clos_var = ids; clos_exp = e; clos_ref = kn } = f in let frame = match kn with
| None -> FrAnon e
| Some kn -> FrLtac kn in let ist = { env_ist = ist } in let ist = List.fold_left2 push_name ist ids args in
with_frame frame (interp ist e) in
Tac2ffi.(of_closure (abstract (List.length f.clos_var) ans))
and interp_case ist e cse0 cse1 = if Valexpr.is_int e then
interp ist cse0.(Tac2ffi.to_int e) else let (n, args) = Tac2ffi.to_block e in let (ids, e) = cse1.(n) in let ist = CArray.fold_left2 push_name ist ids args in
interp ist e
and interp_with ist e cse def = let (kn, args) = Tac2ffi.to_open e in let br = try Some (KNmap.find kn cse) with Not_found -> None in beginmatch br with
| None -> let (self, def) = def in let ist = push_name ist self e in
interp ist def
| Some (self, ids, p) -> let ist = push_name ist self e in let ist = CArray.fold_left2 push_name ist ids args in
interp ist p end
and interp_full_match ist e = function
| [] -> CErrors.anomaly Pp.(str "ltac2 match not exhaustive")
| (pat,br) :: rest -> beginmatch match_pattern_against ist pat e with
| exception NoMatch -> interp_full_match ist e rest
| ist -> interp ist br end
and interp_proj ist e p =
return (Valexpr.field e p)
and interp_set ist e p r = let () = Valexpr.set_field e p r in
return (Valexpr.make_int 0)
and eval_global kn = match Tac2env.get_compiled_global kn with
| Some (_info,v) -> v
| None -> match Tac2env.interp_global kn with
| exception Not_found -> anomaly (str "Unbound reference" ++ KerName.print kn)
| { gdata_expr = e } -> eval_pure Id.Map.empty (Some kn) e
and eval_pure bnd kn = function
| GTacVar id -> Id.Map.get id bnd
| GTacAtm (AtmInt n) -> Valexpr.make_int n
| GTacRef kn -> eval_global kn
| GTacFun (na, e) -> let cls = { clos_ref = kn; clos_env = bnd; clos_var = na; clos_exp = e } in
interp_closure cls
| GTacCst (_, n, []) -> Valexpr.make_int n
| GTacCst (_, n, el) -> Valexpr.make_block n (eval_pure_args bnd el)
| GTacOpn (kn, el) -> Tac2ffi.of_open (kn, eval_pure_args bnd el)
| GTacLet (false, vals, body) -> let fold accu (na, e) = match na with
| Anonymous -> (* No need to evaluate, we know this is a value *)
accu
| Name id -> let v = eval_pure bnd None e in
Id.Map.add id v accu in let bnd = List.fold_left fold bnd vals in
eval_pure bnd kn body
| GTacLet (true, el, body) -> let bnd = push_let_rec bnd el in
eval_pure bnd kn body
| GTacPrj (_,e,i) -> let v = eval_pure bnd kn e in
Valexpr.field v i
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.