package fsml

  1. Overview
  2. Docs

Source file types.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
(**********************************************************************)
(*                                                                    *)
(*              This file is part of the FSML library                 *)
(*                     github.com/jserot/fsml                         *)
(*                                                                    *)
(*  Copyright (c) 2020-present, Jocelyn SEROT.  All rights reserved.  *)
(*                                                                    *)
(*  This source code is licensed under the license found in the       *)
(*  LICENSE file in the root directory of this source tree.           *)
(*                                                                    *)
(**********************************************************************)

type t =
  | TyInt of sign attr * size attr * range attr
  | TyBool
  | TyArrow of t * t  (** Internal use only *)
  | TyProduct of t list  (** Internal use only *)
  | TyVar of t var  (** Internal use only *)
  [@@deriving show {with_path=false}, yojson]

and 'a attr =
  | Const of 'a
  | Var of ('a attr) var
  [@@deriving show {with_path=false}, yojson]

and 'a var =
  { stamp: string;
    mutable value: 'a value }
  [@@deriving show {with_path=false}, yojson]

and 'a value =
  | Unknown
  | Known of 'a
  [@@deriving show {with_path=false}, yojson]

and sign = Signed | Unsigned [@@deriving show {with_path=false}, yojson]
and size = int [@@deriving show {with_path=false}, yojson]
and range = { lo: int; hi: int } [@@deriving show {with_path=false}, yojson]
          
type typ_scheme =
  { ts_params: ts_params;
    ts_body: t }
  [@@deriving show {with_path=false}, yojson]

and ts_params = {
  tp_typ: (t var) list;
  tp_sign: ((sign attr) var) list;
  tp_size: ((size attr) var) list;
  tp_range: ((range attr) var) list;
  }

(* Builders *)

let new_stamp =
  let var_cnt = ref 0 in
  function () -> incr var_cnt; "_" ^ string_of_int !var_cnt

let make_var () = { value = Unknown; stamp=new_stamp () }

let new_type_var () = make_var ()
let new_attr_var () = make_var ()

let type_int () = TyInt (Var (make_var ()), Var (make_var ()), Var (make_var()))

let empty_params = { tp_typ=[]; tp_sign=[]; tp_size=[]; tp_range=[] }
let trivial_scheme t = { ts_params=empty_params; ts_body=t }
                     
(* Path compression *)

let rec type_repr = function
  | TyVar ({value = Known ty1; _} as var) ->
      let ty = type_repr ty1 in
      var.value <- Known ty;
      ty
  | ty -> ty

(* TODO: find a way to share type_xxx and attr_xxx fns .. *)
        
let rec attr_repr = function
  | Var ({value = Known r1; _} as var) ->
      let r = attr_repr r1 in
      var.value <- Known r;
      r
  | r -> r

let real_attr a = 
  match attr_repr a with
  | Var { value=Known v'; _} -> v'
  | r -> r

let real_type ty = 
  match type_repr ty with
  | TyInt (sg, sz, rg) -> TyInt (real_attr sg, real_attr sz, real_attr rg)
  | TyVar { value=Known ty'; _} -> ty'
  | ty -> ty

exception Polymorphic of t

(* let rec mono_attr t = function
 *   | Var ({value = Known v1; _}) -> mono_attr t v1
 *   | Var ({value = Unknown; _}) -> raise (Polymorphic t)
 *   | r -> r  *)
                       
let rec mono_type = function
  (* | TyInt (sg, sz, rg) as t -> TyInt (mono_attr t sg, mono_attr t sz, mono_attr t rg) *)
  | TyArrow (t1, t2) -> TyArrow (mono_type t1, mono_type t2)
  | TyProduct ts -> TyProduct (List.map mono_type ts)
  | TyVar ({value = Known ty1; _}) -> mono_type ty1
  | TyVar ({value = Unknown; _}) as t -> raise (Polymorphic t)
  | ty -> ty 

(* Unification *)

exception TypeConflict of t * t
exception TypeCircularity of t * t

let unify_attr (ty1,ty2) a1 a2 =
  let val1 = real_attr a1
  and val2 = real_attr a2 in
  if val1 == val2 then ()
  else
  match (val1, val2) with
    | Const s1, Const s2 when s1 = s2 -> ()
    | Var var1, Var var2 when var1 == var2 -> ()  (* This is hack *)
    | Var var, v -> var.value <- Known v
    | v, Var var -> var.value <- Known v
    | _, _ -> raise (TypeConflict(ty1, ty2))

let rec unify ty1 ty2 =
  let val1 = real_type ty1
  and val2 = real_type ty2 in
  if val1 == val2 then () else
  match (val1, val2) with
  | TyVar v1, TyVar v2 when v1==v2 -> 
      ()
  | TyVar var, ty ->
      occur_check var ty;
      var.value <- Known ty
  | ty, TyVar var ->
      occur_check var ty;
      var.value <- Known ty
  | TyBool, TyBool -> ()
  | TyInt (sg1,sz1,rg1), TyInt (sg2,sz2,rg2) ->
     unify_attr (val1,val2) sg1 sg2;
     unify_attr (val1,val2) sz1 sz2;
     unify_attr (val1,val2) rg1 rg2
  | TyArrow(ty1, ty2), TyArrow(ty1', ty2') ->
      unify ty1 ty1';
      unify ty2 ty2'
  | TyProduct ts1, TyProduct ts2 when List.length ts1 = List.length ts2 ->
      List.iter2 unify ts1 ts2
  | _, _ ->
     raise (TypeConflict(val1, val2))


and occur_check var ty =
  let test s =
    match type_repr s with
    | TyVar var' ->
        if var == var' then raise(TypeCircularity(TyVar var,ty))
    | _ ->
        ()
  in test ty

let copy_attr bs a =
  match attr_repr a with
  | Var var as v ->
      begin try
        List.assq var bs 
      with Not_found ->
        v
      end
  | r -> r

type bindings =
  { tb_typ: (t var * t) list;
    tb_sign: ((sign attr) var * sign attr) list;
    tb_size: ((size attr) var * size attr) list;
    tb_range: ((range attr) var * range attr) list; }
  
let copy_type bs ty =
  let rec copy ty = 
    match type_repr ty with
    | TyVar var as ty ->
        begin try
          List.assq var bs.tb_typ
        with Not_found ->
            ty
        end
    | TyInt (sg, sz, rg) ->
       TyInt (copy_attr bs.tb_sign sg, copy_attr bs.tb_size sz, copy_attr bs.tb_range rg)
    | TyArrow (ty1, ty2) ->
       TyArrow (copy ty1, copy ty2)
    | TyProduct ts ->
       TyProduct (List.map copy ts)
    | ty -> ty in
  copy ty

let type_instance ts =
  match ts.ts_params with
  | { tp_typ=[]; tp_sign=[]; tp_size=[]; tp_range=[] } -> ts.ts_body  (* Monotype *)
  | _ ->
     copy_type
       { tb_typ = List.map (fun var -> (var, TyVar (make_var()))) ts.ts_params.tp_typ;
         tb_sign = List.map (fun var -> (var, Var (make_var()))) ts.ts_params.tp_sign;
         tb_size = List.map (fun var -> (var, Var (make_var()))) ts.ts_params.tp_size;
         tb_range = List.map (fun var -> (var, Var (make_var()))) ts.ts_params.tp_range }
       ts.ts_body

(* Printing *)

let string_of_sign, string_of_size, string_of_range =
  let string_of_attr sf a = match a with
    | Const c -> sf c
    | Var v -> v.stamp in
  (string_of_attr (function Unsigned -> "unsigned" | Signed -> "signed"),
   string_of_attr string_of_int,
   string_of_attr (function r -> string_of_int r.lo ^ ".." ^ string_of_int r.hi))
   
let rec to_string t = match t with
  | TyBool -> "bool"
  (* | TyInt (Const Signed, _, _) -> "signed"
   * | TyInt (Const Unsigned, _, _) -> "unsigned" *)
  | TyInt (_, _, Const r) -> "int<" ^ string_of_int r.lo ^ ".." ^ string_of_int r.hi ^ ">" (* Special case *)
  | TyInt (sg, sz, rg) ->
     "int<" ^ string_of_sign sg ^ "," ^ string_of_size sz ^ "," ^ string_of_range rg ^ ">"
  | TyArrow (t1, t2) -> to_string t1 ^ "->" ^ to_string t2
  | TyProduct ts -> Misc.string_of_list ~f:to_string ~sep:"*" ts
  | TyVar v -> v.stamp