1 {-# LANGUAGE DeriveFunctor #-}
2 {-# LANGUAGE OverloadedStrings #-}
3 module Language.TCT.Tree where
5 import Control.Applicative (Applicative(..))
7 import Data.Eq (Eq(..))
8 import Data.Foldable (Foldable(..))
9 import Data.Foldable (foldr)
10 import Data.Function (($), (.))
11 import Data.Functor (Functor, (<$>))
12 import Data.Maybe (Maybe(..))
13 import Data.Ord (Ordering(..), Ord(..))
14 import Data.Semigroup (Semigroup(..))
15 import Data.Sequence (Seq, ViewL(..), (|>))
16 import Data.Text (Text)
17 import Data.Traversable (Traversable(..))
18 import Prelude (undefined, Int, Num(..))
19 import Text.Show (Show(..))
20 import qualified Data.List as List
21 import qualified Data.Sequence as Seq
22 import qualified Data.Text as Text
24 import Language.TCT.Elem
30 deriving (Eq, Show, Functor)
32 instance Traversable (Tree k) where
33 traverse f (Tree0 a) = Tree0 <$> f a
34 traverse f (TreeN k ts) = TreeN k <$> traverse (traverse f) ts
35 sequenceA (Tree0 a) = Tree0 <$> a
36 sequenceA (TreeN k ts) = TreeN k <$> traverse sequenceA ts
37 instance Foldable (Tree k) where
38 foldMap f (TreeN _k ts) = foldMap (foldMap f) ts
39 foldMap f (Tree0 k) = f k
41 mapTreeWithKey :: (Maybe k -> a -> b) -> Tree k a -> Tree k b
42 mapTreeWithKey = go Nothing
44 go _k f (TreeN k ts) = TreeN k (go (Just k) f <$> ts)
45 go k f (Tree0 a) = Tree0 (f k a)
47 mapTreeKey :: (k -> l) -> (Maybe k -> a -> b) -> Tree k a -> Tree l b
48 mapTreeKey fk fv = go Nothing
50 go _k (TreeN k ts) = TreeN (fk k) $ go (Just k) <$> ts
51 go k (Tree0 a) = Tree0 (fv k a)
53 traverseTreeWithKey :: Applicative f => (Maybe k -> a -> f b) -> Tree k a -> f (Tree k b)
54 traverseTreeWithKey = go Nothing
56 go _p f (TreeN k ts) = TreeN k <$> traverse (go (Just k) f) ts
57 go p f (Tree0 a) = Tree0 <$> f p a
60 type Trees k a = Seq (Tree k a)
62 newtype PrettyTree k a = PrettyTree (Trees k a)
63 instance (Show k, Show a) => Show (PrettyTree k a) where
64 show (PrettyTree t) = Text.unpack $ prettyTrees t
66 prettyTree :: (Show k, Show a) => Tree k a -> Text
67 prettyTree = Text.unlines . pretty
69 prettyTrees :: (Show k, Show a) => Trees k a -> Text
70 prettyTrees = foldr (\t acc -> prettyTree t <> "\n" <> acc) ""
72 pretty :: (Show k, Show a) => Tree k a -> [Text]
73 pretty (Tree0 a) = [Text.pack (show a)]
74 pretty (TreeN k ts0) = Text.pack (show k) : prettySubTrees ts0
79 t:<ts | Seq.null ts -> "|" : shift "`- " " " (pretty t)
80 | otherwise -> "|" : shift "+- " "| " (pretty t) <> prettySubTrees ts
81 shift first other = List.zipWith (<>) (first : List.repeat other)
84 data Pos = Pos {-# UNPACK #-} !Line {-# UNPACK #-} !Column
87 posTree :: Tree (Cell k) (Cell a) -> Pos
88 posTree (TreeN c _) = posCell c
89 posTree (Tree0 c) = posCell c
91 posEndTree :: Tree (Cell k) (Cell a) -> Pos
92 posEndTree (TreeN c _) = posEndCell c
93 posEndTree (Tree0 c) = posEndCell c
101 -- | Line in the source file, counting from 1.
103 linePos :: Pos -> Line
104 linePos (Pos l _) = l
107 -- | Column in the source file, counting from 1.
109 columnPos :: Pos -> Column
110 columnPos (Pos _ c) = c
113 -- | A list of 'Key's, maybe ended by 'Value', all read on the same 'Line'.
114 type Row = [Tree (Cell Key) (Cell Text)]
117 -- | NOTE: every 'Cell' as a 'Pos',
118 -- which is useful to indicate matches/errors/warnings/whatever,
119 -- or outputing in a format somehow preserving
120 -- the original input style.
121 data Cell a = Cell {-# UNPACK #-} !Pos {-# UNPACK #-} !Pos a
124 unCell :: Cell a -> a
125 unCell (Cell _ _ a) = a
127 posCell :: Cell a -> Pos
128 posCell (Cell pos _ _) = pos
129 posEndCell :: Cell a -> Pos
130 posEndCell (Cell _ pos _) = pos
132 lineCell :: Cell a -> Line
133 lineCell = linePos . posCell
134 columnCell :: Cell a -> Column
135 columnCell = columnPos . posCell
138 cell0 = Cell pos0 pos0
140 cell1 = Cell pos1 pos1
143 data Key = KeyColon !Name !White -- ^ @name: @ begin 'Cell'
144 | KeyEqual !Name !White -- ^ @name=@ begin 'Value'
145 | KeyBar !Name !White -- ^ @name|@ continue 'Value'
146 | KeyGreat !Name !White -- ^ @name>@ continue 'Cell'
147 | KeyLower !Name !Attrs -- ^ @<name a=b@ begin HereDoc
148 | KeyDot !Name -- ^ @1. @ begin item
149 | KeyDash -- ^ @- @ begin item
150 | KeySection !LevelSection -- ^ @### @ begin section
156 -- ** Type 'LevelSection'
157 type LevelSection = Int
160 type Rows = [Tree (Cell Key) (Cell Text)]
162 -- | @appendRow rows row@ appends @row@ to @rows@.
164 -- [@rows@] parent 'Rows', from closest to farest (non-strictly descending)
165 -- [@row@] next 'Row', from leftest column to rightest (non-stricly ascending)
166 appendRow :: Rows -> Row -> Rows
167 appendRow [] row = List.reverse row
168 appendRow parents [] = parents
169 appendRow rows@(parent:parents) row@(cell:cells) =
170 trac ("appendRow: rows=" <> show rows) $
171 trac ("appendRow: row=" <> show row) $
173 let colParent = columnPos $ posTree parent in
174 let colRow = columnPos $ posTree cell in
175 case dbg "colParent" colParent`compare`dbg "colRow" colRow of
177 case (dbg "parent" parent,dbg "cell" cell) of
178 (Tree0{}, TreeN{}) -> eq
179 (Tree0 p, Tree0{}) | Text.null (unCell p) -> eq -- FIXME: useful?
180 (Tree0 p, Tree0 r) -> appendTree0 p r
183 case (dbg "parent" parent,dbg "cell" cell) of
184 (Tree0 p, Tree0 r) -> appendTree0 p r
185 (_, TreeN (unCell -> KeySection sectionRow) _)
186 | Just (sectionParent, secPar:secPars) <- collapseSection colRow rows ->
187 case dbg "sectionParent" sectionParent`compare`dbg "sectionRow" sectionRow of
188 LT -> appendRow (cell:secPar:secPars) cells
189 EQ -> appendRow (cell:insertChild secPar secPars) cells
191 (TreeN (unCell -> KeySection{}) _, Tree0{}) -> lt
192 (TreeN (unCell -> KeySection{}) _, TreeN{}) -> lt
193 (Tree0{}, TreeN{}) -> eq
194 (TreeN{}, TreeN{}) -> eq
195 (TreeN{}, Tree0{}) -> eq
199 case appendCellText p r of
200 Nothing -> appendRow (Tree0 r : insertChild (Tree0 p) parents) cells
201 Just c -> appendRow (Tree0 c : parents) cells
202 lt = appendRow [] row <> rows
203 eq = appendRow (cell : insertChild parent parents) cells
204 gt = appendRow (insertChild parent parents) row
205 -- | Find the first section (if any), returning its level, and the path collapsed upto it.
206 collapseSection :: Column -> Rows -> Maybe (Int,Rows)
207 collapseSection col xxs@(x:xs) | columnPos (posTree x) == col =
209 TreeN (unCell -> KeySection lvl) _ -> Just (lvl,xxs)
210 _ -> (\(lvl,cs) -> (lvl,insertChild x cs)) <$> collapseSection col xs
211 collapseSection _ _ = Nothing
213 appendCellText :: Cell Text -> Cell Text -> Maybe (Cell Text)
214 appendCellText (Cell posPar posEndPar p)
215 (Cell posRow posEndRow r) =
216 trac ("appendCellText: p="<>show p) $
217 trac ("appendCellText: r="<>show r) $
218 dbg "appendCellText" $
219 case linePos posRow - linePos posEndPar of
220 0 -> Just $ Cell posPar posEndRow $ p <> pad <> r
221 where pad = padding (columnPos posEndPar) (columnPos posRow)
222 1 -> Just $ Cell posPar posEndRow $ p <> pad <> r
223 where pad = "\n" <> padding (columnPos posPar) (columnPos posRow)
226 padding x y = Text.replicate (y - x) " "
228 insertChild :: Tree (Cell Key) (Cell Text) -> Rows -> Rows
229 insertChild child ps@[] =
230 trac ("insertChild: child="<>show child) $
231 trac ("insertChild: ps="<>show ps) $
234 insertChild _child (Tree0{}:_) = undefined
235 insertChild child ps@(TreeN parent treesParent:parents) =
236 trac ("insertChild: child="<>show child) $
237 trac ("insertChild: ps="<>show ps) $
239 case dbg "colParent" (columnCell parent)`compare`dbg "colChild" (columnPos $ posTree child) of
240 LT -> TreeN parent (treesParent |> child) : parents
241 EQ -> TreeN parent (treesParent |> child) : parents
244 collapseRows :: Rows -> Tree (Cell Key) (Cell Text)
245 collapseRows [] = undefined
246 collapseRows [child] = dbg "collapseRows" $ child
247 collapseRows (child:parents) = dbg "collapseRows" $ collapseRows $ insertChild child parents