]> gitweb @ CieloNegro.org - Lucu.git/commitdiff
Code cleanup
authorPHO <pho@cielonegro.org>
Sun, 6 Nov 2011 08:49:48 +0000 (17:49 +0900)
committerPHO <pho@cielonegro.org>
Sun, 6 Nov 2011 08:49:48 +0000 (17:49 +0900)
Ditz-issue: c566a8433e8af700655680f53e99cfe9f563ed32

Network/HTTP/Lucu/MIMEType/Guess.hs
Network/HTTP/Lucu/Parser.hs

index 8cddcba19bd60934b934f07dd520c97ef9c7fad9..edf177276eecc6feaf98be043ce13f96b3083e0d 100644 (file)
@@ -17,15 +17,13 @@ module Network.HTTP.Lucu.MIMEType.Guess
     )
     where
 import Control.Applicative
-import Control.Monad
-import Control.Monad.Unicode
-import Data.Ascii (Ascii)
-import qualified Data.Ascii as A
 import Data.Attoparsec.Char8 as P
+import Data.Attoparsec.Lazy as LP
+import qualified Data.ByteString.Lazy.Char8 as Lazy
 import qualified Data.Map as M
 import Data.Map (Map)
-import Data.Maybe
 import Data.Typeable
+import Data.List
 import Data.Monoid
 import Data.Monoid.Unicode
 import Data.Text (Text)
@@ -64,54 +62,60 @@ instance Lift ExtMap where
 -- @
 extMap ∷ QuasiQuoter
 extMap = QuasiQuoter {
-             quoteExp  = (lift ∘ parseExtMap =≪) ∘ toAscii
+             quoteExp  = lift ∘ parseExtMap ∘ Lazy.pack
            , quotePat  = const unsupported
            , quoteType = const unsupported
            , quoteDec  = const unsupported
          }
     where
-      toAscii ∷ Monad m ⇒ String → m Ascii
-      toAscii (A.fromChars → Just a) = return a
-      toAscii _ = fail "Malformed extension map"
-
       unsupported ∷ Monad m ⇒ m α
       unsupported = fail "Unsupported usage of extMap quasi-quoter."
 
 -- |Parse Apache @mime.types@.
-parseExtMap ∷ Ascii → ExtMap
+parseExtMap ∷ Lazy.ByteString → ExtMap
 parseExtMap src
-    = case parseOnly (finishOff extMapP) $ A.toByteString src of
-        Right xs → case compile xs of
-                      Right m → ExtMap m
-                      Left  e → error ("Duplicate extension: " ⧺ show e)
-        Left err → error ("Unparsable extension map: " ⧺ err)
-
-extMapP ∷ Parser [(MIMEType, [Text])]
-extMapP = catMaybes <$> P.many (try comment <|> try validLine <|> emptyLine)
+    = case LP.parse pairs src of
+        LP.Fail _ eCtx e
+            → error $ "Unparsable extension map: "
+                    ⧺ intercalate ", " eCtx
+                    ⧺ ": "
+                    ⧺ e
+        LP.Done _ xs
+            → case compile xs of
+                 Right m → ExtMap m
+                 Left  e → error ("Duplicate extension: " ⧺ show e)
     where
-      isSpc ∷ Char → Bool
-      isSpc c = c ≡ '\x20' ∨ c ≡ '\x09'
-
-      comment ∷ Parser (Maybe (MIMEType, [Text]))
-      comment = do skipWhile isSpc
-                   void $ char '#'
-                   skipWhile (≢ '\x0A')
-                   return Nothing
+      pairs ∷ Parser [(MIMEType, [Text])]
+      pairs = do skipMany linebreak
+                 xs ← sepBy pair (skipMany1 linebreak)
+                 skipMany linebreak
+                 endOfInput
+                 return xs
+              <?>
+              "pairs"
 
-      validLine ∷ Parser (Maybe (MIMEType, [Text]))
-      validLine = do skipWhile isSpc
-                     mime ← mimeType
-                     skipWhile isSpc
-                     exts ← sepBy extP (skipWhile isSpc)
-                     return $ Just (mime, exts)
+      pair ∷ Parser (MIMEType, [Text])
+      pair = do skipSpace
+                mime ← mimeType
+                skipSpace1
+                exts ← sepBy1 ext $ skipWhile1 (≡ '\x20')
+                return (mime, exts)
+             <?>
+             "pair"
 
-      extP ∷ Parser Text
-      extP = decodeUtf8 <$> takeWhile1 (\c → (¬) (isSpc c ∨ c ≡ '\x0A'))
+      ext ∷ Parser Text
+      ext = (decodeUtf8 <$> P.takeWhile1 isAlphaNum)
+            <?>
+            "ext"
 
-      emptyLine ∷ Parser (Maybe (MIMEType, [Text]))
-      emptyLine = do skipWhile isSpc
-                     void $ char '\x0A'
-                     return Nothing
+      linebreak ∷ Parser ()
+      linebreak
+          = ( endOfLine
+              <|>
+              try (skipSpace *> char '#' *> skipManyTill anyChar endOfLine)
+            )
+            <?>
+            "linebreak"
 
 compile ∷ Ord k ⇒ [(v, [k])] → Either (k, v, v) (Map k v)
 compile = go (∅) ∘ concat ∘ map tr
index ac1bf02734f0a09485eddf924002f8d4fc27b88e..660f550a9353cc687a56ae0e6e422ecc41a7e3f1 100644 (file)
@@ -6,18 +6,22 @@
 module Network.HTTP.Lucu.Parser
     ( atMost
     , finishOff
+    , skipManyTill
+    , skipWhile1
+    , skipSpace1
+    , isAlphaNum
     )
     where
 import Control.Applicative
 import Control.Applicative.Unicode
 import Control.Monad.Unicode
-import Data.Attoparsec
+import Data.Attoparsec.Char8
 import Prelude.Unicode
 
 -- |@'atMost' n v@ is like @'P.many' v@ but accumulates @v@ at most
 -- @n@ times.
 atMost ∷ Alternative f ⇒ Int → f α → f [α]
-{-# INLINE atMost #-}
+{-# INLINEABLE atMost #-}
 atMost 0 _ = pure []
 atMost n v = ( (:) <$> v ⊛ atMost (n-1) v )
              <|>
@@ -28,3 +32,26 @@ atMost n v = ( (:) <$> v ⊛ atMost (n-1) v )
 finishOff ∷ Parser α → Parser α
 {-# INLINE finishOff #-}
 finishOff = ((endOfInput *>) ∘ return =≪)
+
+-- |Similar to 'manyTill' but discards the result.
+skipManyTill ∷ Alternative f ⇒ f α → f β → f ()
+{-# INLINEABLE skipManyTill #-}
+skipManyTill p end = go
+    where
+      go = (end *> pure ()) <|> (p *> go)
+
+-- |Similar to 'skipWhile' but consumes at least one character.
+skipWhile1 ∷ (Char → Bool) → Parser ()
+{-# INLINE skipWhile1 #-}
+skipWhile1 p = takeWhile1 p *> pure ()
+
+-- |Similar to 'skipSpace' but consumes at least one whitespace.
+skipSpace1 ∷ Parser ()
+{-# INLINE skipSpace1 #-}
+skipSpace1 = skipMany1 space
+
+-- |@'isAlphaNum' c@ returns 'True' iff @'isDigit' c ||
+-- 'isAlpha_ascii' c@.
+isAlphaNum ∷ Char → Bool
+{-# INLINE isAlphaNum #-}
+isAlphaNum c = isDigit c ∨ isAlpha_ascii c