module Language.Elm.TH.Util where
import Language.Haskell.TH.Syntax
import Data.Aeson.TH
import qualified SourceSyntax.Module as M
import qualified SourceSyntax.Declaration as D
import qualified SourceSyntax.Expression as E
import qualified SourceSyntax.Literal as L
import qualified SourceSyntax.Location as Lo
import qualified SourceSyntax.Pattern as P
import qualified SourceSyntax.Type as T
import Data.List (isPrefixOf)
import Language.Haskell.TH.Desugar.Sweeten
import Language.Haskell.TH.Desugar
import Control.Applicative
import Control.Monad.State (StateT)
import qualified Control.Monad.State as S
import qualified Data.Map as Map
liftNewName :: String -> SQ Name
liftNewName s = do
oldState <- S.get
let num = currentNum oldState
name <- S.lift $ newName $ s ++ "__xxfreshxx__" ++ show num
S.put $ oldState {currentNum = num + 1}
return name
doEmitWarning :: String -> SQ [a]
doEmitWarning s = S.lift $ emitWarning s
type SQ a = StateT TranslationState Q a
data TranslationState = TranslationState {
records :: Map.Map String [String],
currentNum :: Int
}
defaultState = TranslationState (Map.fromList []) 1
unImplemented s = error $ "Translation of the The following haskell feature is not yet implemented: " ++ s
emitWarning :: String -> Q [a]
emitWarning s = do
runIO $ putStrLn $ "Warning! Ignoring feature in Haskell source: " ++ s
return []
makeFunction :: [P.Pattern] -> E.LExpr -> E.LExpr
makeFunction args body@(Lo.L s _) =
foldr (\arg body' -> Lo.L s $ E.Lambda arg body') body args
tyVarToName :: TyVarBndr -> Name
tyVarToName (PlainTV n) = n
tyVarToName (KindedTV n _ ) = n
nameToString :: Name -> String
nameToString name =
case nameModule name of
Nothing -> nameBase name
Just base -> if "GHC." `isPrefixOf` base
then nameBase name
else showName name
splitList :: [a] -> ([a], [a])
splitList = foldr (\a ~(x,y) -> (a:y,x)) ([],[])
splitListN :: Int -> [a] -> [[a]]
splitListN 0 l = []
splitListN 1 l = [l]
splitListN 2 l = let (l1, l2) = splitList l
in [l1, l2]
splitListN n l
| even n = let (l1, l2) = splitList l
in (splitListN (quot n 2) l1) ++ (splitListN (quot n 2) l2)
| otherwise = let (l1, l2) = splitList l
in [l1] ++ (splitListN (n1) l2)
int = [t| Int |]
string = [t| String |]
float = [t| Float |]
bool = [t| Bool |]
isIntType t = do
tint <- int
return (t == tint)
isStringType t = do
tstr <- string
return (t == tstr)
isFloatType t = do
tfloat <- float
return (t == tfloat)
isBoolType t = do
tbool <- bool
return (t == tbool)
isTupleType (AppT (TupleT _arity) _) = True
isTupleType (AppT t1 t2) = isTupleType t1
isTupleType _ = False
isMaybeType (AppT (ConT name) _) = (nameToString name) == "Maybe"
isMaybeType _ = False
isMapType (AppT (AppT (ConT name) _) _) = (nameToString name) `elem` ["Map", "Data.Map.Map", "Map.Map"]
isMapType _ = False
tupleTypeToList (AppT (TupleT _arity) t) = [t]
tupleTypeToList (AppT t1 t2) = tupleTypeToList t1 ++ [t2]
recordWithFields :: Map.Map String [String] -> [String] -> String
recordWithFields recMap fields =
case ctors of
[] -> unImplemented $ "Records from other modules\n" ++ (show recMap) ++ "\n" ++ (show fields)
[(ctor, _)] -> ctor
_ -> unImplemented "Records sharing field names"
where
recList = Map.toList recMap
hasFields (_, fieldsInRecord) = not $ null (filter (`elem` fields) fieldsInRecord)
ctors = filter hasFields recList
subTypes :: Type -> [Type]
subTypes (ForallT _ _ t) = [t]
subTypes (VarT _) = []
subTypes (ConT _) = []
subTypes (TupleT _) = []
subTypes ArrowT = []
subTypes ListT = []
subTypes (AppT t1 t2) = [t1, t2]
subTypes (SigT t _) = [t]
subTypes _ = []