aboutsummaryrefslogtreecommitdiff
path: root/bbcode/src
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2016-01-18 05:42:26 +0000
committerGregor Kleen <gkleen@yggdrasil.li>2016-01-18 05:42:26 +0000
commit4914e4d7f638b7771ecdaf24ee0516c05505697c (patch)
tree6c89d30ae2ea97f14f4a35af9013dc74e747492c /bbcode/src
parent539b69b3e3b0c4ffee2323a8fe6239ebda4af48c (diff)
downloadthermoprint-4914e4d7f638b7771ecdaf24ee0516c05505697c.tar
thermoprint-4914e4d7f638b7771ecdaf24ee0516c05505697c.tar.gz
thermoprint-4914e4d7f638b7771ecdaf24ee0516c05505697c.tar.bz2
thermoprint-4914e4d7f638b7771ecdaf24ee0516c05505697c.tar.xz
thermoprint-4914e4d7f638b7771ecdaf24ee0516c05505697c.zip
Disallow paragraphs everywhere but at the top
Diffstat (limited to 'bbcode/src')
-rw-r--r--bbcode/src/Text/BBCode.hs37
1 files changed, 21 insertions, 16 deletions
diff --git a/bbcode/src/Text/BBCode.hs b/bbcode/src/Text/BBCode.hs
index fbd8a33..8f04f19 100644
--- a/bbcode/src/Text/BBCode.hs
+++ b/bbcode/src/Text/BBCode.hs
@@ -6,6 +6,7 @@ module Text.BBCode
6 ( bbcode 6 ( bbcode
7 , BBCodeError(..) 7 , BBCodeError(..)
8 , TreeError(..) 8 , TreeError(..)
9 , DomForest
9 , DomTree(..) 10 , DomTree(..)
10 -- , dom 11 -- , dom
11 -- , BBLabel 12 -- , BBLabel
@@ -40,19 +41,23 @@ import Data.Bifunctor (Bifunctor(first))
40 41
41-- | Our target structure -- a rose tree with an explicit terminal constructor 42-- | Our target structure -- a rose tree with an explicit terminal constructor
42data DomTree = Element (CI Text) (Map (CI Text) Text) [DomTree] 43data DomTree = Element (CI Text) (Map (CI Text) Text) [DomTree]
43 | Paragraph [DomTree]
44 | Content Text 44 | Content Text
45 deriving (Show, Eq) 45 deriving (Show, Eq)
46 46
47dom :: Forest BBLabel -> [DomTree] 47-- | List of paragraphs, which are comprised of lists of 'DomTree's
48type DomForest = [[DomTree]]
49
50dom :: Forest BBLabel -> DomForest
48-- ^ Parse semantically constrained rose tree to syntactically constrained version 51-- ^ Parse semantically constrained rose tree to syntactically constrained version
49-- 52--
50-- Silently drops children of semantically terminal nodes ('BBPlain') 53-- Silently drops children of semantically terminal nodes ('BBPlain') and paragraphs anywhere but at top level
51dom = map dom' 54dom = map fromPar
52 where 55 where
53 dom' (Node (BBPlain t) _) = Content t 56 fromPar (Node BBPar ts) = concatMap dom' ts
54 dom' (Node (BBTag t attrs) ts) = Element (CI.mk t) (Map.mapKeys CI.mk attrs) $ map dom' ts 57 fromPar x = dom' x
55 dom' (Node BBPar ts) = Paragraph $ map dom' ts 58 dom' (Node (BBPlain t) _) = pure $ Content t
59 dom' (Node (BBTag t attrs) ts) = pure . Element (CI.mk t) (Map.mapKeys CI.mk attrs) $ concatMap dom' ts
60 dom' (Node BBPar _) = []
56 61
57-- | Errors encountered during parsing 62-- | Errors encountered during parsing
58data BBCodeError = LexerError String -- ^ Error while parsing input to stream of tokens 63data BBCodeError = LexerError String -- ^ Error while parsing input to stream of tokens
@@ -61,13 +66,14 @@ data BBCodeError = LexerError String -- ^ Error while parsing input to stream of
61 66
62instance Exception BBCodeError 67instance Exception BBCodeError
63 68
64bbcode :: Text -> Either BBCodeError [DomTree] 69bbcode :: Text -> Either BBCodeError DomForest
65-- ^ Parse BBCode 70-- ^ Parse BBCode
66bbcode t = fmap dom $ first LexerError (parseOnly (many token <* endOfInput) t) >>= first TreeError . rose 71bbcode t = fmap dom $ first LexerError (parseOnly (many token <* endOfInput) t) >>= first TreeError . rose
67 72
68-- | Errors in input encountered during parsing of lexed token-stream 73-- | Errors in input encountered during parsing of lexed token-stream
69data TreeError = MismatchedTags Text Text -- ^ Closing tags label does not match opening tags 74data TreeError = MismatchedTags Text Text -- ^ Closing tags label does not match opening tags
70 | ImbalancedTags Text -- ^ We found an extraneous closing tag 75 | ImbalancedTags Text -- ^ We found an extraneous closing tag
76 | ParagraphWithinTag -- ^ We found a paragraph-break within a tag
71 deriving (Show, Eq, Generic, Typeable) 77 deriving (Show, Eq, Generic, Typeable)
72 78
73instance Exception TreeError 79instance Exception TreeError
@@ -93,7 +99,7 @@ rose :: [BBToken] -> Either TreeError (Forest BBLabel)
93rose = fmap Z.toForest . foldM (flip rose') (Z.fromForest []) 99rose = fmap Z.toForest . foldM (flip rose') (Z.fromForest [])
94 where 100 where
95 rose' (BBStr t) = return . Z.nextSpace . Z.insert (Node (BBPlain t) []) 101 rose' (BBStr t) = return . Z.nextSpace . Z.insert (Node (BBPlain t) [])
96 rose' BBNewPar = return . parBreak -- for more pointless 102 rose' BBNewPar = parBreak -- for more pointless
97 rose' (BBOpen t attrs) = return . Z.children . Z.insert (Node (BBTag t $ Map.fromList attrs) []) 103 rose' (BBOpen t attrs) = return . Z.children . Z.insert (Node (BBTag t $ Map.fromList attrs) [])
98 rose' (BBContained t attrs) = return . Z.nextSpace . Z.insert (Node (BBTag t $ Map.fromList attrs) []) 104 rose' (BBContained t attrs) = return . Z.nextSpace . Z.insert (Node (BBTag t $ Map.fromList attrs) [])
99 rose' (BBClose t) = close t -- for more pointless 105 rose' (BBClose t) = close t -- for more pointless
@@ -110,15 +116,14 @@ rose = fmap Z.toForest . foldM (flip rose') (Z.fromForest [])
110 | isPar . Z.tree $ pos = Z.parent pos >>= traversePars 116 | isPar . Z.tree $ pos = Z.parent pos >>= traversePars
111 | otherwise = return pos 117 | otherwise = return pos
112 118
113 parBreak :: TreePos Empty BBLabel -> TreePos Empty BBLabel 119 parBreak :: TreePos Empty BBLabel -> Either TreeError (TreePos Empty BBLabel)
114 parBreak z = let siblings = reverse $ Z.before z -- We only move ever move right so Z.after will always be empty 120 parBreak z = let siblings = reverse $ Z.before z
115 121
116 siblingsAsPars 122 siblingsAsPars
117 | all isPar siblings = z 123 | all isPar siblings = Right z
118 | otherwise = case Z.parent z of 124 | Z.isRoot z = Right . Z.fromForest $ [Node BBPar siblings]
119 Nothing -> Z.fromForest $ [Node BBPar siblings] 125 | otherwise = Left ParagraphWithinTag
120 Just p -> Z.children . Z.modifyTree (\(Node l _) -> Node l [Node BBPar siblings]) $ p 126 in Z.children . Z.insert (Node BBPar []) . Z.last <$> siblingsAsPars
121 in Z.children . Z.insert (Node BBPar []) . Z.last $ siblingsAsPars
122 127
123 isPar (Node BBPar _) = True 128 isPar (Node BBPar _) = True
124 isPar _ = False 129 isPar _ = False