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.string "- " $> KeyDash
50 , P.try $ KeyDot . Text.pack
51 <$> P.some (P.satisfy Char.isDigit)
53 <* P.lookAhead (P.try $ P.eof <|> void (P.satisfy $ \c -> c=='\n'||c==' '))
55 , P.try $ P.some (P.char '#') <* P.lookAhead (P.try $ P.char ' ') >>= \hs ->
56 return $ KeySection $ List.length hs
59 wh <- Text.pack <$> P.many (P.char ' ')
61 [ P.try $ KeyColon name wh
63 <* P.lookAhead (P.try $ P.eof <|> void (P.satisfy $ \c -> c=='\n'||c==' '))
64 , P.char '>' $> KeyGreat name wh
65 , P.char '=' $> KeyEqual name wh
66 , P.char '|' $> KeyBar name wh
71 let row' = TreeN (Cell pos posEnd key) mempty : row
73 KeySection{} -> p_CellEnd row'
74 KeyDash{} -> p_Row row'
75 KeyDot{} -> p_Row row'
76 KeyColon{} -> p_Row row'
77 KeyGreat{} -> p_Row row'
78 KeyEqual{} -> p_CellEnd row'
79 KeyBar{} -> p_CellEnd row'
80 KeyLower{} -> undefined -- NOTE: handled in 'p_CellLower'
82 p_Name :: Parser e s Name
84 (\h t -> Text.pack (h:t))
85 <$> (P.satisfy $ \c ->
86 Char.isAlphaNum c || c=='_')
87 <*> many (P.satisfy $ \c ->
88 Char.isAlphaNum c || c=='-' || c=='_')
90 p_CellLower :: Row -> Parser e s Row
91 p_CellLower row = pdbg "CellLower" $ do
92 P.skipMany $ P.char ' '
97 posClose <- p_Position
99 TreeN (Cell pos posClose $ KeyLower name attrs) .
100 Seq.singleton . Tree0
101 let treeElem toks (Cell _ p c) =
102 let (o,_) = pairBorders (PairElem name attrs) toks in
103 Tree0 $ Cell pos p (o<>c)
104 let indent = List.replicate (columnPos pos - 1) ' '
106 P.try (P.char '>' >> treeElem (tokens [TokenPlain ""]) <$> p_CellLinesUntilElemEnd indent name) <|>
107 P.try (P.char '\n' >> P.string indent >> treeHere <$> p_CellLines indent) <|>
108 P.try (P.string "/>" >> treeElem mempty <$> p_CellLine) <|>
109 (P.eof $> treeHere (Cell posClose posClose ""))
112 p_attrs = P.many $ P.try $
114 <$> (Text.pack <$> P.some (P.char ' '))
116 p_line :: Parser e s Text
117 p_line = Text.pack <$> P.many (P.satisfy (/='\n'))
118 p_CellLine :: Parser e s (Cell Text)
123 return $ Cell pos posEnd content
124 p_CellLines :: String -> Parser e s (Cell Text)
125 p_CellLines indent = do
128 Text.intercalate "\n"
129 <$> P.sepBy (P.try p_line) (P.try $ P.char '\n' >> P.string indent)
131 return $ Cell pos posEnd content
132 p_CellLinesUntilElemEnd :: String -> Text -> Parser e s (Cell Text)
133 p_CellLinesUntilElemEnd indent name = do
135 content <- Text.intercalate "\n" . List.reverse <$> go []
137 return $ Cell pos posEnd content
139 go :: [Text] -> Parser e s [Text]
141 P.try ((\w p l -> Text.pack w <> Text.pack p <> l : ls)
142 <$> P.many (P.char ' ')
143 <*> P.string ("</"<>Text.unpack name)
145 (p_line >>= \l -> P.try $
150 p_CellText :: Row -> Parser e s Row
151 p_CellText row = pdbg "CellText" $ do
152 P.skipMany $ P.char ' '
154 line <- Text.pack <$> P.some (P.satisfy (/='\n'))
156 return $ Tree0 (Cell pos posEnd line) : row
158 p_CellSpaces :: Row -> Parser e s Row
159 p_CellSpaces row = pdbg "CellSpaces" $ do
160 P.skipSome $ P.char ' '
162 return $ Tree0 (Cell pos pos "") : row
164 p_CellEnd :: Row -> Parser e s Row
165 p_CellEnd row = pdbg "Row" $
166 P.try (p_CellLower row) <|>
167 P.try (p_CellText row) <|>
171 p_Row :: Row -> Parser e s Row
172 p_Row row = pdbg "Row" $
173 P.try (p_CellKey row) <|>
176 p_Rows :: Rows -> Parser e s Rows
179 let rows' = appendRow rows (List.reverse row) in
181 (P.newline >> p_Rows rows')
183 p_Trees :: Parser e s (Trees (Cell Key) (Cell Text))
184 p_Trees = unRoot . collapseRows <$> p_Rows [root]
186 root = TreeN (cell0 KeyDash) mempty
187 unRoot (TreeN (unCell -> KeyDash) roots) = roots