% $Id: ILxml.lhs,v 1.0 2001/06/19 12:19:18 rafa Exp $ % % $Log: ILxml.lhs,v $ % % Revision 1.1 2001/06/19 12:19:18 rafa % Pretty printer in XML for the intermediate language added. % % % Modified by Martin Engelke (men@informatik.uni-kiel.de) % \nwfilename{ILxml.lhs} \section{A pretty printer in XML for the intermediate language} This module implements just another pretty printer, this time in XML and for the intermediate language. It was mainly adapted from the Curry pretty printer (see sect.~\ref{sec:CurryPP}), which in turn is based on Simon Marlow's pretty printer for Haskell. The format of the output intends to be similar to that of Flat-Curry XML representation. \begin{verbatim} > module IL.XML(module IL.XML) where > import Text.PrettyPrint.HughesPJ > import Data.Maybe > import Curry.Base.Ident > import qualified Curry.Syntax as CS > import IL.Type > import CurryEnv > -- identation level > level::Int > level = 3 > xmlModule :: CurryEnv -> Module -> Doc > xmlModule cEnv m = text "" $$ nest level (xmlBody cEnv m) > $$ text "" > xmlBody :: CurryEnv -> Module -> Doc > xmlBody cEnv (Module name imports decls) = > xmlElement "module" xmlModuleDecl moduleDecl $$ > xmlElement "import" xmlImportDecl importDecl $$ > xmlElement "types" xmlTypeDecl typeDecl $$ > xmlElement "functions" xmlFunctionDecl functionDecl $$ > xmlElement "operators" xmlOperatorDecl operatorDecl $$ > xmlElement "translation" xmlTranslationDecl translationDecl > where > moduleDecl = [name] > importDecl = imports > operatorDecl = infixDecls cEnv > translationDecl = foldl (qualIDeclId (moduleId cEnv)) > [] > (interface cEnv) > (functionDecl,typeDecl) = splitDecls decls > -- ========================================================================= > xmlModuleDecl :: ModuleIdent -> Doc > xmlModuleDecl name = xmlModuleIdent name > -- ========================================================================= > xmlImportDecl :: ModuleIdent -> Doc > xmlImportDecl name = xmlElement "module" xmlModuleDecl [name] > -- ========================================================================= > -- T Y P E S > -- ========================================================================= > xmlTypeDecl :: Decl -> Doc > xmlTypeDecl (DataDecl tc arity cs) = > beginType $$ > nest level (xmlTypeParams arity) $$ > xmlLines xmlConstructor cs $$ > endType > where > beginType = text " (xmlQualIdent tc) <> text "\">" > endType = text "" > xmlTypeParams :: Int -> Doc > xmlTypeParams n = xmlElement "params" xmlTypeVar [0..(n-1)] > xmlConstructor :: ConstrDecl [Type] -> Doc > xmlConstructor (ConstrDecl ident []) = xmlConstructorBegin ident 0 > xmlConstructor (ConstrDecl ident l) = > xmlConstructorBegin ident (length l) $$ > xmlLines xmlType l $$ > xmlConstructorEnd > where > xmlConstructorEnd = text "" > xmlConstructorBegin :: QualIdent -> Int -> Doc > xmlConstructorBegin ident n = xmlHeadingWithArity "cons" ident n (n==0) > xmlHeadingWithArity :: String -> QualIdent -> Int -> Bool -> Doc > xmlHeadingWithArity tagName ident n single = > if single > then prefix<>text "/>" > else prefix<> text ">" > where > prefix = text ("<"++tagName++" name=\"") <> name <> text "\" " <> arity > arity = text "arity=\"" <> xmlInt n <> text "\"" > name = xmlQualIdent ident > xmlType :: Type -> Doc > xmlType (TypeConstructor ident []) = xmlTypeConsBegin ident True > xmlType (TypeConstructor ident l) = xmlTypeConsBegin ident False $$ > xmlLines xmlType l $$ > xmlTypeConsEnd > where > xmlTypeConsEnd = text "" > xmlType (TypeVariable n) = xmlTypeVar n > xmlType (TypeArrow a b) = xmlTypeFun a b > xmlTypeConsBegin :: QualIdent -> Bool -> Doc > xmlTypeConsBegin ident single = > if single > then prefix <> text "/>" > else prefix <> text ">" > where > name = xmlQualIdent ident > prefix = text " name <> text "\"" > xmlTypeVar :: Int -> Doc > xmlTypeVar n = text ""<> xmlInt n <> text "" > xmlTypeFun :: Type -> Type -> Doc > xmlTypeFun a b = xmlElement "functype" xmlType [a,b] > -- ========================================================================= > -- F U N C T I O N S > -- ========================================================================= > xmlFunctionDecl :: Decl -> Doc > xmlFunctionDecl (NewtypeDecl tc arity (ConstrDecl ident ty)) = > xmlFunctionDecl (FunctionDecl ident [arg] ftype (Variable arg)) > where > arg = mkIdent "_1" > ftype = TypeArrow ty (TypeConstructor tc (map TypeVariable [0..arity-1])) > xmlFunctionDecl (FunctionDecl ident largs fType expr) = > heading $$ nest level (xmlRule largs expr) $$ end > where > heading = xmlBeginFunction ident (length largs) fType > end = text "" > xmlFunctionDecl (ExternalDecl ident callConv internalName fType) = > heading $$ external $$ end > where > heading = xmlBeginFunction ident (xmlFunctionArity fType) fType > external = text ("" > ++ xmlFormat internalName > ++ "") > end = text "" > xmlBeginFunction :: QualIdent -> Int -> Type -> Doc > xmlBeginFunction ident n fType = > heading $$ typeDecls > where > heading = xmlHeadingWithArity "func" ident n False > typeDecls = nest level (xmlType fType) > xmlEndFunction :: Doc > xmlEndFunction = text "" > xmlFunctionArity :: Type -> Int > xmlFunctionArity (TypeConstructor ident l) = 0 > xmlFunctionArity (TypeVariable n) = 0 > xmlFunctionArity (TypeArrow a b) = 1 + (xmlFunctionArity b) > xmlRule :: [Ident] -> Expression -> Doc > xmlRule lArgs e = text "" $$ > nest level (xmlLhs lArgs) $$ > nest level (xmlRhs lArgs e) $$ > text "" > xmlLhs :: [Ident] -> Doc > xmlLhs l = xmlElement "lhs" xmlVar [0..((length l)-1)] > xmlRhs :: [Ident] -> Expression -> Doc > xmlRhs l e = text "" $$ nest level rhs $$ text "" > where > varDicc = xmlBuildDicc l > (rhs, _) = xmlExpr varDicc e > -- ========================================================================= > -- ========================================================================= > -- E X P R E S S I O N S > -- ========================================================================= > xmlExpr :: [(Int,Ident)] -> Expression -> (Doc,[(Int,Ident)]) > xmlExpr d (Literal lit) = (xmlLiteral (xmlLit lit),d) > xmlExpr d (Variable ident) = xmlExprVar d ident > xmlExpr d (Function ident arity) = (xmlSingleApp ident arity True,d) > xmlExpr d (Constructor ident arity) = (xmlSingleApp ident arity False,d) > xmlExpr d exp@(Apply e1 e2) = xmlApply d exp (xmlAppArgs exp) > xmlExpr d (Case _ eval expr alt) = xmlCase d eval expr alt > xmlExpr d (Or expr1 expr2) = xmlOr d expr1 expr2 > xmlExpr d (Exist ident expr) = xmlFree d ident expr > xmlExpr d (Let binding expr) = xmlLet d binding expr > xmlExpr d (Letrec lBinding expr) = xmlLetrec d lBinding expr > --error "Recursive let bindings not supported in FlatCurry" > -- ========================================================================= > xmlSingleApp :: QualIdent -> Int -> Bool -> Doc > xmlSingleApp ident arity isFunction = > if arity>0 > then xmlCombHeading identDoc (text "PartCall") True > else xmlCombHeading identDoc (text totalApp) True > where > identDoc = xmlQualIdent ident > totalApp = if isFunction then "FuncCall" else "ConsCall" > xmlCombHeading :: Doc -> Doc -> Bool -> Doc > xmlCombHeading name cType single = > if single > then prefix <> text " />" > else prefix <> text ">" > where > prefix = text "cType<>text "\" name=\""<>name<>text "\"" > -- ========================================================================= > xmlExprVar :: [(Int,Ident)] -> Ident -> (Doc,[(Int,Ident)]) > xmlExprVar d ident = > if isNew > then (xmlVar newVar, (newVar,ident):d) > else (xmlVar var, d) > where > var = xmlLookUp ident d > isNew = var == -1 > newVar = xmlNewVar d > -- ========================================================================= > xmlApply :: [(Int,Ident)] -> Expression -> (Expression,[Expression]) -> > (Doc,[(Int,Ident)]) > xmlApply d exp ((Function ident arity),lExp) = > xmlApplyFunctor d ident arity lExp True > xmlApply d exp ((Constructor ident arity),lExp) = > xmlApplyFunctor d ident arity lExp False > xmlApply d (Apply expr1 expr2) e' = > (text "" $$ nest level e1 $$ nest level e2 $$ text "", d2) > where > (e1,d1) = xmlExpr d expr1 > (e2,d2) = xmlExpr d1 expr2 > xmlApplyFunctor ::[(Int,Ident)] -> QualIdent -> Int -> [Expression] -> > Bool -> (Doc,[(Int,Ident)]) > xmlApplyFunctor d ident arity lArgs isFunction = > xmlCombApply d (xmlQualIdent ident) (text cTypeS) n lArgs > where > n = length (lArgs) > cTypeS = if n==arity > then if isFunction > then "FuncCall" > else "ConsCall" > else "PartCall" > xmlCombApply :: [(Int,Ident)] -> Doc -> Doc -> Int -> > [Expression] -> (Doc,[(Int,Ident)]) > xmlCombApply d name cType 0 lArgs = > (xmlCombHeading name cType True,d) > xmlCombApply d name cType n lArgs = > (xmlCombHeading name cType False $$ xmlLines id lDocs$$ text "", d1) > where > (lDocs,d1) = xmlMapDicc d xmlExpr lArgs > xmlAppArgs :: Expression -> (Expression,[Expression]) > xmlAppArgs (Apply e1 e2) = (e,lArgs++[e2]) > where > (e,lArgs) = (xmlAppArgs e1) > xmlAppArgs e = (e,[]) > -- ========================================================================= > -- ========================================================================= > xmlCase :: [(Int,Ident)] -> Eval -> Expression -> [Alt] -> (Doc,[(Int,Ident)]) > xmlCase d eval expr lAlt = > (heading $$ nest level e1 $$ xmlLines id lDocs$$ end,d2) > where > sEval = if eval==Rigid then "\"Rigid\"" else "\"Flex\"" > heading = text "" > end = text "" > (e1,_) = xmlExpr d expr > (lDocs,d2) = xmlMapDicc d xmlBranch lAlt > xmlOr :: [(Int,Ident)] -> Expression -> Expression -> (Doc,[(Int,Ident)]) > xmlOr d expr1 expr2 = > (text "" $$ nest level e1 $$ nest level e2 $$ text "",d2) > where > (e1,d1) = xmlExpr d expr1 > (e2,d2) = xmlExpr d1 expr2 > xmlBranch :: [(Int,Ident)] -> Alt -> (Doc,[(Int,Ident)]) > xmlBranch d (Alt pattern expr) = > (text "" $$ nest level e1 $$ nest level e2 $$ text "",d2) > where > (e1,d1) = xmlPattern d pattern > (e2,d2) = xmlExpr d1 expr > xmlPattern :: [(Int,Ident)] -> ConstrTerm -> (Doc,[(Int,Ident)]) > xmlPattern d (LiteralPattern lit) = (xmlLitPattern (xmlLit lit),d) > xmlPattern d (ConstructorPattern ident lArgs) = xmlConsPattern d ident lArgs > xmlPattern d (VariablePattern _) = error "Variable patterns not allowed in Flat Curry" > xmlConsPattern :: [(Int,Ident)] -> QualIdent -> [Ident] -> (Doc,[(Int,Ident)]) > xmlConsPattern d ident lArgs = > (heading $$ xmlLines id lDocs $$ end,d2) > where > heading = text " (xmlQualIdent ident) <> > text "\"" <> endh > endh = if (length lArgs)>0 then text ">" else text "/>" > end = if (length lArgs)>0 then text "" else empty > (lDocs,d2) = xmlMapDicc d xmlExprVar lArgs > -- ========================================================================= > xmlFree :: [(Int,Ident)] -> Ident -> Expression -> (Doc,[(Int,Ident)]) > xmlFree d ident exp = > (text "" $$ nest level v $$ nest level e $$ text "",d2) > where > (v,d1) = xmlExprVar d ident > (e,d2) = xmlExpr d1 exp > -- ========================================================================= > xmlLet :: [(Int,Ident)] -> Binding -> Expression -> (Doc,[(Int,Ident)]) > xmlLet d binding exp = > (text "" $$ nest level b $$ nest level e $$ text "", d2) > where > (b,d1) = xmlBinding d binding > (e,d2) = xmlExpr d1 exp > xmlBinding :: [(Int,Ident)] -> Binding -> (Doc,[(Int,Ident)]) > xmlBinding d (Binding ident exp) = > (text "" $$ nest level v $$ nest level e $$ text "",d2) > where > (v,_) = xmlExprVar d ident > (e,d2) = xmlExpr d exp > -- ========================================================================= > xmlLetrec :: [(Int,Ident)] -> [Binding] -> Expression -> (Doc,[(Int,Ident)]) > xmlLetrec d lB exp = > (text "" $$ xmlLines id b $$ nest level e $$ text "",d2) > where > (b,d1) = xmlMapDicc d xmlBinding lB > (e,d2) = xmlExpr d1 exp > -- ========================================================================= > -- ========================================================================= > -- A U X I L I A R Y F U N C T I O N S > -- ========================================================================= > splitDecls :: [Decl] -> ([Decl],[Decl]) > splitDecls [] = ([],[]) > splitDecls (x:xs) = case x of > DataDecl _ _ _ -> (functionDecl,x:typeDecl) > NewtypeDecl _ _ _ -> (x:functionDecl,typeDecl) > FunctionDecl _ _ _ _ -> (x:functionDecl,typeDecl) > ExternalDecl _ _ _ _ -> (x:functionDecl,typeDecl) > where > (functionDecl,typeDecl) = splitDecls xs > xmlElement :: Eq a => String -> (a -> Doc) -> [a] -> Doc > xmlElement name f [] = text ("<"++name++" />") > xmlElement name f lDecls = beginElement $$ xmlLines f lDecls $$ endElement > where > beginElement = text ("<"++name++">") > endElement = text ("") > > xmlLines :: (a -> Doc) -> [a] -> Doc > xmlLines f = (nest level).vcat.(map f) > xmlMapDicc::[(Int,Ident)] -> ([(Int,Ident)] -> a -> (Doc,[(Int,Ident)])) -> > [a] -> ([Doc],[(Int,Ident)]) > xmlMapDicc d f lArgs = foldl newArg ([],d) lArgs > where > newArg (l,d) e = (l++[v'],d') > where (v',d') = f d e > > -- The dictionary identifies var names with integers > -- it will be ordered starting at the greatest integer > xmlBuildDicc :: [Ident] -> [(Int,Ident)] > xmlBuildDicc l = reverse (zip [0..((length l)-1)] l) > -- looks for a ident in the dictorionary. If it appears returns its > -- associated value. Otherwise, -1 is returned > xmlLookUp :: Ident -> [(Int,Ident)] -> Int > xmlLookUp ident [] = -1 > xmlLookUp ident ((n,name):xs) = if ident==name > then n > else xmlLookUp ident xs > -- generates a integer corresponding to a new var > xmlNewVar :: [(Int,Ident)] -> Int > xmlNewVar [] = 0 > xmlNewVar ((n,ident):xs) = n+1 > xmlVar :: Int -> Doc > xmlVar n = text "" <> xmlInt n <> text "" > xmlLiteral :: Doc -> Doc > xmlLiteral d = text "" $$ nest level d $$ text "" > xmlLitPattern :: Doc -> Doc > xmlLitPattern d = text "" $$ nest level d $$ text "" > xmlLit :: Literal -> Doc > xmlLit (Char _ c) = text "" <> xmlInt (fromEnum c) <> text "" > xmlLit (Int _ n) = text "" <> xmlInteger n <> text "" > xmlLit (Float _ n) = text "" <> xmlFloat n <> text "" > xmlOperatorDecl :: CS.IDecl -> Doc > xmlOperatorDecl (CS.IInfixDecl _ fixity prec qident) = > text " xmlFixity fixity > <> text "\" prec=\"" <> xmlInteger prec <> text "\">" > <> xmlIdent (unqualify qident) > <> text "" > xmlFixity :: CS.Infix -> Doc > xmlFixity CS.InfixL = text "InfixlOp" > xmlFixity CS.InfixR = text "InfixrOp" > xmlFixity CS.Infix = text "InfixOp" > xmlTranslationDecl :: QualIdent -> Doc > xmlTranslationDecl expId = > text "" > $$ nest level ( text "" <> xmlIdent (unqualify expId) <> text "" > $$ text "" <> xmlQualIdent expId <> text "") > $$ text "" > xmlIdent :: Ident -> Doc > xmlIdent ident = text (xmlFormat (name ident)) > xmlInt :: Int -> Doc > xmlInt n = text (show n) > xmlInteger :: Integer -> Doc > xmlInteger n = text (show n) > xmlFloat :: Double -> Doc > xmlFloat n = text (show n) > xmlQualIdent :: QualIdent -> Doc > xmlQualIdent ident = text (xmlFormat (qualName ident)) > xmlModuleIdent:: ModuleIdent -> Doc > xmlModuleIdent name = text (xmlFormat (moduleName name)) > xmlFormat :: String -> String > xmlFormat [] = [] > xmlFormat ('>':xs) = ">"++xmlFormat xs > xmlFormat ('<':xs) = "<"++xmlFormat xs > xmlFormat ('&':xs) = "&"++xmlFormat xs > xmlFormat (x:xs) = x:(xmlFormat xs) > -- ========================================================================= > qualIDeclId :: ModuleIdent -> [QualIdent] -> CS.IDecl -> [QualIdent] > qualIDeclId mid qids (CS.IDataDecl _ qid _ mcdecls) > = foldl (qualConstrDeclId mid) (qid:qids) (catMaybes mcdecls) > qualIDeclId mid qids (CS.INewtypeDecl _ qid _ ncdecl) > = qualNewConstrDeclId mid (qid:qids) ncdecl > qualIDeclId mid qids (CS.ITypeDecl _ qid _ _) > = qid:qids > qualIDeclId mid qids (CS.IFunctionDecl _ qid _ _) > = qid:qids > qualIDeclId mid qids _ = qids > qualConstrDeclId :: ModuleIdent -> [QualIdent] -> CS.ConstrDecl > -> [QualIdent] > qualConstrDeclId mid qids (CS.ConstrDecl _ _ id _) > = (qualifyWith mid id):qids > qualConstrDeclId mid qids (CS.ConOpDecl _ _ _ id _) > = (qualifyWith mid id):qids > qualNewConstrDeclId :: ModuleIdent -> [QualIdent] -> CS.NewConstrDecl > -> [QualIdent] > qualNewConstrDeclId mid qids (CS.NewConstrDecl _ _ id _) > = (qualifyWith mid id):qids \end{verbatim}