gdritter repos s-cargot / 9343e1b
Renamed Data.SExpression to non-conflicting (but terribly punny) name Data.SCargot Getty Ritter 9 years ago
14 changed file(s) with 263 addition(s) and 261 deletion(s). Collapse all Expand all
1 -- | Contains the type of atoms that Common Lisp understands, as
2 -- well as the built-in reader macros that Common Lisp provides.
3 -- Given a Common Lisp source file that contains no extra reader
4 -- macro definitions, this module should successfully parse and
5 -- desugar even quoted lists and vector literals.
6
7 module Data.SCargot.CommonLisp where
8
9 data Atom
10 = Symbol Text
11 | String Text
12 | Integer Int
13 | True
14 deriving (Eq, Show, Read)
15
16 parseSexpr :: Text -> Either SExprError
1 module Data.SCargot.General where
2
3 import Control.Applicative
4 import Data.Attoparsec.Text
5 import Data.Map.String (Map)
6 import qualified Data.Map.String as M
7
8 import Data.SCargot.Repr
9
10 type ReaderMacroMap atom = Map Char (Reader atom)
11 type Reader atom = (Parser (SExpr atom) -> Parser (SExpr atom))
12 type Serializer atom = atom -> Text
13
14 -- | A 'SExprSpec' describes a parser and emitter for a particular
15 -- variant of S-Expressions. The @atom@ type corresponds to a
16 -- Haskell type used to represent the atoms, and the @carrier@
17 -- type corresponds to the parsed S-Expression structure. This
18 -- is deliberately opaque so that it must be constructed and
19 -- modified with other helper functions.
20 data SExprSpec atom carrier = SExprSpec
21 { sesPAtom :: Parser atom
22 , sesSAtom :: Serializer atom
23 , rmMap :: ReaderMacroMap atom
24 , postparse :: SExpr atom -> Either String carrier
25 , preserial :: carrier -> SExpr atom
26 }
27
28 -- | This creates a basic 'SExprSpec' when given a parser and serializer
29 -- for an atom type.
30 mkSpec :: Parser atom -> Serializer atom -> SExprSpec atom (SExpr atom)
31 mkSpec p s = SExprSpec
32 { sesPAtom = p
33 , sesSAtom = s
34 , rmMap = M.empty
35 , postparse = return
36 , preserial = id
37 }
38
39 -- | This is used to modify the carrier type for a 'SExprSpec'. This is
40 -- used internally to convert between various 'SExpr' representations,
41 -- but could also be used externally to add an extra conversion layer
42 -- onto a 'SExprSpec', e.g. for a custom Lisp-like language:
43 --
44 -- > mySpec :: SExprSpec MyAtomType MyAST
45 -- > mySpec = convertSpec sexprToMyAST myASTToSexpr spec
46 -- > where spec = mkSpec myParser mySerializer
47 convertSpec :: (b -> Either String c) -> (c -> b) -> SExprSpec a b -> SExprSpec a c
48 convertSpec f g spec = spec
49 { postparse = postparse spec >=> f
50 , preserial = g . preserial spec
51 }
52
53 addReader :: Char -> Reader a -> SExprSpec a c -> SExprSpec a c
54 addReader c reader spec = spec { rmMap = insert c reader (rmMap spec) }
55
56 quote :: atom -> Reader atom
57 quote q parse = go <$> parse
58 where go v = SCons q (SCons v SNil)
59
60 toRich :: SExprSpec a (SExpr b) -> SExprSpec a (RichSExpr b)
61 toRich = convertSpec (return . toRich) fromRich
62
63 toWellFormed :: SExprSpec a (SExpr b) -> SExprSpec a (WellFormedSExpr b)
64 toWellFormed = convertSpec toWellFormed fromWellFormed
65
66 parseGenericSExpr :: Parser atom -> ReaderMacroMap atom -> Parser (SExpr atom)
67
68 -- |
69 parseSExpr :: SExprSpec atom carrier -> Text -> Either String carrier
70 parseSExpr spec = undefined
71
72 -- | blah
73 serializeSExpr :: SExprSpec atom carrier -> carrier -> Text
74 serializeSExpr spec = serializeGenericSExpr ses . preserial
1 {-# LANGUAGE PatternSynonyms #-}
2
3 module Data.SCargot.Repr.Rich
4 ( pattern List
5 , pattern DotList
6 , pattern Atom
7 ) where
8
9 import Data.SCargot.Repr as R
10
11 pattern List xs = R.RSList xs
12 pattern DotList xs = R.RSDotted xs
13 pattern Atom a = R.RSAtom a
1 {-# LANGUAGE PatternSynonyms #-}
2
3 module Data.SCargot.Repr.Rich
4 ( pattern List
5 , pattern Atom
6 ) where
7
8 import Data.SCargot.Repr as R
9
10 pattern List xs = R.WFSList xs
11 pattern Atom a = R.WFSAtom a
1 module Data.SCargot.Repr
2 ( SExpr(..)
3 , RichSExpr(..)
4 , toRich
5 , fromRich
6 , WellFormedSExpr(..)
7 , toWellFormed
8 , fromWellFormed
9 ) where
10
11 -- | All S-Expressions can be understood as a sequence
12 -- of @cons@ cells (represented here by 'SCons'), the
13 -- empty list @nil@ (represented by 'SNil') or an
14 -- @atom@.
15 data SExpr atom
16 = SCons (SExpr atom) (SExpr atom)
17 | SAtom atom
18 | SNil
19 deriving (Eq, Show, Read)
20
21 -- | Sometimes, the cons-based interface is too low
22 -- level, and we'd rather have the lists themselves
23 -- exposed. In this case, we have 'RSList' to
24 -- represent a well-formed cons list, and 'RSDotted'
25 -- to represent an improper list of the form
26 -- @(a b c . d)@.
27 data RichSExpr atom
28 = RSList [RichSExpr atom]
29 | RSDotted [RichSExpr atom] atom
30 | RSAtom atom
31 deriving (Eq, Show, Read)
32
33 -- | A Rich S-Expression might be a nicer interface
34 -- for certain libraries. It should always be true
35 -- that
36 --
37 -- > fromRich . toRich == id
38 --
39 -- and that
40 --
41 -- > toRich . fromRich == id
42 toRich :: SExpr atom -> RichSExpr atom
43 toRich (SAtom a) = RSAtom a
44 toRich (SCons x xs) = go xs [toRich x]
45 where go (SAtom a) rs = RSDotted rs a
46 go SNil rs = RSList rs
47 go (SCons x xs) rs = go xs (toRich x:rs)
48
49 -- | This follows the same laws as 'toRich'.
50 fromRich :: RichSExpr atom -> SExpr atom
51 fromRich (RSAtom a) = SAtom a
52 fromRich (RSList xs) = foldr SCons SNil (map fromRich xs)
53 fromRich (RSDotted xs x) = foldr SCons (SAtom x) (map fromRich xs)
54
55 -- | A well-formed s-expression is one which does not
56 -- contain any dotted lists. This means that not
57 -- every value of @SExpr a@ can be converted to a
58 -- @WellFormedSExpr a@, although the opposite is
59 -- fine.
60 data WellFormedSExpr atom
61 = WFSList [WellFormedSExpr atom]
62 | WFSAtom atom
63 deriving (Eq, Show, Read)
64
65 -- | This will be @Nothing@ is the argument contains an
66 -- improper list. It should hold that
67 --
68 -- > toWellFormed . fromWellFormed == Right
69 toWellFormed :: SExpr atom -> Either String (WellFormedSExpr atom)
70 toWellFormed (SAtom a) = return (WFSAtom a)
71 toWellFormed (SCons x xs) = do
72 x' <- toWellFormed x
73 go xs [x']
74 where go (SAtom a) rs = Left "Found atom in cdr position"
75 go SNil rs = return (WFSList rs)
76 go (SCons x xs) rs = do
77 x' <- toWellFormed x
78 go xs (x':rs)
79
80 -- | Convert a WellFormedSExpr back into a SExpr.
81 fromWellFormed :: WellFormedSExpr atom -> SExpr atom
82 fromWellFormed (WFSAtom a) = SAtom a
83 fromWellFormed (WFSList xs) =
84 foldr SCons SNil (map fromWellFormed xs)
1 module Data.SCargot.Rivest where
2
3 import Data.ByteString (ByteString)
4 import qualified Data.ByteString as BS
5 import qualified Data.ByteString.Base64 as B64
6 import Data.Text (Text)
7 import qualified Data.Text as T
8
9 newtype Atom = Atom { fromAtom :: ByteString } deriving (Eq, Show, Read)
10
11 pToken :: Parser ByteString
12 pToken = undefined
13
14 pQuoted :: Maybe Int -> Parser ByteString
15 pQuoted = do
16 char '"'
17 ss <- many1 quoteChar
18 char '"'
19 return ss
20
21 pHex :: Parser ByteString
22 pHex = undefined
23
24 pVerbatim :: Int -> Parser ByteString
25 pVerbatim = do
26 char ':'
27 take n
28
29 pBase64Verbatim :: Parser ByteString
30 pBase64 :: Parser ByteString
1 {-| The "s-cargot" library attempts to be as general as possible, and
2 to support a wide range of use-cases for s-expressions. It is built
3 around a core of primitives which are then exposed in various
4 ways, and can be easily and flexibly extended. This tutorial
5 describes particular use-cases, and then shows how to adapt this
6 library to that use-case.
7 -}
8
9 module Data.SCargot.Tutorial
10 ( -- * Basic Usage and Organization
11 -- $usage
12 -- * Analyzing Scheme code
13 -- $scheme
14 -- * Building a Custom Config Format
15 -- $config
16 -- * Building a Custom Lisp
17 -- $lisp
18 ) where
19
20 {- $usage
21
22 -}
23
24 {- $scheme
25
26 -}
27
28
29 {- $config
30
31 -}
32
33 {- $lisp
34
35 -}
+0
-16
Data/SExpression/CommonLisp.hs less more
1 -- | Contains the type of atoms that Common Lisp understands, as
2 -- well as the built-in reader macros that Common Lisp provides.
3 -- Given a Common Lisp source file that contains no extra reader
4 -- macro definitions, this module should successfully parse and
5 -- desugar even quoted lists and vector literals.
6
7 module Data.SExpression.CommonLisp where
8
9 data Atom
10 = Symbol Text
11 | String Text
12 | Integer Int
13 | True
14 deriving (Eq, Show, Read)
15
16 parseSexpr :: Text -> Either SExprError
+0
-72
Data/SExpression/General.hs less more
1 module Data.SExpression.General where
2
3 import Control.Applicative
4 import Data.Attoparsec.Text
5 import Data.Map.String (Map)
6 import qualified Data.Map.String as M
7
8 type ReaderMacroMap atom = Map Char (Reader atom)
9 type Reader atom = (Parser (SExpr atom) -> Parser (SExpr atom))
10 type Serializer atom = atom -> Text
11
12 -- | A 'SExprSpec' describes a parser and emitter for a particular
13 -- variant of S-Expressions. The @atom@ type corresponds to a
14 -- Haskell type used to represent the atoms, and the @carrier@
15 -- type corresponds to the parsed S-Expression structure. This
16 -- is deliberately opaque so that it must be constructed and
17 -- modified with other helper functions.
18 data SExprSpec atom carrier = SExprSpec
19 { sesPAtom :: Parser atom
20 , sesSAtom :: Serializer atom
21 , rmMap :: ReaderMacroMap atom
22 , postparse :: SExpr atom -> Either String carrier
23 , preserial :: carrier -> SExpr atom
24 }
25
26 -- | This creates a basic 'SExprSpec' when given a parser and serializer
27 -- for an atom type.
28 mkSpec :: Parser atom -> Serializer atom -> SExprSpec atom (SExpr atom)
29 mkSpec p s = SExprSpec
30 { sesPAtom = p
31 , sesSAtom = s
32 , rmMap = M.empty
33 , postparse = return
34 , preserial = id
35 }
36
37 -- | This is used to modify the carrier type for a 'SExprSpec'. This is
38 -- used internally to convert between various 'SExpr' representations,
39 -- but could also be used externally to add an extra conversion layer
40 -- onto a 'SExprSpec', e.g. for a custom Lisp-like language:
41 --
42 -- > mySpec :: SExprSpec MyAtomType MyAST
43 -- > mySpec = convertSpec sexprToMyAST myASTToSexpr spec
44 -- > where spec = mkSpec myParser mySerializer
45 convertSpec :: (b -> Either String c) -> (c -> b) -> SExprSpec a b -> SExprSpec a c
46 convertSpec f g spec = spec
47 { postparse = postparse spec >=> f
48 , preserial = g . preserial spec
49 }
50
51 addReader :: Char -> Reader a -> SExprSpec a c -> SExprSpec a c
52 addReader c reader spec = spec { rmMap = insert c reader (rmMap spec) }
53
54 quote :: atom -> Reader atom
55 quote q parse = go <$> parse
56 where go v = SCons q (SCons v SNil)
57
58 toRich :: SExprSpec a (SExpr b) -> SExprSpec a (RichSExpr b)
59 toRich = convertSpec (return . toRich) fromRich
60
61 toWellFormed :: SExprSpec a (SExpr b) -> SExprSpec a (WellFormedSExpr b)
62 toWellFormed = convertSpec toWellFormed fromWellFormed
63
64 parseGenericSExpr :: Parser atom -> ReaderMacroMap atom -> Parser (SExpr atom)
65
66 -- |
67 parseSExpr :: SExprSpec atom carrier -> Text -> Either String carrier
68 parseSExpr spec = undefined
69
70 -- | blah
71 serializeSExpr :: SExprSpec atom carrier -> carrier -> Text
72 serializeSExpr spec = serializeGenericSExpr ses . preserial
+0
-13
Data/SExpression/Repr/Rich.hs less more
1 {-# LANGUAGE PatternSynonyms #-}
2
3 module Data.SExpression.Repr.Rich
4 ( pattern List
5 , pattern DotList
6 , pattern Atom
7 ) where
8
9 import Data.SExpression.Repr as R
10
11 pattern List xs = R.RSList xs
12 pattern DotList xs = R.RSDotted xs
13 pattern Atom a = R.RSAtom a
+0
-11
Data/SExpression/Repr/WellFormed.hs less more
1 {-# LANGUAGE PatternSynonyms #-}
2
3 module Data.SExpression.Repr.Rich
4 ( pattern List
5 , pattern Atom
6 ) where
7
8 import Data.SExpression.Repr as R
9
10 pattern List xs = R.WFSList xs
11 pattern Atom a = R.WFSAtom a
+0
-84
Data/SExpression/Repr.hs less more
1 module Data.SExpression.Repr
2 ( SExpr(..)
3 , RichSExpr(..)
4 , toRich
5 , fromRich
6 , WellFormedSExpr(..)
7 , toWellFormed
8 , fromWellFormed
9 ) where
10
11 -- | All S-Expressions can be understood as a sequence
12 -- of @cons@ cells (represented here by 'SCons'), the
13 -- empty list @nil@ (represented by 'SNil') or an
14 -- @atom@.
15 data SExpr atom
16 = SCons (SExpr atom) (SExpr atom)
17 | SAtom atom
18 | SNil
19 deriving (Eq, Show, Read)
20
21 -- | Sometimes, the cons-based interface is too low
22 -- level, and we'd rather have the lists themselves
23 -- exposed. In this case, we have 'RSList' to
24 -- represent a well-formed cons list, and 'RSDotted'
25 -- to represent an improper list of the form
26 -- @(a b c . d)@.
27 data RichSExpr atom
28 = RSList [RichSExpr atom]
29 | RSDotted [RichSExpr atom] atom
30 | RSAtom atom
31 deriving (Eq, Show, Read)
32
33 -- | A Rich S-Expression might be a nicer interface
34 -- for certain libraries. It should always be true
35 -- that
36 --
37 -- > fromRich . toRich == id
38 --
39 -- and that
40 --
41 -- > toRich . fromRich == id
42 toRich :: SExpr atom -> RichSExpr atom
43 toRich (SAtom a) = RSAtom a
44 toRich (SCons x xs) = go xs [toRich x]
45 where go (SAtom a) rs = RSDotted rs a
46 go SNil rs = RSList rs
47 go (SCons x xs) rs = go xs (toRich x:rs)
48
49 -- | This follows the same laws as 'toRich'.
50 fromRich :: RichSExpr atom -> SExpr atom
51 fromRich (RSAtom a) = SAtom a
52 fromRich (RSList xs) = foldr SCons SNil (map fromRich xs)
53 fromRich (RSDotted xs x) = foldr SCons (SAtom x) (map fromRich xs)
54
55 -- | A well-formed s-expression is one which does not
56 -- contain any dotted lists. This means that not
57 -- every value of @SExpr a@ can be converted to a
58 -- @WellFormedSExpr a@, although the opposite is
59 -- fine.
60 data WellFormedSExpr atom
61 = WFSList [WellFormedSExpr atom]
62 | WFSAtom atom
63 deriving (Eq, Show, Read)
64
65 -- | This will be @Nothing@ is the argument contains an
66 -- improper list. It should hold that
67 --
68 -- > toWellFormed . fromWellFormed == Right
69 toWellFormed :: SExpr atom -> Either String (WellFormedSExpr atom)
70 toWellFormed (SAtom a) = return (WFSAtom a)
71 toWellFormed (SCons x xs) = do
72 x' <- toWellFormed x
73 go xs [x']
74 where go (SAtom a) rs = Left "Found atom in cdr position"
75 go SNil rs = return (WFSList rs)
76 go (SCons x xs) rs = do
77 x' <- toWellFormed x
78 go xs (x':rs)
79
80 -- | Convert a WellFormedSExpr back into a SExpr.
81 fromWellFormed :: WellFormedSExpr atom -> SExpr atom
82 fromWellFormed (WFSAtom a) = SAtom a
83 fromWellFormed (WFSList xs) =
84 foldr SCons SNil (map fromWellFormed xs)
+0
-30
Data/SExpression/Rivest.hs less more
1 module Data.SExpression.Rivest where
2
3 import Data.ByteString (ByteString)
4 import qualified Data.ByteString as BS
5 import qualified Data.ByteString.Base64 as B64
6 import Data.Text (Text)
7 import qualified Data.Text as T
8
9 newtype Atom = Atom { fromAtom :: ByteString } deriving (Eq, Show, Read)
10
11 pToken :: Parser ByteString
12 pToken = undefined
13
14 pQuoted :: Maybe Int -> Parser ByteString
15 pQuoted = do
16 char '"'
17 ss <- many1 quoteChar
18 char '"'
19 return ss
20
21 pHex :: Parser ByteString
22 pHex = undefined
23
24 pVerbatim :: Int -> Parser ByteString
25 pVerbatim = do
26 char ':'
27 take n
28
29 pBase64Verbatim :: Parser ByteString
30 pBase64 :: Parser ByteString
+0
-35
Data/SExpression/Tutorial.hs less more
1 {-| The @blah@ library attempts to be as general as possible, and to
2 support a wide range of use-cases for s-expressions. It is built
3 around a core of primitives which are then exposed in various
4 ways, and can be easily and flexibly extended. This tutorial
5 describes particular use-cases, and then shows how to adapt this
6 library to that use-case.
7 -}
8
9 module Data.SExpression.Tutorial
10 ( -- * Basic Usage and Organization
11 -- $usage
12 -- * Analyzing Scheme code
13 -- $scheme
14 -- * Building a Custom Config Format
15 -- $config
16 -- * Building a Custom Lisp
17 -- $lisp
18 ) where
19
20 {- $usage
21
22 -}
23
24 {- $scheme
25
26 -}
27
28
29 {- $config
30
31 -}
32
33 {- $lisp
34
35 -}