Use Tree Zipper for rendering DTC ToF in HTML5.
[doclang.git] / Language / TCT / Read.hs
index c88655ada08fe49c160d921d79ba24ed2f5f657f..204a9ea62b903971ddb51ad4640bc2fdf9dc8fb9 100644 (file)
@@ -1,93 +1,98 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE TypeFamilies #-}
 module Language.TCT.Read
  ( module Language.TCT.Read.Tree
  , module Language.TCT.Read.Token
+ , module Language.TCT.Read.Cell
  , module Language.TCT.Read
  ) where
 
 import Control.Applicative (Applicative(..))
 import Data.Char (Char)
 import Data.Either (Either(..))
+import Data.Eq (Eq(..))
 import Data.Function (($))
 import Data.Functor ((<$>))
 import Data.Maybe (Maybe(..))
+import Data.Ord (Ord(..))
+import Data.Proxy (Proxy(..))
 import Data.Semigroup (Semigroup(..))
+import Data.Sequence (Seq)
+import Data.String (IsString)
 import Data.Text (Text)
 import Data.Traversable (Traversable(..))
-import Data.Tuple (fst, snd)
-import Prelude (fromIntegral)
+import Data.TreeSeq.Strict (Tree)
+import Data.Tuple (snd)
+import Data.Void (Void)
 import System.IO (FilePath)
+import qualified Data.Text as Text
+import qualified Data.TreeSeq.Strict as TreeSeq
 import qualified Text.Megaparsec as P
-import Text.Show (Show(..))
 
 import Language.TCT.Tree
 import Language.TCT.Token
+import Language.TCT.Cell
+import Language.TCT.Read.Cell
 import Language.TCT.Read.Tree
 import Language.TCT.Read.Token
 
-import Debug.Trace (trace)
+-- * Type 'TCT'
+type TCT = Tree (Cell Key) Tokens
 
-readTreeCell ::
- FilePath -> Text ->
- Either (P.ParseError (P.Token Text) P.Dec)
-        (Trees (Cell Key) (Cell Tokens))
-readTreeCell inp txt = do
-       tct <- P.runParser (p_Trees <* P.eof) inp txt
-       (`traverse` tct) {- $ (<$> trace (show $ PrettyTree tct) tct)-} $ \tr ->
-               sequence $ (`mapTreeWithKey`tr) $ \key (Cell pos posEnd t) ->
-                       case key of
-                        -- Verbatim Keys
-                        Just (unCell -> KeyBar{})   -> Right $ Cell pos posEnd $ tokens [TokenPlain t]
-                        Just (unCell -> KeyLower{}) -> Right $ Cell pos posEnd $ tokens [TokenPlain t]
-                        Just (unCell -> KeyEqual{}) -> Right $ Cell pos posEnd $ tokens [TokenPlain t]
-                        -- Token Keys
-                        _ ->
-                               Cell pos posEnd <$>
-                                       P.runParser (do
-                                               P.setTabWidth $ P.unsafePos $ fromIntegral $ columnPos pos
-                                               P.setPosition $ P.SourcePos inp
-                                                (P.unsafePos $ fromIntegral $ linePos   pos)
-                                                (P.unsafePos $ fromIntegral $ columnPos pos)
-                                               p_Tokens <* P.eof
-                                        ) inp (StreamCell t)
+-- * Type 'TCTs'
+type TCTs = Seq TCT
 
-readTree ::
+readTCTs ::
  FilePath -> Text ->
- Either (P.ParseError (P.Token Text) P.Dec)
-        (Trees Key Tokens)
-readTree inp txt = do
+ Either (P.ParseError (P.Token Text) (P.ErrorFancy Void)) TCTs
+readTCTs inp txt = do
        tct <- P.runParser (p_Trees <* P.eof) inp txt
        (`traverse` tct) $ \tr ->
-               sequence $ (\f -> mapTreeKey unCell f tr) $ \key (Cell pos _posEnd t) ->
-                       case unCell <$> key of
+               sequence $ (`TreeSeq.mapWithKey`tr) $ \key c@(Cell pos _posEnd t) ->
+                       case key of
                         -- Verbatim Keys
-                        Just KeyBar{}   -> Right $ tokens [TokenPlain t]
-                        Just KeyLower{} -> Right $ tokens [TokenPlain t]
-                        Just KeyEqual{} -> Right $ tokens [TokenPlain t]
+                        Just (unCell -> KeyBar{})   -> Right $ tokens [TokenPlain <$> c]
+                        Just (unCell -> KeyLower{}) -> Right $ tokens [TokenPlain <$> c]
+                        Just (unCell -> KeyEqual{}) -> Right $ tokens [TokenPlain <$> c]
                         -- Token Keys
                         _ ->
-                               P.runParser (do
-                                       P.setTabWidth $ P.unsafePos $ fromIntegral $ columnPos pos
-                                       P.setPosition $ P.SourcePos inp
-                                        (P.unsafePos $ fromIntegral $ linePos   pos)
-                                        (P.unsafePos $ fromIntegral $ columnPos pos)
-                                       p_Tokens <* P.eof
-                                ) inp (StreamCell t)
+                               snd $ P.runParser'
+                                (p_Tokens <* P.eof)
+                                P.State
+                                        { P.stateInput = StreamCell t
+                                        , P.statePos   = pure $ P.SourcePos inp
+                                                (P.mkPos $ linePos   pos)
+                                                (P.mkPos $ columnPos pos)
+                                        , P.stateTabWidth = P.mkPos $ columnPos pos
+                                        , P.stateTokensProcessed = 0
+                                        }
 
 -- * Type 'StreamCell'
 -- | Wrap 'Text' to have a 'P.Stream' instance
--- whose 'P.updatePos' method abuses the tab width state
+-- whose 'P.advance1' method abuses the tab width state
 -- to instead pass the line indent.
 -- This in order to report correct 'P.SourcePos'
 -- when parsing a 'Cell' containing newlines.
-newtype StreamCell = StreamCell Text
+newtype StreamCell = StreamCell { unStreamCell :: Text }
+ deriving (IsString,Eq,Ord)
 instance P.Stream StreamCell where
-       type Token StreamCell = Char
-       uncons (StreamCell t) = (StreamCell <$>) <$> P.uncons t
-       updatePos _s indent apos@(P.SourcePos n l c) ch = (apos, npos)
-               where
-               u = P.unsafePos 1
-               npos =
-                       case ch of
-                        '\n' -> P.SourcePos n (l <> u) indent
-                        _    -> P.SourcePos n l (c <> u)
+       type Token  StreamCell = Char
+       type Tokens StreamCell = StreamCell
+       take1_ (StreamCell t) = (StreamCell <$>) <$> P.take1_ t
+       takeN_ n (StreamCell t) =
+               (\(ts,s) -> (StreamCell ts, StreamCell s)) <$>
+               P.takeN_ n t
+       takeWhile_ f (StreamCell t) =
+               (\(ts,s) -> (StreamCell ts, StreamCell s)) $
+               P.takeWhile_ f t
+       tokensToChunk _s ts = StreamCell (P.tokensToChunk (Proxy::Proxy Text) ts)
+       chunkToTokens _s (StreamCell ch) = P.chunkToTokens (Proxy::Proxy Text) ch
+       chunkLength _s (StreamCell ch) = P.chunkLength (Proxy::Proxy Text) ch
+       advance1 _s  = advance1
+       advanceN _s indent pos (StreamCell t) = Text.foldl' (advance1 indent) pos t
+
+advance1 :: P.Pos -> P.SourcePos -> Char -> P.SourcePos
+advance1 indent (P.SourcePos n line col) c =
+       case c of
+        '\n' -> P.SourcePos n (line <> P.pos1) indent
+        _    -> P.SourcePos n line (col <> P.pos1)