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
23 import qualified System.FilePath as FP
25 import Language.TCT.Elem
31 deriving (Eq, Show, Functor)
33 instance Traversable (Tree k) where
34 traverse f (Tree0 a) = Tree0 <$> f a
35 traverse f (TreeN k ts) = TreeN k <$> traverse (traverse f) ts
36 sequenceA (Tree0 a) = Tree0 <$> a
37 sequenceA (TreeN k ts) = TreeN k <$> traverse sequenceA ts
38 instance Foldable (Tree k) where
39 foldMap f (TreeN _k ts) = foldMap (foldMap f) ts
40 foldMap f (Tree0 k) = f k
42 isTree0 :: Tree k a -> Bool
43 isTree0 Tree0{} = True
46 mapTreeWithKey :: (Maybe k -> a -> b) -> Tree k a -> Tree k b
47 mapTreeWithKey = go Nothing
49 go _k f (TreeN k ts) = TreeN k (go (Just k) f <$> ts)
50 go k f (Tree0 a) = Tree0 (f k a)
52 mapTreeKey :: (k -> l) -> (Maybe k -> a -> b) -> Tree k a -> Tree l b
53 mapTreeKey fk fv = go Nothing
55 go _k (TreeN k ts) = TreeN (fk k) $ go (Just k) <$> ts
56 go k (Tree0 a) = Tree0 (fv k a)
58 traverseTreeWithKey :: Applicative f => (Maybe k -> a -> f b) -> Tree k a -> f (Tree k b)
59 traverseTreeWithKey = go Nothing
61 go _p f (TreeN k ts) = TreeN k <$> traverse (go (Just k) f) ts
62 go p f (Tree0 a) = Tree0 <$> f p a
65 type Trees k a = Seq (Tree k a)
67 newtype PrettyTree k a = PrettyTree (Trees k a)
68 instance (Show k, Show a) => Show (PrettyTree k a) where
69 show (PrettyTree t) = Text.unpack $ prettyTrees t
71 prettyTree :: (Show k, Show a) => Tree k a -> Text
72 prettyTree = Text.unlines . pretty
74 prettyTrees :: (Show k, Show a) => Trees k a -> Text
75 prettyTrees = foldr (\t acc -> prettyTree t <> "\n" <> acc) ""
77 pretty :: (Show k, Show a) => Tree k a -> [Text]
78 pretty (Tree0 a) = [Text.pack (show a)]
79 pretty (TreeN k ts0) = Text.pack (show k) : prettySubTrees ts0
84 t:<ts | Seq.null ts -> "|" : shift "`- " " " (pretty t)
85 | otherwise -> "|" : shift "+- " "| " (pretty t) <> prettySubTrees ts
86 shift first other = List.zipWith (<>) (first : List.repeat other)
89 data Pos = Pos {-# UNPACK #-} !Line {-# UNPACK #-} !Column
92 posTree :: Tree (Cell k) (Cell a) -> Pos
93 posTree (TreeN c _) = posCell c
94 posTree (Tree0 c) = posCell c
96 posEndTree :: Tree (Cell k) (Cell a) -> Pos
97 posEndTree (TreeN c _) = posEndCell c
98 posEndTree (Tree0 c) = posEndCell c
106 -- | Line in the source file, counting from 1.
108 linePos :: Pos -> Line
109 linePos (Pos l _) = l
112 -- | Column in the source file, counting from 1.
114 columnPos :: Pos -> Column
115 columnPos (Pos _ c) = c
118 -- | A list of 'Key's, maybe ended by 'Value', all read on the same 'Line'.
119 type Row = [Tree (Cell Key) (Cell Text)]
122 -- | NOTE: every 'Cell' as a 'Pos',
123 -- which is useful to indicate matches/errors/warnings/whatever,
124 -- or outputing in a format somehow preserving
125 -- the original input style.
126 data Cell a = Cell {-# UNPACK #-} !Pos {-# UNPACK #-} !Pos a
129 unCell :: Cell a -> a
130 unCell (Cell _ _ a) = a
132 posCell :: Cell a -> Pos
133 posCell (Cell pos _ _) = pos
134 posEndCell :: Cell a -> Pos
135 posEndCell (Cell _ pos _) = pos
137 lineCell :: Cell a -> Line
138 lineCell = linePos . posCell
139 columnCell :: Cell a -> Column
140 columnCell = columnPos . posCell
143 cell0 = Cell pos0 pos0
145 cell1 = Cell pos1 pos1
148 data Key = KeyColon !Name !White -- ^ @name: @
149 | KeyEqual !Name !White -- ^ @name=@
150 | KeyBar !Name !White -- ^ @name|@
151 | KeyGreat !Name !White -- ^ @name>@
152 | KeyLower !Name !Attrs -- ^ @<name a=b@
153 | KeyDot !Name -- ^ @1. @
155 | KeyDashDash -- ^ @-- @
156 | KeySection !LevelSection -- ^ @# @
157 | KeyBrackets !Name -- ^ @[ name ]@
158 | KeyDotSlash !PathFile -- ^ @./file @
164 -- ** Type 'PathFile'
165 type PathFile = FP.FilePath
167 -- ** Type 'LevelSection'
168 type LevelSection = Int
171 type Rows = [Tree (Cell Key) (Cell Text)]
173 -- | @appendRow rows row@ appends @row@ to @rows@.
175 -- [@rows@] parent 'Rows', from closest to farest (non-strictly descending)
176 -- [@row@] next 'Row', from leftest column to rightest (non-stricly ascending)
177 appendRow :: Rows -> Row -> Rows
178 appendRow [] row = List.reverse row
179 appendRow parents [] = parents
180 appendRow rows@(parent:parents) row@(cell:cells) =
181 trac ("appendRow: rows=" <> show rows) $
182 trac ("appendRow: row=" <> show row) $
184 let colParent = columnPos $ posTree parent in
185 let colRow = columnPos $ posTree cell in
186 case dbg "colParent" colParent`compare`dbg "colRow" colRow of
188 case (dbg "parent" parent,dbg "cell" cell) of
189 (Tree0{}, TreeN{}) -> eq
190 (Tree0 p, Tree0{}) | Text.null (unCell p) -> eq -- FIXME: useful?
191 (Tree0 p, Tree0 r) -> appendTree0 p r
194 case (dbg "parent" parent,dbg "cell" cell) of
195 (Tree0 p, Tree0 r) -> appendTree0 p r
196 (_, TreeN (unCell -> KeySection sectionRow) _)
197 | Just (sectionParent, secPar:secPars) <- collapseSection colRow rows ->
198 case dbg "sectionParent" sectionParent`compare`dbg "sectionRow" sectionRow of
199 LT -> appendRow (cell:secPar:secPars) cells
200 EQ -> appendRow (cell:insertChild secPar secPars) cells
202 (TreeN (unCell -> KeySection{}) _, Tree0{}) -> lt
203 (TreeN (unCell -> KeySection{}) _, TreeN{}) -> lt
204 (Tree0{}, TreeN{}) -> eq
205 (TreeN{}, TreeN{}) -> eq
206 (TreeN{}, Tree0{}) -> eq
210 case appendCellText p r of
211 Nothing -> appendRow (Tree0 r : insertChild (Tree0 p) parents) cells
212 Just c -> appendRow (Tree0 c : parents) cells
213 lt = appendRow [] row <> rows
214 eq = appendRow (cell : insertChild parent parents) cells
215 gt = appendRow (insertChild parent parents) row
216 -- | Find the first section (if any), returning its level, and the path collapsed upto it.
217 collapseSection :: Column -> Rows -> Maybe (Int,Rows)
218 collapseSection col xxs@(x:xs) | columnPos (posTree x) == col =
220 TreeN (unCell -> KeySection lvl) _ -> Just (lvl,xxs)
221 _ -> (\(lvl,cs) -> (lvl,insertChild x cs)) <$> collapseSection col xs
222 collapseSection _ _ = Nothing
224 appendCellText :: Cell Text -> Cell Text -> Maybe (Cell Text)
225 appendCellText (Cell posPar posEndPar p)
226 (Cell posRow posEndRow r) =
227 trac ("appendCellText: p="<>show p) $
228 trac ("appendCellText: r="<>show r) $
229 dbg "appendCellText" $
230 case linePos posRow - linePos posEndPar of
231 0 -> Just $ Cell posPar posEndRow $ p <> pad <> r
232 where pad = padding (columnPos posEndPar) (columnPos posRow)
233 1 -> Just $ Cell posPar posEndRow $ p <> pad <> r
234 where pad = "\n" <> padding (columnPos posPar) (columnPos posRow)
237 padding x y = Text.replicate (y - x) " "
239 insertChild :: Tree (Cell Key) (Cell Text) -> Rows -> Rows
240 insertChild child ps@[] =
241 trac ("insertChild: child="<>show child) $
242 trac ("insertChild: ps="<>show ps) $
245 insertChild _child (Tree0{}:_) = undefined
246 insertChild child ps@(TreeN parent treesParent:parents) =
247 trac ("insertChild: child="<>show child) $
248 trac ("insertChild: ps="<>show ps) $
250 case dbg "colParent" (columnCell parent)`compare`dbg "colChild" (columnPos $ posTree child) of
251 LT -> TreeN parent (treesParent |> child) : parents
252 EQ -> TreeN parent (treesParent |> child) : parents
255 collapseRows :: Rows -> Tree (Cell Key) (Cell Text)
256 collapseRows [] = undefined
257 collapseRows [child] = dbg "collapseRows" $ child
258 collapseRows (child:parents) = dbg "collapseRows" $ collapseRows $ insertChild child parents