github
Advanced Search
  • Home
  • Pricing and Signup
  • Explore GitHub
  • Blog
  • Login

spl / splonderzoek

  • Admin
  • Watch Unwatch
  • Fork
  • Your Fork
  • Pull Request
  • Download Source
    • 2
    • 0
  • Source
  • Commits
  • Network (0)
  • Graphs
  • Tree: 1d1f93b

click here to add a description

click here to add a homepage

  • Branches (1)
    • master
  • Tags (0)
Sending Request…
Enable Donations

Pledgie Donations

Once activated, we'll place the following badge in your repository's detail box:
Pledgie_example
This service is courtesy of Pledgie.

Code for blog entries — Read more

  cancel

http://splonderzoek.blogspot.com/

  cancel
  • Private
  • Read-Only
  • HTTP Read-Only

This URL has Read+Write access

Import Format library files. 
Sean Leather (author)
Fri Jun 19 04:24:32 -0700 2009
commit  1d1f93b25756ee6dee167bc5ee58a467cdfea06b
tree    f5781739919d00305d8eec61272175cbb2266f18
parent  4ce40d281cf0a1e7ab2455fd85db701eff174fc2
splonderzoek / Format.hs Format.hs
100644 169 lines (133 sloc) 5.473 kb
edit raw blame history
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
 
-- A library for printing formats to strings, reminiscent of the C sprintf
-- function. This library uses Template Haskell to ensure the arguments are
-- statically well-typed. Derived from work by Oleg Kiselyov.
 
module Format (sprintf, sprintff, fmt, fmtq) where
 
--------------------------------------------------------------------------------
 
import Prelude hiding ((^))
import qualified Prelude (Show, show)
 
import Language.Haskell.TH
import Language.Haskell.TH.Quote
 
import Generics.EMGM (Rep)
import qualified Generics.EMGM as EMGM (Show, show)
 
import Data.Data (Data)
import Data.Generics.Text (gshow)
 
import Data.Ratio (Ratio)
 
--------------------------------------------------------------------------------
 
-- A language of format descriptors
data Fmt
  = Literal String
  | EMGMFmt
  | SYBFmt
  | StringFmt
  | ShowFmt
  | NumFmt
  | RealFmt
  | IntFmt
  | IntegerFmt
  | FloatFmt
  | DoubleFmt
  | RatioFmt
  | CharFmt
  deriving (Eq, Show)
 
-- Parse a character code to get a format descriptor
fmtOf :: Char -> Maybe Fmt
fmtOf c =
  case c of
    'e' -> Just EMGMFmt
    'y' -> Just SYBFmt
    's' -> Just StringFmt
    'S' -> Just ShowFmt
    'N' -> Just NumFmt
    'R' -> Just RealFmt
    'i' -> Just IntFmt
    'n' -> Just IntegerFmt
    'f' -> Just FloatFmt
    'd' -> Just DoubleFmt
    'r' -> Just RatioFmt
    'c' -> Just CharFmt
    _ -> Nothing
 
--------------------------------------------------------------------------------
 
-- Interpret a literal or a format descriptor into generated code.
expOf :: Fmt -> ExpQ
expOf (Literal s) = [| literal s |]
expOf EMGMFmt = [| emgmFmt |]
expOf SYBFmt = [| sybFmt |]
expOf StringFmt = [| stringFmt |]
expOf ShowFmt = [| showFmt |]
expOf NumFmt = [| showFmt :: Num a => Formatter a w |]
expOf RealFmt = [| showFmt :: Real a => Formatter a w |]
expOf IntFmt = [| showFmt :: Formatter Int w |]
expOf IntegerFmt = [| showFmt :: Formatter Integer w |]
expOf FloatFmt = [| showFmt :: Formatter Float w |]
expOf DoubleFmt = [| showFmt :: Formatter Double w |]
expOf RatioFmt = [| showFmt :: Integral a => Formatter (Ratio a) w |]
expOf CharFmt = [| showFmt :: Formatter Char w |]
 
literal :: String -> (String -> w) -> w
literal str k = k str
 
type Formatter a w = (String -> w) -> (a -> w)
 
stringFmt :: Formatter String w
stringFmt k x = k x
 
printFmt :: (a -> String) -> (String -> w) -> a -> w
printFmt f k x = k (f x)
 
emgmFmt :: (Rep EMGM.Show a) => Formatter a w
emgmFmt = printFmt EMGM.show
 
sybFmt :: (Data a) => Formatter a w
sybFmt = printFmt gshow
 
showFmt :: (Prelude.Show a) => Formatter a w
showFmt = printFmt Prelude.show
 
-- Composition of formatters
infixr 8 ^
(^) :: ((String -> w1) -> w1') -> ((String -> w2) -> w1) -> ((String -> w2) -> w1')
f1 ^ f2 = \k -> f1 (\s1 -> f2 (\s2 -> k (s1 ++ s2)))
 
-- Interpret a list of format descriptors to generate code.
interpret :: [Fmt] -> ExpQ
interpret [f] = expOf f
interpret (f:fs) = [| $(expOf f) ^ $(interpret fs)|]
 
-- Parse the string into a list of literal strings and format descriptors.
parse :: String -> [Fmt]
parse input = result
  where
    (first,last) = break (=='%') input
    next =
      case last of
        "" -> []
        '%':'%':rest -> Literal "%" : parse rest
        '%':c:rest ->
          case fmtOf c of
            Nothing -> error $ showString "Bad format: %" . showChar c $ ""
            Just f -> f : parse rest
    result = if null first then next else Literal first : next
 
--------------------------------------------------------------------------------
 
-- Exported functions
 
-- For use inside the spicing, e.g. @$(fmt "Hi!")@ generates @lit "Hi!@. Only
-- really useful if combined with 'sprintf'.
fmt :: String -> ExpQ
fmt = interpret . parse
 
-- For use as a quasi-quoter, e.g. @[$fmtq|Hi!|]@ generates @lit "Hi!@. Only
-- really useful if combined with 'sprintf'.
fmtq :: QuasiQuoter
fmtq = QuasiQuoter fmt (const $ error "A fmt cannot be used in a pattern.")
 
-- Print a formatted string with a variable number of arguments to a string. The
-- first argument is a Template Haskell spliced value using either 'fmt' or
-- 'fmtq'.
sprintf :: ((String -> String) -> a) -> a
sprintf f = f id
 
-- Same as 'sprintf' but used inside the splice with an extra parameter. Thus:
-- @$(sprintff "Hi!")@. Warning: The errors reported for this function may be
-- less comprehensible than those for 'sprintf'.
sprintff :: String -> ExpQ
sprintff s = [| $(fmt s) id |]
 
--------------------------------------------------------------------------------
 
-- Testing
 
showCode cde = runQ cde >>= putStrLn . pprint
 
tc1 = showCode (fmt "abc")
tc2 = showCode (fmt "Hello %e!")
 
test_lexFmt = and
  [ parse "Simple lit" == [Literal "Simple lit"]
  , parse "%s insert" == [StringFmt, Literal " insert"]
  , parse "insert %s here" == [Literal "insert ", StringFmt, Literal " here"]
  , parse "The value of %s is %i" == [Literal "The value of ", StringFmt, Literal " is ", IntFmt]
  , parse "A %e prints generically!" == [Literal "A ", EMGMFmt, Literal " prints generically!"]
  ]
 
 
Blog | Support | Training | Contact | API | Status | Twitter | Help | Security
© 2010 GitHub Inc. All rights reserved. | Terms of Service | Privacy Policy
Powered by the Dedicated Servers and
Cloud Computing of Rackspace Hosting®
Dedicated Server