瀏覽代碼

More documentation updates for Parsec change

Getty Ritter 9 年之前
父節點
當前提交
4293524824
共有 4 個文件被更改,包括 49 次插入31 次删除
  1. 9 7
      Data/SCargot/Comments.hs
  2. 21 3
      Data/SCargot/General.hs
  3. 0 0
      Data/SCargot/Scheme.hs
  4. 19 21
      README.md

+ 9 - 7
Data/SCargot/Comments.hs

@@ -34,10 +34,10 @@ import           Text.Parsec ( (<|>)
                              , string
                              )
 
-import Data.SCargot.General ( Comment
-                            , SExprSpec
-                            , setComment
-                            )
+import            Data.SCargot.General ( Comment
+                                       , SExprSpec
+                                       , setComment
+                                       )
 
 -- | Given a string, produce a comment parser that matches that
 --   initial string and ignores everything until the end of the
@@ -57,8 +57,8 @@ lineComment s = string s >> skipMany (noneOf "\n") >> return ()
 --
 -- > { this { comment }
 --
+-- to be a complete comment, despite the apparent improper nesting.
+-- This is analogous to standard C-style comments in which
 --
 -- > /* this /* comment */
 --
@@ -124,7 +124,7 @@ of commenting capability, so the below functions will produce a new
 For example:
 
 > mySpec :: SExprSpec Text (SExpr Text)
-> mySpec = asWellFormed (mkSpec (takeWhile1 isAlphaNum) id)
+> mySpec = asWellFormed $ mkSpec (pack <$> many1 alphaNum) id
 >
 > myLispySpec :: SExprSpec Text (SExpr Text)
 > myLispySpec = withLispComments mySpec
@@ -136,11 +136,11 @@ We can then use these to parse s-expressions with different kinds of
 comment syntaxes:
 
 > > decode mySpec "(foo ; a lisp comment\n  bar)\n"
-> Left "Failed reading: takeWhile1"
+> Left "(line 1, column 6):\nunexpected \";\"\nexpecting space or atom"
 > > decode myLispySpec "(foo ; a lisp comment\n  bar)\n"
 > Right [WFSList [WFSAtom "foo", WFSAtom "bar"]]
 > > decode mySpec "(foo /* a c-like\n   comment */ bar)\n"
-> Left "Failed reading: takeWhile1"
+> Left "(line 1, column 6):\nunexpected \"/\"\nexpecting space or atom"
 > > decode myCLikeSpec "(foo /* a c-like\n   comment */ bar)\n"
 > Right [WFSList [WFSAtom "foo", WFSAtom "bar"]]
 

+ 21 - 3
Data/SCargot/General.hs

@@ -27,11 +27,13 @@ import           Control.Monad ((>=>))
 import           Data.Char (isAlpha, isDigit, isAlphaNum)
 import           Data.Map.Strict (Map)
 import qualified Data.Map.Strict as M
+import           Data.Maybe (fromJust)
 import           Data.Monoid ((<>))
 import           Data.String (IsString)
 import           Data.Text (Text, pack, unpack)
 import qualified Data.Text as T
 import           Text.Parsec ( (<|>)
+                             , (<?>)
                              , char
                              , eof
                              , lookAhead
@@ -80,10 +82,10 @@ data SExprSpec atom carrier = SExprSpec
 --   any alphanumeric sequence as a valid atom looks like:
 --
 --   > simpleSpec :: SExprSpec Text (SExpr Text)
+--   > simpleSpec = mkSpec (pack <$> many1 isAlphaNum) id
 mkSpec :: Parser atom -> Serializer atom -> SExprSpec atom (SExpr atom)
 mkSpec p s = SExprSpec
-  { sesPAtom   = p
+  { sesPAtom   = p <?> "atom"
   , sesSAtom   = s
   , readerMap  = M.empty
   , comment    = Nothing
@@ -101,22 +103,22 @@ mkSpec p s = SExprSpec
 --   the internal S-expression representation using 'asWellFormed', and
 --   then providing a conversion between the 'WellFormedSExpr' type and
 --   an @Expr@ AST. Notice that the below parser uses 'String' as its
+--   underlying atom type, instead of some token type.
 --
 --   > data Expr = Add Expr Expr | Num Int deriving (Eq, Show)
 --   >
 --   > toExpr :: WellFormedSExpr String -> Either String Expr
+--   > toExpr (L [A "+", l, r])     = Add <$> toExpr l <*> toExpr r
+--   > toExpr (A c) | all isDigit c = pure (Num (read c))
+--   > toExpr c                     = Left ("Invalid expr: " ++ show c)
 --   >
 --   > fromExpr :: Expr -> WellFormedSExpr String
+--   > fromExpr (Add l r) = L [A "+", fromExpr l, fromExpr r]
+--   > fromExpr (Num n)   = A (show n)
 --   >
 --   > mySpec :: SExprSpec String Expr
 --   > mySpec = convertSpec toExpr fromExpr $ asWellFormed $ mkSpec parser pack
+--   >   where parser = many1 (satisfy isValidChar)
 --   >         isValidChar c = isDigit c || c == '+'
 convertSpec :: (b -> Either String c) -> (c -> b)
                -> SExprSpec a b -> SExprSpec a c
@@ -143,10 +145,12 @@ asWellFormed = convertSpec toWellFormed fromWellFormed
 --   stream.
 --
 --   The following defines an S-expression variant that treats
+--   @'expr@ as being sugar for @(quote expr)@. Note that this is done
+--   already in a more general way by the 'withQuote' function, but
+--   it is a good illustration of using reader macros in practice:
 --
+--   > mySpec :: SExprSpec String (SExpr Text)
+--   > mySpec = addReader '\'' reader $ mkSpec (many1 alphaNum) pack
 --   >   where reader p = quote <$> p
 --   >         quote e  = SCons (SAtom "quote") (SCons e SNil)
 addReader :: Char -> Reader a -> SExprSpec a c -> SExprSpec a c
@@ -163,12 +167,12 @@ addReader c reader spec = spec
 --   C++-style comments, i.e. those which begin with @//@ and last
 --   until the end of a line:
 --
+--   > t :: SExprSpec String (SExpr Text)
+--   > t = setComment comm $ mkSpec (many1 alphaNum) pack
+--   >   where comm = try (string "//" *> manyTill newline *> pure ())
 
 setComment :: Comment -> SExprSpec a c -> SExprSpec a c
-setComment c spec = spec { comment = Just c }
+setComment c spec = spec { comment = Just (c <?> "comment") }
 
 -- | Add the ability to understand a quoted S-Expression. In general,
 --   many Lisps use @'sexpr@ as sugar for @(quote sexpr)@. This is
@@ -185,7 +189,7 @@ peekChar = Just <$> lookAhead anyChar <|> pure Nothing
 parseGenericSExpr ::
   Parser atom  -> ReaderMacroMap atom -> Parser () -> Parser (SExpr atom)
 parseGenericSExpr atom reader skip = do
-  let sExpr = parseGenericSExpr atom reader skip
+  let sExpr = parseGenericSExpr atom reader skip <?> "s-expr"
   skip
   c <- peekChar
   r <- case c of

+ 0 - 0
Data/SCargot/Scheme.hs


+ 19 - 21
README.md

@@ -116,7 +116,7 @@ is just the identity function:
 
 ~~~~.haskell
 spec :: SExprSpec Text (SExpr Text)
-spec = mkSpec (takeWhile1 (\ c -> isAlphaNum c || c `elem` "+-*/!?")) id
+spec = mkSpec (pack <$> many1 (alphaNum <|> oneOf "+-*/!?")) id
 ~~~~
 
 A more elaborate atom type would distinguish between different
@@ -124,19 +124,17 @@ varieties of token, so a small example (that understands just
 identifiers and numbers) is
 
 ~~~~.haskell
-import           Data.Char (isDigit, isAlpha)
-import           Data.Text (Text)
-import qualified Data.Text as T
+import Data.Text (Text, pack)
 
 data Atom = Ident Text | Num Int deriving (Eq, Show)
 
 pAtom :: Parser Atom
-pAtom =  ((Num . read . T.unpack) <$> takeWhile1 isDigit)
-     <|> (Ident <$> takeWhile1 isAlpha)
+pAtom =  ((Num . read) <$> many1 digit)
+     <|> (Ident . pack) <$> takeWhile1 isAlpha)
 
 sAtom :: Atom -> Text
 sAtom (Ident t) = t
-sAtom (Num n)   = T.pack (show n)
+sAtom (Num n)   = pack (show n)
 
 mySpec :: SExprSpec Atom (SExpr Atom)
 mySpec = mkSpec pAtom sAtom
@@ -172,15 +170,15 @@ import qualified Data.Text as T
 data Expr = Add Expr Expr | Num Int deriving (Eq, Show)
 
 toExpr :: RichSExpr Text -> Either String Expr
-toExpr (RSList [RSAtom "+", l, r]) = Add <$> toExpr l <*> toExpr r
-toExpr (RSAtom c)
+toExpr (L [A "+", l, r]) = Add <$> toExpr l <*> toExpr r
+toExpr (A c)
   | T.all isDigit c = pure (Num (read (T.unpack c)))
   | otherwise       = Left "Non-numeric token as argument"
 toExpr _ = Left "Unrecognized s-expr"
 
 fromExpr :: Expr -> RichSExpr Text
-fromExpr (Add x y) = RSList [RSAtom "+", fromExpr x, fromExpr y]
-fromExpr (Num n) = RSAtom (T.pack (show n))
+fromExpr (Add x y) = L [A "+", fromExpr x, fromExpr y]
+fromExpr (Num n)   = A (T.pack (show n))
 ~~~~
 
 then we could use the `convertSpec` function to add this directly to
@@ -196,13 +194,13 @@ Left "Unrecognized s-expr"
 ## Comments
 
 By default, an S-expression spec does not include a comment syntax, but
-the provided `withSemicolonComments` function will cause it to understand
+the provided `withLispComments` function will cause it to understand
 traditional Lisp line-oriented comments that begin with a semicolon:
 
 ~~~~.haskell
 > decode spec "(this ; has a comment\n inside)\n"
-Left "Failed reading: takeWhile1"
-> decode (withSemicolonComments spec) "(this ; has a comment\n inside)\n"
+Left "(line 1, column 7):\nunexpected \";\"\nexpecting space or atom"
+> decode (withLispComments spec) "(this ; has a comment\n inside)\n"
 Right [SCons (SAtom "this") (SCons (SAtom "inside") SNil)]
 ~~~~
 
@@ -217,7 +215,7 @@ wrapping the parser in a call to `try`
 For example, the following adds C++-style comments to an S-expression format:
 
 ~~~~.haskell
-> let cppComment = string "//" >> takeWhile (/= '\n') >> return ()
+> let cppComment = string "//" >> manyTill newline >> return ()
 > decode (setComment cppComment spec) "(a //comment\n  b)\n"
 Right [SCons (SAtom "a") (SCons (SAtom "b") SNil)]
 ~~~~
@@ -227,8 +225,8 @@ Right [SCons (SAtom "a") (SCons (SAtom "b") SNil)]
 A _reader macro_ is a Lisp macro which is invoked during read time. This
 allows the _lexical_ syntax of a Lisp to be modified. The most commonly
 seen reader macro is the quote, which allows the syntax `'expr` to stand
-in for the s-expression `(quote expr)`. The S-Cargot library enables this
-by keeping a map of characters to Parsec parsers that can be used as
+in for the s-expression `(quote expr)`. The S-Cargot library accomodates
+this by keeping a map of characters to Parsec parsers that can be used as
 readers. There is a special case for the aforementioned quote, but that
 could easily be written by hand as
 
@@ -272,8 +270,8 @@ with Haskell-style line comments and a special reader to understand hex
 literals:
 
 ~~~~.haskell
-data Op = Add | Sub | Mul
-data Atom = AOp Op | ANum Int
+data Op = Add | Sub | Mul deriving (Eq, Show)
+data Atom = AOp Op | ANum Int deriving (Eq, Show)
 data Expr = EOp Op Expr Expr | ENum Int deriving (Eq, Show)
 
 -- Conversions for our Expr type
@@ -288,7 +286,7 @@ fromExpr (ENum n)     = ANum n
 
 -- Parser and serializer for our Atom type
 pAtom :: Parser Atom
-pAtom = ((ANum . read . T.unpack) <$> takeWhile1 isDigit)
+pAtom = ((ANum . read . T.unpack) <$> many1 isDigit)
      <|> (char "+" *> pure (AOp Add))
      <|> (char "-" *> pure (AOp Sub))
      <|> (char "*" *> pure (AOp Mul))
@@ -301,7 +299,7 @@ sAtom (ANum n)  = T.pack (show n)
 
 -- Our comment syntax
 hsComment :: Parser ()
-hsComment = string "--" >> takeWhile (/= '\n') >> return ()
+hsComment = string "--" >> manyTill newline >> return ()
 
 -- Our custom reader macro
 hexReader :: Reader Atom