typecheck.ml 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. open Printf
  2. open Ast
  3. open Util
  4. open Stringify
  5. (*
  6. * Do a number of checks:
  7. * x A void function must not return a value.
  8. * x 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. * x 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. * x The operands of a unary or binary operation must have valid types.
  17. * x The predicate expression of an if, while, or do-while statement must be
  18. * a boolean.
  19. * x Only values having a basic type can be type cast.
  20. *)
  21. let check_type ?(msg="") expected = function
  22. | Type (node, got) when got != expected ->
  23. let msg = match msg with
  24. | "" -> sprintf "expected type %s, got %s"
  25. (type2str expected) (type2str got)
  26. | _ -> msg
  27. in
  28. raise (NodeError (node, msg))
  29. | Type _ -> ()
  30. | _ -> raise InvalidNode
  31. let op_types = function
  32. | Not | And | Or -> [Bool]
  33. | Mod -> [Int]
  34. | Neg | Sub | Div | Lt | Le | Gt | Ge -> [Int; Float]
  35. | Add | Mul | Eq | Ne -> [Bool; Int; Float]
  36. let op_result_type operand_type = function
  37. | Not | And | Or | Eq | Ne | Lt | Le | Gt | Ge -> Bool
  38. | Neg | Add | Sub | Mul | Div | Mod -> operand_type
  39. (* Check if the given operator can be applied to the given type *)
  40. let check_type_op allowed_types desc = function
  41. | Type (node, ctype) when not (List.mem ctype allowed_types) ->
  42. let msg =
  43. sprintf "%s cannot be applied to type %s, only to %s"
  44. desc (type2str ctype) (types2str allowed_types)
  45. in
  46. raise (NodeError (node, msg))
  47. | Type _ -> ()
  48. | _ -> raise InvalidNode
  49. let rec typecheck node = match node with
  50. | BoolConst (value, _) -> Type (node, Bool)
  51. | IntConst (value, _) -> Type (node, Int)
  52. | FloatConst (value, _) -> Type (node, Float)
  53. | VarUse (_, ctype, _) -> Type (node, ctype)
  54. | FunUse (_, ret_type, _) -> Type (node, ret_type)
  55. | Monop (op, (Type (_, vtype) as value), _) ->
  56. let desc = sprintf "unary operator \"%s\"" (op2str op) in
  57. check_type_op (op_types op) desc value;
  58. Type (node, op_result_type vtype op)
  59. | Monop (op, value, loc) ->
  60. typecheck (Monop (op, typecheck value, loc))
  61. | Binop (op, (Type (_, ltype) as left), right, loc) ->
  62. let desc = sprintf "binary operator \"%s\"" (op2str op) in
  63. check_type_op (op_types op) desc left;
  64. check_type ltype right;
  65. Type (node, op_result_type ltype op)
  66. | Binop (op, left, right, loc) ->
  67. typecheck (Binop (op, typecheck left, typecheck right, loc))
  68. | Cond (Type (cond, condtype), Type (texpr, ttype), fexpr, loc) ->
  69. check_type ttype fexpr;
  70. Type (node, ttype)
  71. | VarLet (_, (Type (_, vtype) as value), dec_type, depth) ->
  72. check_type dec_type value;
  73. Type (node, vtype)
  74. | VarLet (assign, value, dec_type, depth) ->
  75. typecheck (VarLet (assign, typecheck value, dec_type, depth))
  76. | TypeCast (ctype, (Type _ as value), loc) ->
  77. check_type_op [Bool; Int; Float] "typecast" value;
  78. Type (node, ctype)
  79. | TypeCast (ctype, value, loc) ->
  80. typecheck (TypeCast (ctype, typecheck value, loc))
  81. | Return (Type _, _) ->
  82. node
  83. | Return (value, loc) ->
  84. typecheck (Return (typecheck value, loc))
  85. | FunDef (export, ret_type, name, params, body, loc) ->
  86. let params = transform_all typecheck params in
  87. let body = typecheck body in
  88. let rec find_return = function
  89. | [] -> None
  90. | [Return (Type (_, rtype), _) as ret] -> Some (ret, rtype)
  91. | hd :: tl -> find_return tl
  92. in (
  93. match (ret_type, find_return (block_body body)) with
  94. | (Void, Some (ret, _)) ->
  95. raise (NodeError (ret, "void function should not have a return value"))
  96. | ((Bool | Int | Float), None) ->
  97. let msg =
  98. sprintf "expected return value of type %s for function \"%s\""
  99. (type2str ret_type) name
  100. in
  101. raise (NodeError (node, msg))
  102. | ((Bool | Int | Float), Some (ret, t)) when t != ret_type ->
  103. let msg =
  104. sprintf "function \"%s\" has return type %s, got %s"
  105. name (type2str ret_type) (type2str t)
  106. in
  107. raise (NodeError (ret, msg))
  108. | _ ->
  109. FunDef (export, ret_type, name, params, body, loc)
  110. )
  111. (* Conditions in if-statements and loop must be type bool *)
  112. | If (Type _ as cond, _, _)
  113. | IfElse (Type _ as cond, _, _, _)
  114. | While (Type _ as cond, _, _)
  115. | DoWhile (Type _ as cond, _, _) ->
  116. check_type Bool cond (*~msg:"condition should have type bool"*);
  117. node
  118. | If (cond, body, loc) ->
  119. typecheck (If (typecheck cond, typecheck body, loc))
  120. | IfElse (cond, tbody, fbody, loc) ->
  121. typecheck (IfElse (typecheck cond, typecheck tbody, typecheck fbody, loc))
  122. | While (cond, body, loc) ->
  123. typecheck (While (typecheck cond, typecheck body, loc))
  124. | DoWhile (cond, body, loc) ->
  125. typecheck (DoWhile (typecheck cond, typecheck body, loc))
  126. | _ -> transform_children typecheck node
  127. let rec phase input =
  128. prerr_endline "- Type checking";
  129. match input with
  130. | Ast (node, args) ->
  131. Ast (typecheck node, args)
  132. | _ -> raise (InvalidInput "typecheck")