(* ||M|| This file is part of HELM, an Hypertextual, Electronic ||A|| Library of Mathematics, developed at the Computer Science ||T|| Department, University of Bologna, Italy. ||I|| ||T|| HELM is free software; you can redistribute it and/or ||A|| modify it under the terms of the GNU General Public License \ / version 2 or (at your option) any later version. \ / This software is distributed as is, NO WARRANTY. V_______________________________________________________________ *) module C = Cps module L = Log module B = Bag module O = BagOutput module E = BagEnvironment module S = BagSubstitution exception LRefNotFound of B.message type machine = { c: B.context; s: B.term list } type whd_result = | Sort_ of int | LRef_ of int * B.term option | GRef_ of int * B.bind | Bind_ of int * B.id * B.term * B.term type ho_whd_result = | Sort of int | Abst of B.term (* Internal functions *******************************************************) let level = 5 let error i = raise (LRefNotFound (L.items1 (string_of_int i))) let empty_machine = {c = B.empty_context; s = []} let contents f c m = let f gl ges = B.contents (f gl ges) m.c in B.contents f c let unwind_to_context f c m = B.append f c m.c let unwind_to_term f m t = let map f t (l, id, b) = f (B.Bind (l, id, b, t)) in let f mc = C.list_fold_left f map t mc in B.contents f m.c let get f c m i = let f = function | Some (_, b) -> f b | None -> error i in let f c = B.get f c i in unwind_to_context f c m let push f c m l id w = assert (m.s = []); let f w = B.push f c l id (B.Abst w) in unwind_to_term f m w (* to share *) let rec whd f c m x = match x with | B.Sort h -> f m (Sort_ h) | B.GRef uri -> let f (i, _, b) = f m (GRef_ (i, b)) in E.get_obj f uri | B.LRef i -> let f = function | B.Void -> f m (LRef_ (i, None)) | B.Abst t -> f m (LRef_ (i, Some t)) | B.Abbr t -> whd f c m t in get f c m i | B.Cast (_, t) -> whd f c m t | B.Appl (v, t) -> whd f c {m with s = v :: m.s} t | B.Bind (l, id, B.Abst w, t) -> begin match m.s with | [] -> f m (Bind_ (l, id, w, t)) | v :: tl -> let f mc = whd f c {c = mc; s = tl} t in B.push f m.c l id (B.Abbr (B.Cast (w, v))) end | B.Bind (l, id, b, t) -> let f mc = whd f c {m with c = mc} t in B.push f m.c l id b (* Interface functions ******************************************************) let rec ho_whd f c m x = let aux m = function | Sort_ h -> f c (Sort h) | Bind_ (_, _, w, _) -> let f c = f c (Abst w) in unwind_to_context f c m | LRef_ (_, Some w) -> ho_whd f c m w | GRef_ (_, B.Abst u) -> ho_whd f c m u | GRef_ (_, B.Abbr t) -> ho_whd f c m t | LRef_ (_, None) -> assert false | GRef_ (_, B.Void) -> assert false in whd aux c m x let ho_whd f c t = let f c r = L.unbox level; f c r in L.box level; L.log O.specs level (L.ct_items1 "Now scanning" c t); ho_whd f c empty_machine t let rec are_convertible f c m1 t1 m2 t2 = let rec aux m1 r1 m2 r2 = match r1, r2 with | Sort_ h1, Sort_ h2 -> f (h1 = h2) | LRef_ (i1, _), LRef_ (i2, _) -> if i1 = i2 then are_convertible_stacks f c m1 m2 else f false | GRef_ (a1, B.Abst _), GRef_ (a2, B.Abst _) -> if a1 = a2 then are_convertible_stacks f c m1 m2 else f false | GRef_ (a1, B.Abbr v1), GRef_ (a2, B.Abbr v2) -> if a1 = a2 then are_convertible_stacks f c m1 m2 else if a1 < a2 then whd (aux m1 r1) c m2 v2 else whd (aux_rev m2 r2) c m1 v1 | _, GRef_ (_, B.Abbr v2) -> whd (aux m1 r1) c m2 v2 | GRef_ (_, B.Abbr v1), _ -> whd (aux_rev m2 r2) c m1 v1 | Bind_ (l1, id1, w1, t1), Bind_ (l2, id2, w2, t2) -> let f b = if b then let f c = S.subst (are_convertible f c m1 t1 m2) l1 l2 t2 in push f c m1 l1 id1 w1 else f false in are_convertible f c m1 w1 m2 w2 | _ -> f false and aux_rev m2 r2 m1 r1 = aux m1 r1 m2 r2 in let f m1 r1 = whd (aux m1 r1) c m2 t2 in whd f c m1 t1 and are_convertible_stacks f c m1 m2 = let mm1, mm2 = {m1 with s = []}, {m2 with s = []} in let map f v1 v2 = are_convertible f c mm1 v1 mm2 v2 in if List.length m1.s <> List.length m2.s then f false else C.forall2 f map m1.s m2.s let are_convertible f c t1 t2 = let f b = L.unbox level; f b in L.box level; L.log O.specs level (L.ct_items2 "Now converting" c t1 "and" c t2); are_convertible f c empty_machine t1 empty_machine t2