packages feed

INblobs-0.1.1: src/DocumentFile.hs

module DocumentFile where


import Document as Doc
import Palette
import Shape
import Ports
import INRule
import InfoKind
import NetworkFile

import Text.XML.HaXml.Types
import Text.XML.HaXml.Posn (noPos)
import Text.XML.HaXml.Parse
import Text.XML.HaXml.XmlContent as XML
import Text.PrettyPrint.HughesPJ
import qualified Text.XML.HaXml.Pretty as Pretty


-- | Print the document data structure to an XML text
toString :: (InfoKind n g, InfoKind e g, XmlContent g) =>
            Doc.Document g n e -> String
toString doc = render . Pretty.document $
    Document (Prolog Nothing [] Nothing []) emptyST (f (toContents doc)) []
  where
    f [CElem e _] = e
    f _ = error "bad"	-- shouldn't happen

-- | Parses a string to the document data structure
--   Returns either an error message (Left) or the document,
--   a list of warnings (Right) and a boolean indicating whether
--   the file was an old INBlobs file
fromString :: (InfoKind n g, InfoKind e g, XmlContent g) =>
              String -> Either String (Doc.Document g n e, [String], Bool)
fromString xml =
    case xmlParse' "input file" xml of
        Left err -> Left err -- lexical or initial (generic) parse error
        Right (Document _ _ e _) ->
            case runParser parseContents [CElem e noPos] of
                (Left err, _) -> Left err  -- secondary (typeful) parse error
                (Right v, _)  -> Right (v,[],False)



instance HTypeable (Doc.Document g n e) where
    toHType _ = Defined "Document" [] [Constr "Document" [] []]
instance (InfoKind n g, InfoKind e g, XmlContent g) =>
         XmlContent (Doc.Document g n e) where
    toContents document = 
        [CElem (Elem "Document" []
                   $  (toContents $ getNetwork document)
                   ++ (toContents $ getPalette document)
                   ++ [ makeTag "Rules" (concatMap toContents
                                                      $ getRules document)
                   ]) () ]
    parseContents = do
        { inElement "Document" $ do
              { net <- parseContents
              ; pal <- parseContents
              ; rus <- inElement "Rules"   $ many1 parseContents
              ; return ( setRules   rus
                       . setPalette pal
                       . setNetwork net
                       $ Doc.empty undefined undefined undefined)
              }
        }

instance HTypeable a => HTypeable (Palette a) where
    toHType p = Defined "Palette" [toHType a] [Constr "Palette" [] []]
              where (Palette ((_,(_,_,Just a)):_)) = p
instance XmlContent a => XmlContent (Palette a) where
    toContents (Palette shapes) =
        [ mkElemC "Palette" (map aux shapes) ]
     where
	-- aux :: (ShapeName,(Shape,Ports,Maybe a)) -> Content ()
	aux (name,(shape,pPort:ports, info)) =
	  CElem (Elem "Symbol" []
		[ escapeString "ShapeName" name
		, makeTag "Shape"	$ toContents shape
		, makeTag "Ports"
			[ makeTag "Principals" [auxPort pPort]
			, makeTag "Auxiliaries" $ map auxPort ports]
		, makeTag "Info"	$ toContents info
		]) ()
	auxPort :: Port -> Content ()
	auxPort = makeTag "Port" . toContents
    parseContents = do
        { inElement "Palette" $ fmap Palette (many1 parseSymbol) }

parseSymbol :: (XmlContent a) => XMLParser (ShapeName,(Shape,Ports,Maybe a))
parseSymbol = do
    { inElement "Symbol" $ do
              { name  		<- inElement "ShapeName" $ XML.text
              ; shape 		<- inElement "Shape"     $ parseContents
              ; ([pP],aPs) 	<- inElement "Ports"     $ parsePorts
              ; info  		<- inElement "Info"      $ parseContents
              ; return (name,(shape,pP:aPs,info)) } }

parsePorts :: XMLParser (Ports,Ports)
parsePorts =
     do
	pPorts <- inElement "Principals" $ many1 parsePort -- principal ports
	aPorts <- inElement "Auxiliaries" $ many parsePort -- auxiliary ports
	return (pPorts, aPorts)

parsePort :: XMLParser Port
parsePort = inElement "Port" $ parseContents

instance HTypeable (INRule g n e) where
    toHType _ = Defined "INRule" [] [Constr "INRule" [] []]
instance (InfoKind n g, InfoKind e g, XmlContent g) =>
         XmlContent (INRule g n e) where
    toContents rule = 
        [CElem (Elem "INRule" []
                   [ escapeString  "Name"    (getName rule)
                   , makeTag       "LHS"     (toContents $ getLHS rule)
                   , makeTag       "RHS"     (toContents $ getRHS rule)
                   , makeTag       "Mapping" (map toContentsMappingElement
                                                        $ getMapping rule)
                   ]) () ]
      where
	toContentsMappingElement :: MappingElement -> Content ()
	toContentsMappingElement (nNr1,nNr2) =
		CElem (Elem "MappingElement"
			[ mkAttr "lhs" (show nNr1)
			, mkAttr "rhs" (show nNr2)
			] []) ()
    parseContents = do
        { inElement "INRule" $ do
              { nam <- inElement "Name"    $ XML.text
              ; lhs <- inElement "LHS"     $ parseContents
              ; rhs <- inElement "RHS"     $ parseContents
              ; maa <- inElement "Mapping" $ many parseMappingElement
              ; return ( INRule.construct nam lhs rhs maa)
              }
        }

parseMappingElement :: XMLParser MappingElement
parseMappingElement = do
	      { (p, e@(Elem _ [("lhs",nNr1),("rhs",nNr2)] [])) <- posnElement ["MappingElement"]
	      ; nNr1' <- attr2value nNr1
	      ; nNr2' <- attr2value nNr2
              ; return (nNr1', nNr2')
              }