1 {-# LANGUAGE FlexibleContexts #-}
2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE Rank2Types #-}
4 {-# LANGUAGE TupleSections #-}
5 {-# LANGUAGE TypeFamilies #-}
6 module Language.TCT.Read.Tree where
8 import Control.Applicative (Applicative(..), Alternative(..))
9 import Control.Monad (Monad(..), void)
11 import Data.Eq (Eq(..))
12 import Data.Function (($), (.))
13 import Data.Functor ((<$>), ($>), (<$))
14 import Data.Monoid (Monoid(..))
15 import Data.Semigroup (Semigroup(..))
16 import Data.String (String)
17 import Data.Text (Text)
18 import Prelude (undefined, Int, Num(..), toInteger)
19 import qualified Data.Char as Char
20 import qualified Data.List as List
21 import qualified Data.Sequence as Seq
22 import qualified Data.Text as Text
23 import qualified Data.Text.Lazy as TL
24 import qualified Text.Megaparsec as P
26 import Language.TCT.Tree
27 import Language.TCT.Token
28 import Language.TCT.Read.Elem
30 p_Position :: Parser e s Pos
31 p_Position = (<$> P.getPosition) $ \p ->
33 (intOfPos $ P.sourceLine p)
34 (intOfPos $ P.sourceColumn p)
35 intOfPos :: P.Pos -> Int
36 intOfPos = fromInteger . toInteger . P.unPos
38 p_Line :: Parser e s Line
39 p_Line = intOfPos . P.sourceLine <$> P.getPosition
41 p_Column :: Parser e s Column
42 p_Column = intOfPos . P.sourceColumn <$> P.getPosition
44 p_CellKey :: Row -> Parser e s Row
45 p_CellKey row = pdbg "CellKey" $ do
46 P.skipMany $ P.char ' '
50 [ P.try $ P.string "- " $> KeyDash
51 , P.try $ KeyDot . Text.pack
52 <$> P.some (P.satisfy Char.isDigit)
54 <* P.lookAhead (P.try $ P.eof <|> void (P.satisfy $ \c -> c=='\n'||c==' '))
56 , P.try $ P.some (P.char '#') <* P.lookAhead (P.try $ P.char ' ') >>= \hs ->
57 return $ KeySection $ List.length hs
60 wh <- Text.pack <$> P.many (P.char ' ')
62 [ P.try $ KeyColon name wh
64 <* P.lookAhead (P.try $ P.eof <|> void (P.satisfy $ \c -> c=='\n'||c==' '))
65 , P.char '>' $> KeyGreat name wh
66 , P.char '=' $> KeyEqual name wh
67 , P.char '|' $> KeyBar name wh
72 let row' = TreeN (Cell pos posEnd key) mempty : row
74 KeySection{} -> p_CellEnd row'
75 KeyDash{} -> p_Row row'
76 KeyDot{} -> p_Row row'
77 KeyColon{} -> p_Row row'
78 KeyGreat{} -> p_Row row'
79 KeyEqual{} -> p_CellEnd row'
80 KeyBar{} -> p_CellEnd row'
81 KeyLower{} -> undefined -- NOTE: handled in 'p_CellLower'
83 p_Name :: Parser e s Name
85 (\h t -> Text.pack (h:t))
86 <$> (P.satisfy $ \c ->
87 Char.isAlphaNum c || c=='_')
88 <*> many (P.satisfy $ \c ->
89 Char.isAlphaNum c || c=='-' || c=='_')
91 p_CellLower :: Row -> Parser e s Row
92 p_CellLower row = pdbg "CellLower" $ do
93 P.skipMany $ P.char ' '
98 posClose <- p_Position
100 TreeN (Cell pos posClose $ KeyLower name attrs) .
101 Seq.singleton . Tree0
102 let treeElem toks (Cell _ p c) =
103 let (o,_) = pairBorders (PairElem name attrs) toks in
104 Tree0 $ Cell pos p (o<>c)
105 let indent = List.replicate (columnPos pos - 1) ' '
107 P.try (P.char '>' >> treeElem (tokens [TokenPlain ""]) <$> p_CellLinesUntilElemEnd indent name) <|>
108 P.try (P.char '\n' >> P.string indent >> treeHere <$> p_CellLines indent) <|>
109 P.try (P.string "/>" >> treeElem mempty <$> p_CellLine) <|>
110 (P.eof $> treeHere (Cell posClose posClose ""))
113 p_attrs = P.many $ P.try $
115 <$> (Text.pack <$> P.some (P.char ' '))
117 p_line :: Parser e s TL.Text
118 p_line = TL.pack <$> P.many (P.satisfy (/='\n'))
119 p_CellLine :: Parser e s (Cell TL.Text)
124 return $ Cell pos posEnd content
125 p_CellLines :: String -> Parser e s (Cell TL.Text)
126 p_CellLines indent = do
130 <$> P.sepBy (P.try p_line) (P.try $ P.char '\n' >> P.string indent)
132 return $ Cell pos posEnd content
133 p_CellLinesUntilElemEnd :: String -> Text -> Parser e s (Cell TL.Text)
134 p_CellLinesUntilElemEnd indent name = do
136 content <- TL.intercalate "\n" . List.reverse <$> go []
138 return $ Cell pos posEnd content
140 go :: [TL.Text] -> Parser e s [TL.Text]
142 P.try ((\w p l -> TL.pack w <> TL.pack p <> l : ls)
143 <$> P.many (P.char ' ')
144 <*> P.string ("</"<>Text.unpack name)
146 (p_line >>= \l -> P.try $
151 p_CellText :: Row -> Parser e s Row
152 p_CellText row = pdbg "CellText" $ do
153 P.skipMany $ P.char ' '
155 line <- TL.pack <$> P.some (P.satisfy (/='\n'))
157 return $ Tree0 (Cell pos posEnd line) : row
159 p_CellSpaces :: Row -> Parser e s Row
160 p_CellSpaces row = pdbg "CellSpaces" $ do
161 P.skipSome $ P.char ' '
163 return $ Tree0 (Cell pos pos "") : row
165 p_CellEnd :: Row -> Parser e s Row
166 p_CellEnd row = pdbg "Row" $
167 P.try (p_CellLower row) <|>
168 P.try (p_CellText row) <|>
172 p_Row :: Row -> Parser e s Row
173 p_Row row = pdbg "Row" $
174 P.try (p_CellKey row) <|>
177 p_Rows :: Rows -> Parser e s Rows
180 let rows' = appendRow rows (List.reverse row) in
182 (P.newline >> p_Rows rows')
184 p_Trees :: Parser e s (Trees (Cell Key) (Cell TL.Text))
185 p_Trees = unRoot . collapseRows <$> p_Rows [root]
187 root = TreeN (Cell pos0 pos0 KeyDash) mempty
188 unRoot (TreeN (unCell -> KeyDash) roots) = roots