diff options
author | Gregor Kleen <gkleen@yggdrasil.li> | 2016-01-12 04:35:47 +0000 |
---|---|---|
committer | Gregor Kleen <gkleen@yggdrasil.li> | 2016-01-12 04:35:47 +0000 |
commit | ed629414fbc3af1700f7ed6829744f0fb30417c9 (patch) | |
tree | e83e6280607bba4cec25778741ead3f466976809 /bbcode | |
parent | c2e72615a166e1cfa479e44283b5f7f9ecdeb942 (diff) | |
download | thermoprint-ed629414fbc3af1700f7ed6829744f0fb30417c9.tar thermoprint-ed629414fbc3af1700f7ed6829744f0fb30417c9.tar.gz thermoprint-ed629414fbc3af1700f7ed6829744f0fb30417c9.tar.bz2 thermoprint-ed629414fbc3af1700f7ed6829744f0fb30417c9.tar.xz thermoprint-ed629414fbc3af1700f7ed6829744f0fb30417c9.zip |
Morph [BBNode] (Forest Text)
Diffstat (limited to 'bbcode')
-rw-r--r-- | bbcode/src/Text/BBCode.hs | 48 | ||||
-rw-r--r-- | bbcode/thermoprint-bbcode.cabal | 2 | ||||
-rw-r--r-- | bbcode/thermoprint-bbcode.nix | 10 |
3 files changed, 51 insertions, 9 deletions
diff --git a/bbcode/src/Text/BBCode.hs b/bbcode/src/Text/BBCode.hs index 7a328a8..dfa1db7 100644 --- a/bbcode/src/Text/BBCode.hs +++ b/bbcode/src/Text/BBCode.hs | |||
@@ -1,14 +1,52 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | 1 | {-# LANGUAGE OverloadedStrings #-} |
2 | {-# LANGUAGE DeriveGeneric #-} | ||
2 | 3 | ||
3 | module Text.BBCode | 4 | module Text.BBCode |
4 | ( | 5 | ( TreeError(..) |
6 | , rose | ||
7 | , matches | ||
5 | ) where | 8 | ) where |
6 | 9 | ||
7 | import Data.Attoparsec.Text | ||
8 | |||
9 | import Data.Text (Text) | 10 | import Data.Text (Text) |
10 | import qualified Data.Text as T (singleton, head, tail) | ||
11 | 11 | ||
12 | import Control.Applicative | 12 | import GHC.Generics (Generic) |
13 | import Control.Exception (Exception) | ||
14 | import Data.Typeable (Typeable) | ||
15 | |||
16 | import Control.Monad (unless) | ||
13 | 17 | ||
14 | import Text.BBCode.Lexer (BBToken(..), token) | 18 | import Text.BBCode.Lexer (BBToken(..), token) |
19 | |||
20 | import Data.Tree | ||
21 | import Data.Tree.Zipper (TreePos, Empty, Full) | ||
22 | import qualified Data.Tree.Zipper as Z | ||
23 | |||
24 | data TreeError = ImbalancedTags Text Text | ||
25 | | LeftoverClose Text | ||
26 | deriving (Show, Eq, Generic, Typeable) | ||
27 | |||
28 | instance Exception TreeError | ||
29 | |||
30 | matches :: Text -> Text -> Bool | ||
31 | -- ^ @`matches` "open" "close"@ should be true iff @[/close]@ is a valid closing tag for @[open]@ | ||
32 | -- | ||
33 | -- Until we allow for attributes this is equality according to `(==)` | ||
34 | matches = (==) | ||
35 | |||
36 | rose :: [BBToken] -> Either TreeError (Forest Text) | ||
37 | -- ^ Assuming that both tags and content have the same type (we use 'Text') bbcode is a flat representation of a rose tree | ||
38 | rose = fmap Z.toForest . flip rose' (Z.fromForest []) | ||
39 | where | ||
40 | rose' :: [BBToken] -> TreePos Empty Text -> Either TreeError (TreePos Empty Text) | ||
41 | rose' [] = return | ||
42 | rose' (x:xs) = (>>= rose' xs) . rose'' x | ||
43 | |||
44 | rose'' (BBStr t) = return . Z.nextSpace . Z.insert (Node t []) | ||
45 | rose'' (BBOpen t) = return . Z.children . Z.insert (Node t []) | ||
46 | rose'' (BBClose t) = close t -- for more pointless | ||
47 | |||
48 | close :: Text -> TreePos Empty Text -> Either TreeError (TreePos Empty Text) | ||
49 | close tag pos = do | ||
50 | pos' <- maybe (Left $ LeftoverClose tag) Right $ Z.parent pos | ||
51 | unless (Z.label pos' `matches` tag) . Left $ ImbalancedTags (Z.label pos') tag -- The structure shows that this mode of failure is not logically required -- it's just nice to have | ||
52 | return $ Z.nextSpace pos' | ||
diff --git a/bbcode/thermoprint-bbcode.cabal b/bbcode/thermoprint-bbcode.cabal index f1018a5..80a9da5 100644 --- a/bbcode/thermoprint-bbcode.cabal +++ b/bbcode/thermoprint-bbcode.cabal | |||
@@ -24,6 +24,8 @@ library | |||
24 | build-depends: base >=4.8 && <4.9 | 24 | build-depends: base >=4.8 && <4.9 |
25 | , attoparsec >=0.13.0 && <1 | 25 | , attoparsec >=0.13.0 && <1 |
26 | , text >=1.2.1 && <2 | 26 | , text >=1.2.1 && <2 |
27 | , containers >=0.4.0 && <1 | ||
28 | , rosezipper >=0.2 && <1 | ||
27 | hs-source-dirs: src | 29 | hs-source-dirs: src |
28 | default-language: Haskell2010 | 30 | default-language: Haskell2010 |
29 | 31 | ||
diff --git a/bbcode/thermoprint-bbcode.nix b/bbcode/thermoprint-bbcode.nix index 5521b10..c379053 100644 --- a/bbcode/thermoprint-bbcode.nix +++ b/bbcode/thermoprint-bbcode.nix | |||
@@ -1,14 +1,16 @@ | |||
1 | { mkDerivation, attoparsec, base, hspec, QuickCheck | 1 | { mkDerivation, attoparsec, base, containers, hspec, QuickCheck |
2 | , quickcheck-instances, stdenv, text | 2 | , quickcheck-instances, rosezipper, stdenv, text |
3 | }: | 3 | }: |
4 | mkDerivation { | 4 | mkDerivation { |
5 | pname = "thermoprint-bbcode"; | 5 | pname = "thermoprint-bbcode"; |
6 | version = "0.0.0"; | 6 | version = "0.0.0"; |
7 | src = ./.; | 7 | src = ./.; |
8 | libraryHaskellDepends = [ | 8 | libraryHaskellDepends = [ |
9 | attoparsec base QuickCheck quickcheck-instances text | 9 | attoparsec base containers rosezipper text |
10 | ]; | ||
11 | testHaskellDepends = [ | ||
12 | attoparsec base hspec QuickCheck quickcheck-instances text | ||
10 | ]; | 13 | ]; |
11 | testHaskellDepends = [ attoparsec base hspec QuickCheck text ]; | ||
12 | homepage = "http://dirty-haskell.org/tags/thermoprint.html"; | 14 | homepage = "http://dirty-haskell.org/tags/thermoprint.html"; |
13 | description = "A parser for a subset of bbcode compatible with thermoprint-spec"; | 15 | description = "A parser for a subset of bbcode compatible with thermoprint-spec"; |
14 | license = stdenv.lib.licenses.publicDomain; | 16 | license = stdenv.lib.licenses.publicDomain; |