- let new_ty = do
- -- Use the Maybe Monad for failing when one of these fails
- (tycon, args) <- Type.splitTyConApp_maybe ty
- let name = Name.getOccString (TyCon.tyConName tycon)
- case name of
- "TFVec" -> Just $ mk_vector_ty (tfvec_len ty) ty
- "SizedWord" -> Just $ mk_vector_ty (sized_word_len ty) ty
- "RangedWord" -> Just $ mk_natural_ty 0 (ranged_word_bound ty) ty
- otherwise -> Nothing
- -- Return new_ty when a new type was successfully created
- Maybe.fromMaybe
- (error $ "Unsupported Haskell type: " ++ (showSDoc $ ppr ty))
- new_ty
+ newty_maybe <- (construct_vhdl_ty ty)
+ case newty_maybe of
+ Just (ty_id, ty_def) -> do
+ -- TODO: Check name uniqueness
+ modA vsTypes (Map.insert (OrdType ty) (ty_id, ty_def))
+ return ty_id
+ Nothing -> error $ "Unsupported Haskell type: " ++ (showSDoc $ ppr ty)
+
+-- Construct a new VHDL type for the given Haskell type.
+construct_vhdl_ty :: Type.Type -> VHDLState (Maybe (AST.TypeMark, Either AST.TypeDef AST.SubtypeIn))
+construct_vhdl_ty ty = do
+ case Type.splitTyConApp_maybe ty of
+ Just (tycon, args) -> do
+ let name = Name.getOccString (TyCon.tyConName tycon)
+ case name of
+ "TFVec" -> do
+ res <- mk_vector_ty (tfvec_len ty) ty
+ return $ Just $ (Arrow.second Left) res
+ "SizedWord" -> do
+ res <- mk_vector_ty (sized_word_len ty) ty
+ return $ Just $ (Arrow.second Left) res
+ "RangedWord" -> do
+ res <- mk_natural_ty 0 (ranged_word_bound ty) ty
+ return $ Just $ (Arrow.second Right) res
+ -- Create a custom type from this tycon
+ otherwise -> mk_tycon_ty tycon args
+ Nothing -> return $ Nothing
+
+-- | Create VHDL type for a custom tycon
+mk_tycon_ty :: TyCon.TyCon -> [Type.Type] -> VHDLState (Maybe (AST.TypeMark, Either AST.TypeDef AST.SubtypeIn))
+mk_tycon_ty tycon args =
+ case TyCon.tyConDataCons tycon of
+ -- Not an algebraic type
+ [] -> error $ "Only custom algebraic types are supported: " ++ (showSDoc $ ppr tycon)
+ [dc] -> do
+ let arg_tys = DataCon.dataConRepArgTys dc
+ -- TODO: CoreSubst docs say each Subs can be applied only once. Is this a
+ -- violation? Or does it only mean not to apply it again to the same
+ -- subject?
+ let real_arg_tys = map (CoreSubst.substTy subst) arg_tys
+ elem_tys <- mapM vhdl_ty real_arg_tys
+ let elems = zipWith AST.ElementDec recordlabels elem_tys
+ -- For a single construct datatype, build a record with one field for
+ -- each argument.
+ -- TODO: Add argument type ids to this, to ensure uniqueness
+ -- TODO: Special handling for tuples?
+ let ty_id = mkVHDLExtId $ nameToString (TyCon.tyConName tycon)
+ let ty_def = AST.TDR $ AST.RecordTypeDef elems
+ return $ Just (ty_id, Left ty_def)
+ dcs -> error $ "Only single constructor datatypes supported: " ++ (showSDoc $ ppr tycon)
+ where
+ -- Create a subst that instantiates all types passed to the tycon
+ -- TODO: I'm not 100% sure that this is the right way to do this. It seems
+ -- to work so far, though..
+ tyvars = TyCon.tyConTyVars tycon
+ subst = CoreSubst.extendTvSubstList CoreSubst.emptySubst (zip tyvars args)