{- BNF Converter: Template Generator Copyright (C) 2004 Author: Markus Forsberg -} {-# LANGUAGE OverloadedStrings #-} module BNFC.Backend.Haskell.CFtoTemplate (cf2Template) where import Prelude hiding ((<>)) import BNFC.CF import BNFC.PrettyPrint import BNFC.Utils ( ModuleName ) import BNFC.Backend.Haskell.Utils ( catvars, noWarnUnusedMatches ) cf2Template :: ModuleName -> ModuleName -> Bool -> CF -> String cf2Template skelName absName functor cf = unlines $ concat [ [ "-- Haskell module generated by the BNF converter" , "" , noWarnUnusedMatches , "" , "module "++ skelName ++ " where" , "" , "import Prelude (($), Either(..), String, (++), Show, show)" ] , [ "import qualified " ++ absName | importAbsMod ] , [ "" , "type Err = Either String" , "type Result = Err String" , "" , "failure :: Show a => a -> Result" , "failure x = Left $ \"Undefined case: \" ++ show x" , "" , render . vsep $ map (uncurry (case_fun absName functor)) datas ] ] where datas = specialData cf ++ cf2data cf importAbsMod = not $ null datas -- | -- >>> case_fun "M" False (Cat "Expr") [("EInt", [TokenCat "Integer"]), ("EAdd", [Cat "Expr", Cat "Expr"])] -- transExpr :: M.Expr -> Result -- transExpr x = case x of -- M.EInt integer -> failure x -- M.EAdd expr1 expr2 -> failure x -- -- >>> case_fun "" True (Cat "Expr") [("EInt", [TokenCat "Integer"]), ("EAdd", [Cat "Expr", Cat "Expr"])] -- transExpr :: Show a => Expr' a -> Result -- transExpr x = case x of -- EInt _ integer -> failure x -- EAdd _ expr1 expr2 -> failure x -- -- TokenCat are not generated as functors: -- >>> case_fun "" True (TokenCat "MyIdent") [("MyIdent", [TokenCat "String"])] -- transMyIdent :: MyIdent -> Result -- transMyIdent x = case x of -- MyIdent string -> failure x case_fun :: ModuleName -> Bool -> Cat -> [(Fun,[Cat])] -> Doc case_fun absName functor' cat xs = vcat [ fname <+> "::" <+> iffunctor "Show a =>" <+> type_ <+> "-> Result" , fname <+> "x = case x of" , nest 2 $ vcat (map mkOne xs) ] where -- If the functor option is set AND the category is not a token type, -- then the type is a functor. iffunctor doc | functor' && not (isTokenCat cat) = doc | otherwise = empty type_ = qualify $ cat' <> iffunctor "' a" fname = "trans" <> cat' cat' = pretty cat mkOne (cons, args) = let ns = catvars [render fname] args -- names False (map (checkRes .var) args) 1 in qualify (text cons) <+> iffunctor "_" <+> hsep ns <+> "-> failure x" qualify :: Doc -> Doc qualify | null absName = id | otherwise = (text absName <> "." <>)