diff options
| -rw-r--r-- | spec/src/Thermoprint/Printout/BBCode.hs | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/spec/src/Thermoprint/Printout/BBCode.hs b/spec/src/Thermoprint/Printout/BBCode.hs index 8825732..ce2aa43 100644 --- a/spec/src/Thermoprint/Printout/BBCode.hs +++ b/spec/src/Thermoprint/Printout/BBCode.hs | |||
| @@ -29,6 +29,8 @@ import Data.Typeable (Typeable) | |||
| 29 | import Data.Bifunctor (bimap, first) | 29 | import Data.Bifunctor (bimap, first) |
| 30 | import Control.Monad (join) | 30 | import Control.Monad (join) |
| 31 | 31 | ||
| 32 | import Data.List (groupBy) | ||
| 33 | |||
| 32 | import Text.BBCode (DomForest, DomTree(..), TreeError(..)) | 34 | import Text.BBCode (DomForest, DomTree(..), TreeError(..)) |
| 33 | import qualified Text.BBCode as Raw (bbcode, BBCodeError(..)) | 35 | import qualified Text.BBCode as Raw (bbcode, BBCodeError(..)) |
| 34 | 36 | ||
| @@ -63,6 +65,7 @@ data ParseResult = RBlock Block -- ^ Parses only as 'Block' | |||
| 63 | | RLine Line -- ^ Parses only as 'Line' | 65 | | RLine Line -- ^ Parses only as 'Line' |
| 64 | | RAmbiguous Block Line -- ^ Parses as either 'Block' or 'Line' depending on context | 66 | | RAmbiguous Block Line -- ^ Parses as either 'Block' or 'Line' depending on context |
| 65 | | RNoParse SemanticError SemanticError -- ^ Does not parse as either 'Block' or 'Line' | 67 | | RNoParse SemanticError SemanticError -- ^ Does not parse as either 'Block' or 'Line' |
| 68 | deriving (Show) | ||
| 66 | 69 | ||
| 67 | -- | Current parser context | 70 | -- | Current parser context |
| 68 | data Context a where | 71 | data Context a where |
| @@ -80,6 +83,16 @@ extract LineCtx (RNoParse _ lErr) = Left lErr | |||
| 80 | extract BlockCtx _ = Left LineInBlockContext | 83 | extract BlockCtx _ = Left LineInBlockContext |
| 81 | extract LineCtx _ = Left BlockInLineContext | 84 | extract LineCtx _ = Left BlockInLineContext |
| 82 | 85 | ||
| 86 | hasBlockCtx :: ParseResult -> Bool | ||
| 87 | -- ^ Result can be 'extract'ed in a 'Block' 'Context' | ||
| 88 | hasBlockCtx (RLine _) = False | ||
| 89 | hasBlockCtx _ = True | ||
| 90 | |||
| 91 | hasLineCtx :: ParseResult -> Bool | ||
| 92 | -- ^ Result can be 'extract'ed in a 'Line' 'Context' | ||
| 93 | hasLineCtx (RBlock _) = False | ||
| 94 | hasLineCtx _ = True | ||
| 95 | |||
| 83 | bbcode :: Text -> Either BBCodeError Printout | 96 | bbcode :: Text -> Either BBCodeError Printout |
| 84 | -- ^ Parse BBCode | 97 | -- ^ Parse BBCode |
| 85 | bbcode = join . fmap (first SemanticError) . bimap morph' morph . Raw.bbcode | 98 | bbcode = join . fmap (first SemanticError) . bimap morph' morph . Raw.bbcode |
| @@ -88,7 +101,7 @@ morph :: DomForest -> Either SemanticError Printout | |||
| 88 | -- ^ Parse a list of paragraphs | 101 | -- ^ Parse a list of paragraphs |
| 89 | -- | 102 | -- |
| 90 | -- Since we permit only cooked input via 'Raw' 'Paragraph' is identical to 'Block' | 103 | -- Since we permit only cooked input via 'Raw' 'Paragraph' is identical to 'Block' |
| 91 | morph f = Seq.fromList <$> mapM (\t -> Seq.singleton . Cooked <$> parse BlockCtx t) f | 104 | morph = fmap Seq.fromList . mapM (\t -> Seq.singleton . Cooked <$> parse BlockCtx t) |
| 92 | 105 | ||
| 93 | parseDom :: DomTree -> ParseResult | 106 | parseDom :: DomTree -> ParseResult |
| 94 | -- ^ Invoke 'asLine' and 'asBlock' to parse a single 'DomTree' | 107 | -- ^ Invoke 'asLine' and 'asBlock' to parse a single 'DomTree' |
| @@ -107,7 +120,6 @@ parseDom (Element t attrs cs) | |||
| 107 | mergeResult :: Monoid a => Context a -> [ParseResult] -> Either SemanticError a | 120 | mergeResult :: Monoid a => Context a -> [ParseResult] -> Either SemanticError a |
| 108 | -- ^ Merge a list of 'ParseResults' in a certain 'Context' | 121 | -- ^ Merge a list of 'ParseResults' in a certain 'Context' |
| 109 | mergeResult _ [] = Right mempty | 122 | mergeResult _ [] = Right mempty |
| 110 | mergeResult BlockCtx xs@((RLine _):_) = bimap (const LineInBlockContext) Line $ mergeResult LineCtx xs | ||
| 111 | mergeResult ctx (amb@(RAmbiguous _ _):xs) = mappend <$> extract ctx amb <*> mergeResult ctx xs | 123 | mergeResult ctx (amb@(RAmbiguous _ _):xs) = mappend <$> extract ctx amb <*> mergeResult ctx xs |
| 112 | mergeResult ctx (err@(RNoParse _ _):_) = extract ctx err | 124 | mergeResult ctx (err@(RNoParse _ _):_) = extract ctx err |
| 113 | mergeResult ctx (x:xs) = mappend <$> extract ctx x <*> mergeResult ctx xs | 125 | mergeResult ctx (x:xs) = mappend <$> extract ctx x <*> mergeResult ctx xs |
| @@ -116,7 +128,13 @@ parse :: Monoid a => Context a -> [DomTree] -> Either SemanticError a | |||
| 116 | -- ^ Parse a list of 'DomTree's in a certain 'Context' | 128 | -- ^ Parse a list of 'DomTree's in a certain 'Context' |
| 117 | -- | 129 | -- |
| 118 | -- @parse ctx = 'mergeResult' ctx . map 'parseDom'@ | 130 | -- @parse ctx = 'mergeResult' ctx . map 'parseDom'@ |
| 119 | parse ctx = mergeResult ctx . map parseDom | 131 | parse BlockCtx = fmap mconcat . mapM mergeResult' . groupBy sameCtx . map parseDom |
| 132 | where | ||
| 133 | sameCtx a b = (hasLineCtx a && hasLineCtx b) || (hasBlockCtx a && hasBlockCtx b) | ||
| 134 | mergeResult' xs | ||
| 135 | | hasLineCtx `all` xs = Line <$> mergeResult LineCtx xs | ||
| 136 | | otherwise = mergeResult BlockCtx xs | ||
| 137 | parse ctx = mergeResult ctx . map parseDom | ||
| 120 | 138 | ||
| 121 | asBlock :: CI Text -> [DomTree] -> Map (CI Text) Text -> Either SemanticError Block | 139 | asBlock :: CI Text -> [DomTree] -> Map (CI Text) Text -> Either SemanticError Block |
| 122 | asBlock "VSpace" _ = Right . VSpace . lookupAttr "height" True 1 | 140 | asBlock "VSpace" _ = Right . VSpace . lookupAttr "height" True 1 |
