Source file unit.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

module Pth = Paths.Simple

type precision =
  | Exact
  | Approx

(** Base type *)
type 'ext t = {
  path: Namespaced.t; (** module path of the compilation unit *)
  src: Pkg.t; (** source file of the compilation unit *)
  kind: M2l.kind;
  precision: precision;
  code: M2l.t;
  more: 'ext
}

(** Extension for output type *)
type ext = {
  signature: Module.signature;
  dependencies: Deps.t
}

type 'ext base = 'ext t
type s = unit t
type u = ext t
type r = u

let signature unit = unit.more.signature
let deps u = u.more.dependencies
let update dependencies u =
  { u with more = { u.more with dependencies } }

let local_dependencies unit =
  let filter { Deps.pkg; _ } =
    match pkg with
    | {Pkg.source=(Unknown | Special _); _ } -> false
    | _ -> true
  in
  List.filter filter @@ Deps.all @@ deps unit

let lift signature dependencies u =
  {u with more = {signature;dependencies} }

let proj u = { u with more = () }


let read_file policy kind filename path : s =
  let code = Read.file kind filename in
  let precision, code = match code with
    | Ok c -> Exact, c
    | Error (Serialized e) ->
      Standard_faults.schematic_errors policy (filename,"m2l",e);
      Approx, []
    | Error (Ocaml (Syntax msg)) ->
      Fault.raise policy Standard_faults.syntaxerr msg;
      Approx, Approx_parser.lower_bound filename
    | Error (Ocaml (Lexer msg)) ->
      Fault.raise policy Standard_faults.lexerr (!Location.input_name,msg);
      Approx, Approx_parser.lower_bound filename

  in
      { path;
        kind = kind.kind;
        precision;
        src = Pkg.local filename;
        code;
        more = ()
      }

type 'a pair = { ml:'a; mli:'a}
let map fs xs = { ml = fs.ml xs.ml; mli = fs.mli xs.mli}
let unimap f xs = { ml = f xs.ml; mli = f xs.mli }

let adder add p = function
  | M2l.Structure, x -> { p with ml = add x p.ml }
  | M2l.Signature, x -> { p with mli = add x p.mli }

module Group = struct

  let key unit =  unit.path

  type 'ext group = 'ext t list pair

  let add_mli mli x =
    { x with mli = mli :: x.mli }

  let add_ml ml x =
    { x with ml =  ml :: x.ml }

  let raw_add kind elt x =
    match kind with
    | M2l.Structure -> add_ml elt x
    | Signature -> add_mli elt x
  let add elt x = raw_add elt.kind elt x

  let empty = { mli = []; ml = [] }

  module Map = struct
    type 'ext t = 'ext group Namespaced.Map.t

    let find path m = Namespaced.Map.find path m

    let raw_add kind unit m =
      let key = key unit in
      let grp = Option.default empty (Namespaced.Map.find_opt key m) in
      Namespaced.Map.add key (raw_add kind unit grp) m

    let add unit m = raw_add unit.kind unit m


    let of_list x = List.fold_left (fun x y -> add  y x) Namespaced.Map.empty x

    let fold f map start = Namespaced.Map.fold (fun _ -> f) map start
    let iter f map = fold (fun x () -> f x) map ()
  end

  let group {ml;mli} =
    let start = Namespaced.Map.empty in
    let add kind m x = Map.raw_add kind x m in
    let mid = List.fold_left (add Structure) start ml in
    List.fold_left (add Signature) mid mli

  let flatten grp =
    let flat  = function
      | [] -> None, []
      | [x] -> Some x, []
      | x :: q -> Some x, x::q in
    let mli, mli_err = flat grp.mli in
    let ml, ml_err = flat grp.ml in
    { ml; mli }, { ml = ml_err; mli = mli_err }

  let split map =
    Namespaced.Map.fold ( fun name grp ({ml; mli}, errors ) ->
        let g, err = flatten grp in
        let err = err.ml @ err.mli in
        let errors = if err = [] then errors else
            (name, err) :: errors in
        begin match g with
          | { ml = Some x; mli = None }
          | { ml = None; mli = Some x } ->
            { ml; mli = x :: mli }
          | { ml = Some x ;mli = Some y} ->
            { ml = x::ml; mli = y::mli}
          | { ml = None; mli = None } -> {ml;mli}
        end
      ,  errors
      ) map ({ ml = []; mli = [] },[])

end

let pp ppf unit =
  Pp.fp ppf "@[<2>[@ path=%a;@ source=%a;@ \
             m2l = @[%a@];@ \
             signature=[ @[%a@] ];@ \
             dependencies=@[%a@]@ \
             ]@]@."
    Namespaced.pp unit.path
    Pkg.pp_simple unit.src
    M2l.pp unit.code
    Module.pp_signature (signature unit)
    Deps.pp (deps unit)

let pp_input ppf (unit:s) =
  Pp.fp ppf "@[<hov2>[ path=%a;@ source=%a;@ \
             m2l = @[%a@];@ \
             ] @]@."
    Namespaced.pp unit.path
    Pkg.pp_simple unit.src
    M2l.pp unit.code

module Set = Set.Make(struct type t = u let compare = compare end)