(* ||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 S = Share module L = Log module B = Brg module O = BrgOutput module E = BrgEnvironment 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 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 get f c m i = let f = function | Some (_, b) -> f b | None -> error i in let f gl _ = if i < gl then B.get f c i else B.get f m.c (i - gl) in B.contents f c 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 (id, b) = f (B.Bind (id, b, t)) in let f _ mc = C.list_fold_left f map t mc in B.contents f m.c let rec lref_map_bind f map b = match b with | B.Abbr v -> let f v' = f (S.sh1 v v' b B.abbr) in lref_map f map v | B.Abst w -> let f w' = f (S.sh1 w w' b B.abst) in lref_map f map w | B.Void -> f b and lref_map f map t = match t with | B.LRef i -> f (B.LRef (map i)) | B.GRef _ -> f t | B.Sort _ -> f t | B.Cast (w, u) -> let f w' u' = f (S.sh2 w w' u u' t B.cast) in let f w' = lref_map (f w') map u in lref_map f map w | B.Appl (w, u) -> let f w' u' = f (S.sh2 w w' u u' t B.appl) in let f w' = lref_map (f w') map u in lref_map f map w | B.Bind (id, b, u) -> let f b' u' = f (S.sh2 b b' u u' t (B.bind id)) in let f b' = lref_map (f b') map u in lref_map_bind f map b (* to share *) let lift f c m = let f gl _ = let map i = if i >= gl then succ i else i in let map f = function | id, B.Abbr t -> let f t = f (id, B.Abbr t) in lref_map f map t | _ -> assert false in let f mc = f {m with c = mc} in B.map f map m.c in B.contents f c (* to share *) let xchg f c m t = let f gl _ ll _ = let map i = if i < gl || i > gl + ll then i else if i >= gl && i < gl + ll then succ i else gl in lref_map f map t in contents f c m let push f c m id w t = assert (m.s = []); let f c m = xchg (f c m) c m t in let f c = lift (f c) c m in let f w = B.push f c 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 (id, B.Abst w, t) -> begin match m.s with | [] -> f m (Bind_ (id, w, t)) | v :: tl -> let f mc = whd f c {c = mc; s = tl} t in B.push f m.c id (B.Abbr (B.Cast (w, v))) end | B.Bind (id, b, t) -> let f mc = whd f c {m with c = mc} t in B.push f m.c 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 = L.log O.specs level (L.ct_items1 "Now scanning" c t); ho_whd f c empty_machine t let rec are_convertible f c1 m1 t1 c2 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 c1 m1 c2 m2 else f false | GRef_ (a1, B.Abst _), GRef_ (a2, B.Abst _) -> if a1 = a2 then are_convertible_stacks f c1 m1 c2 m2 else f false | GRef_ (a1, B.Abbr v1), GRef_ (a2, B.Abbr v2) -> if a1 = a2 then are_convertible_stacks f c1 m1 c2 m2 else if a1 < a2 then whd (aux m1 r1) c2 m2 v2 else whd (aux_rev m2 r2) c1 m1 v1 | _, GRef_ (_, B.Abbr v2) -> whd (aux m1 r1) c2 m2 v2 | GRef_ (_, B.Abbr v1), _ -> whd (aux_rev m2 r2) c1 m1 v1 | Bind_ (id1, w1, t1), Bind_ (id2, w2, t2) -> let f b = if b then let f c1 m1 t1 = push (are_convertible f c1 m1 t1) c2 m2 id2 w2 t2 in push f c1 m1 id1 w1 t1 else f false in are_convertible f c1 m1 w1 c2 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) c2 m2 t2 in whd f c1 m1 t1 and are_convertible_stacks f c1 m1 c2 m2 = let mm1, mm2 = {m1 with s = []}, {m2 with s = []} in let map f v1 v2 = are_convertible f c1 mm1 v1 c2 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 = L.log O.specs level (L.ct_items2 "Now converting" c t1 "and" c t2); are_convertible f c empty_machine t1 c empty_machine t2