]> gitweb @ CieloNegro.org - Lucu.git/commitdiff
Better name-rewriting engine
authorPHO <pho@cielonegro.org>
Fri, 11 Nov 2011 05:30:27 +0000 (14:30 +0900)
committerPHO <pho@cielonegro.org>
Fri, 11 Nov 2011 05:30:27 +0000 (14:30 +0900)
Ditz-issue: 123424c3b4a0d83452e26403cd79676f319d4295

18 files changed:
ImplantFile.hs
Lucu.cabal
Network/HTTP/Lucu.hs
Network/HTTP/Lucu/Authentication.hs
Network/HTTP/Lucu/ETag.hs
Network/HTTP/Lucu/HandleLike.hs
Network/HTTP/Lucu/Headers.hs
Network/HTTP/Lucu/HttpVersion.hs
Network/HTTP/Lucu/Implant.hs [moved from Network/HTTP/Lucu/Implant/Input.hs with 95% similarity]
Network/HTTP/Lucu/Implant/PrettyPrint.hs
Network/HTTP/Lucu/Implant/Rewrite.hs
Network/HTTP/Lucu/MultipartForm.hs
Network/HTTP/Lucu/Parser.hs
Network/HTTP/Lucu/SocketLike.hs
Network/HTTP/Lucu/Utils.hs
bugs/issue-123424c3b4a0d83452e26403cd79676f319d4295.yaml
cabal-package.mk
examples/Makefile

index b6545a85df72082b0260f879a37e3bdb31c618dd..bd01923ef9f56275f1deec021dce20d89d9ae374 100644 (file)
@@ -10,7 +10,7 @@ import Data.Maybe
 import Language.Haskell.TH.PprLib
 import Language.Haskell.TH.Syntax
 import Network.HTTP.Lucu.ETag
-import Network.HTTP.Lucu.Implant.Input
+import Network.HTTP.Lucu.Implant
 import Network.HTTP.Lucu.Implant.PrettyPrint
 import Network.HTTP.Lucu.MIMEType
 import Prelude.Unicode
index 7ceb6c2c0e457a3543635c6b9ce0d7ec0754a921..604fc273ac86d871ecc508af650881bac7531a79 100644 (file)
@@ -1,26 +1,30 @@
-Name: Lucu
-Synopsis: Embedded HTTP Server
+Name:          Lucu
+Synopsis:      Embedded HTTP Server
 Description:
-
-        Lucu is an embedded HTTP server library.
-
-        It's not a replacement for Apache nor lighttpd. It is intended
-        to be used to build an efficient web-based RESTful application
-        which runs behind a reverse-proxy so it doesn't have some
-        functionalities like logging, client filtering and such.
-
-Version: 1.0
-License: PublicDomain
-License-File: COPYING
-Author: PHO <pho at cielonegro dot org>
-Maintainer: PHO <pho at cielonegro dot org>
-Stability: experimental
-Homepage: http://cielonegro.org/Lucu.html
-Bug-Reports: http://static.cielonegro.org/ditz/Lucu/
-Category: Network
-Tested-With: GHC == 7.0.3
+    .
+    Lucu is an embedded HTTP server library.
+    .
+    This isn't a replacement for Apache nor lighttpd. It is intended
+    to be used to build an efficient web-based RESTful application
+    which runs behind a reverse-proxy so it doesn't have some
+    functionalities like logging, client filtering and such.
+    .
+    The library has indeed so many exposed modules, but in general
+    you don't need to import any modules other than
+    "Network.HTTP.Lucu".
+    .
+Version:       1.0
+License:       PublicDomain
+License-File:  COPYING
+Author:        PHO <pho at cielonegro dot org>
+Maintainer:    PHO <pho at cielonegro dot org>
+Stability:     experimental
+Homepage:      http://cielonegro.org/Lucu.html
+Bug-Reports:   http://static.cielonegro.org/ditz/Lucu/
+Category:      Network
+Tested-With:   GHC == 7.0.3
 Cabal-Version: >= 1.6
-Build-Type: Simple
+Build-Type:    Simple
 Extra-Source-Files:
     NEWS
     examples/HelloWorld.hs
@@ -72,8 +76,13 @@ Library
         Network.HTTP.Lucu.Authentication
         Network.HTTP.Lucu.Config
         Network.HTTP.Lucu.ETag
+        Network.HTTP.Lucu.HandleLike
+        Network.HTTP.Lucu.Headers
         Network.HTTP.Lucu.HttpVersion
         Network.HTTP.Lucu.Httpd
+        Network.HTTP.Lucu.Implant
+        Network.HTTP.Lucu.Implant.PrettyPrint
+        Network.HTTP.Lucu.Implant.Rewrite
         Network.HTTP.Lucu.MIMEParams
         Network.HTTP.Lucu.MIMEType
         Network.HTTP.Lucu.MIMEType.DefaultExtensionMap
@@ -86,6 +95,7 @@ Library
         Network.HTTP.Lucu.Resource
         Network.HTTP.Lucu.Resource.Tree
         Network.HTTP.Lucu.Response
+        Network.HTTP.Lucu.SocketLike
         Network.HTTP.Lucu.StaticFile
         Network.HTTP.Lucu.StatusCode
         Network.HTTP.Lucu.Utils
@@ -95,15 +105,12 @@ Library
         Network.HTTP.Lucu.Chunk
         Network.HTTP.Lucu.ContentCoding
         Network.HTTP.Lucu.DefaultPage
-        Network.HTTP.Lucu.HandleLike
-        Network.HTTP.Lucu.Headers
         Network.HTTP.Lucu.Interaction
         Network.HTTP.Lucu.Postprocess
         Network.HTTP.Lucu.Preprocess
         Network.HTTP.Lucu.RequestReader
         Network.HTTP.Lucu.Resource.Internal
         Network.HTTP.Lucu.ResponseWriter
-        Network.HTTP.Lucu.SocketLike
         Network.HTTP.Lucu.StatusCode.Internal
 
     ghc-options:
@@ -117,11 +124,6 @@ Executable lucu-implant-file
 
     Main-Is: ImplantFile.hs
 
-    Other-Modules:
-        Network.HTTP.Lucu.Implant.Input
-        Network.HTTP.Lucu.Implant.PrettyPrint
-        Network.HTTP.Lucu.Implant.Rewrite
-
     Build-Depends:
         SHA  == 1.5.*,
         syb  == 0.3.*,
index 79ae0613664294801ad5c3289a8f458eafdaa6f4..b2c78952c9b202253b1be4f29160aedc4219dd0a 100644 (file)
@@ -57,6 +57,7 @@ module Network.HTTP.Lucu
 
       -- *** MIME Type
     , MIMEType(..)
+    , MIMEParams(..)
     , parseMIMEType
     , mimeType
 
@@ -74,6 +75,7 @@ import Network.HTTP.Lucu.Authentication
 import Network.HTTP.Lucu.Config
 import Network.HTTP.Lucu.ETag
 import Network.HTTP.Lucu.Httpd
+import Network.HTTP.Lucu.MIMEParams
 import Network.HTTP.Lucu.MIMEType hiding (mimeType)
 import Network.HTTP.Lucu.MIMEType.TH
 import Network.HTTP.Lucu.Resource
index 753af6ecbe72153ab3394a76ba1e1b0da2e79c81..495c931604696c9f8b7a4741bcba861a335254f0 100644 (file)
@@ -2,7 +2,7 @@
     OverloadedStrings
   , UnicodeSyntax
   #-}
--- |HTTP Authentication
+-- |An internal module for HTTP authentication.
 module Network.HTTP.Lucu.Authentication
     ( AuthChallenge(..)
     , AuthCredential(..)
index b8191a353fd86dd05c325b3d99d872d5a34e3e9b..13357383941c983896e7481c24f627c5264f4b85 100644 (file)
@@ -5,7 +5,7 @@
   , TemplateHaskell
   , UnicodeSyntax
   #-}
--- |Entity tags
+-- |An internal module for entity tags.
 module Network.HTTP.Lucu.ETag
     ( ETag(..)
     , parseETag
index c4a4c62fc23298558b6ee48a0cc906f8191232f4..a45ce6cbf066f3d0a6bac21335b4b16dbef6cca1 100644 (file)
@@ -2,6 +2,7 @@
     DoAndIfThenElse
   , UnicodeSyntax
   #-}
+-- |Type class for things behaves like a 'I.Handle'.
 module Network.HTTP.Lucu.HandleLike
     ( HandleLike(..)
     , hPutBuilder
index a47f2ac9ea60c1869221c573238b2186f076618e..80b9b1339501d95a08c80511645e3603a5b1d9ea 100644 (file)
@@ -3,6 +3,7 @@
   , OverloadedStrings
   , UnicodeSyntax
   #-}
+-- |An internal module for HTTP headers.
 module Network.HTTP.Lucu.Headers
     ( Headers
     , HasHeaders(..)
index 36b6c499b1428e48f9ea4c0c1a383fbeab8f8026..4466f1ecda8959aa102e76e6137cd57c8b53e420 100644 (file)
@@ -2,7 +2,7 @@
     OverloadedStrings
   , UnicodeSyntax
   #-}
--- |HTTP version number
+-- |An internal module for HTTP version numbers.
 module Network.HTTP.Lucu.HttpVersion
     ( HttpVersion(..)
     , printHttpVersion
similarity index 95%
rename from Network/HTTP/Lucu/Implant/Input.hs
rename to Network/HTTP/Lucu/Implant.hs
index 4b462e338701c47b328b82bfa69d6c7fd0ed4efc..f80ac99cfdbc768bcb0f931ed50f0058b1364129 100644 (file)
@@ -3,7 +3,9 @@
   , RecordWildCards
   , UnicodeSyntax
   #-}
-module Network.HTTP.Lucu.Implant.Input
+-- |An internal module for generating Haskell modules eith an
+-- arbitrary file implanted.
+module Network.HTTP.Lucu.Implant
     ( Input(..)
 
     , originalLen
index 027003d2b07bb551c5e06ff93ff316747f84cf0e..ecdb4fe8aed35dacc39f1f4234060d366cc1a070 100644 (file)
@@ -4,7 +4,10 @@
   , RecordWildCards
   , TemplateHaskell
   , UnicodeSyntax
+  , ViewPatterns
   #-}
+-- |An internal module for generating Haskell modules eith an
+-- arbitrary file implanted.
 module Network.HTTP.Lucu.Implant.PrettyPrint
     ( pprInput
     )
@@ -14,15 +17,17 @@ import Control.Monad
 import Data.Ascii (CIAscii)
 import qualified Data.Ascii as A
 import qualified Data.ByteString.Lazy as L
+import Data.Char
+import Data.Foldable
 import Data.List
-import qualified Data.Map as M
+import Data.Ratio
 import Data.Time
 import Language.Haskell.TH.Lib
 import Language.Haskell.TH.Ppr
 import Language.Haskell.TH.PprLib
 import Language.Haskell.TH.Syntax
 import Network.HTTP.Lucu.ETag
-import Network.HTTP.Lucu.Implant.Input
+import Network.HTTP.Lucu.Implant
 import Network.HTTP.Lucu.Implant.Rewrite
 import Network.HTTP.Lucu.MIMEType
 import Network.HTTP.Lucu.Resource
@@ -68,27 +73,50 @@ header i@(Input {..})
 
 moduleDecl ∷ ModName → Name → Doc
 moduleDecl modName symName
-    = hsep [ text "module"
-           , text (modString modName)
-           , lparen
-           , ppr symName
-           , rparen
-           , text "where"
-           ]
+    = text "module" <+> text (modString modName) $+$
+      nest 4 (vcat [ lparen <+> ppr symName
+                   , rparen
+                   , text "where"
+                   ])
+
+importDecls ∷ Imports ImportOp → Doc
+importDecls = vcat ∘ map pprImport ∘ toList
 
-importDecls ∷ ModMap → Doc
-importDecls = vcat ∘ map f ∘ M.toAscList
+pprImport ∷ ImportOp → Doc
+pprImport (QualifiedImp {..})
+    = hsep [ text "import"
+           , text "qualified"
+           , text (modString impModule)
+           , text "as"
+           , text (modString impAlias)
+           ]
+pprImport (UnqualifiedImp {impNames = Nothing, ..})
+    = hsep [ text "import"
+           , text (modString impModule)
+           ]
+pprImport (UnqualifiedImp {impNames = Just ns, ..})
+    = hsep [ text "import"
+           , text (modString impModule)
+           , hcat [ lparen
+                  , sep $ punctuate comma
+                        $ map (uncurry pprImpName)
+                        $ toList ns
+                  , rparen
+                  ]
+           ]
     where
-      f ∷ (ModName, Maybe ModName) → Doc
-      f (m, Nothing) = hsep [ text "import"
-                            , text (modString m)
-                            ]
-      f (m, Just m') = hsep [ text "import"
-                            , text "qualified"
-                            , text (modString m)
-                            , text "as"
-                            , text (modString m')
-                            ]
+      pprImpName ∷ NameSpace → OccName → Doc
+      pprImpName TcClsName (occString → o)
+          = hcat [text o, text "(..)"]
+      pprImpName _         (occString → o)
+          | needParen o = hcat [lparen, text o, rparen]
+          | otherwise   = text o
+
+      needParen ∷ String → Bool
+      needParen (head → c)
+          | isPunctuation c = True
+          | isSymbol      c = True
+          | otherwise       = False
 
 entityTag ∷ Name
 entityTag = mkName "entityTag"
@@ -132,39 +160,38 @@ resourceE i = [| emptyResource {
 resGetE ∷ Input → Q Exp
 resGetE i
     | useGZip i
-        = [| Just $
-             do foundEntity $(varE entityTag) $(varE lastModified)
-                setContentType $(varE contentType)
-
-                gzipAllowed ← isEncodingAcceptable $(varE gzipEncoding)
-                if gzipAllowed then
-                    do setContentEncoding [$(varE gzipEncoding)]
-                       putChunks $(varE gzippedData)
-                else
-                    putChunks (decompress $(varE gzippedData))
+        = [| Just ( do foundEntity $(varE entityTag) $(varE lastModified)
+                       setContentType $(varE contentType)
+
+                       gzipAllowed ← isEncodingAcceptable $(varE gzipEncoding)
+                       if gzipAllowed then
+                           do setContentEncoding [$(varE gzipEncoding)]
+                              putChunks $(varE gzippedData)
+                       else
+                           putChunks (decompress $(varE gzippedData))
+                  )
            |]
     | otherwise
-        = [| Just $
-             do foundEntity $(varE entityTag) $(varE lastModified)
-                setContentType $(varE contentType)
-                putChunks $(varE rawData)
+        = [| Just ( do foundEntity $(varE entityTag) $(varE lastModified)
+                       setContentType $(varE contentType)
+                       putChunks $(varE rawData)
+                  )
            |]
 
 resHeadE ∷ Input → Q Exp
 resHeadE i
     | useGZip i
-        = [| Just $
-             do foundEntity $(varE entityTag) $(varE lastModified)
-                setContentType $(varE contentType)
+        = [| Just ( do foundEntity $(varE entityTag) $(varE lastModified)
+                       setContentType $(varE contentType)
 
-                gzipAllowed ← isEncodingAcceptable $(varE gzipEncoding)
-                when gzipAllowed (setContentEncoding [$(varE gzipEncoding)])
+                       gzipAllowed ← isEncodingAcceptable $(varE gzipEncoding)
+                       when gzipAllowed (setContentEncoding [$(varE gzipEncoding)])
+                  )
            |]
     | otherwise
-        = [| Just $
-             do foundEntity $(varE entityTag)
-                            $(varE lastModified)
-                setContentType $(varE contentType)
+        = [| Just ( do foundEntity $(varE entityTag) $(varE lastModified)
+                       setContentType $(varE contentType)
+                  )
            |]
 
 eTagDecl ∷ Input → Q [Dec]
@@ -196,6 +223,29 @@ binDecl i@(Input {..})
                    , valD (varP rawData) (normalB (liftLazyByteString iRawData)) []
                    ]
 
+rules ∷ Rules
+rules = [ qualifyAll   "Codec.Compression.GZip"              "G"
+        , unqualify    ''CIAscii                             "Data.Ascii"
+        , qualifyAll   "Data.Ascii"                          "A"
+        , qualifyAll   "Data.ByteString.Char8"               "B"
+        , qualifyAll   "Data.ByteString.Lazy.Internal"       "L"
+        , qualifyAll   "Data.Map"                            "M"
+        , qualifyAll   "Data.Text"                           "T"
+        , unqualifyAll "Network.HTTP.Lucu.ETag"              "Network.HTTP.Lucu"
+        , unqualifyAll "Network.HTTP.Lucu.Resource"          "Network.HTTP.Lucu"
+        , unqualifyAll "Network.HTTP.Lucu.Resource.Internal" "Network.HTTP.Lucu"
+        , unqualifyAll "Network.HTTP.Lucu.MIMEParams"        "Network.HTTP.Lucu"
+        , unqualifyAll "Network.HTTP.Lucu.MIMEType"          "Network.HTTP.Lucu"
+        , unqualify    'when                                 "Control.Monad"
+        , unqualify    '(%)                                  "Data.Ratio"
+        , unqualify    ''DiffTime                            "Data.Time"
+        , unqualifyIn  'ModifiedJulianDay  ''Day             "Data.Time"
+        , unqualifyIn  'UTCTime            ''UTCTime         "Data.Time"
+        , unqualifyIn  'False              ''Bool            "Prelude"
+        , unqualifyIn  'Just               ''Maybe           "Prelude"
+        , unqualify    'fromRational                         "Prelude"
+        ]
+
 pprInput ∷ Quasi m ⇒ Input → ModName → Name → m Doc
 pprInput i modName symName
     = do decls ← runQ $ sequence [ resourceDecl i symName
@@ -204,7 +254,7 @@ pprInput i modName symName
                                  , contTypeDecl i
                                  , binDecl i
                                  ]
-         let (decls', mods) = rewriteNames decls
+         let (decls', mods) = rewriteNames rules decls
          return $ vcat [ header i
                        , moduleDecl modName symName
                        , importDecls mods
index 37fbfbb45c1b657566fae58662d598f8891ebe7e..e4ec8322f753ac8284dab224af85a3bf17ad8113 100644 (file)
 {-# LANGUAGE
-    UnicodeSyntax
+    FlexibleInstances
+  , GeneralizedNewtypeDeriving
+  , RecordWildCards
+  , UnicodeSyntax
   #-}
+-- |An internal module for rewriting 'Name's in Template Haskell AST.
 module Network.HTTP.Lucu.Implant.Rewrite
-    ( ModMap
+    ( NamePat(..)
+    , RewriteOp(..)
+
+    , Imports
+    , ImportOp(..)
+
+    , Rules
+    , RewriteRule(..)
+    , qualifyAll
+    , unqualify
+    , unqualifyIn
+    , unqualifyAll
+
     , rewriteNames
     )
     where
 import Control.Applicative
 import Control.Monad.State
 import Data.Data
-import Data.Generics.Aliases
+import Data.Foldable
+import Data.Generics.Aliases hiding (GT)
 import Data.Generics.Schemes
-import Data.Map (Map)
-import qualified Data.Map as M
+import Data.Monoid
 import Data.Monoid.Unicode
+import Data.Set (Set)
+import qualified Data.Set as S
 import Language.Haskell.TH.Syntax
+import Prelude
 import Prelude.Unicode
 
--- FIXME: Document at least these data types.
-type ModMap    = Map ModName (Maybe ModName)
-data RewriteTo = Qual (Maybe ModName) ModName | UnQual (Maybe ModName)
-
-rewriteNames ∷ Data d ⇒ d → (d, ModMap)
-rewriteNames
-    = flip runState (∅) ∘ gmapM (everywhereM (mkM rewriteName))
-
-rewriteName ∷ (Functor m, Monad m)
-            ⇒ Name
-            → StateT ModMap m Name
-rewriteName (Name o fl) = Name o <$> rewriteNameFlavour fl
-
-rewriteNameFlavour ∷ (Functor m, Monad m)
-                   ⇒ NameFlavour
-                   → StateT ModMap m NameFlavour
-rewriteNameFlavour fl
-    = case getModName fl of
-        Nothing → return fl
-        Just m  → do let r = M.lookup m modules
-                     insertIntoModMap m r
-                     return $ setModName r fl
-
-insertIntoModMap ∷ Monad m
-                 ⇒ ModName
-                 → Maybe RewriteTo
-                 → StateT ModMap m ()
-insertIntoModMap _ (Just (Qual   (Just m) m')) = modify $ M.insert m (Just m')
-insertIntoModMap m (Just (Qual   Nothing  m')) = modify $ M.insert m (Just m')
-insertIntoModMap _ (Just (UnQual (Just m)   )) = modify $ M.insert m Nothing
-insertIntoModMap _ (Just (UnQual Nothing    )) = return ()
-insertIntoModMap m Nothing                     = modify $ M.insert m Nothing
-
-getModName ∷ NameFlavour → Maybe ModName
-getModName (NameQ     m) = Just m
-getModName (NameG _ _ m) = Just m
-getModName _             = Nothing
-
-setModName ∷ Maybe RewriteTo → NameFlavour → NameFlavour
-setModName (Just (Qual _ m)) (NameQ _    ) = NameQ m
-setModName (Just (Qual _ m)) (NameG _ _ _) = NameQ m
-setModName (Just (UnQual _)) (NameQ _    ) = NameS
-setModName (Just (UnQual _)) (NameG _ _ _) = NameS
-setModName Nothing           (NameQ _    ) = NameS
-setModName Nothing           (NameG _ _ _) = NameS
-setModName _ _ = error "setModName: internal error"
-
-modules ∷ Map ModName RewriteTo
-modules
-    = M.fromList
-      [ ( mkModName "Codec.Compression.GZip"
-        , Qual Nothing $ mkModName "G"
-        )
-      , ( mkModName "Data.Ascii"
-        , Qual Nothing $ mkModName "A"
-        )
-      , ( mkModName "Data.ByteString.Char8"
-        , Qual Nothing $ mkModName "B"
-        )
-      , ( mkModName "Data.ByteString.Lazy.Internal"
-        , Qual Nothing $ mkModName "L"
-        )
-      , ( mkModName "Data.ByteString.Unsafe"
-        , Qual Nothing $ mkModName "B"
-        )
-      , ( mkModName "Data.Map"
-        , Qual Nothing $ mkModName "M"
-        )
-      , ( mkModName "Data.Maybe"
-        , UnQual Nothing
-        )
-      , ( mkModName "Data.Text"
-        , Qual Nothing $ mkModName "T"
-        )
-      , ( mkModName "Data.Time.Calendar.Days"
-        , UnQual $ Just $ mkModName "Data.Time"
-        )
-      , ( mkModName "Data.Time.Clock.Scale"
-        , UnQual $ Just $ mkModName "Data.Time"
-        )
-      , ( mkModName "Data.Time.Clock.UTC"
-        , UnQual $ Just $ mkModName "Data.Time"
-        )
-      , ( mkModName "GHC.Base"
-        , UnQual Nothing
-        )
-      , ( mkModName "GHC.Bool"
-        , UnQual Nothing
-        )
-      , ( mkModName "GHC.IO"
-        -- for 'unsafePerformIO', but rather problematic...
-        , UnQual $ Just $ mkModName "System.IO.Unsafe"
-        )
-      , ( mkModName "GHC.Real"
-        -- for '%', but rather problematic...
-        , UnQual $ Just $ mkModName "Data.Ratio"
-        )
-      , ( mkModName "Network.HTTP.Lucu.ETag"
-        , UnQual $ Just $ mkModName "Network.HTTP.Lucu"
-        )
-      , ( mkModName "Network.HTTP.Lucu.MIMEType"
-        , UnQual $ Just $ mkModName "Network.HTTP.Lucu"
-        )
-      , ( mkModName "Network.HTTP.Lucu.Resource"
-        , UnQual $ Just $ mkModName "Network.HTTP.Lucu"
-        )
-      , ( mkModName "Network.HTTP.Lucu.Resource.Internal"
-        , UnQual $ Just $ mkModName "Network.HTTP.Lucu"
-        )
-      ]
+-- |Pattern for 'Name's. 'Just' represents a perfect matching pattern,
+-- and 'Nothing' represensts a wildcard.
+data NamePat
+    = NamePat !(Maybe ModName) !(Maybe OccName)
+
+-- |Instruction for rewriting 'Name's.
+data RewriteOp
+    = Identity
+    | Unqualify
+    | Qualify !ModName
+
+-- |A 'Set' of modules and names to be imported.
+newtype Imports α = Imports (Set α)
+    deriving Foldable
+
+-- |Instruction for declaring module imports.
+data ImportOp
+    = -- |> import qualified M as A
+      QualifiedImp {
+        impModule ∷ !ModName
+      , impAlias  ∷ !ModName
+      }
+      -- |> import M
+      --
+      -- or
+      --
+      -- > import M (a, b, c, ...)
+    | UnqualifiedImp {
+        impModule ∷ !ModName
+      , impNames  ∷ !(Maybe (Set (NameSpace, OccName)))
+      }
+    deriving Eq
+
+-- |List of 'RewriteRule's.
+type Rules = [RewriteRule]
+
+-- |Instruction for rewriting 'Name's and declaring module imports.
+data RewriteRule
+    = RewriteRule {
+        rrPat  ∷ !NamePat
+      , rrOp   ∷ !RewriteOp
+      , rrImps ∷ !(Imports ImportOp)
+      }
+
+instance Ord ImportOp where
+    α `compare` β
+        | impModule α < impModule β = LT
+        | impModule α > impModule β = GT
+        | otherwise
+            = case (α, β) of
+                (QualifiedImp   {}, QualifiedImp   {})
+                    → impAlias α `compare` impAlias β
+                (QualifiedImp   {}, _                )
+                    → GT
+                (UnqualifiedImp {}, UnqualifiedImp {})
+                    → impNames α `compare` impNames β
+                (UnqualifiedImp {}, _                )
+                    → LT
+
+instance Monoid (Imports ImportOp) where
+    mempty
+        = Imports (∅)
+    mappend (Imports α) (Imports β)
+        = Imports (foldl' insertImp α β)
+
+insertImp ∷ Set ImportOp → ImportOp → Set ImportOp
+insertImp α qi@(QualifiedImp   {}) = S.insert qi α
+insertImp α ui@(UnqualifiedImp {})
+    = case find sameMod α of
+        Nothing  → S.insert ui α
+        Just ui' → S.insert (merge ui') (S.delete ui' α)
+    where
+      sameMod ∷ ImportOp → Bool
+      sameMod ui'@(UnqualifiedImp {})
+          = impModule ui ≡ impModule ui'
+      sameMod _
+          = False
+
+      merge ∷ ImportOp → ImportOp
+      merge ui'
+          = case (impNames ui, impNames ui') of
+              (Nothing, _      ) → ui
+              (_      , Nothing) → ui'
+              (Just s , Just s') → ui { impNames = Just (s ⊕ s') }
+
+-- |@'qualifyAll' module alias@: qualify every symbols defined in
+-- @module@ with @alias@.
+qualifyAll ∷ String → String → RewriteRule
+qualifyAll m a
+    = let pat = NamePat (Just (mkModName m)) Nothing
+          rop = Qualify (mkModName a)
+          iop = QualifiedImp (mkModName m) (mkModName a)
+      in
+        RewriteRule pat rop (Imports (S.singleton iop))
+
+-- |@'unqualify' name module@: unqualify the symbol @name@ with
+-- importing @module@.
+unqualify ∷ Name → String → RewriteRule
+unqualify (Name o _) m
+    = let pat = NamePat Nothing (Just o)
+          iop = UnqualifiedImp (mkModName m)
+                $ Just
+                $ S.singleton (VarName, o)
+      in
+        RewriteRule pat Unqualify (Imports (S.singleton iop))
+
+-- |@'unqualifyIn' name tycl module@: unqualify a constructor, field
+-- name, or whatever resides in the type or class @tycl@ with
+-- importing @module@.
+unqualifyIn ∷ Name → Name → String → RewriteRule
+unqualifyIn (Name name _) (Name tycl _) m
+    = let pat = NamePat Nothing (Just name)
+          iop = UnqualifiedImp (mkModName m)
+                $ Just
+                $ S.singleton (TcClsName, tycl)
+      in
+        RewriteRule pat Unqualify (Imports (S.singleton iop))
+
+-- |@'unqualifyAll' origMod impMod@: unqualify every symbols
+-- defined in @origMod@ with importing @impMod@.
+unqualifyAll ∷ String → String → RewriteRule
+unqualifyAll origMod impMod
+    = let pat = NamePat (Just (mkModName origMod)) Nothing
+          iop = UnqualifiedImp (mkModName impMod) Nothing
+      in
+        RewriteRule pat Unqualify (Imports (S.singleton iop))
+
+-- |@'rewriteNames' rules d@ rewrites each and every 'Name's included
+-- in @d@ according to the name-rewriting @rules@ while at the same
+-- time building a set of modules to be imported.
+rewriteNames ∷ Data d ⇒ Rules → d → (d, Imports ImportOp)
+rewriteNames rules = flip runState (∅) ∘ gmapM (everywhereM (mkM f))
+    where
+      f ∷ (Functor m, Monad m) ⇒ Name → StateT (Imports ImportOp) m Name
+      f n = case findRule rules n of
+              Nothing → fail $ "No rules matches to name: " ⧺ showName n
+              Just r  → applyRule r n
+
+findRule ∷ Rules → Name → Maybe RewriteRule
+findRule _  (Name _  NameS       ) = Just identityRule
+findRule rs (Name o (NameQ     m)) = find (matchPat m o ∘ rrPat) rs
+findRule _  (Name _ (NameU _    )) = Just identityRule
+findRule rs (Name o (NameG _ _ m)) = find (matchPat m o ∘ rrPat) rs
+findRule _  _                      = Nothing
+
+identityRule ∷ RewriteRule
+identityRule = RewriteRule {
+                 rrPat  = NamePat Nothing Nothing
+               , rrOp   = Identity
+               , rrImps = (∅)
+               }
+
+matchPat ∷ ModName → OccName → NamePat → Bool
+matchPat m o (NamePat mp op)
+    = maybe True (≡ m) mp ∧ maybe True (≡ o) op
+
+applyRule ∷ (Functor m, Monad m)
+          ⇒ RewriteRule
+          → Name
+          → StateT (Imports ImportOp) m Name
+applyRule (RewriteRule {..}) n
+    = modify (⊕ rrImps) *> pure (rewrite rrOp n)
+
+rewrite ∷ RewriteOp → Name → Name
+rewrite Identity    n          = n
+rewrite Unqualify   (Name o _) = Name o NameS
+rewrite (Qualify m) (Name o _) = Name o (NameQ m)
index a28a80461ede0d502d4de626121731c232c940cc..155003024b9c2e82989bc017bdcb0f58ed8541f6 100644 (file)
@@ -10,8 +10,6 @@
   #-}
 -- |Parse \"multipart/form-data\" based on RFC 2388:
 -- <http://tools.ietf.org/html/rfc2388>
---
--- You usually don't have to use this module directly.
 module Network.HTTP.Lucu.MultipartForm
     ( FormData(..)
     , parseMultipartFormData
index 660f550a9353cc687a56ae0e6e422ecc41a7e3f1..db83b9c20107818236b1292969ad17e9d7c3e231 100644 (file)
@@ -1,8 +1,7 @@
 {-# LANGUAGE
     UnicodeSyntax
   #-}
--- |This is an auxiliary parser utilities. You usually don't have to
--- use this module directly.
+-- |A set of auxiliary parser utilities.
 module Network.HTTP.Lucu.Parser
     ( atMost
     , finishOff
index dd9c34b00fc54935c051e4dd560cc123a7c28402..b9668e067d47a281516c9fc1cc0c6835a693a20a 100644 (file)
@@ -4,6 +4,7 @@
   , TypeFamilies
   , UnicodeSyntax
   #-}
+-- |Type class for things behaves like a 'So.Socket'.
 module Network.HTTP.Lucu.SocketLike
     ( SocketLike(..)
     )
index 55acf0adc481929338a4639c7c88118f614a7e76..18370fab68cc3aa673b1ef6a85bf11bd3a87eb25 100644 (file)
@@ -4,8 +4,7 @@
   , TemplateHaskell
   , UnicodeSyntax
   #-}
--- |Utility functions used internally in the Lucu httpd. These
--- functions may be useful too for something else.
+-- |Utility functions used internally in this package.
 module Network.HTTP.Lucu.Utils
     ( splitBy
     , quoteStr
@@ -26,7 +25,6 @@ import Data.Ascii (Ascii, CIAscii, AsciiBuilder)
 import qualified Data.Ascii as A
 import Data.ByteString (ByteString)
 import qualified Data.ByteString.Char8 as Strict
-import qualified Data.ByteString.Unsafe as Strict
 import qualified Data.ByteString.Lazy.Internal as Lazy
 import Data.Char
 import Data.List hiding (last)
@@ -42,7 +40,6 @@ import Language.Haskell.TH.Syntax
 import Network.URI
 import Prelude hiding (last)
 import Prelude.Unicode
-import System.IO.Unsafe
 
 -- |>>> splitBy (== ':') "ab:c:def"
 -- ["ab", "c", "def"]
@@ -129,17 +126,7 @@ liftLazyByteString = Lazy.foldrChunks f [| Lazy.Empty |]
 
 -- |Convert an 'Ascii' to an 'Exp' representing it as a literal.
 liftAscii ∷ Ascii → Q Exp
-liftAscii a = [| A.unsafeFromByteString
-                 $ unsafePerformIO
-                 $ Strict.unsafePackAddressLen $len $ptr
-               |]
-    where
-      bs ∷ Strict.ByteString
-      bs = A.toByteString a
-
-      len, ptr ∷ Q Exp
-      len = lift $ Strict.length bs
-      ptr = litE $ stringPrimL $ Strict.unpack bs
+liftAscii a = [| A.unsafeFromByteString $(liftByteString $ A.toByteString a) |]
 
 -- |Convert a 'CIAscii' to an 'Exp' representing it as a literal.
 liftCIAscii ∷ CIAscii → Q Exp
@@ -162,18 +149,11 @@ liftMap liftK liftV m
 -- |Convert an 'UTCTime' to an 'Exp' representing it as a literal.
 liftUTCTime ∷ UTCTime → Q Exp
 liftUTCTime (UTCTime {..})
-    = [| UTCTime {
-           utctDay     = $(liftDay utctDay)
-         , utctDayTime = $(liftDiffTime utctDayTime)
-         }
-       |]
+    = [| UTCTime $(liftDay utctDay) $(liftDiffTime utctDayTime) |]
 
 liftDay ∷ Day → Q Exp
 liftDay (ModifiedJulianDay {..})
-    = [| ModifiedJulianDay {
-           toModifiedJulianDay = $(lift toModifiedJulianDay)
-         }
-       |]
+    = [| ModifiedJulianDay $(lift toModifiedJulianDay) |]
 
 liftDiffTime ∷ DiffTime → Q Exp
 liftDiffTime dt = [| fromRational ($n % $d) ∷ DiffTime |]
index 959fcd444e75913eda00e766a844e4d8578d1b1d..4b7c9e60a562ad9e29e1571f1a3d93ae1a0316be 100644 (file)
@@ -5,8 +5,8 @@ type: :task
 component: Lucu
 release: Lucu-1.0
 reporter: PHO <pho@cielonegro.org>
-status: :unstarted
-disposition: 
+status: :closed
+disposition: :fixed
 creation_time: 2011-11-07 15:28:34.417982 Z
 references: []
 
@@ -16,4 +16,8 @@ log_events:
   - PHO <pho@cielonegro.org>
   - created
   - ""
+- - 2011-11-11 05:29:34.851297 Z
+  - PHO <pho@cielonegro.org>
+  - closed with disposition fixed
+  - It has now cleaner code than before, but not simple at all. I'm done anyway.
 git_branch: template-haskell
index cc534f4648d16242d8d4f33147d30acee9b61f7d..9e8e549b72ef493e9fc6dcb26c0a223c67b0c4b1 100644 (file)
@@ -18,6 +18,7 @@ HPC      ?= hpc
 DITZ     ?= ditz
 
 CONFIGURE_ARGS ?= --disable-optimization
+HADDOCK_OPTS   ?= --hyperlink-source
 HLINT_OPTS     ?= --cross --report=dist/report.html
 
 SETUP_FILE := $(wildcard Setup.*hs)
@@ -81,7 +82,7 @@ clean: clean-hook
 clean-hook:
 
 doc: setup-config
-       ./Setup haddock
+       ./Setup haddock $(HADDOCK_OPTS)
 
 install: build
        $(SUDO) ./Setup install
index 0902512ce6eba5e77918566db661895ee728266a..37c59cb9ab74d6169cb31ac88dfd7e946ed29006 100644 (file)
@@ -27,6 +27,6 @@ dist/MiseRafturai.hs: mise-rafturai.html $(IMPLANT)
 ImplantedSmall.hs: dist/SmallFile.hs
 dist/SmallFile.hs: small-file.txt $(IMPLANT)
        mkdir -p dist
-       $(IMPLANT) -m SmallFile -o $@ $<
+       $(IMPLANT) -m SmallFile -t "text/plain; charset=\"UTF-8\"" -o $@ $<
 
 .PHONY: build run clean