{-# LANGUAGE TemplateHaskell, TypeOperators #-}
module ForSyDe.Deep.Backend.VHDL.Translate where
import ForSyDe.Deep.Backend.VHDL.AST
import qualified ForSyDe.Deep.Backend.VHDL.AST as VHDL
import ForSyDe.Deep.Backend.VHDL.Constants
import ForSyDe.Deep.Backend.VHDL.Generate
import ForSyDe.Deep.Backend.VHDL.Traverse.VHDLM
import ForSyDe.Deep.Backend.VHDL.Translate.HigherOrderFunctions
import ForSyDe.Deep.Ids
import ForSyDe.Deep.AbsentExt
import ForSyDe.Deep.Signal
import ForSyDe.Deep.Bit hiding (not)
import ForSyDe.Deep.ForSyDeErr
import ForSyDe.Deep.System.SysDef
import ForSyDe.Deep.Process.ProcFun
import ForSyDe.Deep.Process.ProcVal
import ForSyDe.Deep.Process.ProcType
import Data.Data (tyconUQname)
import Data.Int
import Data.Char (digitToInt)
import Data.List (intersperse)
import Data.Maybe (isJust, fromJust)
import Control.Monad.State
import qualified Data.Set as S
import qualified Language.Haskell.TH as TH
import Language.Haskell.TH hiding (global,Loc)
import qualified Data.Traversable as DT
import Data.Typeable
import Data.Typeable.Internal
import qualified Data.Param.FSVec as V
import Text.Regex.Posix ((=~))
import Data.TypeLevel.Num.Reps
import Data.Typeable.FSDTypeRepLib
debug :: a -> String -> a
debug a _ = a
transSysDef2Ent :: SysLogic
-> SysDefVal
-> VHDLM EntityDec
transSysDef2Ent logic sysDefVal = do
entId <- transSysId2VHDL (sid sysDefVal)
inDecs <- mapM (uncurry $ transPort2IfaceSigDec In) (iIface sysDefVal)
outDecs <- mapM (uncurry $ transPort2IfaceSigDec Out) (oIface sysDefVal)
let implicitDecs = if logic == Sequential then
[IfaceSigDec resetId In std_logicTM,
IfaceSigDec clockId In std_logicTM]
else []
return $ EntityDec entId (implicitDecs ++ inDecs ++ outDecs)
transZipWithN2Block :: Label
-> [VHDLId]
-> Loc
-> TypedProcFunAST
-> VHDLId
-> VHDLM (BlockSm, SigDec)
transZipWithN2Block vPid ins loc ast out = do
(f,fName , inFPars, inFTypes, retFType) <-
withProcFunC ((name.tpast) ast) loc $ transProcFun2VHDL ast
let inPars = map (\n -> unsafeIdAppend vPid ("_in" ++ show n)) [1..length ins]
outPar = unsafeIdAppend vPid "_out"
inDecs = zipWith (\par typ -> IfaceSigDec par In typ) inPars inFTypes
outDec = IfaceSigDec outPar Out retFType
iface = inDecs ++ [outDec]
pMap = genPMap (inPars ++ [outPar]) (ins ++ [out])
outAssign = genFCallAssign out fName inFPars ins
return (BlockSm vPid iface pMap [BDISPB f] [CSSASm outAssign],
SigDec out retFType Nothing)
transZipWithx2Block :: Label
-> [VHDLId]
-> Loc
-> TypedProcFunAST
-> VHDLId
-> VHDLM (BlockSm, SigDec)
transZipWithx2Block vPid ins loc ast out = do
(f, fName, [inFPar], [inFType], retFType) <-
withProcFunC ((name.tpast) ast) loc $ transProcFun2VHDL ast
let [[_,suffix]] = (fromVHDLId inFType) =~ "^fsvec_[0-9]*_(.*)$"
inType = unsafeVHDLBasicId $ suffix
inPars = map (\n -> unsafeIdAppend vPid ("_in" ++ show n)) [1..length ins]
outPar = unsafeIdAppend vPid "_out"
inDecs = map (\par -> IfaceSigDec par In inType) inPars
outDec = IfaceSigDec outPar Out retFType
iface = inDecs ++ [outDec]
pMap = genPMap (inPars ++ [outPar]) (ins ++ [out])
aggregate = Aggregate $
map (\e -> ElemAssoc Nothing (PrimName(NSimple e))) inPars
fCall = PrimFCall $ FCall (NSimple fName)
[Just inFPar :=>: ADExpr aggregate]
outAssign = genExprAssign outPar fCall
return (BlockSm vPid iface pMap [BDISPB f] [CSSASm outAssign],
SigDec out retFType Nothing)
transUnzipNSY2Block :: Label
-> VHDLId
-> [VHDLId]
-> [FSDTypeRep]
-> VHDLM (BlockSm, [SigDec])
transUnzipNSY2Block vPid inSig outSigs outTRTypes = do
let inPar = unsafeIdAppend vPid "_in"
outPars = map (\n -> unsafeIdAppend vPid ("_out" ++ show n))
[1..length outSigs]
nOuts = length outSigs
inTRType = (fsdTupleTyCon nOuts) `fsdTyConApp` outTRTypes
outTMTypes <- mapM transTR2TM outTRTypes
inTMType <- transTR2TM inTRType
let inDec = IfaceSigDec inPar In inTMType
outDecs = zipWith (\par typ -> IfaceSigDec par Out typ) outPars outTMTypes
iface = inDec : outDecs
pMap = genPMap (inPar : outPars) (inSig : outSigs)
genOrigExp n = (PrimName $ NSelected
(NSimple inPar :.: tupVHDLSuffix n))
genOutAssign outSig n = CSSASm $ genExprAssign outSig (genOrigExp n)
outAssigns = zipWith genOutAssign outPars [(1::Int)..]
return (BlockSm vPid iface pMap [] outAssigns,
zipWith (\sig typ -> SigDec sig typ Nothing) outSigs outTMTypes)
transUnzipxSY2Block :: Label
-> VHDLId
-> [VHDLId]
-> FSDTypeRep
-> Int
-> VHDLM (BlockSm, [SigDec])
transUnzipxSY2Block vPid inSig outSigs elemTR vSize = do
let inPar = unsafeIdAppend vPid "_in"
outPars = map (\n -> unsafeIdAppend vPid ("_out" ++ show n))
[1..length outSigs]
inTRType = fSVecTyCon `fsdTyConApp` [transInt2TLNat vSize, elemTR]
inTMType <- transTR2TM inTRType
elemTM <- transTR2TM elemTR
let inDec = IfaceSigDec inPar In inTMType
outDecs = map (\par -> IfaceSigDec par Out elemTM) outPars
iface = inDec : outDecs
pMap = genPMap (inPar : outPars) (inSig : outSigs)
genOrigExp n =
PrimName $ NIndexed (NSimple inPar `IndexedName` [PrimLit $ show n])
genOutAssign outSig n = CSSASm $ genExprAssign outSig (genOrigExp n)
outAssigns = zipWith genOutAssign outPars [(0::Int)..]
return (BlockSm vPid iface pMap [] outAssigns,
map (\sig -> SigDec sig elemTM Nothing) outSigs)
transDelay2Block :: Label
-> VHDLId
-> ProcValAST
-> VHDLId
-> VHDLM (BlockSm, SigDec)
transDelay2Block vPid inS (ProcValAST exp tr enums) outS = do
addEnumTypes enums
initTR <- transTR2TM tr
initExp <- withProcValC exp $ withInitFunTransST $ (transExp2VHDL exp)
let formalIn = unsafeIdAppend vPid "_in"
formalOut = unsafeIdAppend vPid "_out"
iface = [IfaceSigDec resetId In std_logicTM,
IfaceSigDec clockId In std_logicTM,
IfaceSigDec formalIn In initTR,
IfaceSigDec formalOut Out initTR]
assocs = [Just resetId :=>: ADName (NSimple resetId),
Just clockId :=>: ADName (NSimple clockId),
Just formalIn :=>: ADName (NSimple inS),
Just formalOut :=>: ADName (NSimple outS)]
sigAssign = CSSASm (NSimple formalOut :<==:
(ConWforms [whenElseReset] inWform (Just whenRE)))
whenElseReset = WhenElse (Wform [WformElem initExp Nothing])
(PrimName (NSimple resetId) :=: PrimLit "'0'")
inWform = Wform [WformElem (PrimName $ NSimple formalIn) Nothing]
whenRE = When (PrimFCall $ FCall (NSimple $ unsafeVHDLBasicId "rising_edge")
[Nothing :=>: ADName (NSimple clockId) ])
return (BlockSm vPid iface (PMapAspect assocs) [] [sigAssign],
SigDec outS initTR Nothing)
transSysIns2CompIns :: SysLogic
-> Label
-> [VHDLId]
-> [(VHDLId, FSDTypeRep)]
-> SysId
-> [PortId]
-> [PortId]
-> VHDLM (Maybe CompInsSm, [SigDec])
transSysIns2CompIns logic vPid ins typedOuts parentId parentInIds parentOutIds = do
if length ins == 0 && length typedOuts == 0
then return (Nothing, [])
else do
decs <- mapM (\(name,typ) -> transVHDLName2SigDec name typ Nothing) typedOuts
vParentId <- transSysId2VHDL parentId
vParentInIds <- liftEProne $ mapM mkVHDLExtId parentInIds
vParentOutIds <- liftEProne $ mapM mkVHDLExtId parentOutIds
let implicitAssocIds = if logic == Sequential then [resetId, clockId] else []
assocs = genAssocElems
(implicitAssocIds ++ vParentInIds ++ vParentOutIds)
(implicitAssocIds ++ ins ++ map fst typedOuts)
entityName = NSelected (NSimple workId :.: SSimple vParentId)
instantiation = CompInsSm vPid (IUEntity entityName) (PMapAspect assocs)
return (Just instantiation, decs)
transVHDLName2SigDec :: SimpleName
-> FSDTypeRep
-> Maybe TH.Exp
-> VHDLM SigDec
transVHDLName2SigDec vId tr mExp = do
tm <- transTR2TM tr
mVExp <- DT.mapM (\e -> withInitFunTransST (transExp2VHDL e)) mExp
return $ SigDec vId tm mVExp
transVHDLId2IfaceSigDec :: Mode -> VHDLId -> FSDTypeRep -> VHDLM IfaceSigDec
transVHDLId2IfaceSigDec m vid trep = do
tm <- transTR2TM trep
return $ IfaceSigDec vid m tm
transPort2IfaceSigDec :: Mode -> PortId -> FSDTypeRep -> VHDLM IfaceSigDec
transPort2IfaceSigDec m pid trep = do
sid <- transPortId2VHDL pid
transVHDLId2IfaceSigDec m sid trep
transTHName2VHDL :: TH.Name -> VHDLM VHDLId
transTHName2VHDL = transPortId2VHDL . tyconUQname . pprint
transSysId2VHDL :: SysId -> VHDLM VHDLId
transSysId2VHDL = transPortId2VHDL
transProcId2VHDL :: ProcId -> VHDLM VHDLId
transProcId2VHDL = transPortId2VHDL
transPortId2VHDL :: PortId -> VHDLM VHDLId
transPortId2VHDL str = liftEProne $ mkVHDLExtId str
transTR2TM :: FSDTypeRep -> VHDLM TypeMark
transTR2TM rep
| isSignal = transTR2TM nestedTR `debug` (dbgStr "S")
| isJust mPrimitiveTM = return $ fromJust mPrimitiveTM `debug` (dbgStr "P")
| otherwise = customTR2TM rep `debug` (dbgStr "T")
where (isSignal, nestedTR) = let (tc,~[tr]) = fsdSplitTyConApp rep
in (tc == signalTyCon, tr)
signalTyCon = fsdTyConOf (undefined :: Signal ())
mPrimitiveTM = lookup rep primTypeTable
dbgStr k = ">>>>" ++ k ++ " " ++ (typeRepQName rep) ++ "/" ++ (show rep)
customTR2TM :: FSDTypeRep -> VHDLM TypeMark
customTR2TM rep = do
mTranslated <- lookupCustomType rep
case mTranslated of
Nothing -> do
e <- doCustomTR2TM rep
addCustomType rep e
case e of
Left (TypeDec id _) -> return id
Right (SubtypeDec id _) -> return id
Just tm -> return tm `debug` "'--> (cache hit)"
doCustomTR2TM :: FSDTypeRep -> VHDLM (Either TypeDec SubtypeDec)
doCustomTR2TM rep | isFSVec = do
valTM <- transTR2TM valueType
let vectorId = unsafeVHDLContainerId [valTM] ("fsvec_"++ fromVHDLId valTM)
vecs <- gets (transUnconsFSVecs.global)
when (not $ elem valueType vecs) `debug` (" vectors: " ++ (show vecs)) $ do
when (valueType /= (fsdTy $ typeOf (undefined :: Bit)))
((addTypeDec $ TypeDec vectorId (TDA (UnconsArrayDef [fsvec_indexTM] valTM))) `debug` "allegiedly not FSVec _ Bit")
let funs = genUnconsVectorFuns valTM vectorId
mapM_ addSubProgBody funs
addUnconsFSVec $ valueType
let subvectorId = unsafeVHDLBasicId ("fsvec_" ++ show size ++ "_" ++
fromVHDLId valTM)
return $ Right $
SubtypeDec subvectorId (SubtypeIn vectorId
(Just $ IndexConstraint [ToRange (PrimLit "0")
(PrimLit (show $ size-1))]))
where (cons, ~[sizeType,valueType]) = fsdSplitTyConApp rep
isFSVec = cons == fSVecTyCon
size = transTLNat2Int sizeType
doCustomTR2TM rep | isTuple = do
fieldTMs <- mapM transTR2TM args
let elems = zipWith (\fieldId fieldTM -> ElementDec fieldId fieldTM )
[tupVHDLIdSuffix n | n <- [1..]] fieldTMs
recordId = unsafeVHDLContainerId fieldTMs $
(tupStrSuffix $ length fieldTMs) ++ "_" ++
(concatMap fromVHDLId.intersperse (unsafeVHDLBasicId "_")) fieldTMs
funs = genTupleFuns fieldTMs recordId
mapM_ addSubProgBody funs
return $ Left $ (TypeDec recordId (TDR $ RecordTypeDef elems))
where (cons, args) = fsdSplitTyConApp rep
conStr = fsdTyConName cons
isTuple = (length conStr > 2) && (all (==',') (reverse.tail.reverse.tail $ conStr))
doCustomTR2TM rep | isAbsExt = do
valueTM <- transTR2TM valueTR
let elems = [ElementDec isPresentId booleanTM,
ElementDec valueId valueTM ]
recordId = unsafeVHDLContainerId [valueTM] $
"abs_ext_" ++ fromVHDLId valueTM
funs = genAbstExtFuns valueTM recordId
mapM_ addSubProgBody funs
return $ Left $ (TypeDec recordId (TDR $ RecordTypeDef elems))
where (cons, ~[valueTR]) = fsdSplitTyConApp rep
absExtTyCon = fsdTyConOf (undefined :: AbstExt ())
isAbsExt = cons == absExtTyCon
doCustomTR2TM rep = do
eTys <- gets (enumTypes.global)
let strRep = typeRepQName rep
let equalsRep (EnumAlgTy name _) = name == strRep
case (S.toList.(S.filter equalsRep)) eTys of
[enumDef] -> liftM Left $ enumAlg2TypeDec enumDef `debug` (">>>>? "++strRep)
_ -> throwFError $ UnsupportedType rep
enumAlg2TypeDec :: EnumAlgTy
-> VHDLM TypeDec
enumAlg2TypeDec (EnumAlgTy tn cons) = do
tMark <- liftEProne $ mkVHDLExtId tn
enumLits@(firstLit:_) <- liftEProne $ mapM mkVHDLExtId cons
let funs = genEnumAlgFuns tMark firstLit
mapM_ addSubProgBody funs
return (TypeDec tMark (TDE $ EnumTypeDef enumLits))
primTypeTable :: [(FSDTypeRep, TypeMark)]
primTypeTable = [
(fsdTypeOf (undefined :: Int32), int32TM) ,
(fsdTypeOf (undefined :: Int16), int16TM) ,
(fsdTypeOf (undefined :: Int8) , int8TM) ,
(fsdTypeOf (undefined :: Bool) , booleanTM) ,
(fsdTypeOf (undefined :: Bit) , std_logicTM)]
funErr :: VHDLFunErr -> VHDLM a
funErr err = throwFError $ UntranslatableVHDLFun err
transProcFun2VHDL :: TypedProcFunAST
-> VHDLM (SubProgBody, VHDLId, [VHDLId], [TypeMark], TypeMark)
transProcFun2VHDL (TypedProcFunAST fType fEnums fAST) = do
addEnumTypes fEnums
(fName, fInputPats, fBodyExp, whereDecs) <- checkProcFunAST fAST
(fSpec, fVHDLName, fVHDLPars, argsTM, retTM) <-
transProcFunSpec fName fType fInputPats
transDecs whereDecs
putCurrentFunctionSpec fSpec
bodySms <- transFunBodyExp2VHDL fBodyExp
decs <- gets (auxDecs.funTransST.local)
let fBody = SubProgBody fSpec decs bodySms
return (fBody, fVHDLName, fVHDLPars, argsTM, retTM)
transProcFun2VHDLBody :: TypedProcFunAST -> VHDLM SubProgBody
transProcFun2VHDLBody tpf = do
(body, _, _, _, _) <- transProcFun2VHDL tpf
return body
decs2ProcFuns :: [Dec] -> VHDLM [TypedProcFunAST]
decs2ProcFuns [] = return []
decs2ProcFuns decs = do
(dec, t, name, clauses, restDecs) <- case decs of
SigD n1 t : f@(FunD n2 cls) : xs | n1 == n2 ->
return (f, t, n1, cls, xs)
SigD n1 t : v@(ValD (VarP n2) bdy ds) : xs | n1 == n2 -> do
return (v, t, n1, [Clause [] bdy ds] , xs)
_ -> funErr $ UnsupportedDecBlock decs
t' <- maybe (funErr $ PolyDec dec) return (type2FSDTypeRep t)
let tpf = TypedProcFunAST t' S.empty (ProcFunAST name clauses [])
restTPFs <- decs2ProcFuns restDecs
return $ tpf:restTPFs
transDecs :: [Dec] -> VHDLM ()
transDecs decs = do
clearAux
tpfs <- decs2ProcFuns decs
mapM_ addDecName tpfs
bodyDecs <- mapM (liftM SPSB . transProcFun2VHDLBody) tpfs
addDecsToFunTransST bodyDecs
where addDecName :: TypedProcFunAST -> VHDLM ()
addDecName (TypedProcFunAST t _ (ProcFunAST n _ _)) = do
let arity = (length.fst.fsdUnArrowT) t
vhdlId <- transTHName2VHDL n
addTransNamePair n arity (genExprFCallN vhdlId arity)
clearAux = do
lState <- gets local
let s = funTransST lState
modify (\st -> st{local=lState{funTransST=s{auxDecs=[]}}})
checkProcFunAST :: ProcFunAST
-> VHDLM (Name, [Pat], Exp, [Dec])
checkProcFunAST (ProcFunAST thName [Clause pats (NormalB exp) decs] []) =
return (thName, pats, exp, decs)
checkProcFunAST (ProcFunAST _ _ (_:_)) =
intError "ForSyDe.Backend.VHDL.Translate.checkProcFunSpec"
(UntranslatableVHDLFun $ GeneralErr (Other "default parameters are not yet supported"))
checkProcFunAST (ProcFunAST _ [Clause _ bdy@(GuardedB _) _] _) =
funErr (FunGuardedBody bdy)
checkProcFunAST (ProcFunAST _ clauses@(_:_) _) =
funErr (MultipleClauses clauses)
checkProcFunAST (ProcFunAST _ [] _) =
intError "ForSyDe.Backend.VHDL.Translate.checkProcFunSpec"
(UntranslatableVHDLFun $ GeneralErr (Other "inconsistentency"))
transProcFunSpec :: TH.Name
-> FSDTypeRep
-> [Pat]
-> VHDLM (SubProgSpec, VHDLId, [VHDLId], [TypeMark], TypeMark)
transProcFunSpec fName fType fPats = do
let (argsTR, retTR) = fsdUnArrowT fType
expectedN = length argsTR `debug` ("expected (args): "++ (show (length argsTR)))
actualN = length fPats `debug` ("actual (patterns): "++ (show (length fPats)))
when (expectedN /= actualN) (funErr $ InsParamNum fName actualN)
fVHDLParIds <- mapM transInputPat2VHDLId fPats
fVHDLName <- transTHName2VHDL fName
argsTM <- mapM transTR2TM argsTR
retTM <- transTR2TM retTR
let iface = zipWith (\name typ -> IfaceVarDec name typ) fVHDLParIds argsTM
fSpec = Function fVHDLName iface retTM
return (fSpec, fVHDLName, fVHDLParIds, argsTM, retTM)
transInputPat2VHDLId :: TH.Pat -> VHDLM VHDLId
transInputPat2VHDLId pat = do
id <- case pat of
VarP name -> transTHName2VHDL name
AsP name _ -> transTHName2VHDL name
_ -> genFreshVHDLId
preparePatNameSpace (NSimple id) pat
return id
preparePatNameSpace :: Prefix
-> Pat
-> VHDLM ()
preparePatNameSpace prefix (VarP name) =
addTransNamePair name 0 (\[] -> PrimName prefix)
preparePatNameSpace prefix (AsP name pat) = do
addTransNamePair name 0 (\[] -> PrimName prefix)
preparePatNameSpace prefix pat
preparePatNameSpace _ WildP = return ()
preparePatNameSpace prefix (TupP pats) = do
let prepTup n pat = preparePatNameSpace
(NSelected (prefix :.: tupVHDLSuffix n)) pat
zipWithM_ prepTup [1..] pats
preparePatNameSpace prefix (ConP name ~[pat]) | isAbstExt name =
when isPrst (preparePatNameSpace (NSelected (prefix :.: valueSuffix)) pat)
where isAbstExt name = isPrst || name == 'Abst
isPrst = name == 'Prst
-- Unary Constructor patterns
-- We try an enumerated type patterns
-- otherwise we throw an unknown constructor pattern error
preparePatNameSpace _ pat@(ConP name []) = do
mId <- getEnumConsId name
case mId of
-- it is an enumerated data constructor, however, since we only admit
-- one clause per function there is nothing to do about it
Just _ -> return ()
-- it is an unknown data constructor
Nothing -> funErr $ UnsupportedFunPat pat
-- otherwise the pattern is not supported
preparePatNameSpace _ pat = funErr $ UnsupportedFunPat pat
--------------------------
-- Translating expressions
--------------------------
-- | Throw an expression error
expErr :: Exp -> VHDLExpErr -> VHDLM a
expErr exp err = throwFError $ UntranslatableVHDLExp exp err
-- | Create the unique statement of a VHDL from a TH expression.
transFunBodyExp2VHDL :: TH.Exp -> VHDLM [SeqSm]
transFunBodyExp2VHDL (CondE condE thenE elseE) =
do condVHDLE <- transExp2VHDL condE
thenVHDLSm <- transFunBodyExp2VHDL thenE
elseVHDLSm <- transFunBodyExp2VHDL elseE
return [IfSm condVHDLE thenVHDLSm [] (Just $ Else elseVHDLSm)]
transFunBodyExp2VHDL caseE@(CaseE exp matches) =
do caseVHDLE <- transExp2VHDL exp
caseSmAlts <- mapM (transMatch2VHDLCaseSmAlt caseE) matches
return [CaseSm caseVHDLE caseSmAlts]
-- A higher order function needs to be treated specially
transFunBodyExp2VHDL e@(AppE _ _)
| isHigherOrderFunction e = translateHigherOrderFunctionBody e
-- In other case it is an expression returned directly
transFunBodyExp2VHDL e =
do vHDLe <- transExp2VHDL e
return [ReturnSm $ Just vHDLe]
-- | Translate a case alternative from Haskell to VHDL
transMatch2VHDLCaseSmAlt :: TH.Exp -> TH.Match -> VHDLM CaseSmAlt
-- FIXME: the exp passed (which contains the full case expression for
-- error reporting purposes) should be part of the context once VHDLM
-- is reworked
transMatch2VHDLCaseSmAlt contextExp (Match pat (NormalB matchExp) decs) =
do transDecs decs
sm <- transFunBodyExp2VHDL matchExp
case pat of
-- FIXME: support pattern matching with tuples, AbsExt,
-- and enumerated types
WildP -> return $ CaseSmAlt [Others] sm
LitP lit -> do vHDLExp <- transExp2VHDL (LitE lit)
return $ CaseSmAlt [ChoiceE vHDLExp] sm
-- FIXME: check! this case introduces new names into scope
VarP name -> do vHDLExp <- transExp2VHDL (VarE name)
return $ CaseSmAlt [ChoiceE vHDLExp] sm
_ -> expErr contextExp $ UnsupportedCasePat pat
transMatch2VHDLCaseSmAlt contextExp (Match _ bdy@(GuardedB _) _) =
expErr contextExp $ CaseGuardedBody bdy
-- | Translate a Haskell expression to a VHDL expression
transExp2VHDL :: TH.Exp -> VHDLM VHDL.Expr
-- TypeLevel-package numerical constant aliases
transExp2VHDL (VarE name) | isTypeLevelAlias = do
let constant = nameBase name
([baseSym], val) = splitAt 1 constant
basePrefix = case baseSym of
'b' -> "2#"
'o' -> "8#"
'h' -> "16#"
'd' -> ""
_ -> error "unexpected base symbol"
return (PrimLit $ basePrefix ++ val)
where isTypeLevelAlias = (show name =~ aliasPat)
aliasPat = "^Data\\.TypeLevel\\.Num\\.Aliases\\.(b[0-1]+|o[0-7]+|d[0-9]+|h[0-9A-F]+)$"
-- A FSVec generated with Template Haskell
transExp2VHDL (VarE unsafeFSVecCoerce `AppE` _ `AppE` (ConE con `AppE` ListE exps))
| show unsafeFSVecCoerce == "Data.Param.FSVec.unsafeFSVecCoerce" &&
show con == "Data.Param.FSVec.FSVec" = do
vhdlExps <- mapM transExp2VHDL exps
return $ Aggregate (map (\e -> ElemAssoc Nothing e) vhdlExps)
-- Is it function/constructor application, a constant
-- or an unkown name.
transExp2VHDL e | isConsOrFun =
do -- get the symbol table (name translation table)
nameTable <- gets (nameTable.funTransST.local)
case lookup name nameTable of
-- found name
Just (arity, transF) ->
if arity /= numArgs
then expErr e $ CurryUnsupported arity numArgs
else do exps <- mapM transExp2VHDL args
return $ transF exps
-- Didn't find the name in the global table
Nothing -> do
-- Check if it is a user-defined enumerated data constructor
mId <- getEnumConsId name
case mId of
Just id -> return $ PrimName (NSimple id)
Nothing -> expErr e $ UnkownIdentifier name
where (f,args,numArgs) = unApp e
mName = getName f
name = fromJust mName
isConsOrFun = isJust mName
getName (VarE n) = Just n
getName (ConE n) = Just n
getName _ = Nothing
-- Literals
transExp2VHDL (LitE (IntegerL integer)) = (return.transInteger2VHDL) integer
transExp2VHDL (LitE (IntPrimL integer)) = (return.transInteger2VHDL) integer
-- Unsupported literal
transExp2VHDL lit@(LitE _) = expErr lit $ UnsupportedLiteral
-- Infix expressions
transExp2VHDL (InfixE (Just argl) f@(VarE _) (Just argr)) =
transExp2VHDL $ f `AppE` argl `AppE` argr
-- Sections (unsupported)
transExp2VHDL infixExp@(InfixE _ (VarE _) _) = expErr infixExp Section
-- Tuples: e.g. (1,2)
transExp2VHDL (TupE exps) = do
vExps <- mapM transExp2VHDL exps
return $ Aggregate $ map (\expr -> ElemAssoc Nothing expr) vExps
-- Let expressions
transExp2VHDL (LetE decs e) = do
transDecs decs
transExp2VHDL e
-- Unsupported expressions
transExp2VHDL lamE@(LamE _ _) = expErr lamE LambdaAbstraction
transExp2VHDL condE@(CondE _ _ _) = expErr condE Conditional
transExp2VHDL caseE@(CaseE _ _) = expErr caseE Case
transExp2VHDL doE@(DoE _) = expErr doE Do
transExp2VHDL compE@(CompE _) = expErr compE ListComprehension
transExp2VHDL arithSeqE@(ArithSeqE _) = expErr arithSeqE ArithSeq
transExp2VHDL listE@(ListE _) = expErr listE List
transExp2VHDL sigE@(SigE _ _) = expErr sigE Signature
transExp2VHDL reConE@(RecConE _ _) = expErr reConE Record
transExp2VHDL recUpE@(RecUpdE _ _) = expErr recUpE Record
-- The rest of expressions are not valid in practice and thus, not supported
-- (e.g. InfixE Nothing (RecConE _ _) _
transExp2VHDL exp = expErr exp Unsupported
-- | Translate an integer to VHDL
transInteger2VHDL :: Integer -> Expr
transInteger2VHDL = PrimLit . show
--------------------
-- Helper Functions
--------------------
-- Translate the TypeRep of a type-level natural (e.g: D1 :* D2) to a number
-- Make sure you don't supply an incorrect TypeRep or the function will break
transTLNat2Int :: FSDTypeRep -> Int
transTLNat2Int tr
-- Digit
-- FIXME: Could be made cleaner. It was like this before:
-- isDigit = (digitToInt.last.tyConName) cons
-- which was not able to take care of e.g. Data.TypeLevel.Num.Aliases.D10
| isDigit = (read.reverse.takeWhile (/='D').reverse.fsdTyConName) cons
-- Connective
| otherwise = 10 * (transTLNat2Int prefix) + (transTLNat2Int lastDigit)
where (cons, args@(~[prefix, lastDigit])) = fsdSplitTyConApp tr
isDigit = null args
-- Tranlate an Int to the TypeRep of a type-level natural (e.g: D1 :* D2)
transInt2TLNat :: Int -> FSDTypeRep
transInt2TLNat n
| n < 0 = intError fName (Other "negative index")
| n < 10 = digit n
| otherwise = fsdTyConApp conTyCon [transInt2TLNat suffix, digit last]
where fName = "ForSyDe.Backend.VHDL.Translate.transInt2TLNat"
(suffix, last) = n `divMod` 10
digit 0 = fsdTypeOf (undefined :: D0)
digit 1 = fsdTypeOf (undefined :: D1)
digit 2 = fsdTypeOf (undefined :: D2)
digit 3 = fsdTypeOf (undefined :: D3)
digit 4 = fsdTypeOf (undefined :: D4)
digit 5 = fsdTypeOf (undefined :: D5)
digit 6 = fsdTypeOf (undefined :: D6)
digit 7 = fsdTypeOf (undefined :: D7)
digit 8 = fsdTypeOf (undefined :: D8)
digit 9 = fsdTypeOf (undefined :: D9)
-- Just to hush the compiler warnings
digit _ = undefined
conTyCon = fsdTyConOf (undefined :: () :* ())
-- Type constructor of FSVec
fSVecTyCon :: FSDTypeCon
fSVecTyCon = fsdTyConOf (undefined :: V.FSVec () ())
-- unApply an expression and obtain the number of arguments found
unApp :: Exp -> (Exp, [Exp], Int)
unApp e = (first, rest, n)
where (first:rest, n) = unAppAc ([],0) e
unAppAc (xs,n) (f `AppE` arg) = unAppAc (arg:xs, n+1) f
unAppAc (xs,n) f = (f:xs,n)
typeRepQName :: FSDTypeRep -> String
typeRepQName rep = mod ++ dot ++ name
where tr = fsdTyRep rep
tc = typeRepTyCon tr
mod = tyConModule tc
name = tyConName tc
dot = if mod=="" then "" else "."