1 -----------------------------------------------------------------------------
3 -- Module : Data.Generics.Text
4 -- Copyright : (c) The University of Glasgow, CWI 2001--2003
5 -- License : BSD-style (see the file libraries/base/LICENSE)
7 -- Maintainer : libraries@haskell.org
8 -- Stability : experimental
9 -- Portability : non-portable
11 -- \"Scrap your boilerplate\" --- Generic programming in Haskell
12 -- See <http://www.cs.vu.nl/boilerplate/>. The present module provides
13 -- generic operations for text serialisation of terms.
15 -----------------------------------------------------------------------------
17 module Data.Generics.Text (
24 ------------------------------------------------------------------------------
31 import Data.Generics.Basics
32 import Data.Generics.Aliases
33 import Text.ParserCombinators.ReadP
35 ------------------------------------------------------------------------------
38 -- | Generic show: an alternative to \"deriving Show\"
39 gshow :: Data a => a -> String
41 -- This is a prefix-show using surrounding "(" and ")",
42 -- where we recurse into subterms with gmapQ.
46 ++ showConstr (toConstr t)
47 ++ concat (gmapQ ((++) " " . gshow) t)
49 ) `extQ` (show :: String -> String)
53 -- | Generic read: an alternative to \"deriving Read\"
54 gread :: Data a => ReadS a
58 This is a read operation which insists on prefix notation. (The
59 Haskell 98 read deals with infix operators subject to associativity
60 and precedence as well.) We use fromConstrM to "parse" the input. To be
61 precise, fromConstrM is used for all types except String. The
62 type-specific case for String uses basic String read.
66 gread = readP_to_S gread'
70 -- Helper for recursive read
71 gread' :: Data a' => ReadP a'
72 gread' = allButString `extR` stringCase
76 -- A specific case for strings
77 stringCase :: ReadP String
78 stringCase = readS_to_P reads
80 -- Determine result type
81 myDataType = dataTypeOf (getArg allButString)
83 getArg :: ReadP a'' -> a''
86 -- The generic default for gread
90 skipSpaces -- Discard leading space
92 skipSpaces -- Discard following space
95 str <- parseConstr -- Get a lexeme for the constructor
96 con <- str2con str -- Convert it to a Constr (may fail)
97 x <- fromConstrM gread' con -- Read the children
100 skipSpaces -- Discard leading space
101 char ')' -- Parse ')'
102 skipSpaces -- Discard following space
106 -- Turn string into constructor driven by the requested result type,
107 -- failing in the monad if it isn't a constructor of this data type
108 str2con :: String -> ReadP Constr
109 str2con = maybe mzero return
110 . readConstr myDataType
112 -- Get a Constr's string at the front of an input string
113 parseConstr :: ReadP String
115 string "[]" -- Compound lexeme "[]"
116 <++ infixOp -- Infix operator in parantheses
117 <++ readS_to_P lex -- Ordinary constructors and literals
119 -- Handle infix operators such as (:)
120 infixOp :: ReadP String
121 infixOp = do c1 <- char '('
122 str <- munch1 (not . (==) ')')
124 return $ [c1] ++ str ++ [c2]