Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
types.ml1 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 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430(**********************************************************************) (* *) (* This file is part of the RFSM package *) (* *) (* Copyright (c) 2018-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 date = int type dir = IO_In | IO_Out | IO_Inout module VarSet = Set.Make(struct type t = string let compare = Pervasives.compare end) (* Type indexes *) module Index = struct type t = | TiConst of int | TiVar of string | TiBinop of string * t * t type env = (string * int) list type op = int -> int -> int let ops = [ "+", (+); "-", (-); "*", ( * ); "/", ( / ); "mod", ( mod ) ] exception Illegal_op of string exception Illegal_type_index of t exception Unbound_type_index of string let lookup op = try List.assoc op ops with Not_found -> raise (Illegal_op op) let rec subst env i = match i with TiConst _ -> i | TiVar v -> begin try TiConst (List.assoc v env) with Not_found -> raise (Unbound_type_index v) end | TiBinop (op,e1,e2) -> begin match subst env e1, subst env e2 with | TiConst c1, TiConst c2 -> TiConst ((lookup op) c1 c2) | i1, i2 -> TiBinop (op, i1, i2) end let rec vars_of = function | TiConst _ -> VarSet.empty | TiVar v -> VarSet.singleton v | TiBinop (_,e1,e2) -> VarSet.union (vars_of e1) (vars_of e2) let rec to_string = function TiConst c -> string_of_int c | TiVar v -> v | TiBinop (op,e1,e2) -> to_string e1 ^ op ^ to_string e2 (* TODO: add parens *) end type typ = | TyEvent | TyBool | TyEnum of name * string list (** Name, list of values *) | TyInt of siz | TyFloat | TyChar | TyArray of Index.t * typ (** size, subtype *) | TyVar of typ var (** Internal use only *) | TyArrow of typ * typ (** Internal use only *) | TyProduct of typ list (** Internal use only *) | TyRecord of name * (string * typ) list (** Name, fields *) and siz = | SzExpr1 of Index.t (* For ints: bit width, for arrays: dimension *) | SzExpr2 of Index.t * Index.t (* For ints: range, for arrays: dimensions *) | SzVar of siz var and name = | NmLit of string | NmVar of name var and 'a var = { stamp: string; (* for debug only *) mutable value: 'a value } and 'a value = | Unknown | Known of 'a type typ_scheme = { ts_tparams: (typ var) list; ts_sparams: (siz var) list; ts_body: typ } (* Type variables *) 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 () = TyVar (make_var ()) let new_size_var () = SzVar (make_var ()) let new_name_var () = NmVar (make_var ()) (* Builders *) let no_type = TyProduct [] let type_int = function [] -> TyInt (new_size_var ()) | [w] -> TyInt (SzExpr1 (TiConst w)) | [lo;hi] -> TyInt (SzExpr2 (TiConst lo, TiConst hi)) | _ -> invalid_arg "Types.type_int" let rec type_repr = function | TyVar ({value = Known ty1} as var) -> let ty = type_repr ty1 in var.value <- Known ty; ty | ty -> ty let rec size_repr = function | SzVar ({value = Known sz1} as var) -> let sz = size_repr sz1 in var.value <- Known sz; sz | sz -> sz let rec name_repr = function | NmVar ({value = Known nm1} as var) -> let nm = name_repr nm1 in var.value <- Known nm; nm | nm -> nm (* Real type : path compression + unabbreviation *) let rec real_type ty = match type_repr ty with | TyArrow (ty1,ty2) -> TyArrow (real_type ty1, real_type ty2) | TyProduct ts -> TyProduct (List.map real_type ts) | TyArray (sz, ty') -> TyArray (sz, real_type ty') | TyVar { value=Known ty'} -> ty' | TyInt sz -> TyInt (real_size sz) | TyEnum (name, desc) -> TyEnum (real_name name, desc) | TyRecord (name, fds) -> TyRecord (real_name name, List.map (function (n,ty') -> n, real_type ty') fds) | ty -> ty and real_size sz = match size_repr sz with | SzVar { value=Known sz'} -> sz' | sz -> sz and real_name nm = match name_repr nm with | NmVar { value=Known nm'} -> nm' | nm -> nm let rec copy_type tvbs svbs ty = let rec copy ty = match type_repr ty with | TyVar var as ty -> begin try List.assq var tvbs with Not_found -> ty end | TyArrow (ty1, ty2) -> TyArrow (copy ty1, copy ty2) | TyProduct ts -> TyProduct (List.map copy ts) | TyArray (sz, ty') -> TyArray (sz, copy ty') | TyInt sz -> TyInt (copy_size ty svbs sz) | TyEnum (nm, desc) -> TyEnum (nm, desc) | TyRecord (nm, fds) -> TyRecord(nm, List.map (function (n,t) -> n, copy t) fds) | ty -> ty in copy ty and copy_size ty svbs sz = match size_repr sz with | SzVar var as sz -> begin try List.assq var svbs with Not_found -> sz end | sz -> sz let type_instance ty_sch = match ty_sch.ts_tparams, ty_sch.ts_sparams with | [], [] -> ty_sch.ts_body | tparams, sparams -> let unknown_ts = List.map (fun var -> (var, new_type_var())) tparams in let unknown_ss = List.map (fun var -> (var, new_size_var())) sparams in copy_type unknown_ts unknown_ss ty_sch.ts_body (* Type unification - the classical algorithm *) exception TypeConflict of typ * typ exception TypeCircularity of typ * typ 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 | 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 | TyArray (sz1, ty1), TyArray (sz2, ty2) when sz1 = sz2 -> unify ty1 ty2 | TyInt sz1, TyInt sz2 -> unify_size (val1,val2) sz1 sz2 | TyBool, TyBool -> () | TyEvent, TyEvent -> () | TyFloat, TyFloat -> () | TyChar, TyChar -> () | TyEnum (nm1,cs1), TyEnum (nm2,cs2) -> if List.sort compare cs1 = List.sort compare cs2 then unify_name (val1,val2) nm1 nm2 else raise (TypeConflict(val1, val2)) | TyRecord (nm1,fds1), TyRecord (nm2,fds2) -> List.iter2 (fun (n1,t1) (n2,t2) -> if n1 = n2 then unify t1 t2 else raise (TypeConflict(val1, val2))) fds1 fds2; unify_name (val1,val2) nm1 nm2 | _, _ -> raise (TypeConflict(val1, val2)) and unify_size (ty1,ty2) sz1 sz2 = let val1 = real_size sz1 and val2 = real_size sz2 in if val1 == val2 then () else match (val1, val2) with | SzVar var1, SzVar var2 when var1 == var2 -> (* This is hack *) () | SzVar var, sz -> occur_check_size (ty1,ty2) var sz; var.value <- Known sz | sz, SzVar var -> occur_check_size (ty1,ty2) var sz; var.value <- Known sz | SzExpr1 (TiConst w1), SzExpr1 (TiConst w2) when w1 = w2 -> () | SzExpr2 (TiConst lo1, TiConst hi1), SzExpr2 (TiConst lo2, TiConst hi2) when lo1 = lo2 && hi1 = hi2 -> () | _, _ -> raise (TypeConflict(ty1, ty2)) and unify_name (ty1,ty2) nm1 nm2 = let val1 = real_name nm1 and val2 = real_name nm2 in if val1 == val2 then () else match (val1, val2) with | NmLit s1, NmLit s2 when s1 = s2 -> () | NmVar var1, NmVar var2 when var1 == var2 -> () (* This is hack *) | NmVar var, nm -> var.value <- Known nm | nm, NmVar var -> var.value <- Known nm | _, _ -> raise (TypeConflict(ty1, ty2)) and occur_check var ty = let rec test t = match type_repr t with | TyVar var' -> if var == var' then raise(TypeCircularity(TyVar var, ty)) | TyArrow (ty1,ty2) -> test ty1; test ty2 | TyProduct ts -> List.iter test ts | _ -> () in test ty and occur_check_size (ty1,ty2) var sz = let test s = match size_repr s with | SzVar var' -> if var == var' then raise(TypeCircularity(ty1,ty2)) | _ -> () in test sz let ivars_of = function | TyInt (SzExpr1 sz) -> VarSet.elements (Index.vars_of sz) | TyInt (SzExpr2 (lo,hi)) -> VarSet.elements (VarSet.union (Index.vars_of lo) (Index.vars_of hi)) | TyArray (sz, ty) -> VarSet.elements (Index.vars_of sz) | _ -> [] (* Index manipulation *) let subst_indexes env ty = match ty with | TyInt (SzExpr1 sz) -> TyInt (SzExpr1 (Index.subst env sz)) | TyInt (SzExpr2 (hi,lo)) -> TyInt (SzExpr2 (Index.subst env hi, Index.subst env lo)) | TyArray (sz, ty') -> TyArray (Index.subst env sz, ty') | _ -> ty (* Checking *) let is_event_type t = match t with | TyEvent -> true | _ -> false let rec type_equal ~strict t1 t2 = match real_type t1, real_type t2 with | TyBool, TyBool -> true | TyEvent, TyEvent -> true | TyInt sz1, TyInt sz2 -> size_equal ~strict:strict sz1 sz2 | TyFloat, TyFloat -> true | TyChar, TyChar -> true | TyEnum (nm1,cs1), TyEnum (nm2,cs2) -> name_equal ~strict nm1 nm2 && (if strict then List.sort compare cs1 = List.sort compare cs2 else List.for_all (function c -> List.mem c cs1) cs2) (* so that, for ex, [type_equal ~strict:false {On,Off} {On} = true] *) | TyVar { stamp=s1; value=Unknown }, TyVar { stamp=s2; value=Unknown } -> s1 = s2 | TyArrow (ty1, ty1'), TyArrow (ty2, ty2') -> type_equal ~strict ty1 ty2 && type_equal ~strict ty1' ty2' | TyProduct ts, TyProduct ts' when List.length ts = List.length ts'-> List.for_all2 (type_equal ~strict) ts ts' | TyArray (sz1, ty1), TyArray (sz2, ty2) -> sz1 = sz2 && type_equal ~strict ty1 ty2 | TyRecord (nm1, fds1), TyRecord (nm2, fds2) -> name_equal ~strict nm1 nm2 && List.for_all2 (fun (n1,t1) (n2,t2) -> type_equal ~strict t1 t2) fds1 fds2 | _, _ -> false and size_equal ~strict s1 s2 = match real_size s1, real_size s2 with | SzExpr1 w1, SzExpr1 w2 -> w1 = w2 | SzExpr2 (lo1,hi1), SzExpr2 (lo2,hi2) -> lo1 = lo2 && hi1 = hi2 | SzVar v1, SzVar v2 -> v1 == v2 | _, _ -> false and name_equal ~strict nm1 nm2 = match real_name nm1, real_name nm2 with | NmLit s1, NmLit s2 -> s1 = s2 | NmVar v1, NmVar v2 -> v1 == v2 | _, _ -> false (* Accessors *) let enums_of ty = match ty with | TyEnum (_,cs) -> List.map (function c -> c, ty) cs | _ -> [] let size_of ty = match ty with | TyArray (TiConst sz, _) -> sz | TyProduct ts -> List.length ts | _ -> 0 let subtype_of = function | TyArray (_,t) -> t | _ -> Misc.fatal_error "Types.subtype_of" let is_lit_name nm = match real_name nm with | NmLit _ -> true | _ -> false (* Printing *) let string_of_range (lo,hi) = Index.to_string lo ^ ":" ^ Index.to_string hi let rec string_of_type ?(szvars=false) t = match t with | TyEvent -> "event" | TyBool -> "bool" | TyEnum (nm, cs) -> begin match real_name nm with NmLit s -> s | _ -> "{" ^ Utils.ListExt.to_string (function c -> c) "," cs ^ "}" end | TyInt sz -> "int" ^ string_of_size ~szvars sz | TyFloat -> "float" | TyChar -> "char" | TyVar v -> v.stamp | TyArrow (t1,t2) -> string_of_type t1 ^ "->" ^ string_of_type t2 | TyProduct ts -> Utils.ListExt.to_string string_of_type "*" ts | TyArray (sz,ty') -> string_of_type ty' ^ " array[" ^ Index.to_string sz ^ "]" | TyRecord (nm,fs) -> begin match real_name nm with NmLit s -> s | _ -> "{" ^ Utils.ListExt.to_string string_of_field "," fs ^ "}" end and string_of_size ?(szvars=false) sz = let s = match size_repr sz with | SzVar v -> if szvars then v.stamp else "" | SzExpr1 e -> Index.to_string e | SzExpr2 (e1,e2) -> Index.to_string e1 ^ ":" ^ Index.to_string e2 in match s with | "" -> "" | _ -> "<" ^ s ^ ">" and string_of_name nm = match name_repr nm with | NmLit s -> s | NmVar v -> v.stamp and string_of_field (n,ty) = n ^ ":" ^ string_of_type ty let string_of_type_scheme ts = "[]" ^ string_of_type ts.ts_body (* TOFIX *)