aboutsummaryrefslogtreecommitdiff
path: root/bbcode/src/BBCode.hs
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2015-12-25 17:56:13 +0000
committerGregor Kleen <gkleen@yggdrasil.li>2015-12-25 17:56:13 +0000
commit9db2c42f4880362cf098358de830415c14f6878c (patch)
tree2b0b9257f01eec926152746fc2e7646764063c3a /bbcode/src/BBCode.hs
parent08eee2f0de77ffa631e84ccf734e8e95817b7c81 (diff)
downloadthermoprint-9db2c42f4880362cf098358de830415c14f6878c.tar
thermoprint-9db2c42f4880362cf098358de830415c14f6878c.tar.gz
thermoprint-9db2c42f4880362cf098358de830415c14f6878c.tar.bz2
thermoprint-9db2c42f4880362cf098358de830415c14f6878c.tar.xz
thermoprint-9db2c42f4880362cf098358de830415c14f6878c.zip
Cleaned tree for rewrite
Diffstat (limited to 'bbcode/src/BBCode.hs')
-rw-r--r--bbcode/src/BBCode.hs120
1 files changed, 0 insertions, 120 deletions
diff --git a/bbcode/src/BBCode.hs b/bbcode/src/BBCode.hs
deleted file mode 100644
index 087842f..0000000
--- a/bbcode/src/BBCode.hs
+++ /dev/null
@@ -1,120 +0,0 @@
1{-# LANGUAGE OverloadedStrings, OverloadedLists, RankNTypes, ImpredicativeTypes #-}
2
3module BBCode
4 ( parse
5 , make
6 ) where
7
8import Thermoprint
9
10import BBCode.Tokenizer
11import BBCode.Syntax
12
13import Data.Maybe
14import Data.Monoid
15import Data.Either
16import Data.Bifunctor
17import Data.List
18import Data.Ord
19import Data.Foldable
20
21import Data.Function (on)
22
23import Data.CaseInsensitive ( CI )
24import qualified Data.CaseInsensitive as CI
25
26import Data.Map ( Map )
27import qualified Data.Map as Map
28
29import Prelude hiding (takeWhile)
30
31import Debug.Trace
32
33knownTags :: Map (CI String) (Either (Block String -> Block String) (Inline String -> Inline String))
34knownTags = [ ("center", Left Center)
35 , ("u", Right Underline)
36 ]
37
38isBlock, isInline :: String -> Bool
39isBlock = testTag isLeft
40isInline = testTag isRight
41testTag f k = fromMaybe False (f <$> Map.lookup (CI.mk k) knownTags)
42
43data Decorated c = Decorated c [String]
44 deriving (Show, Eq)
45
46make :: Block String -> String
47make (Over blocks) = concat $ map make blocks
48make (Center block) = "[center]" ++ make block ++ "[/center]\n"
49make (Paragraph inline) = make' inline ++ "\n"
50
51make' :: Inline String -> String
52make' (Beside inlines) = concat $ map make' inlines
53make' (Underline inline) = "[u]" ++ make' inline ++ "[/u]"
54make' (Cooked c) = c
55make' (Raw _) = error "Cannot transform block containing raw data to bbcode"
56
57parse :: String -> Either String (Block String)
58parse input = massage <$> ((remerge . blockify <$> (tokenize input >>= treeify)) >>= semantics)
59
60massage :: Block String -> Block String
61massage (Over [x]) = massage x
62massage (Over xs) = Over $ map massage xs
63massage (Center x) = Center $ massage x
64massage (Paragraph x) = Paragraph $ massage' x
65
66massage' :: Inline String -> Inline String
67massage' (Beside [x]) = massage' x
68massage' (Beside xs) = Beside $ map massage' xs
69massage' (Underline x) = Underline $ massage' x
70massage' z = z
71
72blockify :: ContentForest -> [Decorated String]
73blockify = map sortDeco . concat . map (blockify' [])
74 where
75 blockify' _ Empty = []
76 blockify' initial (Content str) = [str `Decorated` initial]
77 blockify' initial (Tagged cs tag) = concat $ map (blockify' $ tag : initial) cs
78 sortDeco :: Decorated c -> Decorated c
79 sortDeco (Decorated c tags) = Decorated c $ (nubBy ((==) `on` CI.mk) . sortBy blockiness) tags
80 blockiness :: String -> String -> Ordering
81 blockiness a b = comparing isBlock a b <> comparing CI.mk a b -- sort also alphabetically for the benefit of remerge
82
83remerge :: [Decorated String] -> ContentForest
84remerge [] = []
85remerge [(Decorated c deco)] = [appEndo applyDeco $ Content c]
86 where
87 applyDeco = foldMap (\t -> Endo (\c -> Tagged [c] t)) $ reverse deco
88remerge xs = concat $ map toTree $ groupLasts xs
89 where
90 groupLasts = groupBy ((==) `on` (listToMaybe . reverse . (\(Decorated _ ds) -> ds)))
91 -- toTree :: [Decorated String] -> [ContentTree]
92 toTree [] = []
93 toTree (x@(Decorated _ []):xs) = map (Content . (\(Decorated c []) -> c)) (x:xs)
94 toTree (x@(Decorated _ ds):xs) = [Tagged content tag]
95 where
96 tag = last ds
97 content = concat $ map toTree $ groupLasts $ map stripLast (x:xs)
98 stripLast (Decorated c ds) = Decorated c (init ds)
99
100unknownTag :: forall a. String -> Either String a
101unknownTag tag = Left $ "Unknown tag: " ++ tag
102
103semantics :: ContentForest -> Either String (Block String)
104semantics forest = Over <$> mapM semantics' forest
105
106semantics' :: ContentTree -> Either String (Block String)
107semantics' Empty = Right $ Over []
108semantics' (Content str) = Right $ Paragraph (Cooked str)
109semantics' (Tagged cs tag) = case Map.lookup (CI.mk tag) knownTags of
110 Nothing -> unknownTag tag
111 Just (Left f) -> Over . map f <$> mapM semantics' cs
112 Just (Right f) -> Paragraph . Beside . map f<$> mapM iSemantics cs
113
114iSemantics :: ContentTree -> Either String (Inline String)
115iSemantics Empty = Right $ Beside []
116iSemantics (Content str) = Right $ Cooked str
117iSemantics (Tagged cs tag) = case Map.lookup (CI.mk tag) knownTags of
118 Nothing -> unknownTag tag
119 Just (Left f) -> error "Known inline tag sorted within block"
120 Just (Right f) -> Beside . map f <$> mapM iSemantics cs