aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2016-01-18 11:38:31 +0000
committerGregor Kleen <gkleen@yggdrasil.li>2016-01-18 11:38:31 +0000
commit1ec5c1cb2f118c906a27b3763c73c0098fe67b4a (patch)
tree7ea7fada2d7bf380cddb6e135b6af1f58cac31fd
parentf0ad3abb87d540c75a397a722ca5310d6d16cec9 (diff)
downloadthermoprint-1ec5c1cb2f118c906a27b3763c73c0098fe67b4a.tar
thermoprint-1ec5c1cb2f118c906a27b3763c73c0098fe67b4a.tar.gz
thermoprint-1ec5c1cb2f118c906a27b3763c73c0098fe67b4a.tar.bz2
thermoprint-1ec5c1cb2f118c906a27b3763c73c0098fe67b4a.tar.xz
thermoprint-1ec5c1cb2f118c906a27b3763c73c0098fe67b4a.zip
Added failure mode: UnclosedTags
-rw-r--r--bbcode/bbcode.cabal2
-rw-r--r--bbcode/bbcode.nix2
-rw-r--r--bbcode/src/Text/BBCode.hs17
3 files changed, 17 insertions, 4 deletions
diff --git a/bbcode/bbcode.cabal b/bbcode/bbcode.cabal
index 49e7a01..ad8bb5a 100644
--- a/bbcode/bbcode.cabal
+++ b/bbcode/bbcode.cabal
@@ -2,7 +2,7 @@
2-- documentation, see http://haskell.org/cabal/users-guide/ 2-- documentation, see http://haskell.org/cabal/users-guide/
3 3
4name: bbcode 4name: bbcode
5version: 2.0.0 5version: 3.0.0
6synopsis: A parser for bbcode 6synopsis: A parser for bbcode
7-- description: 7-- description:
8homepage: http://dirty-haskell.org/tags/thermoprint.html 8homepage: http://dirty-haskell.org/tags/thermoprint.html
diff --git a/bbcode/bbcode.nix b/bbcode/bbcode.nix
index ddb055c..6426b0b 100644
--- a/bbcode/bbcode.nix
+++ b/bbcode/bbcode.nix
@@ -3,7 +3,7 @@
3}: 3}:
4mkDerivation { 4mkDerivation {
5 pname = "bbcode"; 5 pname = "bbcode";
6 version = "2.0.0"; 6 version = "3.0.0";
7 src = ./.; 7 src = ./.;
8 libraryHaskellDepends = [ 8 libraryHaskellDepends = [
9 attoparsec base case-insensitive containers rosezipper text 9 attoparsec base case-insensitive containers rosezipper text
diff --git a/bbcode/src/Text/BBCode.hs b/bbcode/src/Text/BBCode.hs
index ac56974..f3c9ca2 100644
--- a/bbcode/src/Text/BBCode.hs
+++ b/bbcode/src/Text/BBCode.hs
@@ -20,7 +20,7 @@ import GHC.Generics (Generic)
20import Control.Exception (Exception) 20import Control.Exception (Exception)
21import Data.Typeable (Typeable) 21import Data.Typeable (Typeable)
22 22
23import Control.Monad (unless, join, foldM) 23import Control.Monad (unless, join, foldM, (<=<))
24import Data.Function (on) 24import Data.Function (on)
25import Control.Applicative 25import Control.Applicative
26 26
@@ -39,6 +39,8 @@ import qualified Data.CaseInsensitive as CI
39 39
40import Data.Bifunctor (Bifunctor(first)) 40import Data.Bifunctor (Bifunctor(first))
41 41
42import Data.Maybe (catMaybes)
43
42-- | Our target structure -- a rose tree with an explicit terminal constructor 44-- | Our target structure -- a rose tree with an explicit terminal constructor
43data DomTree = Element (CI Text) (Map (CI Text) Text) [DomTree] 45data DomTree = Element (CI Text) (Map (CI Text) Text) [DomTree]
44 | Content Text 46 | Content Text
@@ -75,6 +77,7 @@ bbcode t = fmap dom $ first LexerError (parseOnly (many token <* endOfInput) t)
75-- | Errors in input encountered during parsing of lexed token-stream 77-- | Errors in input encountered during parsing of lexed token-stream
76data TreeError = MismatchedTags Text Text -- ^ Closing tags label does not match opening tags 78data TreeError = MismatchedTags Text Text -- ^ Closing tags label does not match opening tags
77 | ImbalancedTags Text -- ^ We found an extraneous closing tag 79 | ImbalancedTags Text -- ^ We found an extraneous closing tag
80 | UnclosedTags [Text] -- ^ We found opened tags that were not closed
78 | ParagraphWithinTag -- ^ We found a paragraph-break within a tag 81 | ParagraphWithinTag -- ^ We found a paragraph-break within a tag
79 deriving (Show, Eq, Generic, Typeable) 82 deriving (Show, Eq, Generic, Typeable)
80 83
@@ -98,7 +101,7 @@ rose :: [BBToken] -> Either TreeError (Forest BBLabel)
98-- We use @'Tree' 'BBLabel'@ only as another intermediate structure because it carries no guarantee that the data is semantically valid -- a 'BBPlain'-value semantically has no children. 101-- We use @'Tree' 'BBLabel'@ only as another intermediate structure because it carries no guarantee that the data is semantically valid -- a 'BBPlain'-value semantically has no children.
99-- 102--
100-- The use of 'Tree' was still deemed desirable because the morphism to a more sensible structure is straightforward and 'Data.Tree.Zipper' provides all the tools needed to implement 'rose' in a sensible fashion 103-- The use of 'Tree' was still deemed desirable because the morphism to a more sensible structure is straightforward and 'Data.Tree.Zipper' provides all the tools needed to implement 'rose' in a sensible fashion
101rose = fmap Z.toForest . foldM (flip rose') (Z.fromForest []) 104rose = fmap Z.toForest . checkClosure <=< foldM (flip rose') (Z.fromForest [])
102 where 105 where
103 rose' (BBStr t) = return . Z.nextSpace . Z.insert (Node (BBPlain t) []) 106 rose' (BBStr t) = return . Z.nextSpace . Z.insert (Node (BBPlain t) [])
104 rose' BBNewPar = parBreak -- for more pointless 107 rose' BBNewPar = parBreak -- for more pointless
@@ -129,3 +132,13 @@ rose = fmap Z.toForest . foldM (flip rose') (Z.fromForest [])
129 132
130 isPar (Node BBPar _) = True 133 isPar (Node BBPar _) = True
131 isPar _ = False 134 isPar _ = False
135
136 checkClosure :: TreePos Empty BBLabel -> Either TreeError (TreePos Empty BBLabel)
137 -- This failure mode isn't required either
138 checkClosure z
139 | null parentTags = Right z
140 | otherwise = Left . UnclosedTags $ parentTags
141 where
142 parentTags = catMaybes . map (getTag . (\(_, p, _) -> p)) $ Z.parents z
143 getTag (BBTag t _) = Just t
144 getTag _ = Nothing