module Text.XML.HaXml.DtdToHaskell.TypeDef
(
TypeDef(..)
, Constructors
, AttrFields
, StructType(..)
, ppTypeDef
, ppHName
, ppXName
, ppAName
, Name(..)
, name, name_, name_a, name_ac, name_f, mangle, manglef
) where
import Data.Char (isLower, isUpper, toLower, toUpper, isDigit)
import Data.List (intersperse)
import Text.PrettyPrint.HughesPJ
data Name = Name { xName :: String
, hName :: String
}
deriving Eq
data TypeDef =
DataDef Bool Name AttrFields Constructors
| EnumDef Name [Name]
deriving Eq
type Constructors = [(Name,[StructType])]
type AttrFields = [(Name, StructType)]
data StructType =
Maybe StructType
| Defaultable StructType String
| List StructType
| List1 StructType
| Tuple [StructType]
| OneOf [StructType]
| Any
| StringMixed
| String
| Defined Name
deriving Eq
instance Show StructType where
showsPrec p (Maybe s) = showsPrec (p+1) s . showChar '?'
showsPrec _ (Defaultable s _) = shows s
showsPrec p (List s) = showsPrec (p+1) s . showChar '*'
showsPrec p (List1 s) = showsPrec (p+1) s . showChar '+'
showsPrec _ (Tuple ss) = showChar '('
. foldr1 (.) (intersperse (showChar ',')
(map shows ss))
. showChar ')'
showsPrec _ (OneOf ss) = showChar '('
. foldr1 (.) (intersperse (showChar '|')
(map shows ss))
. showChar ')'
showsPrec _ (Any) = showString "ANY"
showsPrec _ (StringMixed) = showString "#PCDATA"
showsPrec _ (String) = showString "#PCDATA"
showsPrec _ (Defined (Name n _)) = showString n
ppTypeDef :: TypeDef -> Doc
ppTypeDef (DataDef _ n [] []) =
let nme = ppHName n in
text "data" <+> nme <+> text "=" <+> nme <+> text "\t\t" <> derives
ppTypeDef (DataDef _ n [] [c@(_,[_])]) =
text "newtype" <+> ppHName n <+> text "=" <+> ppC c <+> text "\t\t" <> derives
ppTypeDef (DataDef _ n [] cs) =
text "data" <+> ppHName n <+>
( text "=" <+> ppC (head cs) $$
vcat (map (\c-> text "|" <+> ppC c) (tail cs)) $$
derives )
ppTypeDef (DataDef _ n fs []) =
let nme = ppHName n in
text "data" <+> nme <+> text "=" <+> nme $$
nest 4 ( text "{" <+> ppF (head fs) $$
vcat (map (\f-> text "," <+> ppF f) (tail fs)) $$
text "}" <+> derives )
ppTypeDef (DataDef _ n fs cs) =
let attr = ppAName n in
text "data" <+> ppHName n <+>
( text "=" <+> ppAC attr (head cs) $$
vcat (map (\c-> text "|" <+> ppAC attr c) (tail cs)) $$
derives ) $$
text "data" <+> attr <+> text "=" <+> attr $$
nest 4 ( text "{" <+> ppF (head fs) $$
vcat (map (\f-> text "," <+> ppF f) (tail fs)) $$
text "}" <+> derives )
ppTypeDef (EnumDef n es) =
text "data" <+> ppHName n <+>
( text "=" <+>
fsep (intersperse (text " | ") (map ppHName es))
$$ derives )
ppST :: StructType -> Doc
ppST (Defaultable st _) = parens (text "Defaultable" <+> ppST st)
ppST (Maybe st) = parens (text "Maybe" <+> ppST st)
ppST (List st) = text "[" <> ppST st <> text "]"
ppST (List1 st) = parens (text "List1" <+> ppST st)
ppST (Tuple sts) = parens (commaList (map ppST sts))
ppST (OneOf sts) = parens (text "OneOf" <> text (show (length sts)) <+>
hsep (map ppST sts))
ppST StringMixed= text "String"
ppST String = text "String"
ppST Any = text "ANYContent"
ppST (Defined n) = ppHName n
ppC :: (Name,[StructType]) -> Doc
ppC (n,sts) = ppHName n <+> fsep (map ppST sts)
ppF :: (Name,StructType) -> Doc
ppF (n,st) = ppHName n <+> text "::" <+> ppST st
ppAC :: Doc -> (Name,[StructType]) -> Doc
ppAC atype (n,sts) = ppHName n <+> fsep (atype: map ppST sts)
ppHName :: Name -> Doc
ppHName (Name _ s) = text s
ppXName :: Name -> Doc
ppXName (Name s _) = text s
ppAName :: Name -> Doc
ppAName (Name _ s) = text s <> text "_Attrs"
derives :: Doc
derives = text "deriving" <+> parens (commaList (map text ["Eq","Show"]))
name :: String -> Name
name n = Name { xName = n
, hName = mangle n }
name_ :: String -> Name
name_ n = Name { xName = n
, hName = mangle n ++ "_" }
name_a :: String -> String -> Name
name_a e n = Name { xName = n
, hName = mangle e ++ "_" ++ map decolonify n }
name_ac :: String -> String -> String -> Name
name_ac e t n = Name { xName = n
, hName = mangle e ++ "_" ++ map decolonify t
++ "_" ++ map decolonify n }
name_f :: String -> String -> Name
name_f e n = Name { xName = n
, hName = manglef e ++ mangle n }
mangle :: String -> String
mangle (n:ns)
| isLower n = notPrelude (toUpper n: map decolonify ns)
| isDigit n = 'I': n: map decolonify ns
| otherwise = notPrelude (n: map decolonify ns)
notPrelude :: String -> String
notPrelude "Bool" = "ABool"
notPrelude "Bounded" = "ABounded"
notPrelude "Char" = "AChar"
notPrelude "Double" = "ADouble"
notPrelude "Either" = "AEither"
notPrelude "Enum" = "AEnum"
notPrelude "Eq" = "AEq"
notPrelude "FilePath"= "AFilePath"
notPrelude "Float" = "AFloat"
notPrelude "Floating"= "AFloating"
notPrelude "Fractional"= "AFractional"
notPrelude "Functor" = "AFunctor"
notPrelude "IO" = "AIO"
notPrelude "IOError" = "AIOError"
notPrelude "Int" = "AInt"
notPrelude "Integer" = "AInteger"
notPrelude "Integral"= "AIntegral"
notPrelude "List1" = "AList1"
notPrelude "Maybe" = "AMaybe"
notPrelude "Monad" = "AMonad"
notPrelude "Num" = "ANum"
notPrelude "Ord" = "AOrd"
notPrelude "Ordering"= "AOrdering"
notPrelude "Rational"= "ARational"
notPrelude "Read" = "ARead"
notPrelude "ReadS" = "AReadS"
notPrelude "Real" = "AReal"
notPrelude "RealFloat" = "ARealFloat"
notPrelude "RealFrac"= "ARealFrac"
notPrelude "Show" = "AShow"
notPrelude "ShowS" = "AShowS"
notPrelude "String" = "AString"
notPrelude n = n
manglef :: String -> String
manglef (n:ns)
| isUpper n = toLower n: map decolonify ns
| isDigit n = '_': n: map decolonify ns
| otherwise = n: map decolonify ns
decolonify :: Char -> Char
decolonify ':' = '\''
decolonify '-' = '_'
decolonify '.' = '_'
decolonify c = c
commaList :: [Doc] -> Doc
commaList = hcat . intersperse comma