package minicaml

  1. Overview
  2. Docs

Source file typecheck.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
open Types

let terr e f = traise ("expected a value of type: " ^ e ^ ", found a value of type: " ^ f )

let typeof e = match e with
  | EvtUnit -> TUnit
  | EvtInt _ -> TInt
  | EvtFloat _ -> TFloat
  | EvtComplex _ -> TComplex
  | EvtBool _ -> TBool
  | EvtString _ -> TString
  | EvtList _ -> TList
  | EvtDict _ -> TDict
  | Closure (_, _, _, _) -> TLambda

(** Get the lowest (most inclusive set) number type from a list of numbers *)
let rec infer_lowest_numbert low ls = match ls with
  | [] -> low
  | (EvtComplex _)::_ -> TComplex
  | (EvtInt _)::xs -> infer_lowest_numbert low xs
  | (EvtFloat _)::xs -> infer_lowest_numbert TFloat xs
  | (_)::_ -> traise "value is not a number in arithmetical operator"

let cast_numbert lowerto num = match lowerto with
  | TInt -> num
  | TFloat -> (match num with
      | EvtInt x -> EvtFloat(float_of_int x)
      | EvtFloat x -> EvtFloat x
      | EvtComplex x -> EvtComplex x
      | _ -> traise "not a number")
  | TComplex -> (match num with
      | EvtInt x -> EvtComplex {re = float_of_int x; im = 0.}
      | EvtFloat x -> EvtComplex {re = x; im = 0.}
      | EvtComplex x -> EvtComplex x
      | _ -> traise "not a number")
  | _ -> traise "cannot cast to a non-numerical type"

(** Accept a list of numbers and flatten out their
    kind on the numerical tower hierarchy *)
let flatten_numbert_list l =
  let found = infer_lowest_numbert TInt l in
  (found, List.map (cast_numbert found) l)


(* Static typechecking *)
let stcheck (f: typeinfo) (e: typeinfo) =
  let rterr () = terr (show_tinfo e) (show_tinfo f) in
  match e with
  | TNumber -> (match f with
      | TInt | TFloat | TComplex | TNumber -> ()
      | _ -> rterr () )
  | _ -> if e = f then () else rterr()


(** Static typechecking inferer *)
let rec sinfer (e: expr) (state: evalstate) : typeinfo = match e with
  (* Inference only on TNumber. Rely on strict checking for precise number type checking *)
  | NumInt _ | NumFloat _ | NumComplex _ -> TNumber
  | Boolean _ -> TBool
  | String _ -> TString
  | List _ -> TList
  | Purity (_, x) -> sinfer x state
  | Cons (_, b) -> (stcheck (sinfer b state) TList); TList
  | Concat (a, b) ->
    let ta = sinfer a state and tb = sinfer b state in
    (match (ta, tb) with
        | TString, TString -> TString
        | TList, TList -> TList
        | _ -> iraises (TypeError (Printf.sprintf "Cannot concatenate a two values of type %s and %s"
          (show_tinfo ta) (show_tinfo tb))) state.stack )
  | Plus(a, b) | Sub(a, b)
  | Mult(a, b) | Div(a, b) ->
    (stcheck (sinfer a state) TNumber);
    (stcheck (sinfer b state) TNumber);
    TNumber
  | _ -> traise "Could not infer type!"

(** Unpacking functions: extract a value or throw an err *)

let unpack_int x = (match x with EvtInt i -> i | e -> terr "int" (show_tinfo (typeof e)))
let unpack_float x = (match x with EvtFloat i -> i | e -> terr "float" (show_tinfo (typeof e)))
let unpack_complex x = (match x with EvtComplex i -> i | e -> terr "complex" (show_tinfo (typeof e)))
let unpack_bool x = (match x with EvtBool i -> i | e -> terr "bool" (show_tinfo (typeof e)))
let unpack_string x = (match x with EvtString i -> i | e -> terr "string" (show_tinfo (typeof e)))
let unpack_list x = (match x with EvtList i -> i | e -> terr "list" (show_tinfo (typeof e)))
let unpack_dict x = (match x with EvtDict i -> i | e -> terr "dict" (show_tinfo (typeof e)))
let unpack_closure x = (match x with Closure (n, p, b, e) -> (n, p,b,e) | e -> terr "fun" (show_tinfo (typeof e)))
OCaml

Innovation. Community. Security.