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 Text.Megaparsec as P
25 import Language.TCT.Tree
26 import Language.TCT.Token
27 import Language.TCT.Read.Elem
29 p_Position :: Parser e s Pos
30 p_Position = (<$> P.getPosition) $ \p ->
32 (intOfPos $ P.sourceLine p)
33 (intOfPos $ P.sourceColumn p)
34 intOfPos :: P.Pos -> Int
35 intOfPos = fromInteger . toInteger . P.unPos
37 p_LineNum :: Parser e s Line
38 p_LineNum = intOfPos . P.sourceLine <$> P.getPosition
40 p_ColNum :: Parser e s Column
41 p_ColNum = intOfPos . P.sourceColumn <$> P.getPosition
43 p_CellKey :: Row -> Parser e s Row
44 p_CellKey row = pdbg "CellKey" $ do
45 P.skipMany $ P.char ' '
49 [ P.try $ P.char '-' >>
50 P.char ' ' $> KeyDash <|>
51 P.string "- " $> KeyDashDash
52 , P.try $ KeyDot . Text.pack
53 <$> P.some (P.satisfy Char.isDigit)
55 <* 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 <$> P.between (P.string "[") (P.string "]") p_Name
61 <* P.lookAhead (P.try $ P.eof <|> void (P.satisfy (=='\n')))
63 (\p f -> KeyDotSlash $ p<>f)
65 <*> P.many (P.satisfy (/='\n'))
68 wh <- Text.pack <$> P.many (P.char ' ')
70 [ P.try $ KeyColon name wh
72 <* P.lookAhead (P.try $ P.eof <|> void (P.satisfy $ \c -> c=='\n'||c==' '))
73 , P.char '>' $> KeyGreat name wh
74 , P.char '=' $> KeyEqual name wh
75 , P.char '|' $> KeyBar name wh
79 let row' = TreeN (Cell pos posEnd key) mempty : row
81 KeySection{} -> p_CellEnd row'
82 KeyDash{} -> p_Row row'
83 KeyDashDash{} -> p_CellText row'
84 KeyDot{} -> p_Row row'
85 KeyColon{} -> p_Row row'
86 KeyBrackets{} -> p_Row row'
87 KeyGreat{} -> p_Row row'
88 KeyEqual{} -> p_CellEnd row'
89 KeyBar{} -> p_CellEnd row'
90 KeyDotSlash{} -> p_CellEnd row'
91 KeyLower{} -> undefined -- NOTE: handled in 'p_CellLower'
93 p_Name :: Parser e s Name
95 (\h t -> Text.pack (h:t))
96 <$> (P.satisfy $ \c ->
97 Char.isAlphaNum c || c=='_')
98 <*> many (P.satisfy $ \c ->
99 Char.isAlphaNum c || c=='-' || c=='_')
101 p_Line :: Parser e s Text
102 p_Line = Text.pack <$> P.many (P.satisfy (/='\n'))
104 p_CellLower :: Row -> Parser e s Row
105 p_CellLower row = pdbg "CellLower" $ do
106 P.skipMany $ P.char ' '
111 posClose <- p_Position
113 TreeN (Cell pos posClose $ KeyLower name attrs) .
114 Seq.singleton . Tree0
115 let treeElem toks (Cell _ p c) =
116 let (o,_) = pairBorders (PairElem name attrs) toks in
117 Tree0 $ Cell pos p (o<>c)
118 let indent = List.replicate (columnPos pos - 1) ' '
120 P.try (P.char '>' >> treeElem (tokens [TokenPlain ""]) <$> p_CellLinesUntilElemEnd indent name) <|>
121 P.try (P.char '\n' >> P.string indent >> treeHere <$> p_CellLines indent) <|>
122 P.try (P.string "/>" >> treeElem mempty <$> p_CellLine) <|>
123 (P.eof $> treeHere (Cell posClose posClose ""))
126 p_attrs = P.many $ P.try $
128 <$> (Text.pack <$> P.some (P.char ' '))
130 p_CellLine :: Parser e s (Cell Text)
135 return $ Cell pos posEnd content
136 p_CellLines :: String -> Parser e s (Cell Text)
137 p_CellLines indent = do
140 Text.intercalate "\n"
141 <$> P.sepBy (P.try p_Line) (P.try $ P.char '\n' >> P.string indent)
143 return $ Cell pos posEnd content
144 p_CellLinesUntilElemEnd :: String -> Text -> Parser e s (Cell Text)
145 p_CellLinesUntilElemEnd indent name = do
147 content <- Text.intercalate "\n" . List.reverse <$> go []
149 return $ Cell pos posEnd content
151 go :: [Text] -> Parser e s [Text]
153 P.try ((\w p l -> Text.pack w <> Text.pack p <> l : ls)
154 <$> P.many (P.char ' ')
155 <*> P.string ("</"<>Text.unpack name)
157 (p_Line >>= \l -> P.try $
162 p_CellText :: Row -> Parser e s Row
163 p_CellText row = pdbg "CellText" $ do
164 P.skipMany $ P.char ' '
166 line <- Text.pack <$> P.some (P.satisfy (/='\n'))
168 return $ Tree0 (Cell pos posEnd line) : row
170 p_CellSpaces :: Row -> Parser e s Row
171 p_CellSpaces row = pdbg "CellSpaces" $ do
172 P.skipSome $ P.char ' '
174 return $ Tree0 (Cell pos pos "") : row
176 p_CellEnd :: Row -> Parser e s Row
177 p_CellEnd row = pdbg "Row" $
178 P.try (p_CellLower row) <|>
179 P.try (p_CellText row) <|>
183 p_Row :: Row -> Parser e s Row
184 p_Row row = pdbg "Row" $
185 P.try (p_CellKey row) <|>
188 p_Rows :: Rows -> Parser e s Rows
191 let rows' = appendRow rows (List.reverse row) in
193 (P.newline >> p_Rows rows')
195 p_Trees :: Parser e s (Trees (Cell Key) (Cell Text))
196 p_Trees = unRoot . collapseRows <$> p_Rows [root]
198 root = TreeN (cell0 KeyDashDash) mempty
199 unRoot (TreeN (unCell -> KeyDashDash) roots) = roots