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
open Elpi_util
open Util
open Elpi_parser
open Ast
open Compiler_data
module C = Constants
exception StopCheck
type f =
| Functional of f list
| Relational of f list
| NoProp
| AssumedFunctional
| 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;
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
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"
module Compilation = struct
let add_type is_type_abbr fmap ~n ~id v =
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 =
Some e1
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
| Some (_,f) ->
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
| 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
| 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)
| _, 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
| 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
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) ->
begin match get_functionality_bvars functional_preds c with
| (f') -> functionality_leq_err ~loc c f' f
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
functionality_leq_err ~loc hd f' f;
begin match f' with
| Functional l -> aux' (x::xs) l
| _ -> ()
end
| Impl _ -> error "TODO"
| Discard -> ()
| Var (v, ag) ->
begin match F.Map.find_opt v !func_vars with
| None -> func_vars := F.Map.add v f !func_vars
| 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)
| 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
end
| Const (_,_) -> func_vars
| _ -> 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