typecheck.ml 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. open Printf
  2. open Ast
  3. open Util
  4. open Stringify
  5. (*
  6. * Do a number of checks:
  7. * - A void function must not return a value.
  8. * - A non-void function must return a value of the correct type.
  9. * - Array indices must be of type integer.
  10. * - The number of array indices must match the number of array dimensions.
  11. * - The type on the right-hand side of an assignment must match the type on
  12. * the left-hand side.
  13. * - The number of arguments used for a function call must match the number of
  14. * parameters for that function.
  15. * - The types of the function arguments must match the types of parameters.
  16. * - The operands of a unary or binary operation must have valid types.
  17. * - The predicate expression of an if, while, or do-while statement must be
  18. * a boolean.
  19. * - Only values having a basic type can be type cast.
  20. *)
  21. let spec = function
  22. | Array (ctype, dims) -> ArrayDepth (ctype, list_size dims)
  23. | ctype -> ctype
  24. let check_type ?(msg="") expected node =
  25. let got = typeof node in
  26. if (spec got) <> (spec expected) then (
  27. let msg = match msg with
  28. | "" -> sprintf "type mismatch: expected type %s, got %s"
  29. (type2str expected) (type2str got)
  30. (*(type2str (spec expected)) (type2str (spec got))*)
  31. | _ -> msg
  32. in raise (NodeError (node, msg))
  33. ); ()
  34. let op_types = function
  35. | Not | And | Or -> [Bool]
  36. | Mod -> [Int]
  37. | Neg | Sub | Div | Lt | Le | Gt | Ge -> [Int; Float]
  38. | Add | Mul | Eq | Ne -> [Bool; Int; Float]
  39. let op_result_type opnd_type = function
  40. | Not | And | Or | Eq | Ne | Lt | Le | Gt | Ge -> Bool
  41. | Neg | Add | Sub | Mul | Div | Mod -> opnd_type
  42. (* Check if the given operator can be applied to the given type *)
  43. let check_type_op allowed_types desc node =
  44. let got = typeof node in
  45. if not (List.mem got allowed_types) then (
  46. let msg = sprintf
  47. "%s cannot be applied to type %s, only to %s"
  48. desc (type2str got) (types2str allowed_types)
  49. in
  50. raise (NodeError (node, msg))
  51. ); ()
  52. let check_dims_match dims dec_type errnode =
  53. match (list_size dims, array_depth dec_type) with
  54. | (got, expected) when got != expected ->
  55. let msg = sprintf
  56. "dimension mismatch: expected %d indices, got %d" expected got
  57. in
  58. raise (NodeError (errnode, msg))
  59. | _ -> ()
  60. let rec typecheck node =
  61. let check_trav ctype node =
  62. let node = typecheck node in
  63. check_type ctype node;
  64. node
  65. in
  66. match node with
  67. | FunUse ((FunDec (ret_type, name, params, _) as dec), args, ann)
  68. | FunUse ((FunDef (_, ret_type, name, params, _, _) as dec), args, ann) ->
  69. (match (list_size args, list_size params) with
  70. | (nargs, nparams) when nargs != nparams ->
  71. let msg = sprintf
  72. "function \"%s\" expects %d arguments, got %d"
  73. name nparams nargs
  74. in
  75. raise (NodeError (node, msg))
  76. | _ ->
  77. let args = List.map typecheck args in
  78. let check_arg_type arg param =
  79. check_type (typeof param) arg;
  80. in
  81. List.iter2 check_arg_type args params;
  82. FunUse (dec, args, Type ret_type :: ann)
  83. )
  84. (* Operators match operand types and get a new type based on the operator *)
  85. | Monop (op, opnd, ann) ->
  86. let opnd = typecheck opnd in
  87. let desc = sprintf "unary operator \"%s\"" (op2str op) in
  88. check_type_op (op_types op) desc opnd;
  89. Monop (op, opnd, Type (op_result_type (typeof opnd) op) :: ann)
  90. | Binop (op, left, right, ann) ->
  91. let left = typecheck left in
  92. let right = typecheck right in
  93. let desc = sprintf "binary operator \"%s\"" (op2str op) in
  94. check_type_op (op_types op) desc left;
  95. check_type (typeof left) right;
  96. Binop (op, left, right, Type (op_result_type (typeof left) op) :: ann)
  97. (* Conditions must be bool, and right-hand type must match left-hand type *)
  98. | Cond (cond, texpr, fexpr, ann) ->
  99. let cond = check_trav Bool cond in
  100. let texpr = typecheck texpr in
  101. let fexpr = check_trav (typeof texpr) fexpr in
  102. Cond (cond, texpr, fexpr, Type (typeof texpr) :: ann)
  103. (* Only basic types can be typecasted *)
  104. | TypeCast (ctype, value, ann) ->
  105. let value = typecheck value in
  106. check_type_op [Bool; Int; Float] "typecast" value;
  107. TypeCast (ctype, value, Type (typeof value) :: ann)
  108. (* Array allocation dimensions must have type int *)
  109. | Allocate (name, dims, dec, ann) ->
  110. Allocate (name, List.map (check_trav Int) dims, dec, ann)
  111. (* Array dimensions are always integers *)
  112. | Dim (name, ann) ->
  113. Dim (name, Type Int :: ann)
  114. (* Functions and parameters must be traversed to give types to Dim nodes *)
  115. | FunDec (ret_type, name, params, ann) ->
  116. FunDec (ret_type, name, List.map typecheck params, ann)
  117. | Param (Array (ctype, dims), name, ann) ->
  118. Param (Array (ctype, List.map typecheck dims), name, ann)
  119. (* Void functions may have no return statement, other functions must have a
  120. * return statement of valid type *)
  121. | FunDef (export, ret_type, name, params, body, ann) ->
  122. let params = List.map typecheck params in
  123. let body = typecheck body in
  124. let rec find_return = function
  125. | [] -> None
  126. | [Return (value, _) as ret] -> Some (ret, typeof value)
  127. | hd :: tl -> find_return tl
  128. in (
  129. match (ret_type, find_return (block_body body)) with
  130. | (Void, Some (ret, _)) ->
  131. raise (NodeError (ret, "void function should not have a return value"))
  132. | ((Bool | Int | Float), None) ->
  133. let msg = sprintf
  134. "expected return value of type %s for function \"%s\""
  135. (type2str ret_type) name
  136. in
  137. raise (NodeError (node, msg))
  138. | ((Bool | Int | Float), Some (ret, t)) when t != ret_type ->
  139. let msg = sprintf
  140. "function \"%s\" has return type %s, got %s"
  141. name (type2str ret_type) (type2str t)
  142. in
  143. raise (NodeError (ret, msg))
  144. | _ -> FunDef (export, ret_type, name, params, body, ann)
  145. )
  146. (* Conditions in must have type bool *)
  147. | If (cond, body, ann) ->
  148. If (check_trav Bool cond, typecheck body, ann)
  149. | IfElse (cond, tbody, fbody, ann) ->
  150. IfElse (check_trav Bool cond, typecheck tbody, typecheck fbody, ann)
  151. | While (cond, body, ann) ->
  152. While (check_trav Bool cond, typecheck body, ann)
  153. | DoWhile (cond, body, ann) ->
  154. DoWhile (check_trav Bool cond, typecheck body, ann)
  155. (* Constants *)
  156. | BoolConst (value, ann) -> BoolConst (value, Type Bool :: ann)
  157. | IntConst (value, ann) -> IntConst (value, Type Int :: ann)
  158. | FloatConst (value, ann) -> FloatConst (value, Type Float :: ann)
  159. (* Variables inherit the type of their declaration *)
  160. | VarUse (dec, None, ann) ->
  161. VarUse (dec, None, Type (typeof dec) :: ann)
  162. | VarUse (dec, Some dims, ann) ->
  163. let dims = List.map typecheck dims in
  164. List.iter (check_type Int) dims;
  165. check_dims_match dims (typeof dec) node;
  166. VarUse (dec, Some dims, Type (basetypeof dec) :: ann)
  167. (* Assigned values must match variable declaration *)
  168. | VarLet (dec, None, value, ann) ->
  169. VarLet (dec, None, check_trav (typeof dec) value, ann)
  170. | VarLet (dec, Some dims, value, ann) ->
  171. (* Number of assigned indices must match array definition *)
  172. check_dims_match dims (typeof dec) node;
  173. (* Array indices must be ints *)
  174. let dims = List.map typecheck dims in
  175. List.iter (check_type Int) dims;
  176. (* Assigned value must match array base type *)
  177. let value = typecheck value in
  178. check_type (basetypeof dec) value;
  179. VarLet (dec, Some dims, value, ann)
  180. | _ -> transform_children typecheck node
  181. let rec phase input =
  182. log_line 2 "- Type checking";
  183. match input with
  184. | Ast node -> Ast (typecheck node)
  185. | _ -> raise (InvalidInput "typecheck")