-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathnames.ml
197 lines (178 loc) · 8.99 KB
/
names.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
open Util
open Tbwd
open Dim
open Core
open Syntax
open Term
module StringMap = Map.Make (String)
let __DEFAULT_NAME__ = "H"
let default () = __DEFAULT_NAME__
let __ANONYMOUS_VARIABLE__ = "_H"
(* Track the used variable names, to generate fresh ones for bound variables if needed. *)
(* We store a parametrized list like a context, and also a map that counts how many like-named variables already exist, so that we can create a new one with an unused number. *)
type 'b ctx =
| Emp : emp ctx
| Snoc : 'b ctx * 'n variables * (Field.t, string) Abwd.t -> ('b, 'n) snoc ctx
type 'b t = { ctx : 'b ctx; used : int StringMap.t }
let empty : emp t = { ctx = Emp; used = StringMap.empty }
let cubevar x fa : string list =
let fa = string_of_sface fa in
if fa = "" then [ x ] else [ x; fa ]
(* Look up an index variable to find a name for it. *)
let lookup : type n. n t -> n index -> string list =
fun { ctx; used = _ } x ->
let rec lookup : type n. n ctx -> n index -> string list =
fun ctx x ->
match (ctx, x) with
| Emp, _ -> .
| Snoc (ctx, _, _), Index (Later x, fa) -> lookup ctx (Index (x, fa))
| Snoc (_, Variables (_, mn, xs), _), Index (Now, fa) -> (
let (SFace_of_plus (_, fb, fc)) = sface_of_plus mn fa in
match NICubeOf.find xs fc with
| Some x -> cubevar x fb
| None -> [ __ANONYMOUS_VARIABLE__ ]) in
lookup ctx x
(* Look up an index variable together with a field, to find a name for the combination, if there is one. *)
let lookup_field : type n. n t -> n index -> Field.t -> string list option =
fun { ctx; used = _ } x f ->
let rec lookup : type n. n ctx -> n index -> string list option =
fun ctx x ->
match (ctx, x) with
| Emp, _ -> .
| Snoc (ctx, _, _), Index (Later x, fa) -> lookup ctx (Index (x, fa))
| Snoc (_, Variables (_, mn, _), fields), Index (Now, fa) ->
let open Monad.Ops (Monad.Maybe) in
let (SFace_of_plus (_, fb, fc)) = sface_of_plus mn fa in
let* _ = is_id_sface fc in
let* y = Abwd.find_opt f fields in
return (cubevar y fb) in
lookup ctx x
(* Make a variable name unique, adding the new one to the list of used variables and returning it. *)
let uniquify : string -> int StringMap.t -> string * [ `Original | `Renamed ] * int StringMap.t =
fun name used ->
match StringMap.find_opt name used with
| None -> (name, `Original, used |> StringMap.add name 0)
| Some n ->
(* The tentative new name is the original one suffixed by that number. But the user might already have created a variable with that name, so we have to increment the number until we find an unused name. *)
let rec until_unique k =
let namek = name ^ string_of_int k in
match StringMap.find_opt namek used with
| None -> (namek, k)
| Some _ -> until_unique (k + 1) in
let namen, n = until_unique n in
(namen, `Renamed, used |> StringMap.add namen 0 |> StringMap.add name (n + 1))
(* Make a variable name unique, leaving unnamed variables unnamed. *)
let uniquify_opt :
string option -> int StringMap.t -> string option * [ `Original | `Renamed ] * int StringMap.t =
fun name used ->
match name with
| None -> (None, `Original, used)
| Some name ->
let name, orig, used = uniquify name used in
(Some name, orig, used)
(* Do the same thing to a whole cube of variable names, leaving unnamed variables unnamed. *)
let uniquify_cube :
type n left right.
(left, n, string option, right) NICubeOf.t ->
int StringMap.t ->
(left, n, string option, right) NICubeOf.t * int StringMap.t =
fun names used ->
(* Apparently we need to define the iteration function with an explicit type so that it ends up sufficiently polymorphic. *)
let uniquify_nfamof :
type m left right.
(left, m, string option, right) NFamOf.t ->
int StringMap.t ->
(left, m, string option, right) NFamOf.t * int StringMap.t =
fun (NFamOf name) used ->
let name, _, used = uniquify_opt name used in
(NFamOf name, used) in
let open NICubeOf.Applicatic (Applicative.OfMonad (Monad.State (struct
type t = int StringMap.t
end))) in
mapM { map = (fun _ name used -> uniquify_nfamof name used) } names used
(* Add a new cube variable at a specified dimension, generating a fresh version of its name if necessary to avoid conflicts, leaving unnamed variables unnamed. *)
let add_cube : type n b. n D.t -> b t -> string option -> string option * (b, n) snoc t =
fun n { ctx; used } name ->
let name, _, used = uniquify_opt name used in
( name,
{ ctx = Snoc (ctx, Variables (n, D.plus_zero n, NICubeOf.singleton name), Abwd.empty); used } )
(* Same, but starting from an unnamed variable and giving it a default name. *)
let add_cube_autogen : type n b. n D.t -> b t -> string * (b, n) snoc t =
fun n ctx ->
let x, used = add_cube n ctx (Some __DEFAULT_NAME__) in
(Option.get x, used)
(* Add a cube of variables, generating a fresh version of each of their names, leaving unnamed variables unnamed. *)
let add : 'b t -> 'n variables -> 'n variables * ('b, 'n) snoc t =
fun { ctx; used } (Variables (m, mn, names)) ->
let names, used = uniquify_cube names used in
let vars = Variables (m, mn, names) in
(vars, { ctx = Snoc (ctx, vars, Abwd.empty); used })
(* Extract all the names in a context, generating a fresh version of each name from left to right, including field access variables, leaving unnamed variables unnamed. *)
let rec of_ordered_ctx : type a b. (a, b) Ctx.Ordered.t -> b t = function
| Emp -> empty
| Snoc (ctx, Vis { dim; plusdim; vars; bindings = _; hasfields = _; fields; fplus = _ }, _) ->
let { ctx; used } = of_ordered_ctx ctx in
let vars, used = uniquify_cube vars used in
let module M = Mbwd.Monadic (Monad.State (struct
type t = int StringMap.t
end)) in
let fields, used =
M.mmapM
(fun [ (f, x) ] used ->
let x, _, used = uniquify x used in
((f, x), used))
[ Bwv.to_bwd fields ]
used in
{ ctx = Snoc (ctx, Variables (dim, plusdim, vars), fields); used }
| Snoc (ctx, Invis bindings, _) -> snd (add_cube (CubeOf.dim bindings) (of_ordered_ctx ctx) None)
| Lock ctx -> of_ordered_ctx ctx
let of_ctx : type a b. (a, b) Ctx.t -> b t = function
| Permute (_, _, ctx) -> of_ordered_ctx ctx
(* Add a cube of variables WITHOUT replacing them by fresh versions. Should only be used when the variables have already been so replaced, as in the output of uniquify_vars below. *)
let unsafe_add : 'b t -> 'n variables -> (Field.t, string) Abwd.t -> ('b, 'n) snoc t =
fun { ctx; used } vars fields -> { ctx = Snoc (ctx, vars, fields); used }
(* Given a Bwv of variables, proceed through from the *right* to mark them as visible or shadowed, accumulating a list of the visible names in a map. Replaces unnamed variables by a default name. *)
let rec used_vars :
type n.
(string option, n) Bwv.t ->
int StringMap.t ->
(string * [ `Visible | `Shadowed ], n) Bwv.t * int StringMap.t =
fun vars used ->
let do_var x used =
match x with
| Some x ->
if StringMap.mem x used then (x, `Shadowed, used)
else (x, `Visible, used |> StringMap.add x 0)
| None -> (__DEFAULT_NAME__, `Shadowed, used) in
match vars with
| Emp -> (Emp, used)
| Snoc (vars, x) ->
let x, o, used = do_var x used in
let vars, used = used_vars vars used in
(Snoc (vars, (x, o)), used)
(* Uniquify the names in a bwv from the *right*, thus leaving unchanged those that are still in lexical scope. Also assigns an autogenerated name to previously unnamed variables. Returns a Names object in the empty context that can then be used to build up a new one including those variables. Since those variables have already been uniquified, they should be added in with unsafe_add. (TODO: Can we avoid having to expose unsafe_add?) *)
let uniquify_vars :
type a. (string option, a) Bwv.t -> (string * [ `Original | `Renamed ], a) Bwv.t * emp t =
fun vars ->
(* First we collect a map of all the visible names, also marking the given names as visible or shadowed. *)
let vars, used = used_vars vars StringMap.empty in
(* Then we proceed again from right to left, leaving the visible variables alone and replacing the shadowed ones with uniquified versions. We do this in two passes to ensure that the uniquified version of a shadowed variable is never chosen in such a way as would shadow a variable to its left that already had that name. *)
let rec go :
type n.
(string * [ `Visible | `Shadowed ], n) Bwv.t ->
int StringMap.t ->
(string * [ `Original | `Renamed ], n) Bwv.t * int StringMap.t =
fun vars used ->
match vars with
| Emp -> (Emp, used)
| Snoc (vars, (x, sh)) ->
let x, orig, used =
match sh with
| `Visible -> (x, `Original, used)
| `Shadowed ->
let x, _, used = uniquify x used in
(x, `Renamed, used) in
let vars, used = go vars used in
(Snoc (vars, (x, orig)), used) in
let vars, used = go vars used in
(vars, { ctx = Emp; used })