package elpi
ELPI - Embeddable λProlog Interpreter
Install
Dune Dependency
Authors
Maintainers
Sources
elpi-2.0.7.tbz
sha256=80233ebd92babd696148ed553238961ec7b6de6bf157045aae1c7090840aeded
sha512=00c9ec01fabde9db1de4a58cb37480035e6f926d83b8360553419bcb99e9199f0720dde975f97ac9942ce528884d3d59d025cfbd471f12d57547429f15684d49
doc/src/elpi.compiler/determinacy_checker.ml.html
Source file determinacy_checker.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
(* elpi: embedded lambda prolog interpreter *) (* license: GNU Lesser General Public License Version 2.1 or later *) (* ------------------------------------------------------------------------- *) open Elpi_util open Util open Elpi_parser open Ast open Compiler_data module C = Constants exception StopCheck (* TYPE DECLARATION FOR FUNCTIONALITY *) type f = | Functional of f list (* Used for functional preds, the f list represents the functionality relation of the arguments *) | Relational of f list (* Used for non-functional preds, the f list represents the functionality relation of the arguments *) | NoProp (* Used for kinds like list, int, string... and abstractions not being props like: (int -> list bool), (string -> nat -> string) *) | AssumedFunctional (* Currently used for variadic functions, like print, halt... *) | BoundVar of F.t [@@ deriving show, ord] type t' = Lam of F.t * t' | F of f [@@ deriving show, ord] type t = Loc.t * t' [@@ deriving show, ord] type func_map = { ty_abbr: Scope.type_decl_id F.Map.t; (* Invariant every type_abbrev const is already in cmap *) cmap: (F.t * t) C.Map.t } [@@ deriving show, ord] type fname = F.t * t [@@deriving show,ord] let pp_locs fmt (l: t list) = Format.fprintf fmt "[%a]" (pplist (fun fmt -> Format.fprintf fmt "%a" Loc.pp) ",") (List.map fst l) let compare_t (a:t) (b:t) = compare_t' (snd a) (snd b) let compare_fname a b = compare_t (snd a) (snd b) let mk_func_map ty_abbr cmap = {ty_abbr; cmap} let empty_fmap = {ty_abbr = F.Map.empty; cmap = C.Map.empty} let get_functionality_tabbr_opt map k = match F.Map.find_opt k map.ty_abbr with None -> None | Some e -> Some (C.Map.find e map.cmap) let get_functionality map k = C.Map.find k map.cmap (* AUXILIARY FUNCTIONS *) let rec subst ~loc sigma : f -> f = function | BoundVar k as t -> begin match F.Map.find_opt k sigma with | None -> t | Some (F f) -> f | Some (Lam (_,b)) -> error ~loc "type_abbrev not fully applied" end | Functional l -> Functional (List.map (subst ~loc sigma) l) | AssumedFunctional | Relational _ | NoProp as t -> t let rec bind ~loc sigma : (t'*f list) -> f = function | Lam (n,b), x::xs -> bind ~loc (F.Map.add n (F x) sigma) (b,xs) | Lam (_,b), [] -> error ~loc "type_abbrev is not fully applied" | F t, [] -> subst ~loc sigma t | F _, _::_ -> anomaly ~loc "type_abbrev is too much applied" (* COMPILATION from SCOPE_TYPE_EXPRESSION TO FUNCTIONALITY *) module Compilation = struct let add_type is_type_abbr fmap ~n ~id v = (* if F.Map.mem n fmap.ty_abbr then error (Format.asprintf "Adding again type_abbrev %a" F.pp n); *) let cmap = C.Map.add id (n,v) fmap.cmap in let ty_abbr = if is_type_abbr then F.Map.add n id fmap.ty_abbr else fmap.ty_abbr in mk_func_map ty_abbr cmap let merge f1 f2 = let union_same pk pe cmpe k e1 e2 = (* if cmpe e1 e2 = 0 then *) Some e1 (* else error (Format.asprintf "The key %a has two different values (v1:%a) (v2:%a)" pk k pe e1 pe e2) *) in let cmap = C.Map.union (union_same pp_int pp_fname compare_fname) f1.cmap f2.cmap in let ty_abbr = F.Map.union (union_same F.pp pp_int Int.compare) f1.ty_abbr f2.ty_abbr in mk_func_map ty_abbr cmap let map_snd f = List.map (fun (_, ScopedTypeExpression.{it}) -> f it) let rec type2func_ty_abbr ~loc bound_vars (fmap: func_map) c args = match get_functionality_tabbr_opt fmap c with | None -> NoProp (* -> c is a kind (like list, int, ...) *) | Some (_,f) -> (* -> c is a type-abbrev *) bind ~loc F.Map.empty (snd f, List.map (type2func_loc ~loc bound_vars fmap) args) and type2func ~loc bound_vars (fmap: func_map) : ScopedTypeExpression.t_ -> f = function | Pred(Function, xs) -> Functional (map_snd (type2func ~loc bound_vars fmap) xs) | Pred(Relation, xs) -> Relational (map_snd (type2func ~loc bound_vars fmap) xs) | Const (_,c) when F.Set.mem c bound_vars -> BoundVar c | Const (_,c) -> type2func_ty_abbr ~loc bound_vars fmap c [] | App(_,c,x,xs) -> type2func_ty_abbr ~loc bound_vars fmap c (x::xs) | Arrow (Variadic, _, _) -> AssumedFunctional (* Invariant: the rightmost type in the right branch is not a prop due flatten_arrows in compiler *) | Arrow (NotVariadic,_,_) -> NoProp | Any -> NoProp and type2func_loc ~loc bvars fmap ScopedTypeExpression.{it} = type2func ~loc bvars fmap it let rec type2func_lam bound_vars type_abbrevs : ScopedTypeExpression.v_ -> t = function | Lam (n, t) -> let (loc, r) = type2func_lam (F.Set.add n bound_vars) type_abbrevs t in loc, Lam (n,r) | Ty {it;loc} -> loc, F (type2func ~loc bound_vars type_abbrevs it) let type2func f (x:ScopedTypeExpression.t) = type2func_lam F.Set.empty f x.value end let merge = Compilation.merge let rec functionalities_leq l1 l2 = match l1, l2 with | _, [] -> true (* l2 can be any length (due to partial application) *) | x::xs, y::ys -> functionality_leq x y && functionalities_leq xs ys | [], _ -> error "the first list of functional args is can't been smaller then the second one: type error" and functionality_leq a b = match a, b with | AssumedFunctional, AssumedFunctional -> true | AssumedFunctional, t -> error (Format.asprintf "Cannot compare %a with %a" pp_f a pp_f b) (* TODO: print could be passed in a functional position *) | _, AssumedFunctional -> error (Format.asprintf "Cannot compare %a with %a" pp_f a pp_f b) | Relational xs, Relational ys -> functionalities_leq xs ys | _, Relational _ -> true | Relational _, _ -> false | Functional xs, Functional ys -> functionalities_leq xs ys | BoundVar _, _ | _, BoundVar _ -> true (* TODO: this is not correct... *) | NoProp, NoProp -> true | NoProp, _ | _, NoProp -> error "Type error, expected noProp found predicate" let functionality_leq_err ~loc c f' f = if not (functionality_leq f' f) then error ~loc (Format.asprintf "Functionality of %a is %a and is not included in %a" F.pp c pp_f f' pp_f f) let rec eat_lambdas = function | Lam (_,b) -> eat_lambdas b | F b -> b let get_functionality_bvars map k = F.Map.find k map |> eat_lambdas (* Invariant every constant in the map is functional: i.e. for each k in the domain, map[k] = Functional [...] *) let is_functional map k = match get_functionality_bvars map k with | Functional _ | NoProp | AssumedFunctional -> true | Relational _ | BoundVar _ -> false let rec head_ag_func_pairing functional_preds args fs = let func_vars = ref F.Map.empty in let rec aux ~loc f = function | ScopedTerm.Const (Global _,c) -> (* Look into type_abbrev for global symbols *) (* Format.eprintf "1Looking for the constant %a\n%!" F.pp c; *) begin match get_functionality_bvars functional_preds c with | (f') -> functionality_leq_err ~loc c f' f (* | Lam _ -> failwith "Error not fully applied" *) end | Const _ -> failwith "TODO" | App(_,hd,x,xs) -> Format.eprintf "2Looking for the constant %a -- %a\n%!" F.pp hd (pplist ScopedTerm.pp ",") (x::xs); let f' = get_functionality_bvars functional_preds hd in (* let f' = bind functional_preds (f', List.map (get_functionality functional_preds) (x::xs)) in *) functionality_leq_err ~loc hd f' f; begin match f' with | Functional l -> aux' (x::xs) l | _ -> () end | Impl _ -> error "TODO" (* Example p (a => b) *) | Discard -> () | Var (v, ag) -> begin match F.Map.find_opt v !func_vars with | None -> func_vars := F.Map.add v f !func_vars (* -> First appereance of the variable in the head *) | Some f' -> functionality_leq_err ~loc v f' f end | Lam (None, _type, {it}) -> failwith "TODO" | Lam (Some (e,_), _type, {it}) -> failwith "TODO" | CData _ -> assert (f = NoProp) (* note that this is also true, otherwise we would have a type error *) | Spill _ -> error "Spill in the head of a clause forbidden" | Cast ({it},_) -> aux ~loc f it and aux' args fs = match args, fs with | [], [] -> () | ScopedTerm.{it;loc}::xs, y::ys -> aux ~loc y it; aux' xs ys | _ -> failwith "Partial application ??" in aux' args fs; !func_vars and check_head functional_preds func_vars head_name head_args = match get_functionality_bvars functional_preds head_name with | NoProp -> raise StopCheck | AssumedFunctional -> raise StopCheck | Functional l | Relational l -> head_ag_func_pairing functional_preds head_args l | BoundVar v -> error "unreachable branch" and check_body func_vars = func_vars let rec check_clause ~loc ~functional_preds func_vars ScopedTerm.{it} = match it with | Impl(false, hd, body) -> check_clause ~loc ~functional_preds func_vars hd |> check_body | App(_,c,x,xs) -> begin if String.starts_with ~prefix:"std.map." (F.show c) then func_vars else func_vars (* TODO: activate the check by uncommenting the following lines... *) (* try check_head functional_preds func_vars c (x::xs) with StopCheck -> func_vars *) end | Const (_,_) -> func_vars (* a predicate with arity 0 is functional *) | _ -> error ~loc "invalid type" let check_clause ~loc ~functional_preds t = check_clause ~loc ~functional_preds F.Map.empty t |> ignore class merger (all_func: func_map) = object(self) val mutable all_func = all_func val mutable local_func = empty_fmap method private add_func is_ty_abbr n id ty = let func = Compilation.type2func all_func ty in if is_ty_abbr then all_func <- Compilation.add_type is_ty_abbr ~id ~n all_func func; local_func <- Compilation.add_type is_ty_abbr ~id ~n local_func func; method get_all_func = all_func method get_local_func = local_func method add_ty_abbr = self#add_func true method add_func_ty_list name ty (ty_w_id : TypeAssignment.overloaded_skema_with_id) = let id_list = match ty_w_id with Single e -> [fst e] | Overloaded l -> List.map fst l in List.iter2 (self#add_func false name) id_list ty end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>