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_Line :: Parser e s Line
38 p_Line = intOfPos . P.sourceLine <$> P.getPosition
40 p_Column :: Parser e s Column
41 p_Column = 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
63 wh <- Text.pack <$> P.many (P.char ' ')
65 [ P.try $ KeyColon name wh
67 <* P.lookAhead (P.try $ P.eof <|> void (P.satisfy $ \c -> c=='\n'||c==' '))
68 , P.char '>' $> KeyGreat name wh
69 , P.char '=' $> KeyEqual name wh
70 , P.char '|' $> KeyBar name wh
75 let row' = TreeN (Cell pos posEnd key) mempty : row
77 KeySection{} -> p_CellEnd row'
78 KeyDash{} -> p_Row row'
79 KeyDashDash{} -> p_CellText row'
80 KeyDot{} -> p_Row row'
81 KeyColon{} -> p_Row row'
82 KeyBrackets{} -> p_Row row'
83 KeyGreat{} -> p_Row row'
84 KeyEqual{} -> p_CellEnd row'
85 KeyBar{} -> p_CellEnd row'
86 KeyLower{} -> undefined -- NOTE: handled in 'p_CellLower'
88 p_Name :: Parser e s Name
90 (\h t -> Text.pack (h:t))
91 <$> (P.satisfy $ \c ->
92 Char.isAlphaNum c || c=='_')
93 <*> many (P.satisfy $ \c ->
94 Char.isAlphaNum c || c=='-' || c=='_')
96 p_CellLower :: Row -> Parser e s Row
97 p_CellLower row = pdbg "CellLower" $ do
98 P.skipMany $ P.char ' '
103 posClose <- p_Position
105 TreeN (Cell pos posClose $ KeyLower name attrs) .
106 Seq.singleton . Tree0
107 let treeElem toks (Cell _ p c) =
108 let (o,_) = pairBorders (PairElem name attrs) toks in
109 Tree0 $ Cell pos p (o<>c)
110 let indent = List.replicate (columnPos pos - 1) ' '
112 P.try (P.char '>' >> treeElem (tokens [TokenPlain ""]) <$> p_CellLinesUntilElemEnd indent name) <|>
113 P.try (P.char '\n' >> P.string indent >> treeHere <$> p_CellLines indent) <|>
114 P.try (P.string "/>" >> treeElem mempty <$> p_CellLine) <|>
115 (P.eof $> treeHere (Cell posClose posClose ""))
118 p_attrs = P.many $ P.try $
120 <$> (Text.pack <$> P.some (P.char ' '))
122 p_line :: Parser e s Text
123 p_line = Text.pack <$> P.many (P.satisfy (/='\n'))
124 p_CellLine :: Parser e s (Cell Text)
129 return $ Cell pos posEnd content
130 p_CellLines :: String -> Parser e s (Cell Text)
131 p_CellLines indent = do
134 Text.intercalate "\n"
135 <$> P.sepBy (P.try p_line) (P.try $ P.char '\n' >> P.string indent)
137 return $ Cell pos posEnd content
138 p_CellLinesUntilElemEnd :: String -> Text -> Parser e s (Cell Text)
139 p_CellLinesUntilElemEnd indent name = do
141 content <- Text.intercalate "\n" . List.reverse <$> go []
143 return $ Cell pos posEnd content
145 go :: [Text] -> Parser e s [Text]
147 P.try ((\w p l -> Text.pack w <> Text.pack p <> l : ls)
148 <$> P.many (P.char ' ')
149 <*> P.string ("</"<>Text.unpack name)
151 (p_line >>= \l -> P.try $
156 p_CellText :: Row -> Parser e s Row
157 p_CellText row = pdbg "CellText" $ do
158 P.skipMany $ P.char ' '
160 line <- Text.pack <$> P.some (P.satisfy (/='\n'))
162 return $ Tree0 (Cell pos posEnd line) : row
164 p_CellSpaces :: Row -> Parser e s Row
165 p_CellSpaces row = pdbg "CellSpaces" $ do
166 P.skipSome $ P.char ' '
168 return $ Tree0 (Cell pos pos "") : row
170 p_CellEnd :: Row -> Parser e s Row
171 p_CellEnd row = pdbg "Row" $
172 P.try (p_CellLower row) <|>
173 P.try (p_CellText row) <|>
177 p_Row :: Row -> Parser e s Row
178 p_Row row = pdbg "Row" $
179 P.try (p_CellKey row) <|>
182 p_Rows :: Rows -> Parser e s Rows
185 let rows' = appendRow rows (List.reverse row) in
187 (P.newline >> p_Rows rows')
189 p_Trees :: Parser e s (Trees (Cell Key) (Cell Text))
190 p_Trees = unRoot . collapseRows <$> p_Rows [root]
192 root = TreeN (cell0 KeyDashDash) mempty
193 unRoot (TreeN (unCell -> KeyDashDash) roots) = roots