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: @
144 | KeyEqual !Name !White -- ^ @name=@
145 | KeyBar !Name !White -- ^ @name|@
146 | KeyGreat !Name !White -- ^ @name>@
147 | KeyLower !Name !Attrs -- ^ @<name a=b@
148 | KeyDot !Name -- ^ @1. @
150 | KeyDashDash -- ^ @-- @
151 | KeySection !LevelSection -- ^ @# @
152 | KeyBrackets !Name -- ^ @[ name ]@
158 -- ** Type 'LevelSection'
159 type LevelSection = Int
162 type Rows = [Tree (Cell Key) (Cell Text)]
164 -- | @appendRow rows row@ appends @row@ to @rows@.
166 -- [@rows@] parent 'Rows', from closest to farest (non-strictly descending)
167 -- [@row@] next 'Row', from leftest column to rightest (non-stricly ascending)
168 appendRow :: Rows -> Row -> Rows
169 appendRow [] row = List.reverse row
170 appendRow parents [] = parents
171 appendRow rows@(parent:parents) row@(cell:cells) =
172 trac ("appendRow: rows=" <> show rows) $
173 trac ("appendRow: row=" <> show row) $
175 let colParent = columnPos $ posTree parent in
176 let colRow = columnPos $ posTree cell in
177 case dbg "colParent" colParent`compare`dbg "colRow" colRow of
179 case (dbg "parent" parent,dbg "cell" cell) of
180 (Tree0{}, TreeN{}) -> eq
181 (Tree0 p, Tree0{}) | Text.null (unCell p) -> eq -- FIXME: useful?
182 (Tree0 p, Tree0 r) -> appendTree0 p r
185 case (dbg "parent" parent,dbg "cell" cell) of
186 (Tree0 p, Tree0 r) -> appendTree0 p r
187 (_, TreeN (unCell -> KeySection sectionRow) _)
188 | Just (sectionParent, secPar:secPars) <- collapseSection colRow rows ->
189 case dbg "sectionParent" sectionParent`compare`dbg "sectionRow" sectionRow of
190 LT -> appendRow (cell:secPar:secPars) cells
191 EQ -> appendRow (cell:insertChild secPar secPars) cells
193 (TreeN (unCell -> KeySection{}) _, Tree0{}) -> lt
194 (TreeN (unCell -> KeySection{}) _, TreeN{}) -> lt
195 (Tree0{}, TreeN{}) -> eq
196 (TreeN{}, TreeN{}) -> eq
197 (TreeN{}, Tree0{}) -> eq
201 case appendCellText p r of
202 Nothing -> appendRow (Tree0 r : insertChild (Tree0 p) parents) cells
203 Just c -> appendRow (Tree0 c : parents) cells
204 lt = appendRow [] row <> rows
205 eq = appendRow (cell : insertChild parent parents) cells
206 gt = appendRow (insertChild parent parents) row
207 -- | Find the first section (if any), returning its level, and the path collapsed upto it.
208 collapseSection :: Column -> Rows -> Maybe (Int,Rows)
209 collapseSection col xxs@(x:xs) | columnPos (posTree x) == col =
211 TreeN (unCell -> KeySection lvl) _ -> Just (lvl,xxs)
212 _ -> (\(lvl,cs) -> (lvl,insertChild x cs)) <$> collapseSection col xs
213 collapseSection _ _ = Nothing
215 appendCellText :: Cell Text -> Cell Text -> Maybe (Cell Text)
216 appendCellText (Cell posPar posEndPar p)
217 (Cell posRow posEndRow r) =
218 trac ("appendCellText: p="<>show p) $
219 trac ("appendCellText: r="<>show r) $
220 dbg "appendCellText" $
221 case linePos posRow - linePos posEndPar of
222 0 -> Just $ Cell posPar posEndRow $ p <> pad <> r
223 where pad = padding (columnPos posEndPar) (columnPos posRow)
224 1 -> Just $ Cell posPar posEndRow $ p <> pad <> r
225 where pad = "\n" <> padding (columnPos posPar) (columnPos posRow)
228 padding x y = Text.replicate (y - x) " "
230 insertChild :: Tree (Cell Key) (Cell Text) -> Rows -> Rows
231 insertChild child ps@[] =
232 trac ("insertChild: child="<>show child) $
233 trac ("insertChild: ps="<>show ps) $
236 insertChild _child (Tree0{}:_) = undefined
237 insertChild child ps@(TreeN parent treesParent:parents) =
238 trac ("insertChild: child="<>show child) $
239 trac ("insertChild: ps="<>show ps) $
241 case dbg "colParent" (columnCell parent)`compare`dbg "colChild" (columnPos $ posTree child) of
242 LT -> TreeN parent (treesParent |> child) : parents
243 EQ -> TreeN parent (treesParent |> child) : parents
246 collapseRows :: Rows -> Tree (Cell Key) (Cell Text)
247 collapseRows [] = undefined
248 collapseRows [child] = dbg "collapseRows" $ child
249 collapseRows (child:parents) = dbg "collapseRows" $ collapseRows $ insertChild child parents