let check_int expty ~pos : unit =
check_same {exp=(); ty=Type.Int} expty ~pos
+ (* TODO: actual_ty *)
+
let rec transExp ~env exp =
let rec trexp exp =
(match exp with
return_int
| A.StringExp {string=_; _} ->
return_string
- | A.CallExp {func=_; args=_; pos=_} ->
- unimplemented ()
+ | A.CallExp {func; args; pos} ->
+ (match env_get_val ~sym:func ~env ~pos with
+ | Value.Fun {formals; result} ->
+ List.iter2 formals args ~f:(fun ty_expected exp_given ->
+ check_same {exp=(); ty = ty_expected} (trexp exp_given) ~pos;
+ );
+ return result
+ | Value.Var _ ->
+ E.raise (E.Id_not_a_function {id=func; pos})
+ )
| A.OpExp {oper; left; right; pos} ->
trop oper ~left ~right ~pos
- | A.RecordExp {fields=_; typ=_; pos=_} ->
- unimplemented ()
+ | A.RecordExp {fields=field_exps; typ; pos} ->
+ let ty = env_get_typ ~sym:typ ~env ~pos in
+ Type.if_record
+ ty
+ ~f:(fun field_tys ->
+ List.iter field_exps ~f:(fun (field, exp, pos) ->
+ (match List.assoc_opt field field_tys with
+ | Some field_ty ->
+ check_same {exp=(); ty=field_ty} (trexp exp) ~pos
+ | None ->
+ E.raise
+ (E.No_such_field_in_record {field; record=ty; pos})
+ )
+ )
+ )
+ ~otherwise:(fun () ->
+ E.raise (E.Wrong_type_used_as_record {ty_id=typ; ty; pos})
+ );
+ return ty
| A.SeqExp exps ->
(* Ignoring value because we only care if a type-checking exception
* is raised in one of trexp calls: *)
)
)
~otherwise:(fun () -> E.raise (E.Exp_not_a_record {ty; pos}))
- | A.SubscriptVar {var=_; exp=_; pos=_} ->
- unimplemented ()
+ | A.SubscriptVar {var; exp; pos} ->
+ let {exp=_; ty} = trvar var in
+ check_int (trexp exp) ~pos;
+ Type.if_array
+ ty
+ ~f:(fun ty_elements -> return ty_elements)
+ ~otherwise:(fun () -> E.raise (E.Exp_not_an_array {ty; pos}))
)
and trop oper ~left ~right ~pos =
let expty_left = trexp left in