{-# LANGUAGE CPP #-}
module Text.XML.HaXml.DtdToHaskell.Instance
( mkInstance
) where
#if MIN_VERSION_base(4,11,0)
import Prelude hiding ((<>))
#endif
import Data.List (intersperse)
import Text.XML.HaXml.DtdToHaskell.TypeDef
import Text.PrettyPrint.HughesPJ
mkInstance :: TypeDef -> Doc
mkInstance (DataDef _ n fs []) =
let (_, frattr, topat, toattr) = attrpats fs
frretval = if null fs then ppHName n else frattr
topatval = if null fs then ppHName n else topat
in
text "instance HTypeable" <+> ppHName n <+> text "where" $$
nest 4 ( text "toHType x = Defined \"" <> ppXName n <> text "\" [] []" )
$$
text "instance XmlContent" <+> ppHName n <+> text "where" $$
nest 4 (
text "toContents" <+> topatval <+> text "=" $$
nest 4 (text "[CElem (Elem (N \"" <> ppXName n <> text "\")"
<+> toattr <+> text "[]) ()]")
$$
text "parseContents = do" $$
nest 4 (text "{ (Elem _ as []) <- element [\""
<> ppXName n <> text "\"]" $$
text "; return" <+> frretval $$
text "} `adjustErr` (\"in <" <> ppXName n
<> text ">, \"++)"
)
)
$$
mkInstanceAttrs Same n fs
mkInstance (DataDef False n fs [(n0,sts)]) =
let vs = nameSupply sts
(frpat, frattr, topat, toattr) = attrpats fs
in
text "instance HTypeable" <+> ppHName n <+> text "where" $$
nest 4 ( text "toHType x = Defined \"" <> ppXName n <> text "\" [] []" )
$$
text "instance XmlContent" <+> ppHName n <+> text "where" $$
nest 4 (
text "toContents" <+> parens (mkCpat n0 topat vs) <+> text "=" $$
nest 4 (text "[CElem (Elem (N \"" <> ppXName n <> text "\")"
<+> toattr <+> parens (mkToElem sts vs)
<> text ") ()]")
$$
text "parseContents = do" $$
nest 4 (text "{ e@(Elem _"<+> frpat <+> text "_) <- element [\""
<> ppXName n <> text "\"]"
$$ text "; interior e $"
<+> (mkParseConstr frattr (n0,sts))
$$ text "} `adjustErr` (\"in <" <> ppXName n
<> text ">, \"++)")
)
$$
mkInstanceAttrs Extended n fs
mkInstance (DataDef True n [] [(n0,sts)]) =
let vs = nameSupply sts
in
text "instance HTypeable" <+> ppHName n <+> text "where" $$
nest 4 ( text "toHType x = Defined \"" <> ppXName n <> text "\" [] []" )
$$
text "instance XmlContent" <+> ppHName n <+> text "where" $$
nest 4 ( text "toContents" <+> parens (mkCpat n0 empty vs)
<+> text "="
$$ nest 4 (parens (mkToElem sts vs))
$$
text "parseContents =" <+> mkParseConstr empty (n0,sts)
)
mkInstance (DataDef False n fs cs) =
let _ = nameSupply cs
(frpat, frattr, topat, toattr) = attrpats fs
_ = if null fs then False else True
in
text "instance HTypeable" <+> ppHName n <+> text "where" $$
nest 4 ( text "toHType x = Defined \"" <> ppXName n <> text "\" [] []" )
$$
text "instance XmlContent" <+> ppHName n <+> text "where" $$
nest 4 ( vcat (map (mkToMult n topat toattr) cs)
$$ text "parseContents = do "
$$ nest 4 (text "{ e@(Elem _"<+> frpat <+> text "_) <- element [\""
<> ppXName n <> text "\"]"
$$ text "; interior e $ oneOf"
$$ nest 4 ( text "[" <+> mkParseConstr frattr (head cs)
$$ vcat (map (\c-> text "," <+> mkParseConstr frattr c)
(tail cs))
$$ text "] `adjustErr` (\"in <" <> ppXName n
<> text ">, \"++)"
)
$$ text "}"
)
)
$$
mkInstanceAttrs Extended n fs
mkInstance (DataDef True n fs cs) =
let _ = nameSupply cs
(_, frattr, _, _) = attrpats fs
mixattrs = if null fs then False else True
in
text "instance HTypeable" <+> ppHName n <+> text "where" $$
nest 4 ( text "toHType x = Defined \"" <> ppXName n <> text "\" [] []" )
$$
text "instance XmlContent" <+> ppHName n <+> text "where" $$
nest 4 ( vcat (map (mkToAux mixattrs) cs)
$$ text "parseContents = oneOf"
$$ nest 4 ( text "[" <+> mkParseConstr frattr (head cs)
$$ vcat (map (\c-> text "," <+> mkParseConstr frattr c)
(tail cs))
$$ text "] `adjustErr` (\"in <" <> ppXName n
<> text ">, \"++)"
)
)
$$
mkInstanceAttrs Extended n fs
mkInstance (EnumDef n es) =
text "instance XmlAttrType" <+> ppHName n <+> text "where" $$
nest 4 ( text "fromAttrToTyp n (N n',v)" $$
nest 4 (text "| n==n' = translate (attr2str v)" $$
text "| otherwise = Nothing") $$
nest 2 (text "where" <+> mkTranslate es)
$$
vcat (map mkToAttr es)
)
data SameName = Same | Extended
mkInstanceAttrs :: SameName -> Name -> AttrFields -> Doc
mkInstanceAttrs _ _ [] = empty
mkInstanceAttrs s n fs =
let ppName = case s of { Same-> ppHName; Extended-> ppAName; }
in
text "instance XmlAttributes" <+> ppName n <+> text "where" $$
nest 4 ( text "fromAttrs as =" $$
nest 4 ( ppName n $$
nest 2 (vcat ((text "{" <+> mkFrFld n (head fs)):
map (\x-> comma <+> mkFrFld n x) (tail fs)) $$
text "}"))
$$
text "toAttrs v = catMaybes " $$
nest 4 (vcat ((text "[" <+> mkToFld (head fs)):
map (\x-> comma <+> mkToFld x) (tail fs)) $$
text "]")
)
attrpats :: AttrFields -> (Doc,Doc,Doc,Doc)
attrpats fs =
if null fs then (text "[]", empty, empty, text "[]")
else (text "as", parens (text "fromAttrs as"), text "as", parens (text "toAttrs as"))
mkParseConstr :: Doc -> (Name, [StructType]) -> Doc
mkParseConstr frattr (c,sts) =
fsep (text "return" <+> parens (ppHName c <+> frattr)
: map mkParseContents sts)
mkParseContents :: StructType -> Doc
mkParseContents st =
let ap = text "`apply`" in
case st of
(Maybe String) -> ap <+> text "optional text"
(Maybe _) -> ap <+> text "optional parseContents"
(List String) -> ap <+> text "many text"
(List _) -> ap <+> text "many parseContents"
(List1 _) -> ap <+> text "parseContents"
(Tuple _) -> ap <+> text "parseContents"
(OneOf _) -> ap <+> text "parseContents"
(StringMixed) -> ap <+> text "text"
(String) -> ap <+> text "(text `onFail` return \"\")"
(Any) -> ap <+> text "parseContents"
(Defined _) -> ap <+> text "parseContents"
(Defaultable _ _) -> ap <+> text "nyi_fromElem_Defaultable"
mkToElem :: [StructType] -> [Doc] -> Doc
mkToElem [] [] = text "[]"
mkToElem sts vs =
fsep (intersperse (text "++") (zipWith toElem sts vs))
where
toElem st v =
case st of
(Maybe String) -> text "maybe [] toText" <+> v
(Maybe _) -> text "maybe [] toContents" <+> v
(List String) -> text "concatMap toText" <+> v
(List _) -> text "concatMap toContents" <+> v
(List1 _) -> text "toContents" <+> v
(Tuple _) -> text "toContents" <+> v
(OneOf _) -> text "toContents" <+> v
(StringMixed) -> text "toText" <+> v
(String) -> text "toText" <+> v
(Any) -> text "toContents" <+> v
(Defined _) -> text "toContents" <+> v
(Defaultable _ _) -> text "nyi_toElem_Defaultable" <+> v
mkCpat :: Name -> Doc -> [Doc] -> Doc
mkCpat n i vs = ppHName n <+> i <+> fsep vs
nameSupply :: [b] -> [Doc]
nameSupply ss = take (length ss) (map char ['a'..'z']
++ map text [ a:n:[] | n <- ['0'..'9']
, a <- ['a'..'z'] ])
mkTranslate :: [Name] -> Doc
mkTranslate es =
vcat (map trans es) $$
text "translate _ = Nothing"
where
trans n = text "translate \"" <> ppXName n <> text "\" =" <+>
text "Just" <+> ppHName n
mkToAttr :: Name -> Doc
mkToAttr n = text "toAttrFrTyp n" <+> ppHName n <+> text "=" <+>
text "Just (N n, str2attr" <+> doubleQuotes (ppXName n) <> text ")"
mkFrFld :: Name -> (Name,StructType) -> Doc
mkFrFld tag (n,st) =
ppHName n <+> text "=" <+>
( case st of
(Defaultable String s) -> text "defaultA fromAttrToStr" <+>
doubleQuotes (text s)
(Defaultable _ s) -> text "defaultA fromAttrToTyp" <+> text s
(Maybe String) -> text "possibleA fromAttrToStr"
(Maybe _) -> text "possibleA fromAttrToTyp"
String -> text "definiteA fromAttrToStr" <+>
doubleQuotes (ppXName tag)
_ -> text "definiteA fromAttrToTyp" <+>
doubleQuotes (ppXName tag)
) <+> doubleQuotes (ppXName n) <+> text "as"
mkToFld :: (Name,StructType) -> Doc
mkToFld (n,st) =
( case st of
(Defaultable String _) -> text "defaultToAttr toAttrFrStr"
(Defaultable _ _) -> text "defaultToAttr toAttrFrTyp"
(Maybe String) -> text "maybeToAttr toAttrFrStr"
(Maybe _) -> text "maybeToAttr toAttrFrTyp"
String -> text "toAttrFrStr"
_ -> text "toAttrFrTyp"
) <+> doubleQuotes (ppXName n) <+> parens (ppHName n <+> text "v")
mkToAux :: Bool -> (Name,[StructType]) -> Doc
mkToAux mixattrs (n,sts) =
let vs = nameSupply sts
attrs = if mixattrs then text "as" else empty
in
text "toContents" <+> parens (mkCpat n attrs vs) <+> text "=" <+>
mkToElem sts vs
mkToMult :: Name -> Doc -> Doc -> (Name,[StructType]) -> Doc
mkToMult tag attrpat attrexp (n,sts) =
let vs = nameSupply sts
in
text "toContents" <+> parens (mkCpat n attrpat vs) <+> text "="
$$ nest 4 (text "[CElem (Elem (N \"" <> ppXName tag <> text "\")"<+> attrexp
<+> parens (mkToElem sts vs) <+> text ") ()]")