From: Julien Moutinho Date: Wed, 10 Jan 2024 14:12:40 +0000 (+0100) Subject: impl: use newer symantic-base X-Git-Url: https://git.sourcephile.fr/haskell/literate-web.git/commitdiff_plain impl: use newer symantic-base --- diff --git a/Makefile b/Makefile index 1b16ba6..41fbb85 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,8 @@ $(project)-test.eventlog $(project)-test.prof: t/repl tests/repl: cabal repl $(CABAL_REPL_FLAGS) $(CABAL_TEST_FLAGS) --enable-tests $(project)-tests t/ghcid tests/ghcid: - ghcid $(GHCID_OPTIONS) --command 'cabal repl $(CABAL_REPL_FLAGS) $(CABAL_TEST_FLAGS) $(project):tests' --test ":main $(TEST_OPTIONS)" + ghcid $(GHCID_OPTIONS) --command 'cabal repl $(CABAL_REPL_FLAGS) $(project) $(addprefix --repl-options ,$(REPL_OPTIONS))' \ + --run=':! ghcid $(GHCID_OPTIONS) --command "cabal repl $(CABAL_REPL_FLAGS) $(CABAL_TEST_FLAGS) $(project):tests" --test ":main $(TEST_OPTIONS)"' .PHONY: benchmarks/time bt benchmarks/time: diff --git a/flake.lock b/flake.lock index 539ed95..aa67ae1 100644 --- a/flake.lock +++ b/flake.lock @@ -1,12 +1,31 @@ { "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1667077288, - "narHash": "sha256-bdC8sFNDpT0HK74u9fUkpbf1MEzVYJ+ka7NXCdgBoaA=", + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", "owner": "numtide", "repo": "flake-utils", - "rev": "6ee9ebb6b1ee695d2cacc4faa053a7b9baa76817", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", "type": "github" }, "original": { @@ -30,13 +49,34 @@ "type": "github" } }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1686237827, - "narHash": "sha256-fAZB+Zkcmc+qlauiFnIH9+2qgwM0NO/ru5pWEw3tDow=", + "lastModified": 1701389149, + "narHash": "sha256-rU1suTIEd5DGCaAXKW6yHoCfR1mnYjOXQFOaH7M23js=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "81ed90058a851eb73be835c770e062c6938c8a9e", + "rev": "5de0b32be6e85dc1a9404c75131316e4ffbc634c", "type": "github" }, "original": { @@ -44,19 +84,38 @@ "type": "indirect" } }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1685801374, + "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, "pre-commit-hooks": { "inputs": { + "flake-compat": "flake-compat", "flake-utils": "flake-utils", + "gitignore": "gitignore", "nixpkgs": [ "nixpkgs" - ] + ], + "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1667992213, - "narHash": "sha256-8Ens8ozllvlaFMCZBxg6S7oUyynYx2v7yleC5M0jJsE=", + "lastModified": 1692274144, + "narHash": "sha256-BxTQuRUANQ81u8DJznQyPmRsg63t4Yc+0kcyq6OLz8s=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "ebcbfe09d2bd6d15f68de3a0ebb1e4dcb5cd324b", + "rev": "7e3517c03d46159fdbf8c0e5c97f82d5d4b0c8fa", "type": "github" }, "original": { @@ -102,11 +161,11 @@ "pre-commit-hooks": "pre-commit-hooks_2" }, "locked": { - "lastModified": 1670713703, - "narHash": "sha256-9U71SGSWzdFbrvCyo6IbNI8bhoM4Guz9nCGIqKJ7ttQ=", + "lastModified": 1693433189, + "narHash": "sha256-k4bWG1z6qvt7Cee15H0xwgVngBBQRqhFm4rp6JHn8Qg=", "ref": "refs/heads/main", - "rev": "6ce5a7f09fd4bc5bc7df3fd4bf797e8f1803cd88", - "revCount": 81, + "rev": "9d93dbea0b1173304ac78b695371b3e14d0d8b9f", + "revCount": 100, "type": "git", "url": "git://git.sourcephile.fr/haskell/symantic-base" }, @@ -114,6 +173,21 @@ "type": "git", "url": "git://git.sourcephile.fr/haskell/symantic-base" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 7616819..b245509 100644 --- a/flake.nix +++ b/flake.nix @@ -4,6 +4,7 @@ #nixpkgs.url = "github:NixOS/nixpkgs/cdead16a444a3e5de7bc9b0af8e198b11bb01804"; pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix"; pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs"; + #symantic-base.url = "git+file:///home/julm/work/sourcephile/haskell/symantic-base"; symantic-base.url = "git://git.sourcephile.fr/haskell/symantic-base"; symantic-base.inputs.nixpkgs.follows = "nixpkgs"; }; @@ -18,10 +19,13 @@ ${pkg} = doBenchmark (buildFromSdist (hfinal.callCabal2nix pkg ./. { })); symantic-base = buildFromSdist (hfinal.callCabal2nix "symantic-base" inputs.symantic-base { }); #url-slug = buildFromSdist (hfinal.callCabal2nix "url-slug" inputs.url-slug { }); - doctest = dontCheck (doJailbreak (unmarkBroken hsuper.doctest)); - hspec-contrib = dontCheck (doJailbreak (unmarkBroken hsuper.hspec-contrib)); + #doctest = dontCheck (doJailbreak (unmarkBroken hsuper.doctest)); + #hspec-contrib = dontCheck (doJailbreak (unmarkBroken hsuper.hspec-contrib)); #relude = dontCheck (doJailbreak (unmarkBroken hsuper.relude)); - scotty = dontCheck (doJailbreak (unmarkBroken hsuper.scotty)); + #scotty = dontCheck (doJailbreak (unmarkBroken hsuper.scotty)); + mvc = dontCheck (doJailbreak (unmarkBroken hsuper.mvc)); + mvc-updates = dontCheck (doJailbreak (unmarkBroken ( + appendPatch hsuper.mvc-updates ./0001-mvc-updates-fix-L.pretraverseM.patch))); }); }); in diff --git a/literate-web.cabal b/literate-web.cabal index 9312c1d..188a26f 100644 --- a/literate-web.cabal +++ b/literate-web.cabal @@ -42,7 +42,6 @@ source-repository head common boilerplate default-language: Haskell2010 default-extensions: - NoImplicitPrelude BlockArguments DataKinds DefaultSignatures @@ -56,6 +55,7 @@ common boilerplate LambdaCase MultiParamTypeClasses NamedFieldPuns + NoImplicitPrelude NumericUnderscores OverloadedStrings RecordWildCards @@ -88,10 +88,13 @@ common library-deps , directory >=1.3 , filepath >=1.4 , filepattern >=0.1 + , ghc-prim , hashable , http-client >=0.6 , http-media >=0.7 , monad-classes + , mvc + , mvc-updates , peano , reflection , symantic-base >=0.5 @@ -107,23 +110,36 @@ common library-deps , warp , websockets >=0.12 +-- , pipes +-- , pipes-concurrency +-- , pipes-group +-- , pipes-parse +-- , pipes-safe library import: boilerplate, library-deps hs-source-dirs: src exposed-modules: Literate.Web - Literate.Web.Semantics.Compiler Literate.Web.Semantics.Addresser + Literate.Web.Semantics.Compiler Literate.Web.Syntaxes Literate.Web.Types.MIME Literate.Web.Types.URL +--Literate.Web.Semantics.Server +--Literate.Web.Semantics.Client +--Literate.Web.Decoder +--Literate.Web.Encoder +--Literate.Web.Generator +--Literate.Web.MIME + library relactive import: boilerplate, library-deps hs-source-dirs: src build-depends: , async , contravariant >=1.5 + , monad-classes , stm exposed-modules: @@ -135,14 +151,6 @@ library relactive Control.Reactive.TVar Control.Reactive.Value --- Literate.Web.Semantics.Server --- Literate.Web.Semantics.Client ---Literate.Web.Decoder ---Literate.Web.Encoder ---Literate.Web.Generator ---Literate.Web.MIME - ---Literate.Web.Decoder test-suite literate-web-tests -- library-deps is only to have ghcid reloaded on changes in src import: boilerplate, library-deps @@ -159,8 +167,6 @@ test-suite literate-web-tests Paths_literate_web Utils - -- Examples.Ex02 - --HUnits autogen-modules: Paths_literate_web build-depends: , base >=4.6 && <5 @@ -207,7 +213,6 @@ benchmark weigh , relude >=1 , weigh ---, relactive executable async import: boilerplate, library-deps hs-source-dirs: executables/async diff --git a/src/Literate/Web/Semantics/Addresser.hs b/src/Literate/Web/Semantics/Addresser.hs index a171fa5..7876b2e 100644 --- a/src/Literate/Web/Semantics/Addresser.hs +++ b/src/Literate/Web/Semantics/Addresser.hs @@ -1,96 +1,36 @@ -- For Addresser -{-# LANGUAGE DeriveFunctor #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE PartialTypeSignatures #-} {-# LANGUAGE RankNTypes #-} +-- For Dataable {-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE InstanceSigs #-} -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE ConstraintKinds #-} module Literate.Web.Semantics.Addresser where -import Control.Applicative (Applicative (..)) -import Control.Monad (Monad (..), forM, forM_, join, sequence, (>=>), (>>=)) -import Control.Monad.Classes qualified as MC -import Control.Monad.Trans.Class qualified as MT -import Control.Monad.Trans.Reader qualified as MT -import Control.Monad.Trans.State qualified as MT -import Control.Monad.Trans.Writer qualified as MT -import Type.Reflection ((:~:) (..)) import Data.Bool -import Data.ByteString.Lazy qualified as BSL -import Data.Either (Either (..)) -import Data.Eq (Eq (..)) -import Data.Foldable (toList) -import Data.Monoid (Monoid(..)) -import Data.Function (const, id, ($), (.)) -import Data.Functor (Functor (..), (<$>)) -import Data.Kind (Constraint, Type) -import Data.List qualified as List +import Data.Function (id, ($), (.)) import Data.Maybe (Maybe (..)) -import Data.Ord (Ord (..)) -import Data.Proxy (Proxy (..)) +import Data.Monoid (Monoid (..)) import Data.Semigroup (Semigroup (..)) -import Data.String (fromString) -import Data.Text (Text) -import Data.Text qualified as Text -import Data.Tuple (curry) import GHC.Generics (Generic) -import GHC.Stack (HasCallStack) import Literate.Web.Syntaxes -import Literate.Web.Types.MIME import Literate.Web.Types.URL import Symantic qualified as Sym -import System.Directory qualified as Sys -import System.FilePath qualified as Sys -import System.FilePattern.Directory qualified as Sys -import System.IO qualified as Sys import Text.Show (Show (..)) -- * Type 'Addresser' + +-- Interpreter building 'Address'. data Addresser a = Addresser { unAddresser :: forall next. (Address -> next) -> a --> next } --- * Type family '(-->)' --- | Convenient alias for a Tuples of Functions transformation -type (-->) a next = ToFIf (Sym.IsToF a) a next -infixr 0 --> -type family ToFIf t a next :: Type where --- For '<.>': curry. - ToFIf 'True (a, b) next = a --> b --> next --- For '<+>', request both branches. - ToFIf 'True (Either l r) next = (l --> next, r --> next) --- Useless to ask '()' as argument. - ToFIf 'True () next = next --- Enable a different return value for each function. - ToFIf 'True (Sym.Endpoint end a) next = next --- Everything else becomes a new argument. - ToFIf 'False a next = a -> next - --- ** Class 'UnToF' -type UnToF a = UnToFIf (Sym.IsToF a) a -class UnToFIf (t :: Bool) a where - unToF :: ToFIf t a next -> a -> next -instance UnToFIf 'True () where - unToF = const -instance (UnToF a, UnToF b) => UnToFIf 'True (a, b) where - unToF hab (a, b) = (unToF @(Sym.IsToF b) (unToF @(Sym.IsToF a) hab a)) b -instance (UnToF a, UnToF b) => UnToFIf 'True (Either a b) where - unToF (ha, hb) = \case - Left a -> unToF @(Sym.IsToF a) ha a - Right b -> unToF @(Sym.IsToF b) hb b -instance UnToFIf 'False a where - unToF = id - +-- | Nothing is needed at the 'Endpoint' for building an 'Address'. +type instance ToFEndpoint Addresser a next = next address :: Addresser a -> a --> Address address router = unAddresser router id instance PathSegmentable (Addresser) where - pathSegment s = Addresser \f -> f Address {addressPath = [s]} + pathSegment s = Addresser \f -> f Address{addressPath = [s]} instance Sym.SumFunctor Addresser where a <+> b = Addresser \n -> (unAddresser a n, unAddresser b n) @@ -98,19 +38,24 @@ instance Sym.ProductFunctor Addresser where a <.> b = Addresser \k -> unAddresser a \aA -> unAddresser b \bA -> k (bA <> aA) a <. b = Addresser \k -> unAddresser a \aA -> unAddresser b \bA -> k (bA <> aA) a .> b = Addresser \k -> unAddresser a \aA -> unAddresser b \bA -> k (bA <> aA) - instance ( Generic a , Sym.EoTOfRep a , sem ~ Addresser , Sym.IsToF a ~ 'False , e ~ Sym.EoT (Sym.ADT a) - , UnToF e - ) => Dataable__ a Addresser where - data__ :: sem (Sym.EoT (Sym.ADT a)) -> sem a - data__ a = Addresser (\a2n -> unToF @(Sym.IsToF e) @e (unAddresser a a2n) . Sym.eotOfadt) + , Sym.ToFable e + ) => + Dataable a Addresser + where + -- dataType :: sem (Sym.EoT (Sym.ADT a)) -> sem a + dataType a = Addresser (\a2n -> Sym.funOftof (unAddresser a a2n) . Sym.eotOfadt) +instance (Sym.IsToF a ~ 'False) => Optionable a Addresser where + optional aA = Addresser \k -> \case + Nothing -> k mempty + Just a -> unAddresser aA k a -instance end ~ Address => Responsable a ts m end (Addresser) where +instance (end ~ Address) => Responsable a ts m (Addresser) where response = Addresser ($ mempty) -- ** Type 'Address' diff --git a/src/Literate/Web/Semantics/Compiler.hs b/src/Literate/Web/Semantics/Compiler.hs index ec485c9..bd9f3a8 100644 --- a/src/Literate/Web/Semantics/Compiler.hs +++ b/src/Literate/Web/Semantics/Compiler.hs @@ -1,40 +1,32 @@ -- For CompilerToF +{-# LANGUAGE AllowAmbiguousTypes #-} +-- For CompilerToF {-# LANGUAGE ConstraintKinds #-} +-- For Dataable +{-# LANGUAGE InstanceSigs #-} -- For Output -{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE RankNTypes #-} -- For CompilerToF {-# LANGUAGE UndecidableInstances #-} --- For CompilerToF -{-# LANGUAGE AllowAmbiguousTypes #-} --- For Output -{-# LANGUAGE RankNTypes #-} --- For Dataable__ -{-# LANGUAGE InstanceSigs #-} module Literate.Web.Semantics.Compiler where import Control.Applicative (Applicative (..)) -import Control.Monad (Monad (..), forM, forM_, join, sequence, (>=>)) +import Control.Monad (Monad (..), forM_) import Control.Monad.Classes qualified as MC -import Control.Monad.Trans.Class qualified as MT -import Control.Monad.Trans.Reader qualified as MT import Data.Bool import Data.ByteString.Lazy qualified as BSL import Data.Either (Either (..)) -import Data.Eq (Eq (..)) import Data.Foldable (toList) -import Data.Function (const, id, ($), (.)) +import Data.Function (id, ($), (.)) import Data.Functor (Functor (..), (<$>)) -import Data.Kind (Constraint, Type) import Data.List qualified as List import Data.Maybe (Maybe (..)) -import Data.Ord (Ord (..)) import Data.Proxy (Proxy (..)) import Data.Semigroup (Semigroup (..)) -import Data.String (fromString) import Data.Text (Text) import Data.Text qualified as Text -import Data.Tuple (curry, fst, snd) +import Data.Tuple (fst, snd) import GHC.Generics (Generic) import GHC.Stack (HasCallStack) import Literate.Web.Syntaxes @@ -47,17 +39,24 @@ import System.FilePattern.Directory qualified as Sys import System.IO qualified as Sys import Text.Show (Show (..)) import Type.Reflection ((:~:) (..)) -import Prelude (undefined) -- * Type 'Compiler' -newtype Compiler m a = Compiler {unCompiler :: {-FIXME: is m required?-}m [Output a]} - -- deriving (Functor) + +-- | Interpreter building a static Web site. +-- +-- Embed a 'Monad' @m@ to give access to a model if need be. +newtype Compiler m a = Compiler {unCompiler :: m [Output a]} + +type instance Sym.ToFEndpoint (Compiler m) a next = (next :~: m BSL.ByteString, a) + +contentEndpoint :: a -> Sym.ToFEndpoint (Compiler m) a (m BSL.ByteString) +contentEndpoint = (Refl,) compile :: - MC.MonadExec Sys.IO m => + (MC.MonadExec Sys.IO m) => CompilerEnv -> Compiler m a -> - CompilerToF a (m BSL.ByteString) -> + (a --> m BSL.ByteString) -> m () compile CompilerEnv{..} router content = do outputs <- unCompiler router @@ -65,11 +64,11 @@ compile CompilerEnv{..} router content = do forM_ outputs $ \Output{..} -> do let destPath = ( List.intercalate "." $ - encodePath outputPath : - ( if List.null outputExts - then ["txt"] - else Text.unpack . encodePathSegment <$> outputExts - ) + encodePath outputPath + : ( if List.null outputExts + then ["txt"] + else Text.unpack . encodePathSegment <$> outputExts + ) ) -- hPutStrLn stderr $ "mkdir: " <> show (Sys.takeDirectory destPath) MC.exec @Sys.IO $ @@ -81,9 +80,11 @@ compile CompilerEnv{..} router content = do BSL.writeFile (compilerEnvDest Sys. destPath) $ bsl +outputBSL :: Output a -> (a --> m BSL.ByteString) -> m BSL.ByteString +outputBSL = outputData -compi :: Compiler m (m BSL.ByteString) -> Compiler m (m BSL.ByteString) -compi = id +compiler :: Compiler m (m BSL.ByteString) -> Compiler m (m BSL.ByteString) +compiler = id -- compile2 :: -- MC.MonadExec Sys.IO m => @@ -113,7 +114,7 @@ compi = id -- BSL.writeFile (compilerEnvDest Sys. destPath) $ -- outputBSL -manifest :: forall m a. Monad m => Compiler m a -> m [Sys.FilePath] +manifest :: forall m a. (Monad m) => Compiler m a -> m [Sys.FilePath] manifest router = do outputs <- unCompiler router return @@ -121,11 +122,11 @@ manifest router = do | out <- outputs , let destPath = ( List.intercalate "." $ - encodePath (outputPath out) : - ( if List.null (outputExts out) - then ["txt"] - else Text.unpack . encodePathSegment <$> outputExts out - ) + encodePath (outputPath out) + : ( if List.null (outputExts out) + then ["txt"] + else Text.unpack . encodePathSegment <$> outputExts out + ) ) ] @@ -146,27 +147,29 @@ manifest router = do -- { outputPath = outputPath oa <> outputPath ob -- , outputExts = outputExts oa <> outputExts ob -- } -instance Applicative m => Sym.ProductFunctor (Compiler m) where +instance (Applicative m) => Sym.ProductFunctor (Compiler m) where Compiler a <.> Compiler b = Compiler $ liftA2 (liftA2 (<.>)) a b Compiler a <. Compiler b = Compiler $ liftA2 (liftA2 (<.)) a b Compiler a .> Compiler b = Compiler $ liftA2 (liftA2 (.>)) a b ---instance Applicative m => Sym.AlternativeFunctor (Compiler m) where + +-- instance Applicative m => Sym.AlternativeFunctor (Compiler m) where -- Compiler a <|> Compiler b = Compiler (liftA2 (<>) a b) -instance Applicative m => Sym.SumFunctor (Compiler m) where +instance (Applicative m) => Sym.SumFunctor (Compiler m) where Compiler a <+> Compiler b = Compiler $ liftA2 (\as bs -> (a2e <$> as) <> (b2e <$> bs)) a b where - a2e :: Output a -> Output (Either a b) - a2e o = o{ outputData = outputData o . fst } - b2e :: Output b -> Output (Either a b) - b2e o = o{ outputData = outputData o . snd } + a2e :: Output a -> Output (Either a b) + a2e o = o{outputData = outputData o . fst} + b2e :: Output b -> Output (Either a b) + b2e o = o{outputData = outputData o . snd} -instance (Applicative m, CompilerUnToF a) => Optionable a (Compiler m) where +instance (Applicative m, Sym.ToFable a) => Optionable a (Compiler m) where optional (Compiler ma) = Compiler $ (\as -> (a2n <$> as) <> (a2j <$> as)) <$> ma where - a2n :: Output a -> Output (Maybe a) - a2n o = o{ outputData = ($ Nothing) } - a2j :: Output a -> Output (Maybe a) - a2j o = o{ outputData = \k -> outputData o $ compilerUnToF @(CompilerIsToF a) $ k . Just } + a2n :: Output a -> Output (Maybe a) + a2n o = o{outputData = ($ Nothing)} + a2j :: Output a -> Output (Maybe a) + a2j o = o{outputData = \k -> outputData o $ Sym.tofOffun $ k . Just} + -- optional (Compiler ma) = Compiler $ (\as -> (a2n <$> as) <> (a2j <$> as)) <$> ma -- --pure Nothing Sym.<|> (Just <$> ma) -- where @@ -175,252 +178,99 @@ instance (Applicative m, CompilerUnToF a) => Optionable a (Compiler m) where -- a2j :: Output a -> Output (Maybe a) -- a2j o = o{ outputData = outputData o . snd } -- --- ** Class 'CompilerUnToF' -type CompilerUnToF a = CompilerUnToFIf (CompilerIsToF a) a -class CompilerUnToFIf (t :: Bool) a where - compilerUnToF :: (a -> next) -> CompilerToFIf t a next -instance CompilerUnToFIf 'True () where - compilerUnToF = ($ ()) -instance (CompilerUnToF a, CompilerUnToF b) => CompilerUnToFIf 'True (a, b) where - compilerUnToF ab2n = compilerUnToF @(CompilerIsToF a) $ \a -> compilerUnToF @(CompilerIsToF b) $ \b -> ab2n (a,b) -instance (CompilerUnToF a, CompilerUnToF b) => CompilerUnToFIf 'True (Either a b) where - compilerUnToF e2n = ( compilerUnToF @(CompilerIsToF a) $ e2n . Left - , compilerUnToF @(CompilerIsToF b) $ e2n . Right - ) -instance CompilerUnToFIf 'False a where - compilerUnToF = id instance ( Generic a , Sym.RepOfEoT a , sem ~ Compiler m - , CompilerIsToF a ~ 'False - , e ~ Sym.EoT (Sym.ADT a) - , CompilerUnToF e + , Sym.IsToF a ~ 'False + , eot ~ Sym.EoT (Sym.ADT a) + , Sym.ToFable eot , Functor m - ) => Dataable__ a (Compiler m) where - data__ :: sem (Sym.EoT (Sym.ADT a)) -> sem a - data__ (Compiler e) = Compiler ((data__ <$>) <$> e) + ) => + Dataable a (Compiler m) + where + dataType :: sem (Sym.EoT (Sym.ADT a)) -> sem a + dataType (Compiler mos) = Compiler ((dataType <$>) <$> mos) instance ( Generic a - --, Sym.EoTOfRep a , Sym.RepOfEoT a , sem ~ Output - , CompilerIsToF a ~ 'False - --, CompilerIsToF eot ~ 'False + , Sym.IsToF a ~ 'False , eot ~ Sym.EoT (Sym.ADT a) - , CompilerUnToF eot - ) => Dataable__ a Output where - data__ :: sem (Sym.EoT (Sym.ADT a)) -> sem a - data__ o = o { outputData = \k -> (outputData o) $ compilerUnToF @(CompilerIsToF eot) $ k . Sym.adtOfeot } -instance Applicative m => PathSegmentable (Compiler m) where - pathSegment s = Compiler $ pure - [ - Output - { outputPath = [s] - , outputExts = [] - , outputData = id - } - ] + , Sym.ToFable eot + ) => + Dataable a Output + where + dataType :: sem (Sym.EoT (Sym.ADT a)) -> sem a + dataType o = o{outputData = \k -> (outputData o) $ Sym.tofOffun $ k . Sym.adtOfeot} +instance (Applicative m) => PathSegmentable (Compiler m) where + pathSegment s = + Compiler $ + pure + [ Output + { outputPath = [s] + , outputExts = [] + , outputData = id + } + ] instance - ( Show a - , Monad m + ( Applicative m , n ~ m - , end ~ m BSL.ByteString , MimeTypes ts (MimeEncodable a) ) => - Responsable a ts n end (Compiler m) + Responsable a ts n (Compiler m) where - response = Compiler $ pure $ - ( \(_mediaType, MimeType (Proxy :: Proxy t)) -> - Output - { outputPath = [] - , outputExts = [decodePathSegment (fileExtension @t)] - , outputData = \(Refl, Response ma) -> do - a <- ma - pure $ mimeEncode @_ @t a - } - ) - <$> toList (mimeTypesMap @ts @(MimeEncodable a)) + response = + Compiler $ + pure $ + ( \(_mediaType, MimeType (Proxy :: Proxy t)) -> + Output + { outputPath = [] + , outputExts = [decodePathSegment (fileExtension @t)] + , outputData = \(Refl, Response ma) -> mimeEncode @_ @t <$> ma + } + ) + <$> toList (mimeTypesMap @ts @(MimeEncodable a)) -- ** Type 'CompilerEnv' data CompilerEnv = CompilerEnv { compilerEnvDest :: Sys.FilePath , -- , compilerEnvSource :: Sys.FilePath compilerEnvIndex :: Sys.FilePath - --, compilerEnvModel :: model + -- , compilerEnvModel :: model -- , compilerEnvPath :: [PathSegment] } deriving (Show) -- ** Type 'Output' + -- TODO: use Seq instead of [] data Output a = Output { outputPath :: [PathSegment] , outputExts :: [PathSegment] - , outputData :: forall next. CompilerToF a next -> next - --, outputBSL :: BSL.ByteString - -- , outputType :: MimeType (MimeEncodable a) + , outputData :: forall next. (a --> next) -> next } - --- instance Sym.SumFunctor Output where --- a <+> b = Output --- { outputPath = outputPath a <> outputPath b --- , outputExts = outputExts a <> outputExts b --- , outputData = \(a2n, b2n) -> outputData a a2n --- } instance Sym.ProductFunctor Output where - a <.> b = Output - { outputPath = outputPath a <> outputPath b - , outputExts = outputExts a <> outputExts b - , outputData = outputData b . outputData a - } - a <. b = Output - { outputPath = outputPath a <> outputPath b - , outputExts = outputExts a <> outputExts b - , outputData = outputData b . outputData a - } - a .> b = Output - { outputPath = outputPath a <> outputPath b - , outputExts = outputExts a <> outputExts b - , outputData = outputData b . outputData a - } --- deriving (Functor, Show) --- instance Applicative Output where --- pure a = --- Output --- { outputPath = [] --- , outputExts = [] --- , outputData = a --- --, outputBSL = "" --- -- , outputType = mediaType @PlainText --- } --- oa2b <*> oa = --- Output --- { outputPath = outputPath oa2b <> outputPath oa --- , outputExts = outputExts oa2b <> outputExts oa --- , outputData = outputData oa2b (outputData oa) --- --, outputBSL = outputBSL oa2b <> outputBSL oa --- } - - --- * Type family 'CompilerToF' -type CompilerToF a next = CompilerToFIf (CompilerIsToF a) a next -type family CompilerToFIf t a next :: Type where --- For '<.>': curry. - CompilerToFIf 'True (a, b) next = CompilerToF a (CompilerToF b next) --- For '<+>', request both branches. - CompilerToFIf 'True (Either l r) next = (CompilerToF l next, CompilerToF r next) - --CompilerToFIf 'True (Maybe a) next = (CompilerToF () next, CompilerToF a next) --- Useless to ask '()' as argument. - CompilerToFIf 'True () next = next --- Enable a different return value for each function. - CompilerToFIf 'True (Sym.Endpoint end a) next = (next :~: end, a) --- Everything else becomes a new argument. - CompilerToFIf 'False a next = a -> next - - --- | This 'Bool' is added to 'ToFIf' to avoid overlapping instances. -type family CompilerIsToF a :: Bool where - CompilerIsToF () = 'True - CompilerIsToF (a, b) = 'True - CompilerIsToF (Either l r) = 'True - --CompilerIsToF (Maybe a) = 'True - CompilerIsToF (Sym.Endpoint end a) = 'True - CompilerIsToF a = 'False - + a <.> b = + Output + { outputPath = outputPath a <> outputPath b + , outputExts = outputExts a <> outputExts b + , outputData = outputData b . outputData a + } + a <. b = + Output + { outputPath = outputPath a <> outputPath b + , outputExts = outputExts a <> outputExts b + , outputData = outputData b . outputData a + } + a .> b = + Output + { outputPath = outputPath a <> outputPath b + , outputExts = outputExts a <> outputExts b + , outputData = outputData b . outputData a + } --- -- pathSegments _ss = Compiler $ --- -- MT.ReaderT $ \s -> --- -- -- TODO: assert Set.member s ss --- -- lift $ --- -- MT.modify' $ \st -> --- -- st{compilerStatePath = compilerStatePath st Text.unpack (encodePathSegment s)} --- --- {- --- instance --- TypeError ( --- 'Text "The instance (Capturable a Compiler)" --- ':$$: 'Text "is disabled when compiling to a static Web site." --- ':$$: 'Text "You can use (whenInterpreter @Compiler siteNotUsingCapturable siteUsingCapturable)" --- ':$$: 'Text "to replace calls to any method of Capturable." --- ) => Capturable a Compiler where --- capturePathSegment = undefined --- instance --- TypeError ( --- 'Text "The instance (Capturable a (Reader model Compiler))" --- ':$$: 'Text "is disabled when compiling to a static Web site." --- ':$$: 'Text "You can use (whenInterpreter @(Reader model Compiler) siteNotUsingCapturable siteUsingCapturable)" --- ':$$: 'Text "to replace calls to any method of Capturable." --- ) => Capturable a (Reader model Compiler) where --- capturePathSegment = undefined --- -} --- --- -- choosePathSegments _s = Compiler $ MT.ReaderT $ \s -> return $ Endo (List.reverse s <>) --- {- --- instance Capturable Compiler where --- type CapturableConstraint Compiler = --- capturePathSegment _n = Compiler $ MT.ReaderT $ \s -> --- lift $ MT.modify' $ \st -> --- st{compilerStatePath = compilerStatePath st Text.unpack (encodePathSegment s)} --- -} --- {- --- instance Copyable Compiler where --- copy path = Compiler $ --- lift $ --- MT.ReaderT $ \env -> do --- lift $ do --- doesPathExist (compilerEnvSource env path) >>= \case --- True -> do --- Sys.hPutStrLn Sys.stderr $ --- "staticCopy: " --- <> show --- ( (compilerEnvSource env path) --- , (compilerEnvDest env path) --- ) --- copyDirRecursively --- path --- (compilerEnvSource env path) --- (compilerEnvDest env) --- False -> do --- Sys.hPutStrLn Sys.stderr $ "error: path does not exist: " <> (compilerEnvSource env path) --- instance Encodable fmt a => Contentable fmt a Compiler where --- content = Compiler $ --- MT.ReaderT $ \a -> MT.ReaderT $ \env -> do --- st <- MT.get --- let destPath = compilerEnvDest env compilerStatePath st --- lift $ do --- -- Sys.hPutStrLn Sys.stderr $ "mkdir: " <> show (Sys.takeDirectory destPath) --- createDirectoryIfMissing True (Sys.takeDirectory destPath) --- -- Sys.hPutStrLn Sys.stderr $ "write: " <> show destPath --- BSL.writeFile destPath $ encode @fmt a --- -} --- --instance Endable Compiler where --- -- end = Compiler $ return $ Endo id --- --- --pathSegments _cs = Compiler $ MT.ReaderT $ \s -> return $ Endo (s :) --- -- instance Fileable Compiler where --- -- type FileableConstraint Compiler = Typeable --- -- static = Compiler $ MT.ReaderT $ \_a -> --- -- return $ Endo (\x -> x) --- --- {- --- -- * The 'Compiler' interpreter --- --- -- | Create files according to the given model of type 'a'. --- newtype Compiler a = Compiler --- { unCompiler :: [Comp a] --- } --- deriving (Show, Functor) --- --- instance Applicative Compiler where --- pure = Compiler . pure . pure --- Compiler f <*> Compiler x = Compiler $ (<*>) <$> f <*> x --- --- -- instance Monad Compiler where --- -- return = pure --- -- Compiler x >>= f = Compiler (x >>=) --- -- compile :: Show a => Renderable a => Compiler a -> CompilerEnv -> Sys.IO () -- compile compiler conf@CompilerEnv{..} = do -- createDirectoryIfMissing True compilerEnvDest @@ -463,110 +313,9 @@ type family CompilerIsToF a :: Bool where -- createDirectoryIfMissing True (Sys.takeDirectory destPath) -- -- Sys.hPutStrLn Sys.stderr $ "write: " <> show destPath -- BSL.writeFile destPath bs --- --- -- ** Class 'Renderable' --- class Renderable a where --- render :: a -> Either Sys.FilePath BSL.ByteString --- instance Renderable () where --- render () = --- --Left $ pathOfPathSegments compPathSegments --- Right BSL.empty --- --- -- ** Type 'Comp' --- data Comp a = Comp --- { compPathSegments :: [PathSegment] -- TODO: Endo? Seq? --- , compData :: a --- -- , compType :: MimeType (MimeEncodable a) --- } --- deriving instance Eq a => Eq (Comp a) --- deriving instance Ord a => Ord (Comp a) --- deriving instance Show a => Show (Comp a) --- deriving instance Functor Comp --- instance Applicative Comp where --- pure compData = --- Comp --- { compPathSegments = [] --- , compData --- -- , compType = mediaType @PlainText --- } --- f <*> x = --- Comp --- { compPathSegments = compPathSegments f <> compPathSegments x --- , compData = compData f (compData x) --- -- , compType = compType f <> compType x --- } --- --- instance IsoFunctor Compiler where --- (<%>) Iso{..} = (a2b <$>) --- instance ProductFunctor Compiler where --- (<.>) = liftA2 (,) --- (<.) = (<*) --- (.>) = (*>) --- instance SumFunctor Compiler where --- x <+> y = --- Compiler $ --- (<>) --- ((Left <$>) <$> unCompiler x) --- ((Right <$>) <$> unCompiler y) --- instance Optionable Compiler where --- optional x = --- Compiler $ --- Comp { compPathSegments = [] --- , compData = Nothing --- -- , compType = Nothing --- } : --- ((Just <$>) <$> unCompiler x) --- instance PathSegmentable Compiler where --- pathSegment s = Compiler --- [ --- Comp --- { compPathSegments = [s] --- , compData = () --- -- , compType = PlainText --- } --- ] --- pathSegments ss = --- Compiler $ --- [ Comp{ compPathSegments = [s] --- , compData = s --- -- , compType = Nothing --- } --- | s <- toList ss --- ] --- instance ContentTypeable PlainText () Compiler where --- contentType = --- Compiler --- [ Comp --- { compPathSegments = [] --- , compData = () --- --, compType = mediaType @PlainText --- } --- ] --- --- -- instance Repeatable Compiler where --- -- many0 (Compiler x) = --- -- Compiler $ --- -- ((\Comp{} -> Comp [] []) <$> x) --- -- <> ((\(Comp s a) -> Comp s [a]) <$> x) --- -- <> ((\(Comp s a) -> Comp (s <> s) [a, a]) <$> x) --- -- many1 (Compiler x) = --- -- Compiler $ --- -- ((\(Comp s a) -> Comp s [a]) <$> x) --- -- <> ((\(Comp s a) -> Comp (s <> s) [a, a]) <$> x) --- -- instance Endable Compiler where --- -- end = Compiler [Comp [] ()] --- -- instance Capturable Compiler where --- -- capturePathSegment n = Compiler $ [Comp [n] n] --- -- instance Constantable c Compiler where --- -- constant = pure --- -} --- + copyDirRecursively :: - ( --MonadIO m, - --MonadUnliftIO m, - --MonadLoggerIO m, - HasCallStack - ) => + (HasCallStack) => -- | Source file path relative to CWD Sys.FilePath -> -- | Absolute path to source file to copy. @@ -577,16 +326,16 @@ copyDirRecursively :: copyDirRecursively srcRel srcAbs destParent = do Sys.doesFileExist srcAbs >>= \case True -> do - Sys.hPutStrLn Sys.stderr $ "copyDirRecursively: " <> show ("srcAbs is a file", srcAbs) + Sys.hPutStrLn Sys.stderr $ "copyDirRecursively: " <> show ("srcAbs is a file" :: Text, srcAbs) copyFileCreatingParents srcAbs (destParent Sys. srcRel) False -> Sys.doesDirectoryExist srcAbs >>= \case False -> do - Sys.hPutStrLn Sys.stderr $ "copyDirRecursively: " <> show ("srcAbs is neither a file nor directory", srcAbs) + Sys.hPutStrLn Sys.stderr $ "copyDirRecursively: " <> show ("srcAbs is neither a file nor directory" :: Text, srcAbs) return () -- throw $ StaticAssetMissing srcAbs True -> do - Sys.hPutStrLn Sys.stderr $ "copyDirRecursively: " <> show ("srcAbs is a directory", srcAbs) + Sys.hPutStrLn Sys.stderr $ "copyDirRecursively: " <> show ("srcAbs is a directory" :: Text, srcAbs) Sys.createDirectoryIfMissing True (destParent Sys. srcRel) fs <- Sys.getDirectoryFiles srcAbs ["**"] forM_ fs $ \fp -> do diff --git a/src/Literate/Web/Syntaxes.hs b/src/Literate/Web/Syntaxes.hs index 61c83bd..22ecf99 100644 --- a/src/Literate/Web/Syntaxes.hs +++ b/src/Literate/Web/Syntaxes.hs @@ -16,49 +16,48 @@ module Literate.Web.Syntaxes ( Dataable (..), Inferable (..), IsoFunctor (..), - dataType, pattern (:!:), + Endpoint (..), + ToFEndpoint, + ToFable, + type (-->), ) where import Control.Applicative (Applicative) import Control.Monad (Monad) import Control.Monad.Classes qualified as MC import Control.Monad.Trans.Class as MT -import Data.Either (Either) import Data.Bool (Bool (..)) import Data.ByteString.Lazy qualified as BSL +import Data.Either (Either (..)) import Data.Function ((.)) import Data.Functor as Functor -import Data.Maybe (Maybe) import Data.Kind (Constraint, Type) +import Data.Maybe (Maybe) import Data.Typeable (Typeable) import Literate.Web.Types.URL -import Literate.Web.Types.MIME import Symantic.Semantics (Reader (..)) -import Symantic qualified as Sym -import GHC.Generics (Generic) -import Symantic.Semantics.ToFer ( - ToFer (..), - ) +import Symantic.Semantics.Data (Data, SomeData (..)) import Symantic.Syntaxes ( Dataable (..), - Endpoint, + Endpoint (..), Inferable (..), - IsToF, IsoFunctor (..), ProductFunctor (..), Repeatable (..), SumFunctor (..), + ToFEndpoint, + ToFable, dataType, pattern (:!:), + type (-->), ) -import Symantic.Syntaxes.Data (Data, SomeData (..)) -import Symantic.Syntaxes.Derive +import Symantic.Syntaxes.Derive hiding (Semantic) import System.FilePath (FilePath) ---deriving instance PathSegmentable sem => PathSegmentable (Reflector r sem) ---deriving instance Endable sem => Endable (Reflector r sem) ---deriving instance Capturable sem => Capturable (Reflector r sem) +-- deriving instance PathSegmentable sem => PathSegmentable (Reflector r sem) +-- deriving instance Endable sem => Endable (Reflector r sem) +-- deriving instance Capturable sem => Capturable (Reflector r sem) -- * Class 'PathSegmentable' @@ -70,20 +69,11 @@ class PathSegmentable sem where -- pathSegment :: PathSegment -> sem a -> sem a pathSegment :: PathSegment -> sem () - default pathSegment :: FromDerived PathSegmentable sem => PathSegment -> sem () + default pathSegment :: (FromDerived PathSegmentable sem) => PathSegment -> sem () -- default pathSegment :: IsoFunctor sem => PathSegment -> sem () -- pathSegment s = Iso (const ()) (const s) <%> pathSegments (Set.singleton s) pathSegment = liftDerived . pathSegment -instance (PathSegmentable sem, Functor sem) => PathSegmentable (ToFer sem) where - pathSegment s = - ToFer - { tuplesOfFunctions = (Functor.<$ eot) - , eithersOfTuples = eot - } - where - eot = pathSegment s - -- pathSegments :: Set PathSegment -> sem PathSegment -- default pathSegments :: FromDerived PathSegmentable sem => Set PathSegment -> sem PathSegment -- pathSegments = liftDerived . pathSegments @@ -102,7 +92,7 @@ data instance Data PathSegmentable sem a where -- ChoosePathSegments :: Set [PathSegment] -> Data PathSegmentable sem [PathSegment] -- | Initial to final algebra. -instance PathSegmentable sem => Derivable (Data PathSegmentable sem) where +instance (PathSegmentable sem) => Derivable (Data PathSegmentable sem) where derive = \case PathSegment x -> pathSegment x @@ -111,21 +101,21 @@ instance PathSegmentable sem => Derivable (Data PathSegmentable sem) where -- ChoosePathSegments x -> choosePathSegments x -- | Final to initial algebra. -instance PathSegmentable sem => PathSegmentable (SomeData sem) where +instance (PathSegmentable sem) => PathSegmentable (SomeData sem) where pathSegment = SomeData . PathSegment -- pathSegments = SomeData . PathSegments ---choosePathSegments = SomeData . ChoosePathSegments +-- choosePathSegments = SomeData . ChoosePathSegments -- | Convenient alias for an @index.html@ page. -index :: PathSegmentable sem => sem () +index :: (PathSegmentable sem) => sem () index = pathSegment "index.html" -- | Convenient alias for prefixing with a 'pathSegment'. () :: - ProductFunctor sem => - PathSegmentable sem => + (ProductFunctor sem) => + (PathSegmentable sem) => PathSegment -> sem a -> sem a @@ -147,26 +137,12 @@ class Capturable a sem where type Captured a sem = a capturePathSegment :: PathSegment -> sem (Captured a sem) default capturePathSegment :: - Captured a (Derived sem) ~ Captured a sem => - FromDerived (Capturable a) sem => + (Captured a (Derived sem) ~ Captured a sem) => + (FromDerived (Capturable a) sem) => PathSegment -> sem (Captured a sem) capturePathSegment = liftDerived . capturePathSegment @a --- | The @('IsToF' a ~ 'False)@ constraint --- disables capturing tuples or functions. -instance - ( Capturable a sem - , IsToF (Captured a sem) ~ 'False - , Functor sem - ) => Capturable a (ToFer sem) where - type Captured a (ToFer sem) = Captured a sem - capturePathSegment _n = - ToFer - { tuplesOfFunctions = \next -> next <$> capturePathSegment @a _n - , eithersOfTuples = capturePathSegment @a _n - } - -- | @('CapturedExtra' a extra)@ is useful to add @(extra)@ data -- to a 'Captured' value, eg. when using the 'Compiler' semantic, -- to add the content of a page whose name was captured @@ -175,13 +151,13 @@ instance -- when using the 'Server' semantic. newtype CapturedExtra a extra = CapturedExtra (Either (a, extra) a) ---instance Capturable sem => Capturable (Reader r sem) +-- instance Capturable sem => Capturable (Reader r sem) data instance Data (Capturable a) sem r where CapturePathSegment :: - Capturable a sem => + (Capturable a sem) => PathSegment -> Data (Capturable a) sem (Captured a sem) -instance Capturable a sem => Derivable (Data (Capturable a) sem) where +instance (Capturable a sem) => Derivable (Data (Capturable a) sem) where derive = \case CapturePathSegment n -> capturePathSegment @a n instance (Capturable a sem, Typeable a) => Capturable a (SomeData sem) where @@ -192,16 +168,14 @@ instance (Capturable a sem, Typeable a) => Capturable a (SomeData sem) where class Fileable sem where type FileableConstraint sem :: Type -> Constraint static :: sem () - dynamic :: FileableConstraint sem a => sem a + dynamic :: (FileableConstraint sem a) => sem a -- * Class 'Responsable' -class Responsable a (ts::[Type]) (m::Type -> Type) end sem where - --type Responsed a (ts::[Type]) (m::Type -> Type) end sem - --type Responsed a ts m end sem = Endpoint end (Response ts m a) - --response :: sem (Responsed a ts m end sem) - response :: sem (Endpoint end (Response ts m a)) -class Responsable2 a (ts::[Type]) sem where - response2 :: MimeTypes ts (MimeEncodable a) => sem a -> sem a +class Responsable a (ts :: [Type]) (m :: Type -> Type) sem where + -- type Responsed a (ts::[Type]) (m::Type -> Type) end sem + -- type Responsed a ts m end sem = Endpoint end (Response ts m a) + -- response :: sem (Responsed a ts m end sem) + response :: sem (Endpoint sem (Response ts m a)) -- ** Type 'Response' newtype Response (ts :: [Type]) m a = Response {unResponse :: m a} @@ -209,14 +183,11 @@ newtype Response (ts :: [Type]) m a = Response {unResponse :: m a} type instance MC.CanDo (Response ts m) eff = 'False instance MT.MonadTrans (Response ts) where lift = Response -class Generic a => Dataable__ a sem where - data__ :: sem (Sym.EoT (Sym.ADT a)) -> sem a - -- ** Class 'Optionable' class Optionable a sem where optional :: sem a -> sem (Maybe a) optional = liftDerived1 optional default optional :: - FromDerived1 (Optionable a) sem => + (FromDerived1 (Optionable a) sem) => sem a -> sem (Maybe a) diff --git a/tests/Examples/Ex01.hs b/tests/Examples/Ex01.hs index 1a47025..7aa6732 100644 --- a/tests/Examples/Ex01.hs +++ b/tests/Examples/Ex01.hs @@ -6,15 +6,24 @@ module Examples.Ex01 where import Control.Monad (Monad (..)) import Data.Text (Text) import Literate.Web -import Symantic qualified as Sym -- | Polymorphic expression describing the website, -- to be instantiated to the various interpreters. -- NoMonomorphismRestriction is used to avoid specifying manually -- the inferred symantic classes. router = - pathSegment "index" <.> response @Text @'[PlainText] - <+> "about" pathSegment "me" + pathSegment "index" + <.> response @Text @'[PlainText] + <+> "about" + pathSegment "me" content = - (Sym.endpoint (return "INDEX"), return "ABOUT") + ( contentEndpoint (return "INDEX") + , return "ABOUT" + ) + +-- c0 = compile CompilerEnv{} router content +-- m0 = manifest router + +address_Index, address_About :: Address +(address_Index :!: address_About) = address router diff --git a/tests/Examples/Ex02.hs b/tests/Examples/Ex02.hs index 0b6d616..131f3da 100644 --- a/tests/Examples/Ex02.hs +++ b/tests/Examples/Ex02.hs @@ -1,4 +1,5 @@ {-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE PartialTypeSignatures #-} {-# LANGUAGE NoMonomorphismRestriction #-} {-# OPTIONS_GHC -Wno-missing-signatures #-} @@ -17,11 +18,22 @@ data Route -- from the 'Route' algebraic data-type -- a function transforming Eithers-of-Tuples into a 'Route'. router = - dataType @Route $ - pathSegment "index" - <+> "about" - pathSegment "me" + dataType @Route + $ pathSegment "index" -- <.> response @Char @'[PlainText] + <+> "about" + pathSegment "me" + +-- <. response2 @Char @'[PlainText] content = \case - Index -> return "INDEX" + -- In -> Out + Index{} -> return "INDEX" About -> return "ABOUT" + +-- c0 = compile CompilerEnv{} router content + +address_IndexMe :: Address +address_IndexMe = address router Index + +address_AboutMe :: Address +address_AboutMe = address router About diff --git a/tests/Examples/Ex03.hs b/tests/Examples/Ex03.hs index cd2047a..20111b4 100644 --- a/tests/Examples/Ex03.hs +++ b/tests/Examples/Ex03.hs @@ -25,7 +25,9 @@ import Literate.Web router = pathSegment "static" <+> pathSegment "feed" - <+> "filter" (dataType @(Maybe Lang) $ pathSegment "all" <+> infer) <.> optional (capturePathSegment @Tag "tag") + <+> "filter" + (dataType @(Maybe Lang) $ pathSegment "all" <+> infer) + <.> optional (capturePathSegment @Tag "tag") -- content :: -- Monad m => @@ -48,6 +50,15 @@ content = Nothing -> show lang Just tag -> show (lang, tag) +-- c0 = compile CompilerEnv{} router content + +address_static, address_feed :: Address +address_filter :: Maybe Lang -> Maybe (Captured Tag Addresser) -> Address +( address_static + :!: address_feed + :!: address_filter + ) = address router + -- * Type 'Lang' data Lang = LangEn @@ -58,7 +69,7 @@ routeLang = dataType @Lang $ pathSegment "en" <+> pathSegment "fr" -- | Using 'Inferable' has the downside of requiring -- to explicit manually the symantices required. -instance (SumFunctor sem, PathSegmentable sem, Dataable sem) => Inferable Lang sem where +instance (SumFunctor sem, PathSegmentable sem, Dataable Lang sem) => Inferable Lang sem where infer = routeLang -- * Type 'Tag' @@ -70,15 +81,19 @@ instance IsString Tag where -- Hence the 'Compiler' semantic for 'Capturable' -- requires a readable 'Model' somewhere in the monad stack -- in order to generate all 'Tag's folders. -instance MC.MonadReader Model m => Capturable Tag (Compiler m) where +instance (MC.MonadReader Model m) => Capturable Tag (Compiler m) where capturePathSegment _n = Compiler do model <- MC.ask return - [ Output{outputPath = [unTag tag], outputExts = [], outputData = tag} + [ Output{outputPath = [unTag tag], outputExts = [], outputData = ($ tag)} | tag <- Set.toList (modelTags model) ] +instance Capturable Tag Addresser where + -- FIXME: check given tag exists? + capturePathSegment _n = Addresser \k t -> k (Address [unTag t]) + -- * Type 'Model' data Model = Model { modelTags :: Set Tag diff --git a/tests/Examples/Ex04.hs b/tests/Examples/Ex04.hs index f2e1cb4..d65214c 100644 --- a/tests/Examples/Ex04.hs +++ b/tests/Examples/Ex04.hs @@ -5,14 +5,19 @@ module Examples.Ex04 where import Control.Monad.Classes qualified as MC + +-- import Control.Reactive import Data.Map.Strict as Map import Literate.Web import Relude -import Symantic qualified as Sym router = - "post" capturePathSegment @PostName "post" <.> response @Post @'[PlainText] - <+> "page" capturePathSegment @PageName "page" <.> response @Page @'[PlainText] + "post" + capturePathSegment @PostName "post" + <.> response @Post @'[PlainText] + <+> "page" + capturePathSegment @PageName "page" + <.> response @Page @'[PlainText] <+> pathSegment "lorem" -- content :: @@ -27,31 +32,34 @@ router = -- endpoint content = contentPost :!: contentPage :!: contentOther where - contentPost n = Sym.endpoint do + contentPost n = contentEndpoint do Model{..} <- MC.ask return $ modelPosts Map.! n - contentPage = Sym.endpoint . \case - CapturedExtra (Left (_n, p)) -> do - return p - CapturedExtra (Right n) -> do - Model{..} <- MC.ask - return $ modelPages Map.! n + contentPage = + contentEndpoint . \case + CapturedExtra (Left (_n, p)) -> do + return p + CapturedExtra (Right n) -> do + Model{..} <- MC.ask + return $ modelPages Map.! n contentOther = return "ipsum" +-- c0 = compile CompilerEnv{} router content + instance MimeEncodable Post PlainText where mimeEncode (Post t) = mimeEncode @_ @PlainText t instance MimeEncodable Page PlainText where mimeEncode (Page t) = mimeEncode @_ @PlainText t -instance MC.MonadReader Model m => Capturable PostName (Compiler m) where +instance (MC.MonadReader Model m) => Capturable PostName (Compiler m) where capturePathSegment _n = Compiler do model <- MC.ask return - [ Output{outputPath = [unPostName name], outputExts = [], outputData = name} + [ Output{outputPath = [unPostName name], outputExts = [], outputData = ($ name)} | name <- Map.keys (modelPosts model) ] -instance MC.MonadReader Model m => Capturable PageName (Compiler m) where +instance (MC.MonadReader Model m) => Capturable PageName (Compiler m) where -- Keep the 'Page' to avoid looking it up in 'contentPage'. type Captured PageName (Compiler m) = CapturedExtra PageName Page capturePathSegment _n = @@ -59,13 +67,20 @@ instance MC.MonadReader Model m => Capturable PageName (Compiler m) where model <- MC.ask return [ Output - { outputPath = [unPageName name] - , outputExts = [] - , outputData = CapturedExtra (Left (name, page)) - } + { outputPath = [unPageName name] + , outputExts = [] + , outputData = ($ CapturedExtra (Left (name, page))) + } | (name, page) <- Map.toList (modelPages model) ] +{- +data Rodel m = Rodel + { rodelPosts :: RW m (Map PostName (RW m Post)) + , rodelPages :: RW m (Map PageName (RW m Page)) + } +-} + -- * Type 'Model' data Model = Model { modelPosts :: Map PostName Post diff --git a/tests/Examples/Ex05.hs b/tests/Examples/Ex05.hs new file mode 100644 index 0000000..710061a --- /dev/null +++ b/tests/Examples/Ex05.hs @@ -0,0 +1,30 @@ +{-# LANGUAGE NoMonomorphismRestriction #-} +{-# OPTIONS_GHC -Wno-missing-signatures #-} + +module Examples.Ex05 where + +import Literate.Web + +import Examples.Ex03 qualified as Ex03 +import Examples.Ex04 qualified as Ex04 + +router = + "ex03" + Ex03.router + <+> "ex04" + Ex04.router + +content = + Ex03.content + :!: Ex04.content + +data Model = Model + { model03 :: Ex03.Model + , model04 :: Ex04.Model + } + +model1 = + Model + { model03 = Ex03.model1 + , model04 = Ex04.model1 + } diff --git a/tests/Goldens.hs b/tests/Goldens.hs index 501a729..854bf38 100644 --- a/tests/Goldens.hs +++ b/tests/Goldens.hs @@ -9,13 +9,8 @@ module Goldens where -import Control.Monad.Classes qualified as MC import Control.Monad.Trans.Reader as MT -import Data.ByteString.Lazy qualified as BSL -import Data.Functor.Identity (Identity (..)) -import Data.Text qualified as Text import Relude -import Symantic qualified as Sym import System.FilePath qualified as Sys import System.IO.Unsafe (unsafePerformIO) import Test.Tasty @@ -92,30 +87,30 @@ goldens = [ [ Golden { goldenCompiler = \env -> compile env Ex01.router Ex01.content - , goldenManifest = runIdentity $ manifest Ex01.router Ex01.content + , goldenManifest = runIdentity $ manifest Ex01.router } ] , [ Golden { goldenCompiler = \env -> compile env Ex02.router Ex02.content - , goldenManifest = runIdentity $ manifest Ex02.router Ex02.content + , goldenManifest = runIdentity $ manifest Ex02.router } ] , [ Golden { goldenCompiler = \env -> MT.runReaderT (compile env Ex03.router Ex03.content) model - , goldenManifest = runReader (manifest Ex03.router Ex03.content) model + , goldenManifest = runReader (manifest Ex03.router) model } | model <- [Ex03.model1, Ex03.model2] ] , [ Golden { goldenCompiler = \env -> MT.runReaderT (compile env Ex04.router Ex04.content) model - , goldenManifest = runReader (manifest Ex04.router Ex04.content) model + , goldenManifest = runReader (manifest Ex04.router) model } | model <- [Ex04.model1] ] , [ Golden { goldenCompiler = \env -> MT.runReaderT (MT.runReaderT (compile env Ex05.router Ex05.content) model03) model04 - , goldenManifest = MT.runReader (MT.runReaderT (manifest Ex05.router Ex05.content) model03) model04 + , goldenManifest = MT.runReader (MT.runReaderT (manifest Ex05.router) model03) model04 } | model03 <- [Ex03.model1, Ex03.model2] , model04 <- [Ex04.model1] diff --git a/tests/Goldens/Compiler/Site002/Model01/Expected/about/me.txt b/tests/Goldens/Compiler/Site002/Model01/Expected/about/me.txt new file mode 100644 index 0000000..6bf2957 --- /dev/null +++ b/tests/Goldens/Compiler/Site002/Model01/Expected/about/me.txt @@ -0,0 +1 @@ +ABOUT \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site002/Model01/Expected/index.txt b/tests/Goldens/Compiler/Site002/Model01/Expected/index.txt new file mode 100644 index 0000000..bf25fee --- /dev/null +++ b/tests/Goldens/Compiler/Site002/Model01/Expected/index.txt @@ -0,0 +1 @@ +INDEX \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site002/Model01/Got/about/me.txt b/tests/Goldens/Compiler/Site002/Model01/Got/about/me.txt new file mode 100644 index 0000000..6bf2957 --- /dev/null +++ b/tests/Goldens/Compiler/Site002/Model01/Got/about/me.txt @@ -0,0 +1 @@ +ABOUT \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site002/Model01/Got/index.txt b/tests/Goldens/Compiler/Site002/Model01/Got/index.txt new file mode 100644 index 0000000..bf25fee --- /dev/null +++ b/tests/Goldens/Compiler/Site002/Model01/Got/index.txt @@ -0,0 +1 @@ +INDEX \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site003/Model01/Got/filter/all.txt b/tests/Goldens/Compiler/Site003/Model01/Got/filter/all.txt deleted file mode 100644 index 3f09dff..0000000 --- a/tests/Goldens/Compiler/Site003/Model01/Got/filter/all.txt +++ /dev/null @@ -1 +0,0 @@ -ALL-LANG-ALL-TAGS \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site003/Model01/Got/filter/en.txt b/tests/Goldens/Compiler/Site003/Model01/Got/filter/en.txt deleted file mode 100644 index 2297258..0000000 --- a/tests/Goldens/Compiler/Site003/Model01/Got/filter/en.txt +++ /dev/null @@ -1 +0,0 @@ -LangEn \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site003/Model01/Got/filter/fr.txt b/tests/Goldens/Compiler/Site003/Model01/Got/filter/fr.txt deleted file mode 100644 index 919dd92..0000000 --- a/tests/Goldens/Compiler/Site003/Model01/Got/filter/fr.txt +++ /dev/null @@ -1 +0,0 @@ -LangFr \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site003/Model02/Got/filter/all.txt b/tests/Goldens/Compiler/Site003/Model02/Got/filter/all.txt deleted file mode 100644 index 3f09dff..0000000 --- a/tests/Goldens/Compiler/Site003/Model02/Got/filter/all.txt +++ /dev/null @@ -1 +0,0 @@ -ALL-LANG-ALL-TAGS \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site003/Model02/Got/filter/en.txt b/tests/Goldens/Compiler/Site003/Model02/Got/filter/en.txt deleted file mode 100644 index 2297258..0000000 --- a/tests/Goldens/Compiler/Site003/Model02/Got/filter/en.txt +++ /dev/null @@ -1 +0,0 @@ -LangEn \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site003/Model02/Got/filter/fr.txt b/tests/Goldens/Compiler/Site003/Model02/Got/filter/fr.txt deleted file mode 100644 index 919dd92..0000000 --- a/tests/Goldens/Compiler/Site003/Model02/Got/filter/fr.txt +++ /dev/null @@ -1 +0,0 @@ -LangFr \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site004/Model01/Expected/page/page2.txt b/tests/Goldens/Compiler/Site004/Model01/Expected/page/page2.txt new file mode 100644 index 0000000..014e5de --- /dev/null +++ b/tests/Goldens/Compiler/Site004/Model01/Expected/page/page2.txt @@ -0,0 +1 @@ +page-model-2 \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site004/Model01/Got/page/page2.txt b/tests/Goldens/Compiler/Site004/Model01/Got/page/page2.txt new file mode 100644 index 0000000..014e5de --- /dev/null +++ b/tests/Goldens/Compiler/Site004/Model01/Got/page/page2.txt @@ -0,0 +1 @@ +page-model-2 \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site005/Model01/Expected/ex04/page/page2.txt b/tests/Goldens/Compiler/Site005/Model01/Expected/ex04/page/page2.txt new file mode 100644 index 0000000..014e5de --- /dev/null +++ b/tests/Goldens/Compiler/Site005/Model01/Expected/ex04/page/page2.txt @@ -0,0 +1 @@ +page-model-2 \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site005/Model01/Got/ex03/filter/all.txt b/tests/Goldens/Compiler/Site005/Model01/Got/ex03/filter/all.txt deleted file mode 100644 index 3f09dff..0000000 --- a/tests/Goldens/Compiler/Site005/Model01/Got/ex03/filter/all.txt +++ /dev/null @@ -1 +0,0 @@ -ALL-LANG-ALL-TAGS \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site005/Model01/Got/ex03/filter/en.txt b/tests/Goldens/Compiler/Site005/Model01/Got/ex03/filter/en.txt deleted file mode 100644 index 2297258..0000000 --- a/tests/Goldens/Compiler/Site005/Model01/Got/ex03/filter/en.txt +++ /dev/null @@ -1 +0,0 @@ -LangEn \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site005/Model01/Got/ex03/filter/fr.txt b/tests/Goldens/Compiler/Site005/Model01/Got/ex03/filter/fr.txt deleted file mode 100644 index 919dd92..0000000 --- a/tests/Goldens/Compiler/Site005/Model01/Got/ex03/filter/fr.txt +++ /dev/null @@ -1 +0,0 @@ -LangFr \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site005/Model01/Got/ex04/page/page2.txt b/tests/Goldens/Compiler/Site005/Model01/Got/ex04/page/page2.txt new file mode 100644 index 0000000..014e5de --- /dev/null +++ b/tests/Goldens/Compiler/Site005/Model01/Got/ex04/page/page2.txt @@ -0,0 +1 @@ +page-model-2 \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site005/Model02/Expected/ex04/page/page2.txt b/tests/Goldens/Compiler/Site005/Model02/Expected/ex04/page/page2.txt new file mode 100644 index 0000000..014e5de --- /dev/null +++ b/tests/Goldens/Compiler/Site005/Model02/Expected/ex04/page/page2.txt @@ -0,0 +1 @@ +page-model-2 \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site005/Model02/Got/ex03/filter/all.txt b/tests/Goldens/Compiler/Site005/Model02/Got/ex03/filter/all.txt deleted file mode 100644 index 3f09dff..0000000 --- a/tests/Goldens/Compiler/Site005/Model02/Got/ex03/filter/all.txt +++ /dev/null @@ -1 +0,0 @@ -ALL-LANG-ALL-TAGS \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site005/Model02/Got/ex03/filter/en.txt b/tests/Goldens/Compiler/Site005/Model02/Got/ex03/filter/en.txt deleted file mode 100644 index 2297258..0000000 --- a/tests/Goldens/Compiler/Site005/Model02/Got/ex03/filter/en.txt +++ /dev/null @@ -1 +0,0 @@ -LangEn \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site005/Model02/Got/ex03/filter/fr.txt b/tests/Goldens/Compiler/Site005/Model02/Got/ex03/filter/fr.txt deleted file mode 100644 index 919dd92..0000000 --- a/tests/Goldens/Compiler/Site005/Model02/Got/ex03/filter/fr.txt +++ /dev/null @@ -1 +0,0 @@ -LangFr \ No newline at end of file diff --git a/tests/Goldens/Compiler/Site005/Model02/Got/ex04/page/page2.txt b/tests/Goldens/Compiler/Site005/Model02/Got/ex04/page/page2.txt new file mode 100644 index 0000000..014e5de --- /dev/null +++ b/tests/Goldens/Compiler/Site005/Model02/Got/ex04/page/page2.txt @@ -0,0 +1 @@ +page-model-2 \ No newline at end of file