aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Sucan <jan@jansucan.com>2023-03-28 17:09:27 +0200
committerJan Sucan <jan@jansucan.com>2023-04-10 16:52:19 +0200
commit2c4e32dbcd6a74a93d6121212c5a44461160a38f (patch)
tree2640fd4b4218787bb7b7ac93f52b63933b4da38a
parent742195819304c1e009fa20a8c6f387f61d1975fd (diff)
ch05: Copy needed files from the examples
-rw-r--r--ch05/Prettify.hs160
-rw-r--r--ch05/PrettyJSON.hs88
-rw-r--r--ch05/SimpleJSON.hs48
3 files changed, 296 insertions, 0 deletions
diff --git a/ch05/Prettify.hs b/ch05/Prettify.hs
new file mode 100644
index 0000000..7b3ea10
--- /dev/null
+++ b/ch05/Prettify.hs
@@ -0,0 +1,160 @@
+module Prettify
+ (
+ -- * Constructors
+ Doc
+ -- * Basic combinators
+ , (<>)
+ , empty
+ , char
+ , text
+ , line
+ -- * Derived combinators
+ , double
+ , fsep
+ , hcat
+ , punctuate
+ -- * Renderers
+ , compact
+ , pretty
+ ) where
+
+{--
+import Data.Monoid (Monoid(..))
+
+instance Monoid Doc where
+ mempty = empty
+ mappend = (<>)
+--}
+
+{-- snippet Doc --}
+data Doc = Empty
+ | Char Char
+ | Text String
+ | Line
+ | Concat Doc Doc
+ | Union Doc Doc
+ deriving (Show,Eq)
+{-- /snippet Doc --}
+
+{-- snippet append --}
+(<>) :: Doc -> Doc -> Doc
+Empty <> y = y
+x <> Empty = x
+x <> y = x `Concat` y
+{-- /snippet append --}
+
+{-- snippet basic --}
+empty :: Doc
+empty = Empty
+
+char :: Char -> Doc
+char c = Char c
+
+text :: String -> Doc
+text "" = Empty
+text s = Text s
+
+double :: Double -> Doc
+double d = text (show d)
+{-- /snippet basic --}
+
+{-- snippet line --}
+line :: Doc
+line = Line
+{-- /snippet line --}
+
+{-- snippet hcat --}
+hcat :: [Doc] -> Doc
+hcat = fold (<>)
+
+fold :: (Doc -> Doc -> Doc) -> [Doc] -> Doc
+fold f = foldr f empty
+{-- /snippet hcat --}
+
+{-- snippet fsep --}
+fsep :: [Doc] -> Doc
+fsep = fold (</>)
+
+(</>) :: Doc -> Doc -> Doc
+x </> y = x <> softline <> y
+
+softline :: Doc
+softline = group line
+{-- /snippet fsep --}
+
+{-- snippet group --}
+group :: Doc -> Doc
+group x = flatten x `Union` x
+{-- /snippet group --}
+
+{-- snippet flatten --}
+flatten :: Doc -> Doc
+flatten (x `Concat` y) = flatten x `Concat` flatten y
+flatten Line = Char ' '
+flatten (x `Union` _) = flatten x
+flatten other = other
+{-- /snippet flatten --}
+
+{-- snippet punctuate --}
+punctuate :: Doc -> [Doc] -> [Doc]
+punctuate p [] = []
+punctuate p [d] = [d]
+punctuate p (d:ds) = (d <> p) : punctuate p ds
+{-- /snippet punctuate --}
+
+{-- snippet compact --}
+compact :: Doc -> String
+compact x = transform [x]
+ where transform [] = ""
+ transform (d:ds) =
+ case d of
+ Empty -> transform ds
+ Char c -> c : transform ds
+ Text s -> s ++ transform ds
+ Line -> '\n' : transform ds
+ a `Concat` b -> transform (a:b:ds)
+ _ `Union` b -> transform (b:ds)
+{-- /snippet compact --}
+
+{-- snippet pretty.type --}
+pretty :: Int -> Doc -> String
+{-- /snippet pretty.type --}
+
+{-- snippet pretty --}
+pretty width x = best 0 [x]
+ where best col (d:ds) =
+ case d of
+ Empty -> best col ds
+ Char c -> c : best (col + 1) ds
+ Text s -> s ++ best (col + length s) ds
+ Line -> '\n' : best 0 ds
+ a `Concat` b -> best col (a:b:ds)
+ a `Union` b -> nicest col (best col (a:ds))
+ (best col (b:ds))
+ best _ _ = ""
+
+ nicest col a b | (width - least) `fits` a = a
+ | otherwise = b
+ where least = min width col
+{-- /snippet pretty --}
+
+{-- snippet fits --}
+fits :: Int -> String -> Bool
+w `fits` _ | w < 0 = False
+w `fits` "" = True
+w `fits` ('\n':_) = True
+w `fits` (c:cs) = (w - 1) `fits` cs
+{-- /snippet fits --}
+
+{-- snippet nest --}
+nest :: Int -> Doc -> Doc
+{-- /snippet nest --}
+nest = undefined
+
+{-- snippet fill --}
+fill :: Int -> Doc -> Doc
+{-- /snippet fill --}
+fill = undefined
+
+--instance Show Doc where
+-- show doc = pretty 80 doc
diff --git a/ch05/PrettyJSON.hs b/ch05/PrettyJSON.hs
new file mode 100644
index 0000000..d9d7579
--- /dev/null
+++ b/ch05/PrettyJSON.hs
@@ -0,0 +1,88 @@
+{-- snippet module --}
+module PrettyJSON
+ (
+ renderJValue
+ ) where
+
+import Numeric (showHex)
+import Data.Char (ord)
+import Data.Bits (shiftR, (.&.))
+
+import SimpleJSON (JValue(..))
+import Prettify (Doc, (<>), char, double, fsep, hcat, punctuate, text,
+ compact, pretty)
+{-- /snippet module --}
+
+{-- snippet renderJValue --}
+renderJValue :: JValue -> Doc
+renderJValue (JBool True) = text "true"
+renderJValue (JBool False) = text "false"
+renderJValue JNull = text "null"
+renderJValue (JNumber num) = double num
+renderJValue (JString str) = string str
+{-- /snippet renderJValue --}
+{-- snippet renderJValue.array --}
+renderJValue (JArray ary) = series '[' ']' renderJValue ary
+{-- /snippet renderJValue.array --}
+{-- snippet renderJValue.object --}
+renderJValue (JObject obj) = series '{' '}' field obj
+ where field (name,val) = string name
+ <> text ": "
+ <> renderJValue val
+{-- /snippet renderJValue.object --}
+
+{-- snippet enclose --}
+enclose :: Char -> Char -> Doc -> Doc
+enclose left right x = char left <> x <> char right
+{-- /snippet enclose --}
+
+{-- snippet hexEscape --}
+hexEscape :: Char -> Doc
+hexEscape c | d < 0x10000 = smallHex d
+ | otherwise = astral (d - 0x10000)
+ where d = ord c
+{-- /snippet hexEscape --}
+
+{-- snippet smallHex --}
+smallHex :: Int -> Doc
+smallHex x = text "\\u"
+ <> text (replicate (4 - length h) '0')
+ <> text h
+ where h = showHex x ""
+{-- /snippet smallHex --}
+
+{-- snippet astral --}
+astral :: Int -> Doc
+astral n = smallHex (a + 0xd800) <> smallHex (b + 0xdc00)
+ where a = (n `shiftR` 10) .&. 0x3ff
+ b = n .&. 0x3ff
+{-- /snippet astral --}
+
+{-- snippet string --}
+string :: String -> Doc
+string = enclose '"' '"' . hcat . map oneChar
+{-- /snippet string --}
+
+{-- snippet pointyString --}
+pointyString :: String -> Doc
+pointyString s = enclose '"' '"' (hcat (map oneChar s))
+{-- /snippet pointyString --}
+
+{-- snippet oneChar --}
+oneChar :: Char -> Doc
+oneChar c = case lookup c simpleEscapes of
+ Just r -> text r
+ Nothing | mustEscape c -> hexEscape c
+ | otherwise -> char c
+ where mustEscape c = c < ' ' || c == '\x7f' || c > '\xff'
+
+simpleEscapes :: [(Char, String)]
+simpleEscapes = zipWith ch "\b\n\f\r\t\\\"/" "bnfrt\\\"/"
+ where ch a b = (a, ['\\',b])
+{-- /snippet oneChar --}
+
+{-- snippet series --}
+series :: Char -> Char -> (a -> Doc) -> [a] -> Doc
+series open close item = enclose open close
+ . fsep . punctuate (char ',') . map item
+{-- /snippet series --}
diff --git a/ch05/SimpleJSON.hs b/ch05/SimpleJSON.hs
new file mode 100644
index 0000000..d692168
--- /dev/null
+++ b/ch05/SimpleJSON.hs
@@ -0,0 +1,48 @@
+{-- snippet module --}
+module SimpleJSON
+ (
+ JValue(..)
+ , getString
+ , getInt
+ , getDouble
+ , getBool
+ , getObject
+ , getArray
+ , isNull
+ ) where
+{-- /snippet module --}
+
+{-- snippet JValue --}
+data JValue = JString String
+ | JNumber Double
+ | JBool Bool
+ | JNull
+ | JObject [(String, JValue)]
+ | JArray [JValue]
+ deriving (Eq, Ord, Show)
+{-- /snippet JValue --}
+
+{-- snippet getString --}
+getString :: JValue -> Maybe String
+getString (JString s) = Just s
+getString _ = Nothing
+{-- /snippet getString --}
+
+{-- snippet getters --}
+getInt (JNumber n) = Just (truncate n)
+getInt _ = Nothing
+
+getDouble (JNumber n) = Just n
+getDouble _ = Nothing
+
+getBool (JBool b) = Just b
+getBool _ = Nothing
+
+getObject (JObject o) = Just o
+getObject _ = Nothing
+
+getArray (JArray a) = Just a
+getArray _ = Nothing
+
+isNull v = v == JNull
+{-- /snippet getters --}