+ and transDec ~env dec =
+ (match dec with
+ | A.VarDec {name; typ=typ_opt; init; pos=pos_outter; escape=_} ->
+ let ty =
+ (match (typ_opt, transExp ~env init) with
+ | None, {ty; exp=()} ->
+ ty
+ | Some (sym, pos_inner), expty_init ->
+ let ty = env_get_typ ~sym ~env ~pos:pos_inner in
+ check_same {exp=(); ty} expty_init ~pos:pos_outter;
+ ty
+ )
+ in
+ Env.set_val env name (Value.Var {ty})
+ | A.TypeDecs typedecs ->
+ List.fold_left typedecs ~init:env ~f:(
+ fun env (A.TypeDec {name; ty; pos=_}) ->
+ let ty = transTy ~env ty in
+ Env.set_typ env name ty
+ )
+ | A.FunDecs fundecs ->
+ List.fold_left fundecs ~init:env ~f:(
+ fun env (A.FunDec {name; params; result; body; pos=_}) ->
+ let (env_for_body, formals_in_reverse_order) =
+ List.fold_left params ~init:(env, []) ~f:(
+ fun (env, formals) (A.Field {name; escape=_; typ; pos}) ->
+ let ty = env_get_typ ~env ~sym:typ ~pos in
+ let env = Env.set_val env name (Value.Var {ty}) in
+ (env, ty :: formals)
+ )
+ in
+ (* ignore because we only care if an exception is raised *)
+ ignore (transExp ~env:env_for_body body);
+ let formals = List.rev formals_in_reverse_order in
+ let result =
+ match result with
+ | None ->
+ Type.Unit
+ | Some (sym, pos) ->
+ env_get_typ ~sym ~env ~pos
+ in
+ Env.set_val env name (Value.Fun {formals; result})
+ )
+ )
+ and transTy ~env typ =
+ (match typ with
+ | A.NameTy {symbol=sym; pos} ->
+ env_get_typ ~sym ~env ~pos
+ | A.RecordTy fields ->
+ let fields =
+ List.map fields ~f:(fun (A.Field {name; escape=_; typ; pos}) ->
+ let ty = env_get_typ ~sym:typ ~env ~pos in
+ (name, ty)
+ )
+ in
+ Type.new_record fields
+ | A.ArrayTy {symbol=sym; pos} ->
+ let element_ty = env_get_typ ~sym ~env ~pos in
+ Type.new_array element_ty
+ )