gdritter repos s-cargot / 5eb10bd
Improved HaskLike atom type and added more utility functions for processing WFSexprs Getty Ritter 10 years ago
6 changed file(s) with 179 addition(s) and 87 deletion(s). Collapse all Expand all
2323 deriving (Eq, Show, Read)
2424
2525 data CommonLispSpec carrier = CommonLispSpec
26 { sexprSpec :: SExprSpec CLAtom carrier
27 , poundReaders :: ReaderMacroMap CLAtom
26 { sexprSpec :: SExprSpec CLAtom carrier
27 , octoReaders :: ReaderMacroMap CLAtom
2828 }
2929
3030 withComments :: CommonLispSpec c -> CommonLispSpec c
+0
-80
Data/SCargot/Foo.hs less more
1 {-# LANGUAGE OverloadedStrings #-}
2
3 module Data.SCargot.Foo where
4
5 import Control.Applicative hiding ((<|>), many)
6 import Data.Char
7 import Data.Monoid ((<>))
8 import Data.Text (Text, concatMap, pack, singleton)
9 import Numeric (readDec, readFloat, readHex, readSigned)
10 import Text.Parsec
11 import Text.Parsec.Text
12 import Text.Parsec.Token (float, integer, stringLiteral)
13 import Text.Parsec.Language (haskell)
14
15 import Prelude hiding (concatMap)
16
17 import Data.SCargot.Repr.Basic (SExpr)
18 import Data.SCargot.General
19
20
21
22 data Atom
23 = AToken Text
24 | AString Text
25 | AInt Integer
26 | AFloat Double
27 deriving (Eq, Show)
28
29 atomChar :: Parser Char
30 atomChar = satisfy go
31 where go c = isAlphaNum c
32 || c == '-' || c == '*' || c == '/'
33 || c == '+' || c == '<' || c == '>'
34 || c == '=' || c == '!' || c == '?'
35
36 pToken :: Parser Text
37 pToken = pack <$> ((:) <$> letter <*> many atomChar)
38
39 pString :: Parser Text
40 pString = pack <$> between (char '"') (char '"') (many (val <|> esc))
41 where val = Just <$> satisfy (\ c -> c /= '"' && c /= '\\' && c > '\026')
42 esc = do char '\\'
43 Nothing <$ (gap <|> char '&') <|>
44 Just <$> cod
45 gap = many1 space >> char '\\'
46 cod = undefined
47
48 pFloat :: Parser Double
49 pFloat = undefined
50
51 pInt :: Parser Integer
52 pInt = do
53 s <- (negate <$ char '-' <|> id <$ char '+' <|> pure id)
54 n <- read <$> many1 digit
55 return (s n)
56
57 pAtom :: Parser Atom
58 pAtom = AInt <$> pInt
59 <|> AFloat <$> pFloat
60 <|> AToken <$> pToken
61 <|> AString <$> pString
62
63 escape :: Char -> Text
64 escape '\n' = "\\n"
65 escape '\t' = "\\t"
66 escape '\r' = "\\r"
67 escape '\b' = "\\b"
68 escape '\f' = "\\f"
69 escape '\\' = "\\\\"
70 escape '"' = "\\\""
71 escape c = singleton c
72
73 sAtom :: Atom -> Text
74 sAtom (AToken t) = t
75 sAtom (AString s) = "\"" <> concatMap escape s <> "\""
76 sAtom (AInt i) = pack (show i)
77 sAtom (AFloat f) = pack (show f)
78
79 fooSpec :: SExprSpec Atom (SExpr Atom)
80 fooSpec = mkSpec pAtom sAtom
1 {-# LANGUAGE OverloadedStrings #-}
2
3 module Data.SCargot.HaskLike ( -- $info
4 haskLikeSpec
5 , HaskLikeAtom(..)
6 ) where
7
8 import Control.Applicative ((<$>), (<*>), (<$))
9 import Data.Maybe (catMaybes)
10 import Data.String (IsString(..))
11 import Data.Text (Text, pack)
12 import Text.Parsec
13 import Text.Parsec.Text (Parser)
14
15 import Prelude hiding (concatMap)
16
17 import Data.SCargot.Repr.Basic (SExpr)
18 import Data.SCargot.General (SExprSpec, mkSpec)
19
20 {- $info
21
22 This module is intended for simple, ad-hoc configuration or data formats
23 that might not need their on rich structure but might benefit from a few
24 various literal formats. the 'haskLikeSpec' understands identifiers as
25 defined by R6RS as well as string, integer, and floating-point literals
26 as defined by the Haskell spec, but won't get any Lisp-specific vector
27 literals or other structure.
28
29 -}
30
31
32 -- | An atom type that understands Haskell-like values as well as
33 -- Scheme-like identifiers.
34 data HaskLikeAtom
35 = HSIdent Text -- ^ An identifier, parsed according to the R6RS Scheme
36 -- standard
37 | HSString Text -- ^ A string, parsed according to the syntax for string
38 -- literals in the Haskell report
39 | HSInt Integer -- ^ An arbitrary-sized integer value, parsed according to
40 -- the syntax for integer literals in the Haskell report
41 | HSFloat Double -- ^ A double-precision floating-point value, parsed
42 -- according to the syntax for floats in the Haskell
43 -- report
44 deriving (Eq, Show)
45
46 instance IsString HaskLikeAtom where
47 fromString = HSIdent . fromString
48
49 pToken :: Parser Text
50 pToken = pack <$> ( (:) <$> initial <*> many subsequent
51 <|> string "+"
52 <|> string "-"
53 <|> string "..."
54 )
55
56 initial :: Parser Char
57 initial = letter <|> oneOf "!$%&*/:<=>?^_~"
58
59 subsequent :: Parser Char
60 subsequent = initial <|> digit <|> oneOf "+-.@"
61
62 pString :: Parser Text
63 pString = pack . catMaybes <$> between (char '"') (char '"') (many (val <|> esc))
64 where val = Just <$> satisfy (\ c -> c /= '"' && c /= '\\' && c > '\026')
65 esc = do char '\\'
66 Nothing <$ (gap <|> char '&') <|>
67 Just <$> code
68 gap = many1 space >> char '\\'
69 code = eEsc <|> eNum <|> eCtrl <|> eAscii
70 eCtrl = char '^' >> unCtrl <$> upper
71 eNum = (toEnum . fromInteger) <$>
72 (decimal <|> (char 'o' >> number 8 octDigit)
73 <|> (char 'x' >> number 16 hexDigit))
74 eEsc = choice [ char a >> return b | (a, b) <- escMap ]
75 eAscii = choice [ try (string a >> return b)
76 | (a, b) <- asciiMap ]
77 unCtrl c = toEnum (fromEnum c - fromEnum 'A' + 1)
78
79 escMap :: [(Char, Char)]
80 escMap = zip "abfntv\\\"\'" "\a\b\f\n\r\t\v\\\"\'"
81
82 asciiMap :: [(String, Char)]
83 asciiMap = zip
84 ["BS","HT","LF","VT","FF","CR","SO","SI","EM"
85 ,"FS","GS","RS","US","SP","NUL","SOH","STX","ETX"
86 ,"EOT","ENQ","ACK","BEL","DLE","DC1","DC2","DC3"
87 ,"DC4","NAK","SYN","ETB","CAN","SUB","ESC","DEL"]
88 ("\BS\HT\LF\VT\FF\CR\SO\SI\EM\FS\GS\RS\US\SP\NUL\SOH" ++
89 "\STX\ETX\EOT\ENQ\ACK\BEL\DLE\DC1\DC2\DC3\DC4\NAK" ++
90 "\SYN\ETB\CAN\SUB\ESC\DEL")
91
92 decimal :: Parser Integer
93 decimal = number 10 digit
94
95 number :: Integer -> Parser Char -> Parser Integer
96 number base digits = foldl go 0 <$> many1 digits
97 where go x d = base * x + toInteger (value d)
98 value c
99 | c == 'a' || c == 'A' = 0xa
100 | c == 'b' || c == 'B' = 0xb
101 | c == 'c' || c == 'C' = 0xc
102 | c == 'd' || c == 'D' = 0xd
103 | c == 'e' || c == 'E' = 0xe
104 | c == 'f' || c == 'F' = 0xf
105 | c >= '0' && c <= '9' = fromEnum c - fromEnum '0'
106 | otherwise = error ("Unknown letter in number: " ++ show c)
107
108 pFloat :: Parser Double
109 pFloat = fail "???"
110
111 pInt :: Parser Integer
112 pInt = do
113 s <- negate <$ char '-' <|> id <$ char '+' <|> return id
114 n <- pZeroNum <|> decimal
115 return (s n)
116
117 pZeroNum :: Parser Integer
118 pZeroNum = char '0' >>
119 ( (oneOf "xX" >> number 16 hexDigit)
120 <|> (oneOf "oO" >> number 8 octDigit)
121 <|> decimal
122 <|> return 0
123 )
124
125 pHaskLikeAtom :: Parser HaskLikeAtom
126 pHaskLikeAtom =
127 HSInt <$> (try pInt <?> "integer")
128 <|> HSFloat <$> (try pFloat <?> "float")
129 <|> HSString <$> (pString <?> "string literal")
130 <|> HSIdent <$> (pToken <?> "token")
131
132 sHaskLikeAtom :: HaskLikeAtom -> Text
133 sHaskLikeAtom (HSIdent t) = t
134 sHaskLikeAtom (HSString s) = pack (show s)
135 sHaskLikeAtom (HSInt i) = pack (show i)
136 sHaskLikeAtom (HSFloat f) = pack (show f)
137
138 -- | This `SExprSpec` understands s-expressions that contain
139 -- Scheme-like tokens, as well as string literals, integer
140 -- literals, and floating-point literals. These are read
141 -- and shown with Haskell lexical syntax, so the same set
142 -- of values understood by GHC should be understood by this
143 -- spec as well. This includes string escapes, different
144 -- number bases, and so forth.
145 haskLikeSpec :: SExprSpec HaskLikeAtom (SExpr HaskLikeAtom)
146 haskLikeSpec = mkSpec pHaskLikeAtom sHaskLikeAtom
1313 -- * Useful processing functions
1414 , fromPair
1515 , fromList
16 , fromAtom
17 , asPair
18 , asList
19 , isAtom
20 , asAtom
21 , asAssoc
22 , car
23 , cdr
1624 ) where
1725
1826 import Control.Applicative ((<$>), (<*>), pure)
4452 fromList p (L ss) = mapM p ss
4553 fromList _ sx = fail ("Expected list")
4654
55 fromAtom :: Parse t t
56 fromAtom (L _) = fail "Expected atom; found list"
57 fromAtom (A a) = return a
4758
4859 asPair :: ((S t, S t) -> Either String a) -> S t -> Either String a
4960 asPair f (L [l, r]) = f (l, r)
5364 asList f (L ls) = f ls
5465 asList _ sx = fail ("Expected list")
5566
56 asSymbol :: (t -> Either String a) -> S t -> Either String a
57 asSymbol f (A s) = f s
58 asSymbol _ sx = fail ("Expected symbol")
67 isAtom :: Eq t => t -> S t -> Either String ()
68 isAtom s (A s')
69 | s == s' = return ()
70 | otherwise = fail ".."
71 isAtom _ _ = fail ".."
5972
60 asAssoc :: ([(S t, S t)] -> Either String a) -> S t -> Either String a
73 asAtom :: Show t => (t -> Either String a) -> S t -> Either String a
74 asAtom f (A s) = f s
75 asAtom _ sx = fail ("Expected atom; got" ++ show sx)
76
77 asAssoc :: Show t => ([(S t, S t)] -> Either String a) -> S t -> Either String a
6178 asAssoc f (L ss) = gatherPairs ss >>= f
6279 where gatherPairs (L [a, b] : ss) = (:) <$> pure (a, b) <*> gatherPairs ss
6380 gatherPairs [] = pure []
6481 gatherPairs _ = fail "..."
65 asAssoc _ sx = fail ("Expected assoc list")
82 asAssoc _ sx = fail ("Expected assoc list; got " ++ show sx)
83
84 car :: (S t -> Either String t') -> [S t] -> Either String t'
85 car f (x:_) = f x
86 car _ [] = fail "car: Taking car of zero-element list"
87
88 cdr :: ([S t] -> Either String t') -> [S t] -> Either String t'
89 cdr f (_:xs) = f xs
90 cdr _ [] = fail "cdr: Taking cdr of zero-element list"
+0
-0
Data/SCargot/Scheme.hs less more
(Empty file)
2020 Data.SCargot.General,
2121 Data.SCargot.Basic,
2222 Data.SCargot.Comments,
23 Data.SCargot.HaskLike,
2324 Data.SCargot.Tutorial
2425 -- other-modules:
2526 -- other-extensions: