package refl

  1. Overview
  2. Docs

Source file constraints.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
235
236
237
238
239
240
241
242
243
244
245
246
247
open Common

module type PropertyWithLub = sig
  include Fix.PROPERTY

  type t = property

  val union : property -> property -> property
end

module Transfer = struct
  type t =
    | Present
    | Absent
    | Constr of Longident.t * t * t

  let rec compose t t' =
    match t, t' with
    | Present, _ | _, Present -> Present
    | Absent, _ -> t'
    | _, Absent -> t
    | Constr (c, present, absent), _ ->
        Constr (c, present, compose absent t')

  let compare = Stdlib.compare

  let rec to_type t =
    let loc = !Ast_helper.default_loc in
    match t with
    | Present -> [%type: [`Present]]
    | Absent -> [%type: [`Absent]]
    | Constr (txt, present, absent) ->
        Ppxlib.Ast_helper.Typ.constr { loc; txt }
          [to_type present; to_type absent]
end

module PropertyOfSet (X : Set.S)
    : PropertyWithLub with type property = X.t = struct
  type t = X.t

  type property = X.t

  let bottom = X.empty

  let equal = X.equal

  let union = X.union

  let is_maximal _ = false
end

let compare_pair compare_x compare_y (x, y) (x', y') =
  match compare_x x x' with
  | 0 -> compare_y y y'
  | result -> result

module PairOfOrderedType (X : Set.OrderedType) (Y : Set.OrderedType)
  : Set.OrderedType with type t = X.t * Y.t = struct
  type t = X.t * Y.t

  let compare = compare_pair X.compare Y.compare
end

module PropertyOfPair (X : PropertyWithLub) (Y : PropertyWithLub)
    : PropertyWithLub with type property = X.t * Y.t = struct
  type t = X.t * Y.t

  type property = t

  let bottom = (X.bottom, Y.bottom)

  let equal (x, y) (x', y') =
    X.equal x x' && Y.equal y y'

  let union (x, y) (x', y') =
    (X.union x x', Y.union y y')

  let is_maximal (x, y) = X.is_maximal x && Y.is_maximal y
end

let rec compare_list compare_item l l' =
  match l, l' with
  | [], [] -> 0
  | [], _ -> -1
  | _, [] -> 1
  | hd :: tl, hd' :: tl' ->
      compare_pair compare_item (compare_list compare_item) (hd, tl) (hd', tl')

module TransferSet = Set.Make (Transfer)

module Kinds = struct
  include PropertyOfPair (PropertyOfSet (TransferSet)) (PropertyOfPair
      (PropertyOfSet (StringSet))
      (PropertyOfSet (LongidentSet)))

  let to_type (exists, (direct, inherited)) =
    let row_fields =
      if TransferSet.is_empty exists then
        []
      else
        [Metapp.Rf.inherit_
          (Transfer.to_type
            (TransferSet.fold Transfer.compose exists Absent))] in
    let add_direct_kind txt accu =
      Metapp.Rf.tag (Metapp.mkloc txt) false [] :: accu in
    let row_fields = StringSet.fold add_direct_kind direct row_fields in
    let add_inherited_kind txt accu =
      Metapp.Rf.inherit_
        (Ppxlib.Ast_helper.Typ.constr (Metapp.mkloc txt) []) :: accu in
    let row_fields =
      LongidentSet.fold add_inherited_kind inherited row_fields in
    let row_fields =
      if row_fields = [] then
        [Metapp.Rf.tag (Metapp.mkloc "Absent") false []]
      else
        row_fields in
    Ppxlib.Ast_helper.Typ.variant row_fields Closed None
end


module Variables = struct
  module Path = struct
    module PathItem = PairOfOrderedType (OrderedLongident) (Int)

    type t = origin * selector
    and selector =
      | Left
      | Right
      | Direct
    and origin = PathItem.t list

    let left selector =
      match selector with
      | Direct
      | Right -> Left
      | Left -> Right

    let right selector =
      match selector with
      | Direct
      | Right -> Right
      | Left -> Left

    let compare : t -> t -> int =
      compare_pair (compare_list PathItem.compare) compare
  end

  module PathSet = Set.Make (Path)

  type t = PathSet.t IntMap.t

  let find i variables =
    try IntMap.find i variables
    with Not_found -> PathSet.empty

  let add i path variables =
    let path_set = PathSet.add path (find i variables) in
    IntMap.add i path_set variables

  let offset count variables =
    IntMap.fold (fun key value map ->
      if key >= count then
        IntMap.add (key - count) value map
      else
        map) variables IntMap.empty

  type property = t

  let bottom = IntMap.empty

  let equal =
    IntMap.equal PathSet.equal

  let union =
    IntMap.union (fun _ p p' -> Some (PathSet.union p p'))

  let is_maximal _ = false

  let variable_name side type_name i =
     type_name ^ "__variable_" ^ side ^ (string_of_int i)

  let positive_name = variable_name "positive"

  let negative_name = variable_name "negative"

  let direct_name = variable_name "direct"

  let gadt_name = variable_name "gadt"

  type transfer =
    | Present
    | Depend of Longident.t list list

  let make_transfer variables target i =
    let paths = find i variables in
    if PathSet.mem ([], target) paths
        || target = Right && PathSet.mem ([], Direct) paths then
      Present
    else
      let rec add_path (selector : Path.selector) path t cstrs =
        match path with
        | [] ->
            begin match target, selector with
            | Left, Left
            | Right, (Direct | Right)
            | Direct, Direct -> t :: cstrs
            | _ -> cstrs
            end
        | (longident, i) :: path ->
            let apply subst =
              subst_ident (fun name -> subst name i) longident :: t in
            if target = Direct then
              add_path selector path (apply direct_name) cstrs
            else
              cstrs |>
              add_path (Path.left selector) path (apply negative_name) |>
              add_path (Path.right selector) path (apply positive_name) in
      let add_inherited (origin, selector) cstrs =
        add_path selector origin [] cstrs in
      Depend (PathSet.fold add_inherited paths [])

  type transfers = (Longident.t * transfer) list

  let make_transfers type_name arity variables =
    let make target name i =
      name type_name i, make_transfer variables target i in
    List.init arity (make Right positive_name) @
    List.init arity (make Left negative_name) @
    List.init arity (make Direct direct_name)
end

include PropertyOfPair (Kinds) (Variables)

let add_direct_kind kind ((exists, (direct, inherited)), variables) =
  ((exists, (StringSet.add kind direct, inherited)), variables)

let add_inherited_kind type_name ((exists, (direct, inherited)), variables) =
  ((exists, (direct, LongidentSet.add type_name inherited)), variables)

let add_exists_kind transfer ((exists, others), variables) =
  ((TransferSet.add transfer exists, others), variables)

let add_variable variable path ((kinds, variables) : t) =
  (kinds, Variables.add variable path variables)

let offset_variables count ((kinds, variables) : t) =
  (kinds, Variables.offset count variables)
OCaml

Innovation. Community. Security.