Add NodePara and NodeGroup.
authorJulien Moutinho <julm+hdoc@autogeree.net>
Wed, 24 Jan 2018 08:37:56 +0000 (09:37 +0100)
committerJulien Moutinho <julm+hdoc@autogeree.net>
Wed, 24 Jan 2018 08:37:56 +0000 (09:37 +0100)
15 files changed:
Data/TreeSeq/Strict.hs
Language/TCT/Cell.hs
Language/TCT/Elem.hs
Language/TCT/Read.hs
Language/TCT/Read/Cell.hs
Language/TCT/Read/Elem.hs
Language/TCT/Read/Token.hs
Language/TCT/Read/Tree.hs
Language/TCT/Token.hs
Language/TCT/Tree.hs
Language/TCT/Write/HTML5.hs
Language/TCT/Write/Plain.hs
Language/TCT/Write/XML.hs
Language/XML.hs
exe/cli/Main.hs

index 3c967bb3f8a1502f94bf5c7710d4134469cf8af0..38a21ed6979ecfb3c34494b10eb615f461db7948 100644 (file)
 {-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
 module Data.TreeSeq.Strict where
 
 import Control.Applicative (Applicative(..))
-import Control.Monad (Monad(..), ap)
+import Control.Monad (Monad(..))
 import Data.Bool
 import Data.Eq (Eq(..))
 import Data.Foldable (Foldable(..))
 import Data.Foldable (foldr)
 import Data.Function (($), (.))
-import Data.Functor (Functor, (<$>))
-import Data.Maybe (Maybe(..))
+import Data.Functor (Functor(..), (<$>))
+import Data.Monoid (Monoid(..))
 import Data.Ord (Ord(..))
 import Data.Semigroup (Semigroup(..))
 import Data.Sequence (Seq, ViewL(..))
-import Data.Text (Text)
 import Data.Traversable (Traversable(..))
 import Text.Show (Show(..))
 import qualified Data.List as List
 import qualified Data.Sequence as Seq
-import qualified Data.Text as Text
+import qualified Data.Text.Lazy as TL
 
 -- * Type 'Tree'
-data Tree k a
- =   TreeN !k !(Trees k a)
- |   Tree0 !a
- deriving (Eq, Ord, Show, Functor)
-
-instance Traversable (Tree k) where
-       traverse f (Tree0 a)    = Tree0 <$> f a
-       traverse f (TreeN k ts) = TreeN k <$> traverse (traverse f) ts
-       sequenceA (Tree0 a)     = Tree0 <$> a
-       sequenceA (TreeN k ts)  = TreeN k <$> traverse sequenceA ts
-instance Foldable (Tree k) where
-       foldMap f (TreeN _k ts) = foldMap (foldMap f) ts
-       foldMap f (Tree0 a)     = f a
-instance Applicative (Tree k) where
-       pure  = Tree0
-       (<*>) = ap
-instance Monad (Tree k) where
-       return = Tree0
-       Tree0 v >>= f = f v
-       TreeN k ts >>= f =
-               TreeN k $ (>>= f) <$> ts
-
-isTree0 :: Tree k a -> Bool
-isTree0 Tree0{} = True
-isTree0 _       = False
-
-isTreeN :: Tree k a -> Bool
-isTreeN TreeN{} = True
-isTreeN _       = False
-
-unTree :: Tree a a -> a
-unTree (TreeN k _) = k
-unTree (Tree0 a)   = a
-
+data Tree a
+ =   Tree { unTree   :: !a
+          , subTrees :: !(Trees a)
+          }
+ deriving (Eq, Ord, Show)
+instance Functor Tree where
+       fmap f (Tree a ts) = Tree (f a) (fmap (fmap f) ts)
+instance Applicative Tree where
+       pure a = Tree a mempty
+       Tree f tfs <*> ta@(Tree a tas) =
+               Tree (f a) (fmap (f <$>) tas <> fmap (<*> ta) tfs)
+instance Monad Tree where
+       return = pure
+       Tree a ts >>= f =
+               Tree a' (ts' <> fmap (>>= f) ts)
+               where Tree a' ts' = f a
+instance Foldable Tree where
+       foldMap f (Tree a ts) = f a `mappend` foldMap (foldMap f) ts
+instance Traversable Tree where
+       traverse f (Tree a ts) = Tree <$> f a <*> traverse (traverse f) ts
+       sequenceA  (Tree a ts) = Tree <$>   a <*> traverse sequenceA ts
+
+tree0 :: a -> Tree a
+tree0 a = Tree a mempty
+
+isTree0 :: Tree a -> Bool
+isTree0 (Tree _ ts) = null ts
+
+isTreeN :: Tree a -> Bool
+isTreeN (Tree _ ts) = not (null ts)
+
+{-
 mapWithNode :: (Maybe k -> a -> b) -> Tree k a -> Tree k b
 mapWithNode = go Nothing
        where
-       go _k f (TreeN k ts) = TreeN k (go (Just k) f <$> ts)
+       go _k f (Tree k ts) = Tree k (go (Just k) f <$> ts)
        go k  f (Tree0 a)    = Tree0 (f k a)
 
 mapAlsoNode :: (k -> l) -> (Maybe k -> a -> b) -> Tree k a -> Tree l b
 mapAlsoNode fk fv = go Nothing
        where
-       go _k (TreeN k ts) = TreeN (fk k) $ go (Just k) <$> ts
+       go _k (Tree k ts) = Tree (fk k) $ go (Just k) <$> ts
        go k  (Tree0 a)    = Tree0 (fv k a)
 
 traverseWithNode :: Applicative f => (Maybe k -> a -> f b) -> Tree k a -> f (Tree k b)
 traverseWithNode = go Nothing
        where
-       go _p f (TreeN k ts) = TreeN k <$> traverse (go (Just k) f) ts
+       go _p f (Tree k ts) = Tree k <$> traverse (go (Just k) f) ts
        go p  f (Tree0 a)    = Tree0 <$> f p a
 
 foldlWithTree :: (b -> Tree k a -> b) -> b -> Tree k a -> b
 foldlWithTree f b t =
        case t of
-        TreeN _k ts -> foldl' (foldlWithTree f) (f b t) ts
+        Tree _k ts -> foldl' (foldlWithTree f) (f b t) ts
         Tree0{} -> f b t
 
 bindTree :: Tree k a -> (Tree k a -> Tree l b) -> Tree l b
 bindTree t f =
        case t of
         Tree0{} -> f t
-        TreeN _k ks ->
+        Tree _k ks ->
                case f t of
                 u@Tree0{}  -> u
-                TreeN l ls -> TreeN l $ ls <> ((`bindTree` f) <$> ks)
+                Tree l ls -> Tree l $ ls <> ((`bindTree` f) <$> ks)
 
 bindTrees :: Tree k a -> (Tree k a -> Trees l b) -> Trees l b
 bindTrees t f =
        case t of
         Tree0{} -> f t
-        TreeN _k ks ->
+        Tree _k ks ->
                f t >>= \fs ->
                        case fs of
                         Tree0 b  -> Seq.singleton $ Tree0 b
-                        TreeN l ls -> pure $ TreeN l $ ls <> (ks >>= (`bindTrees` f))
+                        Tree l ls -> pure $ Tree l $ ls <> (ks >>= (`bindTrees` f))
 
 joinTrees :: Trees k (Trees k a) -> Trees k a
 joinTrees ts =
        ts >>= \case
         Tree0 s -> s
-        TreeN k ks -> Seq.singleton $ TreeN k $ joinTrees ks
+        Tree k ks -> Seq.singleton $ Tree k $ joinTrees ks
+-}
 
 -- * Type 'Trees'
-type Trees k a = Seq (Tree k a)
+type Trees a = Seq (Tree a)
 
 -- * Type 'Pretty'
-newtype Pretty k a = Pretty (Trees k a)
-instance (Show k, Show a) => Show (Pretty k a) where
-       show (Pretty t) = Text.unpack $ prettyTrees t
+newtype Pretty a = Pretty a
+instance Show a => Show (Pretty (Trees a)) where
+       show (Pretty t) = TL.unpack $ prettyTrees t
+instance Show a => Show (Pretty (Tree a)) where
+       show (Pretty t) = TL.unpack $ prettyTree t
 
-prettyTree :: (Show k, Show a) => Tree k a -> Text
-prettyTree = Text.unlines . pretty
+prettyTree :: Show a => Tree a -> TL.Text
+prettyTree = TL.unlines . pretty
 
-prettyTrees :: (Show k, Show a) => Trees k a -> Text
+prettyTrees :: Show a => Trees a -> TL.Text
 prettyTrees = foldr (\t acc -> prettyTree t <> "\n" <> acc) ""
 
-pretty :: (Show k, Show a) => Tree k a -> [Text]
-pretty (Tree0 a)     = [Text.pack (show a)]
-pretty (TreeN k ts0) = Text.pack (show k) : prettySubTrees ts0
+pretty :: Show a => Tree a -> [TL.Text]
+pretty (Tree a ts0) = TL.pack (show a) : prettySubTrees ts0
        where
        prettySubTrees s =
                case Seq.viewl s of
index 3746748d0a057edb56bb9054539fb1382f8a594e..0c96836dd5375ec019202ad90342b2803e9f8cfc 100644 (file)
 {-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
 module Language.TCT.Cell where
 
 import Data.Eq (Eq(..))
 import Data.Function (($), (.))
 import Data.Functor (Functor)
-import Data.Maybe (Maybe(..))
+import Data.Monoid (Monoid(..))
 import Data.Ord (Ord(..))
--- import Data.Semigroup (Semigroup(..))
-import Data.Sequence (Seq, ViewL(..), ViewR(..))
-import Data.TreeSeq.Strict (Tree(..))
-import Prelude (Int)
+import Data.Semigroup (Semigroup(..))
+import Data.Text (Text)
+import Prelude (Int, Num(..), fromIntegral)
 import Text.Show (Show(..), showParen, showString, showChar)
-import qualified Data.Sequence as Seq
+import qualified Data.Text as Text
+import qualified Data.Text.Lazy as TL
+
+-- * Type 'Pos'
+-- | Relative position
+data Pos
+ =   Pos
+ {   pos_line   :: {-# UNPACK #-} !LineNum
+ ,   pos_column :: {-# UNPACK #-} !ColNum
+ } deriving (Eq)
+instance Semigroup Pos where
+       Pos lx cx <> Pos ly cy =
+               Pos (lx+ly) (cx+cy)
+instance Monoid Pos where
+       mempty  = Pos 0 0
+       mappend = (<>)
+instance Show Pos where
+       showsPrec _p Pos{..} =
+               showsPrec 11 pos_line .
+               showChar ':' .
+               showsPrec 11 pos_column
+
+-- ** Type 'LineNum'
+type LineNum = Int
+
+-- ** Type 'ColNum'
+type ColNum = Int
 
 -- * Type 'Cell'
--- | NOTE: every 'Cell' as a 'Pos',
---         which is useful to indicate matches/errors/warnings/whatever,
---         or outputing in a format somehow preserving
---         the original input style.
 data Cell a
  =   Cell
- { posCell    :: {-# UNPACK #-} !Pos
- , posEndCell :: {-# UNPACK #-} !Pos
- , unCell     :: a
- } deriving (Eq, Ord, Functor)
+ {   cell_begin :: {-# UNPACK #-} !Pos
+ ,   cell_end   :: {-# UNPACK #-} !Pos
+ , unCell       :: !a
+ }   deriving (Eq, Functor)
 instance Show a => Show (Cell a) where
        showsPrec p Cell{..} =
                showParen (p >= 10) $
                showString "Cell" .
-               showChar ' ' . showsPrec 10 posCell .
-               showChar ' ' . showsPrec 10 posEndCell .
+               showChar ' ' . showsPrec 10 cell_begin .
+               showChar ' ' . showsPrec 10 cell_end .
                showChar ' ' . showsPrec 11 unCell
+instance (FromPad a, Semigroup a) => Semigroup (Cell a) where
+       Cell bx (Pos lx _cx) x <> Cell (Pos ly cy) ey y =
+               Cell bx ey $ x <> fromPad (Pos (ly - lx) cy) <> y
+instance (FromPad a, Semigroup a, Monoid a) => Monoid (Cell a) where
+       mempty  = cell0 mempty
+       mappend = (<>)
+cell0 :: a -> Cell a
+cell0 = Cell mempty mempty
+
+-- * Class 'FromPad'
+class FromPad a where
+       fromPad :: Pos -> a
+instance FromPad Text where
+       fromPad Pos{..} =
+               Text.replicate pos_line   "\n" <>
+               Text.replicate pos_column " "
+instance FromPad TL.Text where
+       fromPad Pos{..} =
+               TL.replicate (fromIntegral pos_line)   "\n" <>
+               TL.replicate (fromIntegral pos_column) " "
+
 {-
-instance Semigroup a => Semigroup (Cell a) where
+instance (FromPad a, Semigroup a) => Semigroup (Cell a) where
        Cell bx ex x <> Cell by ey y =
-               Cell (bx`min`by) (ex`max`ey) (x<>y)
-instance (Monoid a, Semigroup a) => Monoid (Cell a) where
-       mempty  = Cell pos1 pos1 mempty
-       mappend = (<>)
+               Cell bx ey $ x <> fromPad by <> y
+instance Applicative Cell where
+       pure = Cell mempty mempty
+       Cell of_ sf f <*> Cell bx ex x =
+               Cell of_ (sf<>bx<>ex) (f x)
+
+cell0 :: a -> Cell a
+cell0 = pure
+
+-- * Class 'Cellified'
+class Cellified a where
+       reachOf :: a -> Pos
+       reachOf a = offsetOf a <> sizeOf a
+       offsetOf :: a -> Pos
+       sizeOf :: a -> Pos
+instance Cellified (Cell a) where
+       offsetOf = cell_begin
+       sizeOf   = cell_end
+instance Cellified a => Cellified [a] where
+       reachOf = foldMap reachOf
+       offsetOf = \case
+        [] -> mempty
+        s0 : ss ->
+               if sizeOf s0 == mempty
+               then offsetOf s0 <> offsetOf ss
+               else offsetOf s0
+       sizeOf = foldMap sizeOf
+instance Cellified a => Cellified (Seq a) where
+       reachOf = foldMap reachOf
+       offsetOf s = case Seq.viewl s of
+        EmptyL -> mempty
+        s0 :< ss ->
+               if sizeOf s0 == mempty
+               then offsetOf s0 <> offsetOf ss
+               else offsetOf s0
+       sizeOf = foldMap sizeOf
+instance (Cellified k, Cellified a) => Cellified (Tree k a) where
+       reachOf = \case
+        TreeN k _ts -> reachOf k
+        Tree0 a -> reachOf a
+       offsetOf = \case
+        TreeN k _ts -> offsetOf k
+        Tree0 a -> offsetOf a
+       sizeOf = \case
+        TreeN k _ts -> sizeOf k
+        Tree0 a -> sizeOf a
+-}
+
+{-
+-- * Class 'Cellify'
+class Cellify a where
+       cellify :: a -> Cell a
+instance Cellify Text where
+       cellify t = Cell mempty s t
+               where
+               s =
+                       Text.foldl' (\acc -> \case
+                        '\n' -> acc{pos_line   = pos_line   acc + 1}
+                        _    -> acc{pos_column = pos_column acc + 1})
+                        mempty t
+
+-- * Type 'Pad'
+type Pad = Pos
+
+-- * Type 'Padded'
+data Padded a
+ =   Padded
+ {   pad    :: !Pad
+ ,   unPad  :: !a
+ } deriving (Eq,Show)
+
+
+-- * Type 'Pos'
+-- | Absolute position
+data Pos
+ =   Pos
+ {   pos_line   :: {-# UNPACK #-} !LineNum
+ ,   pos_column :: {-# UNPACK #-} !ColNum
+ } deriving (Eq, Ord)
+instance Show Pos where
+       showsPrec _p Pos{..} = showsPrec 11 (pos_line,pos_column)
+
+pos1 :: Pos
+pos1 = Pos 1 1
+
 -}
 
-lineCell :: Cell a -> Line
-lineCell = linePos . posCell
-columnCell :: Cell a -> Column
-columnCell = columnPos . posCell
 
-cell0 :: a -> Cell a
-cell0 = Cell pos0 pos0
+
+
+
+
+{-
+instance Applicative (Cell a) where
+       pure = cell0
+       cf@(Cell bf ef f) <*> ca@(Cell ba ea a) =
+        | isCell0 cf || isCell0 ca = cell0 (f a)
+               Cell bf ea (f a)
+isCell0 :: Cell a -> Bool
+isCell0 (Cell bp ep _) = isPos0 bp && isPos0 ep
+-}
+
+{-
+lineCell :: Cell a -> LineNum
+lineCell = pos_line . cell_begin
+columnCell :: Cell a -> ColNum
+columnCell = pos_column . cell_begin
+
 cell1 :: a -> Cell a
 cell1 = Cell pos1 pos1
+-}
 
+{-
 posSeq :: Seq (Cell a) -> Maybe (Pos,Pos)
 posSeq toks =
        case Seq.viewl toks of
@@ -59,8 +200,6 @@ posSeq toks =
                 EmptyR -> Nothing
                 _ :> Cell _bp ep _ ->
                        Just (bp, ep)
-
-{-
 posTrees :: Seq (Trees (Cell k) a) -> Maybe (Pos,Pos)
 posTrees trees =
        case Seq.viewl trees of
@@ -81,38 +220,50 @@ posTrees trees =
                        Just (Cell bp ep ())
 -}
 
--- * Type 'Pos'
-data Pos
- =   Pos
- {   linePos   :: {-# UNPACK #-} !Line
- ,   columnPos :: {-# UNPACK #-} !Column
- } deriving (Eq, Ord)
-instance Show Pos where
-       showsPrec _p Pos{..} = showsPrec 11 (linePos,columnPos)
 {-
-instance Ord Pos where
-       Pos lx cx `compare` Pos ly cy =
-               compare lx ly <>
-               compare cx cy
--}
-
 posTree :: Tree (Cell k) (Cell a) -> Pos
-posTree (TreeN c _) = posCell c
-posTree (Tree0 c)   = posCell c
+posTree (TreeN c _) = cell_begin c
+posTree (Tree0 c)   = cell_begin c
 
 posEndTree :: Tree (Cell k) (Cell a) -> Pos
-posEndTree (TreeN c _) = posEndCell c
-posEndTree (Tree0 c)   = posEndCell c
+posEndTree (TreeN c _) = cell_end c
+posEndTree (Tree0 c)   = cell_end c
 
 pos0 :: Pos
 pos0 = Pos 0 0
-pos1 :: Pos
-pos1 = Pos 1 1
+-}
+{-
+instance Ord Pos where
+       Pos lx cx `compare` Pos ly cy =
+               compare lx ly <>
+               compare cx cy
 
--- ** Type 'Line'
--- | Line in the source file, counting from 1.
-type Line = Int
+isPos0 :: Pos -> Bool
+isPos0 (Pos 0 0 ) = True
+isPos0 _ = False
+-}
 
--- ** Type 'Column'
--- | Column in the source file, counting from 1.
-type Column = Int
+{-
+-- ** Class 'CellOf'
+class CellOf a where
+       firstCellOf :: a -> Maybe (Cell ())
+instance CellOf (Cell a) where
+       firstCellOf = Just . (() <$)
+instance CellOf a => CellOf (Seq a) where
+       firstCellOf s =
+               case Seq.viewl s of
+                EmptyL -> Nothing
+                s0 :< ss ->
+                       firstCellOf s0 <|>
+                       firstCellOf ss
+instance CellOf a => CellOf [a] where
+       firstCellOf = \case
+        [] -> Nothing
+        s0 : ss ->
+               firstCellOf s0 <|>
+               firstCellOf ss
+instance (CellOf k, CellOf a) => CellOf (Tree k a) where
+       firstCellOf = \case
+        Tree0 a -> firstCellOf a
+        TreeN k a -> firstCellOf k <|> firstCellOf a
+-}
index ef1b342c3fcab1b12a99258bb21cda87a5b2b211..ed1f29358cc80d0d5cfcc6d0c94db245a81ec4e7 100644 (file)
@@ -1,36 +1,99 @@
+{-# LANGUAGE OverloadedStrings #-}
 module Language.TCT.Elem where
 
+import Data.Bool
+import Control.Monad (Monad(..), mapM)
 import Data.Eq (Eq)
+import Data.Function (($), (.))
+import Data.Foldable (toList, null)
+import Data.Int (Int)
 import Data.Ord (Ord)
+import Data.Maybe (Maybe(..))
+import Prelude ((+))
 import Data.Semigroup (Semigroup(..))
 import Data.String (String)
-import Data.Text (Text)
+import Data.Sequence (Seq)
 import Text.Show (Show(..))
+import Data.TreeSeq.Strict (Tree(..))
+import qualified Control.Monad.Trans.Reader as R
+import qualified Data.List as List
+import qualified Data.Text.Lazy as TL
+
+import Debug.Trace (trace)
 
--- import Debug.Trace (trace)
 trac :: String -> a -> a
-trac _m x = x
--- trac m x = trace m x
+-- trac _m x = x
+trac = trace
 {-# INLINE trac #-}
-dbg :: Show a => String -> a -> a
-dbg m x = trac (m <> ": " <> show x) x
+
+debug :: Pretty a => String -> String -> a -> b -> b
+debug f n a = trac (f <> ": " <> n <> " = " <> R.runReader (pretty a) 2)
+
+dbg :: Pretty a => String -> a -> a
+dbg m x = trac (m <> ": " <> R.runReader (pretty x) 2) x
 {-# INLINE dbg #-}
 
--- * Type 'Elem'
-type Elem = Text
+-- * Class 'Pretty'
+class Pretty a where
+       pretty :: a -> R.Reader Int String
+instance Pretty Int where
+       pretty = return . show
+instance Pretty TL.Text where
+       pretty = return . show
+instance (Pretty a, Pretty b) => Pretty (a,b) where
+       pretty (a,b) = do
+               i <- R.ask
+               a' <- R.local (+2) $ pretty a
+               b' <- R.local (+2) $ pretty b
+               return $
+                       "\n" <> List.replicate i ' ' <> "( " <> a' <>
+                       "\n" <> List.replicate i ' ' <> ", " <> b' <>
+                       "\n" <> List.replicate i ' ' <> ") "
+instance Pretty a => Pretty [a] where
+       pretty [] = return "[]"
+       pretty as = do
+               i <- R.ask
+               s <- R.local (+2) $ mapM pretty as
+               return $
+                       "\n" <> List.replicate i ' ' <> "[ " <>
+                       List.intercalate ("\n" <> List.replicate i ' ' <> ", ") s <>
+                       "\n" <> List.replicate i ' ' <> "] "
+instance Pretty a => Pretty (Seq a) where
+       pretty ss
+        | null ss = return "[]"
+        | otherwise = do
+               let as = toList ss
+               i <- R.ask
+               s <- R.local (+2) $ mapM pretty as
+               return $
+                       "\n" <> List.replicate i ' ' <> "[ " <>
+                       List.intercalate ("\n" <> List.replicate i ' ' <> ", ") s <>
+                       "\n" <> List.replicate i ' ' <> "] "
+instance Pretty a => Pretty (Maybe a) where
+       pretty Nothing = return "Nothing"
+       pretty (Just m) = do
+               s <- pretty m
+               return $ "Just "<>s
+instance Show a => Pretty (Tree a) where
+       pretty (Tree n ts) = do
+               s <- R.local (+2) (pretty ts)
+               return $ "Tree "<>showsPrec 11 n ""<>" "<>s
+
+-- * Type 'ElemName'
+type ElemName = TL.Text
 
--- ** Type 'Attr'
-data Attr
- =   Attr
- {   attr_name  :: !Text
- ,   attr_open  :: !Text
- ,   attr_value :: !Text
- ,   attr_close :: !Text
+-- ** Type 'ElemAttr'
+data ElemAttr
+ =   ElemAttr
+ {   elemAttr_name  :: !TL.Text
+ ,   elemAttr_open  :: !TL.Text
+ ,   elemAttr_value :: !TL.Text
+ ,   elemAttr_close :: !TL.Text
  }
  deriving (Eq,Ord,Show)
 
 -- ** Type 'White'
-type White = Text
+type White = TL.Text
 
--- ** Type 'Attrs'
-type Attrs = [(White,Attr)]
+-- ** Type 'ElemAttrs'
+type ElemAttrs = [(White,ElemAttr)]
index 740ce238dd73a3dc178347d98b827542061ae148..1250acc2d3e3a1f8a8bd1b7d70c7454625321d86 100644 (file)
@@ -8,34 +8,30 @@ module Language.TCT.Read
  , module Language.TCT.Read
  ) where
 
-import Control.Monad (Monad(..), join)
 import Control.Applicative (Applicative(..))
+import Control.Monad (Monad(..), join)
 import Data.Char (Char)
 import Data.Either (Either(..))
 import Data.Eq (Eq(..))
 import Data.Function (($), (.))
-import Data.Functor (Functor(..), (<$>))
-import Data.Foldable (toList)
+import Data.Functor ((<$>), (<$))
+import Data.Foldable (Foldable(..))
 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.TreeSeq.Strict (Tree)
-import Data.Tuple (snd)
+import Data.TreeSeq.Strict (Tree(..), Trees)
 import Data.Void (Void)
 import System.IO (FilePath)
 import Text.Show (Show(..))
-import qualified Data.Text as Text
-import qualified Text.Megaparsec as P
-import qualified Data.Sequence as Seq
+import qualified Data.Text.Lazy as TL
 import qualified Data.TreeSeq.Strict as Tree
+import qualified Text.Megaparsec as P
+-- import qualified Data.List as List
 
 import Language.TCT.Tree
-import Language.TCT.Token
 import Language.TCT.Cell
 import Language.TCT.Read.Cell
 import Language.TCT.Read.Tree
@@ -43,86 +39,52 @@ import Language.TCT.Read.Token
 
 import Debug.Trace (trace)
 
--- * Type 'TCT'
-type TCT = Tree (Cell Key) Tokens
-
--- * Type 'TCTs'
-type TCTs = Seq TCT
-
-readTCTs ::
- FilePath -> Text ->
- Either (P.ParseError (P.Token Text) (P.ErrorFancy Void)) TCTs
-readTCTs inp txt = do
+readTrees ::
+ FilePath -> TL.Text ->
+ Either (P.ParseError (P.Token TL.Text) (P.ErrorFancy Void)) (Trees (Cell Node))
+readTrees inp txt = do
        trs <- P.runParser (p_Trees <* P.eof) inp txt
-       traverse (go Nothing) $ trace ("### TRS ###\n"<>show (Tree.Pretty trs)) trs
+       {-(join <$>) $ -}
+       traverse (go Nothing) $
+               trace ("### TRS ###\n"<>show (Tree.Pretty trs)) trs
        where
        go ::
-        Maybe Key ->
-        Tree (Cell Key) (Cell Value) ->
-        Either (P.ParseError (P.Token Text) (P.ErrorFancy Void)) TCT
-       go k (Tree0 v) =
-               case k of
-                Just KeyBar{}   -> Right $ Tree0 $ tokens [Tree0 $ TokenPlain <$> v]
-                Just KeyLower{} -> Right $ Tree0 $ tokens [Tree0 $ TokenPlain <$> v]
-                Just KeyEqual{} -> Right $ Tree0 $ tokens [Tree0 $ TokenPlain <$> v]
-                _ -> Tree0 . parseTokens <$> parseLexemes v
-       go _ (TreeN c@(unCell -> key) ts) =
-               case key of
-                KeyBar{}   -> TreeN c <$> traverse (go (Just key)) ts
-                KeyLower{} -> TreeN c <$> traverse (go (Just key)) ts
-                KeyEqual{} -> TreeN c <$> traverse (go (Just key)) ts
-                KeyPara -> do
-                       ls <-
-                               (`traverse` Seq.reverse ts) $ \case
-                                Tree0 v -> parseLexemes v
-                                TreeN ck@(unCell -> k) vs ->
-                                       (pure . LexemeTree . TreeN ck <$>) $
-                                       traverse (go (Just k)) vs
-                       let toks = parseTokens $ join $ toList ls
-                       return $ Tree0 toks
-                _ -> TreeN c <$> traverse (go (Just key)) ts
-       parseLexemes ::
-        Cell Value ->
-        Either (P.ParseError (P.Token Text) (P.ErrorFancy Void)) [Lexeme]
-       parseLexemes (Cell bp _ep v) =
-               snd $
-               P.runParser'
-                (p_Lexemes <* P.eof)
-                P.State
-                { P.stateInput = v
-                , P.statePos   = pure $ P.SourcePos inp
-                        (P.mkPos $ linePos   bp)
-                        (P.mkPos $ columnPos bp)
-                , P.stateTabWidth = P.pos1
-                , P.stateTokensProcessed = 0
-                }
-
--- * Type 'StreamCell'
--- | Wrap 'Text' to have a 'P.Stream' instance
--- 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 { unStreamCell :: Text }
- deriving (IsString,Eq,Ord)
-instance P.Stream StreamCell where
-       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)
+        Maybe Node ->
+        Tree (Cell Node) ->
+        Either (P.ParseError (P.Token TL.Text) (P.ErrorFancy Void))
+               (Tree (Cell Node))
+       go p t@(Tree c@(Cell bn en nod) ts) =
+               case nod of
+                NodeGroup{}  -> Tree c <$> traverse (go (Just nod)) ts
+                NodeHeader{} -> Tree c <$> traverse (go (Just nod)) ts
+                NodeToken{}  -> Tree c <$> traverse (go (Just nod)) ts
+                NodePair{}   -> Tree c <$> traverse (go (Just nod)) ts
+                NodePara{}   -> Tree c <$> traverse (go (Just nod)) ts
+                NodeLower{}  -> Right t
+                -- NodeText n | TL.null n -> Right t
+                NodeText n ->
+                       case p of
+                        Just (NodeHeader HeaderBar{})   -> Right t
+                        Just (NodeHeader HeaderEqual{}) -> Right t
+                        _ -> do
+                               toks <- parseTokens <$> parseLexemes inp (n <$ c)
+                               return $
+                                       case toList toks of
+                                        [tok] -> tok
+                                        _ -> Tree (Cell bn en NodeGroup) toks
+                {-
+                NodeHeader _n -> pure . Tree c . join <$> traverse (go (Just nod)) ts
+                NodeToken  _n -> pure . Tree c . join <$> traverse (go (Just nod)) ts
+                NodePair   _n -> pure . Tree c . join <$> traverse (go (Just nod)) ts
+                NodeLower{} -> Right $ pure t
+                NodeText n | TL.null n  -> Right $ pure t
+                NodeText n ->
+                       case p of
+                        Just (NodeHeader HeaderBar{})   -> Right $ pure t
+                        Just (NodeHeader HeaderEqual{}) -> Right $ pure t
+                        _ -> do
+                               acc <- parseLexemes inp (n <$ c)
+                               sn <- traverse (go (Just nod)) ts
+                               return $ parseTokens $
+                                       foldr (\s a -> orientLexemePairAny $ LexemeTree s:a) acc (join sn)
+                -}
index d5f7d77cf0396d05dd66ea9bd3e82beb3f11ef68..c6f69d37b95de0cc2d7c284bfa6ceaa2103cc73a 100644 (file)
@@ -1,34 +1,47 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE Rank2Types #-}
 {-# LANGUAGE TypeFamilies #-}
 module Language.TCT.Read.Cell 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.Int (Int)
 import Data.List.NonEmpty (NonEmpty(..))
 import Data.Maybe (Maybe(..))
 import Data.Ord (Ord)
+import Data.Proxy (Proxy(..))
+import Data.Semigroup (Semigroup(..))
 import Data.String (String, IsString)
-import Prelude (Num(..), toInteger)
+import Data.Tuple (snd)
+import System.FilePath (FilePath)
 import Text.Show (Show)
 import qualified Data.Set as Set
+import qualified Data.Text.Lazy as TL
 import qualified Text.Megaparsec as P
 
 import Language.TCT.Cell
 
 -- * Type 'Parser'
 -- | Convenient alias.
-type Parser e s a =
+type Parser   e s a =
+     Parsable e s a =>
+     P.Parsec e s a
+
+-- ** Type 'Parsable'
+type Parsable e s a =
  ( P.Stream s
  , P.Token s ~ Char
  , Ord e
  , IsString (P.Tokens s)
  , P.ShowErrorComponent e
- ) => P.Parsec e s a
+ )
 
+-- | Like 'P.satisfy' but with a predicate returning 'Maybe' instead of 'Bool'.
 p_satisfyMaybe :: P.MonadParsec e s m => (P.Token s -> Maybe a) -> m a
 p_satisfyMaybe f = check `P.token` Nothing
        where
@@ -40,19 +53,67 @@ p_satisfyMaybe f = check `P.token` Nothing
 p_Position :: Parser e s Pos
 p_Position = (<$> P.getPosition) $ \p ->
        Pos
-        (intOfPos $ P.sourceLine p)
-        (intOfPos $ P.sourceColumn p)
-intOfPos :: P.Pos -> Int
-intOfPos = fromInteger . toInteger . P.unPos
+        { pos_line   = P.unPos $ P.sourceLine p
+        , pos_column = P.unPos $ P.sourceColumn p
+        }
+
+p_Cell :: Parser e s a -> Parser e s (Cell a)
+p_Cell pa =
+       (\b a e -> Cell b e a)
+        <$> p_Position
+        <*> pa
+        <*> p_Position
+
+p_LineNum :: Parser e s LineNum
+p_LineNum = P.unPos . P.sourceLine <$> P.getPosition
+
+p_ColNum :: Parser e s ColNum
+p_ColNum = P.unPos . P.sourceColumn <$> P.getPosition
+
+-- | Wrapper around |P.runParser'|
+-- to use given 'Cell' as starting position.
+runParserOnCell ::
+ Parsable e StreamCell a =>
+ FilePath ->
+ Parser e StreamCell a ->
+ Cell TL.Text ->
+ Either (P.ParseError (P.Token StreamCell) e) a
+runParserOnCell inp p (Cell bp _ep s) =
+       snd $ P.runParser' (p <* P.eof)
+        P.State
+        { P.stateInput    = StreamCell s
+        , P.statePos      = pure $ P.SourcePos inp (P.mkPos $ pos_line bp) indent
+        , P.stateTabWidth = indent
+        , P.stateTokensProcessed = 0
+        }
+       where indent = P.mkPos $ pos_column bp
 
-p_LineNum :: Parser e s Line
-p_LineNum = intOfPos . P.sourceLine <$> P.getPosition
+-- * Type 'StreamCell'
+-- | Wrap 'TL.Text' to have a 'P.Stream' instance
+-- 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 { unStreamCell :: TL.Text }
+ deriving (IsString,Eq,Ord)
+instance P.Stream StreamCell where
+       type Token  StreamCell = Char
+       type Tokens StreamCell = TL.Text
+       take1_       (StreamCell t) = (StreamCell <$>) <$> P.take1_ t
+       takeN_     n (StreamCell t) = (StreamCell <$>) <$> P.takeN_ n t
+       takeWhile_ f (StreamCell t) = StreamCell <$> P.takeWhile_ f t
+       tokensToChunk _s = P.tokensToChunk (Proxy::Proxy TL.Text)
+       chunkToTokens _s = P.chunkToTokens (Proxy::Proxy TL.Text)
+       chunkLength   _s = P.chunkLength   (Proxy::Proxy TL.Text)
+       advance1 _s 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)
+       advanceN s indent = TL.foldl' (P.advance1 s indent)
 
-p_ColNum :: Parser e s Column
-p_ColNum = intOfPos . P.sourceColumn <$> P.getPosition
 
 -- * Debug
 pdbg :: Show a => String -> Parser e s a -> Parser e s a
--- pdbg m p = P.dbg m p
-pdbg _m p = p
+pdbg = P.dbg
+-- pdbg _m p = p
 {-# INLINE pdbg #-}
index 3e08dc3d2199121e39c907d2291e1e04ed00ae2e..e5f18788507d2f08323673207df3acd73c2ee9e0 100644 (file)
 module Language.TCT.Read.Elem where
 
 import Control.Applicative (Applicative(..), Alternative(..))
-import Control.Monad ((>>))
+import Control.Monad (Monad(..))
 import Data.Bool
 import Data.Char (Char)
 import Data.Eq (Eq(..))
 import Data.Function (($))
-import Data.Functor ((<$>))
+import Data.Functor ((<$>), (<$))
+import Data.Maybe (Maybe(..))
 import Data.Semigroup (Semigroup(..))
-import Data.Text (Text)
 import qualified Data.Char as Char
-import qualified Data.Text as Text
 import qualified Text.Megaparsec as P
 import qualified Text.Megaparsec.Char as P
+import qualified Data.Text.Lazy as TL
 
 import Language.TCT.Elem
+import Language.TCT.Tree
 import Language.TCT.Read.Cell
 
-p_Attrs :: Parser e s [(Text,Attr)]
-p_Attrs = P.many $ P.try $ (,) <$> p_Spaces <*> p_Attr
-p_Attr :: Parser e s Attr
-p_Attr = P.try p_Attr_Eq <|> p_Attr_Word
-p_Spaces :: Parser e s Text
-p_Spaces = Text.pack <$> P.some (P.satisfy Char.isSpace)
-p_Attr_Eq :: Parser e s Attr
-p_Attr_Eq =
-       (\n (o,v,c) -> Attr n ("="<>o) v c)
-        <$> p_Word
+-- * Word
+p_Spaces :: P.Tokens s ~ TL.Text => Parser e s TL.Text
+p_Spaces = P.takeWhileP (Just "Space") Char.isSpace
+p_Spaces1 :: P.Tokens s ~ TL.Text => Parser e s TL.Text
+p_Spaces1 = P.takeWhile1P (Just "Space") Char.isSpace
+p_HSpaces :: P.Tokens s ~ TL.Text => Parser e s TL.Text
+p_HSpaces = P.takeWhileP (Just "HSpace") (==' ')
+p_Digits :: P.Tokens s ~ TL.Text => Parser e s TL.Text
+p_Digits = P.takeWhile1P (Just "Digit") Char.isDigit
+p_AlphaNums :: P.Tokens s ~ TL.Text => Parser e s TL.Text
+p_AlphaNums = P.takeWhile1P (Just "AlphaNum") Char.isAlphaNum
+{-
+-- NOTE: could be done with TL.Text, which has a less greedy (<>).
+p_Word :: Parser e Text Text
+p_Word = pdbg "Word" $ P.try p_take <|> p_copy
+       where
+       p_take = do
+               P.notFollowedBy $ P.satisfy $ not . Char.isAlphaNum
+               w <- P.takeWhile1P (Just "Word") $ \c ->
+                       Char.isAlphaNum c ||
+                       c == '_' ||
+                       c == '-'
+               guard $ Char.isAlphaNum $ Text.last w
+               return w
+       p_copy =
+               (<>)
+                <$> p_AlphaNums
+                <*> P.option "" (P.try $
+                       (<>)
+                        <$> ((Text.pack <$>) $ P.some $ P.char '_' <|> P.char '-')
+                        <*> p_copy)
+-}
+
+-- * Elem
+p_ElemSingle :: P.Tokens s ~ TL.Text => Parser e s Pair
+p_ElemSingle = pdbg "ElemSingle" $
+       PairElem
+        <$  P.char '<'
+        <*> p_ElemName
+        <*> p_ElemAttrs
+        <*  P.string "/>"
+
+p_ElemOpen :: P.Tokens s ~ TL.Text => Parser e s Pair
+p_ElemOpen = pdbg "ElemOpen" $
+       PairElem
+        <$  P.char '<'
+        <*> p_ElemName
+        <*> p_ElemAttrs
+        <*  P.char '>'
+
+p_ElemName :: P.Tokens s ~ TL.Text => Parser e s ElemName
+p_ElemName = p_AlphaNums
+ -- TODO: namespace
+
+p_ElemClose :: P.Tokens s ~ TL.Text => Parser e s Pair
+p_ElemClose = pdbg "ElemClose" $
+       (`PairElem` [])
+        <$  P.string "</"
+        <*> p_ElemName
+        <*  P.char '>'
+
+{-
+p_ElemOpenOrSingle :: Parser e Text Pair
+p_ElemOpenOrSingle =
+       p_ElemOpen >>= \p ->
+               P.char    '>' $> LexemePairOpen p <|>
+               P.string "/>" $> LexemePairAny  p
+-}
+
+-- * 'ElemAttr'
+p_ElemAttrs :: P.Tokens s ~ TL.Text => Parser e s [(White,ElemAttr)]
+p_ElemAttrs = P.many $ P.try $ (,) <$> p_Spaces <*> p_ElemAttr
+p_ElemAttr :: P.Tokens s ~ TL.Text => Parser e s ElemAttr
+p_ElemAttr = P.try p_ElemAttrEq <|> p_ElemAttrName
+
+p_ElemAttrEq :: P.Tokens s ~ TL.Text => Parser e s ElemAttr
+p_ElemAttrEq =
+       (\n (o,v,c) -> ElemAttr n ("="<>o) v c)
+        <$> p_ElemName
         <*  P.char '='
-        <*> p_Attr_Value
-p_Attr_Word :: Parser e s Attr
-p_Attr_Word =
-       (\(o,v,c) -> Attr "" o v c)
-        <$> p_Attr_Value_Word
-p_Attr_Value :: Parser e s (Text,Text,Text)
-p_Attr_Value =
-       p_Attr_Value_Quote '\'' <|>
-       p_Attr_Value_Quote '"'  <|>
-       p_Attr_Value_Word
-p_Attr_Value_Quote :: Char -> Parser e s (Text,Text,Text)
-p_Attr_Value_Quote q =
-       (\o v c -> (Text.singleton o, Text.pack v, Text.singleton c))
+        <*> p_ElemAttrValue
+p_ElemAttrName :: P.Tokens s ~ TL.Text => Parser e s ElemAttr
+p_ElemAttrName =
+       (\n -> ElemAttr n "" "" "")
+        <$> p_ElemName
+
+p_ElemAttrValue :: P.Tokens s ~ TL.Text => Parser e s (TL.Text,TL.Text,TL.Text)
+p_ElemAttrValue =
+       p_ElemAttrValueQuote '\'' <|>
+       p_ElemAttrValueQuote '"'  <|>
+       p_ElemAttrValueWord
+
+p_ElemAttrValueQuote :: Char -> P.Tokens s ~ TL.Text => Parser e s (TL.Text,TL.Text,TL.Text)
+p_ElemAttrValueQuote q =
+       (\o v c -> (TL.singleton o, v, TL.singleton c))
         <$> P.char q
-        <*> P.many (
-               P.notFollowedBy (P.string "/>") >>
-               P.satisfy (\c -> Char.isPrint c && c /= '>' && c/=q))
+        <*> P.takeWhile1P (Just "ElemAttrValueQuoted") (/=q)
         <*> P.char q
-p_Attr_Value_Word :: Parser e s (Text,Text,Text)
-p_Attr_Value_Word =
-       (\v -> ("", Text.pack v, ""))
-        <$> P.many (P.satisfy Char.isAlphaNum)
-
-p_Word :: Parser e s Text
-p_Word = pdbg "Word" $
-       (<>)
-        <$> p_plain
-        <*> P.option "" (p_plain <|> p_link)
-       where
-       p_link = P.try $
-               (<>)
-                <$> (Text.pack <$> P.some (P.satisfy (\c -> c=='_' || c=='-')))
-                <*> p_plain
-       p_plain =
-               Text.pack
-                <$> P.some (P.satisfy $ \c ->
-                       Char.isLetter c ||
-                       Char.isNumber c
-                )
+p_ElemAttrValueWord :: P.Tokens s ~ TL.Text => Parser e s (TL.Text,TL.Text,TL.Text)
+p_ElemAttrValueWord = do
+       w <- P.takeWhile1P (Just "ElemAttrValueWord") $ \c ->
+               Char.isPrint c &&
+               not (Char.isSpace c) &&
+               c /= '\'' &&
+               c /= '"' &&
+               c /= '=' &&
+               c /= '/' &&
+               c /= '<' &&
+               c /= '>'
+       return ("",w,"")
index 8b4014d9867ed636b1024e3aea7f5baeae133b85..14018285ea13af6272c9c951d7c74243b295630b 100644 (file)
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE ViewPatterns #-}
 module Language.TCT.Read.Token where
 
--- import Data.Text.Buildable (Buildable(..))
--- import qualified Data.Text.Lazy as TL
--- import qualified Data.Text.Lazy.Builder as Builder
 import Control.Applicative (Applicative(..), Alternative(..))
 import Control.Monad (Monad(..))
 import Data.Bool
 import Data.Char (Char)
-import Data.Int (Int)
 import Data.Eq (Eq(..))
-import Data.Ord (Ord(..))
+import Data.Either (Either(..))
 import Data.Foldable (Foldable(..))
-import Data.Sequence (Seq)
 import Data.Function (($), (.))
-import Data.Functor ((<$>), ($>), (<$))
+import Data.Functor ((<$>), ($>))
+import Data.List.NonEmpty (NonEmpty(..))
 import Data.Maybe (Maybe(..))
 import Data.Monoid (Monoid(..))
 import Data.Semigroup (Semigroup(..))
-import Data.Sequence (ViewL(..), (<|))
-import Data.Text (Text)
-import Data.TreeSeq.Strict (Tree(..))
+import Data.Sequence (Seq, ViewL(..), ViewR(..), (<|), (|>))
+import Data.String (String)
+import Data.TreeSeq.Strict (Tree(..), Trees)
 import Data.Tuple (fst,snd)
+import Data.Void (Void)
 import Prelude (Num(..))
 import Text.Show (Show(..))
 import qualified Data.Char as Char
+import qualified Data.List.NonEmpty as NonEmpty
 import qualified Data.Sequence as Seq
 import qualified Data.Text as Text
+import qualified Data.Text.Lazy as TL
 import qualified Text.Megaparsec as P
 import qualified Text.Megaparsec.Char as P
-import qualified System.FilePath as FP
 
 import Language.TCT.Cell
 import Language.TCT.Elem
+-- import Language.TCT.Token
+import Language.TCT.Tree
 import Language.TCT.Read.Elem
 import Language.TCT.Read.Cell
 
--- * Type 'Row'
--- | In normal order: a list of 'Key's, maybe ended by 'Value', all read on the same line.
-type Row = [Tree (Cell Key) (Cell Value)]
-
--- * Type 'Key'
-data Key
- =   KeyColon !Name !White     -- ^ @name: @
- |   KeyEqual !Name !White     -- ^ @name=@
- |   KeyBar   !Name !White     -- ^ @name|@
- |   KeyGreat !Name !White     -- ^ @name>@
- |   KeyLower !Name !Attrs     -- ^ @<name a=b@
- |   KeyDot   !Name            -- ^ @1. @
- |   KeyDash                   -- ^ @- @
- |   KeyDashDash               -- ^ @-- @
- |   KeySection  !LevelSection -- ^ @# @
- |   KeyBrackets !Name         -- ^ @[name]@
- |   KeyDotSlash !PathFile     -- ^ @./file @
- |   KeyPara
- deriving (Eq, Ord, Show)
-
--- ** Type 'Name'
-type Name = Text
-
--- ** Type 'Value'
-type Value = Text
-
--- ** Type 'PathFile'
-type PathFile = FP.FilePath
-
--- ** Type 'LevelSection'
-type LevelSection = Int
-
--- * Type 'Rows'
--- | In reverse order: a list of nodes in scope
--- (hence to which the next line can append to).
-type Rows = [Tree (Cell Key) (Cell Value)]
-
--- * Type 'Token'
-type Token = Tree (Cell TokenKey) (Cell TokenValue)
-
--- ** Type 'Tokens'
-type Tokens = Seq Token
-
--- ** Type 'TokenKey'
-type TokenKey = Pair
-data Pair
- =   PairHash              -- ^ @#value#@
- |   PairElem !Elem !Attrs -- ^ @<elem n0=v0 n1=v1>value</elem>@
- |   PairStar              -- ^ @*value*@
- |   PairSlash             -- ^ @/value/@
- |   PairUnderscore        -- ^ @_value_@
- |   PairDash              -- ^ @-value-@
- |   PairBackquote         -- ^ @`value`@
- |   PairSinglequote       -- ^ @'value'@
- |   PairDoublequote       -- ^ @"value"@
- |   PairFrenchquote       -- ^ @«value»@
- |   PairParen             -- ^ @(value)@
- |   PairBrace             -- ^ @{value}@
- |   PairBracket           -- ^ @[value]@
- deriving (Eq,Ord,Show)
-
--- ** Type 'TokenValue'
-data TokenValue
- =   TokenPlain  !Text
- |   TokenTag    !Tag
- |   TokenEscape !Char
- |   TokenLink   !Text
- |   TokenTree (Tree (Cell Key) (Cell Value))
- deriving (Eq,Ord,Show)
-
--- ** Type 'Tag'
-type Tag = Text
+instance Pretty Pair where
+       pretty = return . show
+instance Pretty a => Pretty (Cell a) where
+       pretty (Cell bp ep m) = do
+               s <- pretty m
+               return $ "Cell "<>show bp<>":"<>show ep<>" "<>s
+instance Pretty Lexeme where
+       pretty = return . show
 
 -- * Type 'Pairs'
 -- | Right-only Dyck language
 type Pairs = (Tokens,[Opening])
+type Tokens = Trees (Cell Node)
 
 -- ** Type 'Opening'
 type Opening = (Cell Pair,Tokens)
 
-appendToken :: Pairs -> Token -> Pairs
-appendToken ps = appendTokens ps . Seq.singleton
+appendToken :: Pairs -> Tree (Cell Node) -> Pairs
+appendToken (ts,[])         tok = (ts|>tok,[])
+appendToken (ts,(p0,t0):ps) tok = (ts,(p0,t0|>tok):ps)
 
 appendTokens :: Pairs -> Tokens -> Pairs
-appendTokens (t,[])         toks = (t<>toks,[])
-appendTokens (t,(p0,t0):ps) toks = (t,(p0,t0<>toks):ps)
+appendTokens (ts,[])         toks = (ts<>toks,[])
+appendTokens (ts,(p0,t0):ps) toks = (ts,(p0,t0<>toks):ps)
+
+appendText :: Pairs -> Cell TL.Text -> Pairs
+appendText ps tok =
+       case ps of
+        (ts,[]) -> (appendTokenText ts tok,[])
+        (ts,(p0,ts0):pss) -> (ts,(p0,appendTokenText ts0 tok):pss)
+
+appendTokenText :: Tokens -> Cell TL.Text -> Tokens
+appendTokenText ts (Cell bn en n)
+ {-
+ | TL.null n = ts
+ | otherwise-} =
+       case Seq.viewr ts of
+        EmptyR -> pure $ Tree0 $ Cell bn en $ NodeToken $ TokenText n
+        is :> Tree (Cell bo _eo nod) st ->
+               case nod of
+                NodeToken (TokenText o) -> is |> i
+                       where i = Tree (Cell bo en (NodeToken $ TokenText (o <> n))) st
+                _ -> ts |> Tree0 (Cell bn en $ NodeToken $ TokenText n)
+
+prependTokenText :: Tokens -> Cell TL.Text -> Tokens
+prependTokenText ts (Cell bn en n)
+ {-
+ | TL.null n = ts
+ | otherwise-} =
+       case Seq.viewl ts of
+        EmptyL -> pure $ Tree0 $ Cell bn en $ NodeToken $ TokenText n
+        Tree (Cell _bo eo nod) st :< is ->
+               case nod of
+                NodeToken (TokenText o) -> i <| is
+                       where i = Tree (Cell bn eo (NodeToken $ TokenText (n <> o))) st
+                _ -> Tree0 (Cell bn en $ NodeToken $ TokenText n) <| ts
 
 openPair :: Pairs -> Cell Pair -> Pairs
-openPair (t,ms) p = (t,(p,mempty):ms)
+openPair (t,ps) p = (t,(p,mempty):ps)
 
 -- | Close a 'Pair' when there is a matching 'LexemePairClose'.
 closePair :: Pairs -> Cell Pair -> Pairs
-closePair ps@(_,[]) (Cell bp ep p) = dbg "closePair" $
-       appendToken ps $
-       Tree0 $ Cell bp ep $
-       TokenPlain $ snd $ pairBorders p tokensPlainEmpty
-closePair (t,(p1,t1):ts) p = dbg "closePair" $
+closePair ps@(_,[]) (Cell bp ep p) = -- dbg "closePair" $
+       appendText ps $ Cell bp ep $ snd $ pairBorders p
+closePair (t,(p1,t1):ts) p = -- dbg "closePair" $
        case (p1,p) of
-        (Cell bx _ex (PairElem x ax), Cell _by ey (PairElem y ay)) | x == y ->
+        (Cell bx _ex (PairElem nx ax), Cell _by ey (PairElem ny ay)) | nx == ny ->
                appendToken (t,ts) $
-               TreeN (Cell bx ey $ PairElem x (ax<>ay)) t1
+               Tree (Cell bx ey $ NodePair $ PairElem nx as) t1
+               where as | null ay   = ax
+                        | otherwise = ax<>ay
         (Cell bx _ex x, Cell _by ey y) | x == y ->
                appendToken (t,ts) $
-               TreeN (Cell bx ey x) t1
+               Tree (Cell bx ey $ NodePair x) t1
         _ ->
                (`closePair` p) $
                appendTokens
@@ -155,67 +127,128 @@ closeImpaired :: Tokens -> (Cell Pair,Tokens) -> Tokens
 closeImpaired acc (Cell bp ep p,toks) = dbg "closeImpaired" $
        case p of
         -- NOTE: try to close 'PairHash' as 'TokenTag' instead of 'TokenPlain'.
+        PairHash | Just (Cell bt et t, ts) <- tagFrom $ toks <> acc ->
+               Tree0 (Cell bt et $ NodeToken $ TokenTag t) <| ts
+        {-
         PairHash | (Tree0 (Cell bt et (TokenPlain t))) :< ts <- Seq.viewl $ toks <> acc ->
                case Text.span isTagChar t of
                 ("",_) | Text.null t -> toksHash mempty <> toks <> acc
-                       | otherwise   -> Tree0 (Cell bp et (TokenTag t)) <| ts
+                        | otherwise   -> Tree0 (Cell bp et (TokenTag t)) <| ts
                 (tag,t') ->
                        let len = Text.length tag in
                        Tree0 (Cell bp bt{columnPos = columnPos bt + len} (TokenTag tag)) <|
                        Tree0 (Cell bt{columnPos = columnPos bt + len + 1} et (TokenPlain t')) <|
                        ts
-        _ -> toksHash tokensPlainEmpty <> toks <> acc
+        -}
+        _ -> prependTokenText (toks <> acc) toksHash
        where
-       toksHash = tokens1 . Tree0 . Cell bp ep . TokenPlain . fst . pairBorders p
-       isTagChar c =
-               Char.isAlphaNum c ||
-               c=='·' ||
-               case Char.generalCategory c of
-                Char.DashPunctuation -> True
-                Char.ConnectorPunctuation -> True
-                _ -> False
+       toksHash :: Cell TL.Text
+       toksHash = Cell bp ep $ fst $ pairBorders p
+
+isTagChar :: Char -> Bool
+isTagChar c =
+       Char.isAlphaNum c ||
+       c=='·' ||
+       case Char.generalCategory c of
+        Char.DashPunctuation -> True
+        Char.ConnectorPunctuation -> True
+        _ -> False
+
+-- * Class 'TagFrom'
+class TagFrom a where
+       tagFrom :: a -> Maybe (Cell Tag, a)
+instance TagFrom Tokens where
+       tagFrom ts =
+               case Seq.viewl ts of
+                EmptyL -> Nothing
+                Tree0 (Cell b0 e0 n) :< ns ->
+                       case n of
+                        NodeToken (TokenText t) ->
+                               case tagFrom $ Cell b0 e0 t of
+                                Nothing -> Nothing
+                                Just (t0,r0) ->
+                                       if TL.null (unCell r0)
+                                       then
+                                               case tagFrom ns of
+                                                Just (t1@(Cell b1 _e1 _), r1) | e0 == b1 ->
+                                                       Just (t0<>t1, r1)
+                                                _ -> Just (t0, n0 <| ns)
+                                       else Just (t0, n0 <| ns)
+                                       where n0 = (Tree0 $ NodeToken . TokenText <$> r0)
+                        _ -> Nothing
+                _ -> Nothing
+instance TagFrom (Cell TL.Text) where
+       tagFrom (Cell bp ep t)
+        | (w,r) <- TL.span isTagChar t
+        , not $ TL.null w
+        , ew <- pos_column bp + sum (Text.length <$> (TL.toChunks w)) =
+               Just
+                ( Cell bp bp{pos_column=ew} w
+                , Cell bp{pos_column=ew} ep r )
+       tagFrom _ = Nothing
 
 -- | Close remaining 'Pair's at end of parsing.
 closePairs :: Pairs -> Tokens
-closePairs (t0,ps) = dbg "closePairs" $
+closePairs (t0,ps) = -- dbg "closePairs" $
        t0 <> foldl' closeImpaired mempty ps
 
 appendLexeme :: Lexeme -> Pairs -> Pairs
 appendLexeme lex acc =
-       dbg "appendLexeme" $
+       -- dbg "appendLexeme" $
        case lex of
-        LexemePairOpen ps -> foldl' open acc ps
+        LexemePairOpen ps -> foldl' openPair acc ps
+               {-
                where
-               open a p@(Cell _bp ep (PairElem{})) = openPair a p `appendToken` (Tree0 $ Cell ep ep $ TokenPlain "")
+               open a p@(Cell _bp ep (PairElem{})) = openPair a p `appendToken` (Tree0 $ Cell ep ep $ TokenPhrase $ PhraseWhite "")
                open a p                            = openPair a p
+               -}
         LexemePairClose ps -> foldl' closePair acc ps
-        LexemePairAny   ps -> appendTokens acc $ tokens $ Tree0 . ((\p -> TokenPlain $ fst $ pairBorders p mempty) <$>) <$> ps
-        LexemePairBoth  ps -> appendTokens acc $ tokens $ (`TreeN`mempty) <$> ps
-        LexemeEscape     c -> appendToken  acc $ Tree0 $ TokenEscape <$> c
-        LexemeLink       t -> appendToken  acc $ Tree0 $ TokenLink <$> t
+        LexemePairAny ps ->
+               appendText acc $ sconcat $
+                       ((fst . pairBordersWithoutContent) <$>) <$> ps
+        LexemePairBoth  ps -> appendTokens acc $ Seq.fromList $ toList $ Tree0 . (NodePair <$>) <$> ps
+        LexemeEscape     c -> appendToken  acc $ Tree0 $ NodeToken . TokenEscape <$> c
+        LexemeLink       t -> appendToken  acc $ Tree0 $ NodeToken . TokenLink <$> t
         {-LexemeWhite (unCell -> "") -> acc-}
-        LexemeWhite (unCell -> Text.all (==' ') -> True) -> acc
-        LexemeWhite     cs -> appendToken  acc $ Tree0 $ TokenPlain <$> cs
-        LexemeAlphaNum  cs -> appendToken  acc $ Tree0 $ TokenPlain . Text.pack <$> cs
-        LexemeAny       cs -> appendToken  acc $ Tree0 $ TokenPlain . Text.pack <$> cs
-        -- LexemeToken     ts -> appendTokens acc ts
+        -- LexemeWhite (unCell -> Text.all (==' ') -> True) -> acc
+        LexemeWhite    t -> appendText acc t
+        LexemeAlphaNum t -> appendText acc t
+        LexemeOther    t -> appendText acc t
+        LexemeTree     t -> appendToken acc t
+        LexemeEnd -> acc
+
+{- TODEL
+appendTokenChild :: Pairs -> Tree (Cell Node) -> Pairs
+appendTokenChild pairs tree =
+       debug "appendTokenChild" "pairs" pairs $
+       debug "appendTokenChild" "tree" tree $
+       dbg "appendTokenChild" $
+       go pairs tree
+       where
+       go (ts@(toList -> [unTree -> Cell bo _eo NodeText{}]),[])
+        tok@(Tree (Cell _bn en _n) _ns) =
+               (pure $ Tree (Cell bo en NodePara) (ts |> tok),[])
+       go (ts,[])         tok = (ts |> tok,[])
+       go (ts,(p0,t0):ps) tok = (ts,(p0,t0|>tok):ps)
+-}
 
 appendLexemes :: Pairs -> [Lexeme] -> Pairs
 appendLexemes = foldr appendLexeme
 
 -- * Type 'Lexeme'
 data Lexeme
- =   LexemePairOpen  ![Cell Pair]
- |   LexemePairClose ![Cell Pair]
- |   LexemePairAny   ![Cell Pair]
- |   LexemePairBoth  ![Cell Pair]
+ =   LexemePairOpen  !(NonEmpty (Cell Pair))
+ |   LexemePairClose !(NonEmpty (Cell Pair))
+ |   LexemePairAny   !(NonEmpty (Cell Pair))
+ |   LexemePairBoth  !(NonEmpty (Cell Pair))
  |   LexemeEscape    !(Cell Char)
- |   LexemeLink      !(Cell Text)
- |   LexemeWhite     !(Cell White)
- |   LexemeAlphaNum  !(Cell [Char])
- |   LexemeAny       !(Cell [Char])
- |   LexemeTree      !(Tree (Cell Key) Tokens)
- deriving (Eq, Ord, Show)
+ |   LexemeLink      !(Cell TL.Text)
+ |   LexemeWhite     !(Cell TL.Text)
+ |   LexemeAlphaNum  !(Cell TL.Text)
+ |   LexemeOther     !(Cell TL.Text)
+ |   LexemeTree      !(Tree (Cell Node))
+ |   LexemeEnd
+ deriving (Eq, Show)
 
 -- ** Type 'Lexemes'
 type Lexemes = Seq Lexeme
@@ -224,39 +257,49 @@ parseTokens :: [Lexeme] -> Tokens
 parseTokens ps =
        closePairs $
        appendLexemes mempty $
-       dbg "Lexemes" $
-       orientLexemePairAny $ LexemeWhite (cell0 "") :
+       -- dbg "Lexemes (post orient)" $
+       orientLexemePairAny $ LexemeEnd :
        ps
 
+parseLexemes ::
+ String ->
+ Cell TL.Text ->
+ Either (P.ParseError (P.Token TL.Text) (P.ErrorFancy Void)) [Lexeme]
+parseLexemes inp = runParserOnCell inp (p_Lexemes <* P.eof)
+
 -- | Parse 'Lexeme's, returning them in reverse order to apply 'orientLexemePairAny'.
-p_Lexemes :: Parser e s [Lexeme]
+p_Lexemes :: P.Tokens s ~ TL.Text => Parser e s [Lexeme]
 p_Lexemes = pdbg "Lexemes" $ go []
        where
-       go :: [Lexeme] -> Parser e s [Lexeme]
+       go :: P.Tokens s ~ TL.Text => [Lexeme] -> Parser e s [Lexeme]
        go acc =
                (P.eof $> acc) <|>
                (p_Lexeme >>= \next -> go $ orientLexemePairAny $ next:acc)
 
 orientLexemePairAny :: [Lexeme] -> [Lexeme]
 orientLexemePairAny = \case
-        LexemeAny (Cell _bx ex x):LexemeAny (Cell by _ey y):acc -> LexemeAny (Cell by ex (x<>y)):acc
+        -- LexemeOther (Cell _bx ex x):LexemeOther (Cell by _ey y):acc -> LexemeOther (Cell by ex (x<>y)):acc
        
         -- "   
+        t@LexemeTree{}:LexemePairAny p:acc -> t:LexemePairClose p:acc
         w@LexemeWhite{}:LexemePairAny p:acc -> w:LexemePairClose p:acc
+        LexemeEnd:LexemePairAny p:acc -> LexemePairClose p:acc
         --    "
+        LexemePairAny p:t@LexemeTree{}:acc -> LexemePairOpen p:t:acc
         LexemePairAny p:w@LexemeWhite{}:acc -> LexemePairOpen p:w:acc
         LexemePairAny p:[] -> LexemePairOpen p:[]
        
         --    ,,,"
-        LexemePairAny p:a@LexemeAny{}:w@LexemeWhite{}:acc -> LexemePairOpen p:a:w:acc
-        LexemePairAny p:a@LexemeAny{}:[] -> LexemePairOpen p:a:[]
+        LexemePairAny p:a@LexemeOther{}:w@LexemeWhite{}:acc -> LexemePairOpen p:a:w:acc
+        LexemePairAny p:a@LexemeOther{}:[] -> LexemePairOpen p:a:[]
         -- ",,,   
-        w@LexemeWhite{}:a@LexemeAny{}:LexemePairAny p:acc -> w:a:LexemePairClose p:acc
+        w@LexemeWhite{}:a@LexemeOther{}:LexemePairAny p:acc -> w:a:LexemePairClose p:acc
+        LexemeEnd:a@LexemeOther{}:LexemePairAny p:acc -> a:LexemePairClose p:acc
        
         -- ",,,AAA
-        an@LexemeAlphaNum{}:a@LexemeAny{}:LexemePairAny p:acc -> an:a:LexemePairClose p:acc
+        an@LexemeAlphaNum{}:a@LexemeOther{}:LexemePairAny p:acc -> an:a:LexemePairClose p:acc
         -- ,,,"AAA
-        an@LexemeAlphaNum{}:LexemePairAny p:a@LexemeAny{}:acc -> an:LexemePairOpen p:a:acc
+        an@LexemeAlphaNum{}:LexemePairAny p:a@LexemeOther{}:acc -> an:LexemePairOpen p:a:acc
        
         -- ")
         c@LexemePairClose{}:LexemePairAny p:acc -> c:LexemePairClose p:acc
@@ -270,27 +313,23 @@ orientLexemePairAny = \case
        
         acc -> acc
 
-p_Lexeme :: Parser e s Lexeme
+p_some :: Parser e s a -> Parser e s (NonEmpty a)
+p_some p = NonEmpty.fromList <$> P.some p
+
+p_Lexeme :: P.Tokens s ~ TL.Text => Parser e s Lexeme
 p_Lexeme = pdbg "Lexeme" $
        P.choice
-        [ P.try $ LexemeWhite     <$> p_Cell p_Spaces
-        , P.try $ LexemePairAny   <$> P.some (p_Cell $ p_satisfyMaybe pairAny)
-        , P.try $ LexemePairBoth  <$> P.some (P.try $ p_Cell p_ElemSingle)
-        , P.try $ LexemePairOpen  <$> P.some (p_Cell $ p_satisfyMaybe pairOpen  <|> P.try p_ElemOpen)
-        , P.try $ LexemePairClose <$> P.some (p_Cell $ p_satisfyMaybe pairClose <|> P.try p_ElemClose)
+        [ P.try $ LexemeWhite     <$> p_Cell p_Spaces1
+        , P.try $ LexemePairAny   <$> p_some (p_Cell $ p_satisfyMaybe pairAny)
+        , P.try $ LexemePairBoth  <$> p_some (P.try $ p_Cell p_ElemSingle)
+        , P.try $ LexemePairOpen  <$> p_some (p_Cell $ p_satisfyMaybe pairOpen  <|> P.try p_ElemOpen)
+        , P.try $ LexemePairClose <$> p_some (p_Cell $ p_satisfyMaybe pairClose <|> P.try p_ElemClose)
         , P.try $ LexemeEscape    <$> p_Cell p_Escape
         , P.try $ LexemeLink      <$> p_Cell p_Link
-        , P.try $ LexemeAlphaNum  <$> p_Cell (P.some p_AlphaNum)
-        ,         LexemeAny       <$> p_Cell (pure <$> P.anyChar)
+        , P.try $ LexemeAlphaNum  <$> p_Cell (P.takeWhile1P (Just "AlphaNum") Char.isAlphaNum)
+        ,         LexemeOther     <$> p_Cell (TL.singleton <$> P.anyChar)
         ]
 
-p_Cell :: Parser e s a -> Parser e s (Cell a)
-p_Cell pa = do
-       bp <- p_Position
-       a  <- pa
-       ep <- p_Position
-       return $ Cell bp ep a
-
 pairAny :: Char -> Maybe Pair
 pairAny = \case
  '-'  -> Just PairDash
@@ -319,133 +358,94 @@ pairClose = \case
  '»'  -> Just PairFrenchquote
  _    -> Nothing
 
-p_AlphaNum :: Parser e s Char
-p_AlphaNum = P.satisfy Char.isAlphaNum
-
 p_Escape :: Parser e s Char
 p_Escape = P.char '\\' *> P.satisfy Char.isPrint
 
-p_Link :: Parser e s Text
+p_Link :: P.Tokens s ~ TL.Text => Parser e s TL.Text
 p_Link =
        P.try (P.char '<' *> p <* P.char '>') <|>
        p
        where
+       p :: P.Tokens s ~ TL.Text => Parser e s TL.Text
        p =
-               (\scheme addr -> Text.pack $ scheme <> "//" <> addr)
+               (\scheme addr -> scheme <> "//" <> addr)
                 <$> P.option "" (P.try p_scheme)
                 <*  P.string "//"
                 <*> p_addr
+       p_scheme :: P.Tokens s ~ TL.Text => Parser e s TL.Text
        p_scheme =
                (<> ":")
-                <$> P.some (P.satisfy $ \c ->
+                <$> (P.takeWhile1P (Just "scheme") $ \c ->
                        Char.isAlphaNum c
                        || c=='_'
                        || c=='-'
                        || c=='+')
                 <* P.char ':'
+       p_addr :: P.Tokens s ~ TL.Text => Parser e s TL.Text
        p_addr =
-               P.many $
-                       P.satisfy $ \c ->
-                               Char.isAlphaNum c
-                               || c=='%'
-                               || c=='/'
-                               || c=='('
-                               || c==')'
-                               || c=='-'
-                               || c=='_'
-                               || c=='.'
-                               || c=='#'
-                               || c=='?'
-                               || c=='='
-
-p_ElemSingle :: Parser e s Pair
-p_ElemSingle = pdbg "ElemSingle" $
-       PairElem
-        <$  P.char '<'
-        <*> p_Word
-        <*> p_Attrs
-        <*  P.string "/>"
-
-p_ElemOpen :: Parser e s Pair
-p_ElemOpen = pdbg "ElemOpen" $
-       PairElem
-        <$  P.char '<'
-        <*> p_Word
-        <*> p_Attrs
-        <*  P.char '>'
-
-p_ElemClose :: Parser e s Pair
-p_ElemClose = pdbg "ElemClose" $
-       (`PairElem` [])
-        <$  P.string "</"
-        <*> p_Word
-        <*  P.char '>'
-
-{-
-p_ElemOpenOrSingle :: Parser e s Pair
-p_ElemOpenOrSingle =
-       p_ElemOpen >>= \p ->
-               P.char    '>' $> LexemePairOpen p <|>
-               P.string "/>" $> LexemePairAny  p
--}
-
-
-
-
-
-
-
-
+               P.takeWhileP (Just "addr") $ \c ->
+                       Char.isAlphaNum c
+                       || c=='%'
+                       || c=='/'
+                       || c=='('
+                       || c==')'
+                       || c=='-'
+                       || c=='_'
+                       || c=='.'
+                       || c=='#'
+                       || c=='?'
+                       || c=='='
 
 -- | Build 'Tokens' from many 'Token's.
-tokens :: [Token] -> Tokens
-tokens = Seq.fromList
+tokens :: [Cell Token] -> Tokens
+tokens ts = Seq.fromList $ Tree0 . (NodeToken <$>) <$> ts
 
 -- | Build 'Tokens' from one 'Token'.
-tokens1 :: Token -> Tokens
+tokens1 :: Tree (Cell Node) -> Tokens
 tokens1 = Seq.singleton
 
-tokensPlainEmpty :: Tokens
-tokensPlainEmpty = tokens1 $ Tree0 $ cell1 $ TokenPlain ""
-
-isTokenWhite :: Token -> Bool
-isTokenWhite (Tree0 (unCell -> TokenPlain t)) = Text.all Char.isSpace t
-isTokenWhite _                                = False
-
-unTokenElem :: Tokens -> Maybe (Cell (Elem,Attrs,Tokens))
+unTokenElem :: Tokens -> Maybe (Cell (ElemName,ElemAttrs,Tokens))
 unTokenElem toks =
-       case toList $ Seq.dropWhileR isTokenWhite toks of
-        [TreeN (Cell bp ep (PairElem e as)) ts] -> Just (Cell bp ep (e,as,ts))
+       case toList $ {-Seq.dropWhileR isTokenWhite-} toks of
+        [Tree (Cell bp ep (NodePair (PairElem e as))) ts] -> Just (Cell bp ep (e,as,ts))
         _ -> Nothing
 
 isTokenElem :: Tokens -> Bool
 isTokenElem toks =
-       case toList $ Seq.dropWhileR isTokenWhite toks of
-        [TreeN (unCell -> PairElem{}) _] -> True
+       case toList $ {-Seq.dropWhileR isTokenWhite-} toks of
+        [Tree (unCell -> NodePair PairElem{}) _] -> True
         _ -> False
 
-pairBorders :: TokenKey -> Tokens -> (Text,Text)
-pairBorders p ts =
-       case p of
-        PairElem e attrs ->
-               if Seq.null ts
-               then ("<"<>e<>foldMap f attrs<>"/>","")
-               else ("<"<>e<>foldMap f attrs<>">","</"<>e<>">")
-               where f (attr_white,Attr{..}) =
-                       attr_white <>
-                       attr_name  <>
-                       attr_open  <>
-                       attr_value <>
-                       attr_close
-        PairHash        -> ("#","#")
-        PairStar        -> ("*","*")
-        PairSlash       -> ("/","/")
-        PairUnderscore  -> ("_","_")
-        PairDash        -> ("-","-")
-        PairBackquote   -> ("`","`")
-        PairSinglequote -> ("'","'")
-        PairDoublequote -> ("\"","\"")
-        PairFrenchquote -> ("«","»")
-        PairParen       -> ("(",")")
-        PairBrace       -> ("{","}")
-        PairBracket     -> ("[","]")
+pairBordersWithoutContent :: Pair -> (TL.Text,TL.Text)
+pairBordersWithoutContent = \case
+ PairElem n as ->
+       ("<"<>n<>foldMap f as<>"/>","")
+       where f (elemAttr_white,ElemAttr{..}) =
+               elemAttr_white <>
+               elemAttr_name  <>
+               elemAttr_open  <>
+               elemAttr_value <>
+               elemAttr_close
+ p -> pairBorders p
+
+pairBorders :: Pair -> (TL.Text,TL.Text)
+pairBorders = \case
+ PairElem n as -> ("<"<>n<>foldMap f as<>">","</"<>n<>">")
+       where f (elemAttr_white,ElemAttr{..}) =
+               elemAttr_white <>
+               elemAttr_name  <>
+               elemAttr_open  <>
+               elemAttr_value <>
+               elemAttr_close
+ PairHash        -> ("#","#")
+ PairStar        -> ("*","*")
+ PairSlash       -> ("/","/")
+ PairUnderscore  -> ("_","_")
+ PairDash        -> ("-","-")
+ PairBackquote   -> ("`","`")
+ PairSinglequote -> ("'","'")
+ PairDoublequote -> ("\"","\"")
+ PairFrenchquote -> ("«","»")
+ PairParen       -> ("(",")")
+ PairBrace       -> ("{","}")
+ PairBracket     -> ("[","]")
index d2d536ca7873bad0d5772bd9ea1aecfced507ebc..9763e2b1d8b019b833b0ba8a6f9c1a8885d80fc7 100644 (file)
 {-# LANGUAGE ViewPatterns #-}
 module Language.TCT.Read.Tree where
 
+-- import Data.String (IsString(..))
+-- import qualified Data.TreeSeq.Strict as TreeSeq
 import Control.Applicative (Applicative(..), Alternative(..))
 import Control.Monad (Monad(..), void)
 import Data.Bool
 import Data.Eq (Eq(..))
 import Data.Function (($), (.))
 import Data.Functor ((<$>), ($>), (<$))
+import Data.Foldable (toList)
+import Data.Maybe (Maybe(..))
 import Data.Monoid (Monoid(..))
 import Data.Semigroup (Semigroup(..))
-import Data.String (IsString(..))
-import Data.Text (Text)
 import Data.TreeSeq.Strict (Tree(..), Trees)
-import Prelude (undefined, Num(..))
-import qualified Data.Char as Char
 import qualified Data.List as List
 import qualified Data.Sequence as Seq
-import qualified Data.Text as Text
+import qualified Data.Text.Lazy as TL
 import qualified Text.Megaparsec as P
 import qualified Text.Megaparsec.Char as P
 
 import Language.TCT.Cell
+-- import Language.TCT.Token
 import Language.TCT.Tree
 import Language.TCT.Read.Cell
 import Language.TCT.Read.Elem
 import Language.TCT.Read.Token
 
-p_CellKey :: Row -> Parser e s Row
-p_CellKey row = pdbg "CellKey" $ do
+p_CellHeader :: P.Tokens s ~ TL.Text => Row -> Parser e s Row
+p_CellHeader row = pdbg "CellHeader" $ do
        P.skipMany $ P.char ' '
        pos <- p_Position
-       key <- pdbg "Key" $
+       header <- pdbg "Header" $
                P.choice $
                 [ P.try $ P.char '-' >>
-                       P.char ' ' $> KeyDash <|>
-                       P.string "- " $> KeyDashDash
-                , P.try $ KeyDot . Text.pack
-                        <$> P.some (P.satisfy Char.isDigit)
+                       P.char ' ' $> HeaderDash <|>
+                       P.string "- " $> HeaderDashDash
+                , P.try $ HeaderDot
+                        <$> p_Digits
                         <* P.char '.'
                         <* P.lookAhead (P.try $ P.eof <|> void (P.satisfy $ \c -> c=='\n'||c==' '))
                 , P.try $ P.some (P.char '#') <* P.lookAhead (P.try $ P.char ' ') >>= \hs ->
-                       return $ KeySection $ List.length hs
+                       return $ HeaderSection $ List.length hs
                 , P.try $
-                       KeyBrackets
+                       HeaderBrackets
                         <$> P.between (P.string "[") (P.string "]") p_Name
                         <*  P.lookAhead (P.try $ P.eof <|> void (P.satisfy (=='\n')))
                 , P.try $
-                       (\f -> KeyDotSlash $ "./"<>f)
+                       (\f -> HeaderDotSlash $ "./"<>f)
                         <$  P.string "./"
                         <*> P.many (P.satisfy (/='\n'))
                 , do
                        name <- p_Name
-                       wh <- Text.pack <$> P.many (P.char ' ')
+                       wh <- p_HSpaces
                        P.choice
-                        [ P.try $ KeyColon name wh
+                        [ P.try $ HeaderColon name wh
                                 <$ P.char ':'
                                 <* P.lookAhead (P.try $ P.eof <|> void (P.satisfy $ \c -> c=='\n'||c==' '))
-                        , P.char '>' $> KeyGreat name wh
-                        , P.char '=' $> KeyEqual name wh
-                        , P.char '|' $> KeyBar   name wh
+                        , P.char '>' $> HeaderGreat name wh
+                        , P.char '=' $> HeaderEqual name wh
+                        , P.char '|' $> HeaderBar   name wh
                         ]
                 ]
        posEnd <- p_Position
-       let row' = TreeN (Cell pos posEnd key) mempty : row
-       case key of
-        KeySection{}  -> p_CellEnd  row'
-        KeyDash{}     -> p_Row      row'
-        KeyDashDash{} -> p_CellText row'
-        KeyDot{}      -> p_Row      row'
-        KeyColon{}    -> p_Row      row'
-        KeyBrackets{} -> p_Row      row'
-        KeyGreat{}    -> p_Row      row'
-        KeyEqual{}    -> p_CellEnd  row'
-        KeyBar{}      -> p_CellEnd  row'
-        KeyDotSlash{} -> p_CellEnd  row'
-        KeyLower{}    -> undefined -- NOTE: handled in 'p_CellLower'
+       let row' = Tree (Cell pos posEnd $ NodeHeader header) mempty : row
+       case header of
+        HeaderSection{}  -> p_CellEnd  row'
+        HeaderDash{}     -> p_Row      row'
+        HeaderDashDash{} -> p_CellText row'
+        HeaderDot{}      -> p_Row      row'
+        HeaderColon{}    -> p_Row      row'
+        HeaderBrackets{} -> p_Row      row'
+        HeaderGreat{}    -> p_Row      row'
+        HeaderEqual{}    -> p_CellEnd  row'
+        HeaderBar{}      -> p_CellEnd  row'
+        HeaderDotSlash{} -> p_CellEnd  row'
+        -- HeaderLower{}    -> undefined -- NOTE: handled in 'p_CellLower'
+        -- TODO: move to a NodeLower
+        -- HeaderPara       -> undefined -- NOTE: only introduced later in 'appendRow'
 
-p_Name :: Parser e s Name
-p_Name =
+p_Name :: P.Tokens s ~ TL.Text => Parser e s Name
+p_Name = p_AlphaNums
+       {-
        (\h t -> Text.pack (h:t))
-        <$> (P.satisfy $ \c ->
-               Char.isAlphaNum c || c=='_')
-        <*> many (P.satisfy $ \c ->
-               Char.isAlphaNum c || c=='-' || c=='_')
+        <$> (P.satisfy $ \c -> Char.isAlphaNum c || c=='_')
+        <*> P.takeWhile1P (P.satisfy $ \c -> Char.isAlphaNum c || c=='-' || c=='_')
+       -}
 
-p_Line :: Parser e s Text
-p_Line = Text.pack <$> P.many (P.satisfy (/='\n'))
+p_Line :: P.Tokens s ~ TL.Text => Parser e s TL.Text
+p_Line = P.takeWhileP (Just "Line") (/='\n')
 
-p_CellLower :: forall e s. Row -> Parser e s Row
+p_Line1 :: P.Tokens s ~ TL.Text => Parser e s TL.Text
+p_Line1 = P.takeWhile1P (Just "Line") (/='\n')
+
+p_CellLower :: P.Tokens s ~ TL.Text => Row -> Parser e s Row
 p_CellLower row = pdbg "CellLower" $ do
-       P.skipMany $ P.char ' '
-       pos <- p_Position
-       void $ P.char '<'
-       name <- p_Name
-       attrs <- p_attrs
+       indent   <- p_HSpaces
+       pos      <- p_Position
+       void     $  P.char '<'
+       name     <- p_Name
+       attrs    <- p_ElemAttrs
        posClose <- p_Position
        let treeHere =
-               TreeN (Cell pos posClose $ KeyLower name attrs) .
-               Seq.singleton . Tree0
-       let treeElem toks (Cell _ p c) =
-               let (o,_) = pairBorders (PairElem name attrs) toks in
-               Tree0 $ Cell pos p (o<>c)
-       let indent = fromString $ List.replicate (columnPos pos - 1) ' '
+               Tree (Cell pos posClose $ NodeLower name attrs) .
+               Seq.singleton . Tree0 . (NodeText <$>)
+       let treeElem hasContent nod (Cell _ p t) =
+               let (o,_) = bs $ PairElem name attrs in
+               Tree0 $ Cell pos p $ nod $ o<>t
+               where
+               bs | hasContent = pairBorders
+                  | otherwise  = pairBordersWithoutContent
        tree <-
-               P.try (P.char '>' >> treeElem (tokens [Tree0 $ cell0 $ TokenPlain ""]) <$> p_CellLinesUntilElemEnd indent name) <|>
-               P.try (P.char '\n' >> P.string indent >> treeHere <$> p_CellLines indent) <|>
-               P.try (P.string "/>" >> treeElem mempty <$> p_CellLine) <|>
+               P.try (P.char '>' >> treeElem True NodeText <$> p_CellLinesUntilElemEnd indent name) <|>
+               P.try (P.char '\n' >> P.tokens (==) indent >> treeHere <$> p_CellLines indent) <|>
+               P.try (P.tokens (==) "/>" >> treeElem False NodeText <$> p_CellLine) <|>
                (P.eof $> treeHere (Cell posClose posClose ""))
-       return (tree:row)
+       return $ tree : row
        where
-       p_attrs = P.many $ P.try $
-               (,)
-                <$> (Text.pack <$> P.some (P.char ' '))
-                <*> p_Attr
-       p_CellLine :: Parser e s (Cell Text)
-       p_CellLine = do
-               pos     <- p_Position
-               content <- p_Line
-               posEnd  <- p_Position
-               return $ Cell pos posEnd content
-       p_CellLines :: P.Tokens s -> Parser e s (Cell Text)
-       p_CellLines indent = do
-               pos <- p_Position
-               content <-
-                       Text.intercalate "\n"
-                        <$> P.sepBy (P.try p_Line) (P.try $ P.char '\n' >> P.string indent)
-               posEnd <- p_Position
-               return $ Cell pos posEnd content
-       p_CellLinesUntilElemEnd :: P.Tokens s -> Text -> Parser e s (Cell Text)
-       p_CellLinesUntilElemEnd indent name = do
-               pos     <- p_Position
-               content <- Text.intercalate "\n" . List.reverse <$> go []
-               posEnd  <- p_Position
-               return $ Cell pos posEnd content
+       p_CellLine :: P.Tokens s ~ TL.Text => Parser e s (Cell TL.Text)
+       p_CellLine = p_Cell p_Line
+       p_CellLines :: P.Tokens s ~ TL.Text => P.Tokens TL.Text -> Parser e s (Cell TL.Text)
+       p_CellLines indent =
+               -- TODO: optimize special case indent == "" ?
+               p_Cell $
+                       TL.intercalate "\n"
+                        <$> P.sepBy (P.try p_Line)
+                                (P.try $ P.char '\n' >> P.tokens (==) indent)
+       p_CellLinesUntilElemEnd :: P.Tokens s ~ TL.Text => P.Tokens TL.Text -> Name -> Parser e s (Cell TL.Text)
+       p_CellLinesUntilElemEnd indent name =
+               p_Cell $ TL.intercalate "\n" . List.reverse <$> go []
+               -- TODO: optimize merging, and maybe case indent == ""
                where
-               go :: [Text] -> Parser e s [Text]
+               go :: P.Tokens s ~ TL.Text => [TL.Text] -> Parser e s [TL.Text]
                go ls =
-                       P.try ((\w l -> Text.pack w <> "</" <> name <> l : ls)
-                        <$> P.many (P.char ' ')
-                        <*  P.string (fromString $ "</"<>Text.unpack name)
+                       let end = "</" <> name in
+                       P.try ((\w l -> w <> end <> l : ls)
+                        <$> p_HSpaces
+                        <*  P.tokens (==) end
                         <*> p_Line) <|>
                        (p_Line >>= \l -> P.try $
-                               P.char '\n' >>
-                               P.string indent >>
-                               go (l:ls))
+                               P.char '\n'
+                                >> P.tokens (==) indent
+                                >> go (l:ls))
 
-p_CellText :: Row -> Parser e s Row
+p_CellText :: P.Tokens s ~ TL.Text => Row -> Parser e s Row
 p_CellText row = pdbg "CellText" $ do
        P.skipMany $ P.char ' '
-       pos <- p_Position
-       line <- Text.pack <$> P.some (P.satisfy (/='\n'))
-       posEnd <- p_Position
-       return $ Tree0 (Cell pos posEnd line) : row
+       n <- p_Cell $ NodeText <$> p_Line1
+       return $ Tree0 n : row
 
 p_CellSpaces :: Row -> Parser e s Row
 p_CellSpaces row = pdbg "CellSpaces" $ do
        P.skipSome $ P.char ' '
        pos <- p_Position
-       return $ Tree0 (Cell pos pos "") : row
+       return $ Tree0 (Cell pos pos $ NodeText "") : row
 
-p_CellEnd :: Row -> Parser e s Row
-p_CellEnd row = pdbg "Row" $
+p_CellEnd :: P.Tokens s ~ TL.Text => Row -> Parser e s Row
+p_CellEnd row = pdbg "CellEnd" $
        P.try (p_CellLower row) <|>
        P.try (p_CellText row) <|>
        p_CellSpaces row <|>
        return row
 
-p_Row :: Row -> Parser e s Row
+p_Row :: P.Tokens s ~ TL.Text => Row -> Parser e s Row
 p_Row row = pdbg "Row" $
-       P.try (p_CellKey row) <|>
+       P.try (p_CellHeader row) <|>
        p_CellEnd row
 
-p_Rows :: Rows -> Parser e s Rows
+p_Rows :: P.Tokens s ~ TL.Text => Rows -> Parser e s Rows
 p_Rows rows =
        p_Row [] >>= \row ->
                let rows' = appendRow rows (List.reverse row) in
                (P.eof $> rows') <|>
-               (P.newline >> p_Rows rows')
+               (P.newline >> P.eof $> rows' <|> p_Rows rows')
 
-p_Trees :: Parser e s (Trees (Cell Key) (Cell Value))
-p_Trees = unRoot . collapseRows <$> p_Rows [root]
+p_Trees :: P.Tokens s ~ TL.Text => Parser e s (Trees (Cell Node))
+p_Trees = unNodePara . subTrees . collapseRows <$> p_Rows [root]
        where
-       root = TreeN (cell0 KeyDashDash) mempty
-       unRoot (TreeN (unCell -> KeyDashDash) roots) = roots
-       unRoot _ = undefined
+       root = Tree (cell0 $ NodeHeader HeaderDashDash) mempty
+       unNodePara :: Trees (Cell Node) -> Trees (Cell Node)
+       unNodePara (toList -> [(Tree (unCell -> NodePara) ts)]) = ts
+       unNodePara ts = ts
index 315b8a52fd058a20a2e824f3d3b315d87a3a38bb..a5ba2df64597c6ffd61465935ad8438e6f78805d 100644 (file)
 {-# LANGUAGE ViewPatterns #-}
 module Language.TCT.Token where
 
-{-
-import Data.Bool
 import Data.Char (Char)
 import Data.Eq (Eq(..))
-import Data.Function (($), (.))
-import Data.Foldable (foldMap, foldr)
-import Data.Maybe (Maybe(..))
-import Data.Semigroup (Semigroup(..))
+import Data.Int (Int)
+import Data.Ord (Ord(..))
 import Data.Sequence (Seq)
-import Data.Ord (Ord)
 import Data.Text (Text)
-import Data.Text.Buildable (Buildable(..))
-import Data.Text.Lazy.Builder (Builder)
-import Data.TreeSeq.Strict (Tree(..), Trees)
-import GHC.Exts (IsList(..))
+-- import Data.TreeSeq.Strict (Tree(..))
 import Text.Show (Show(..))
-import qualified Data.Char as Char
-import qualified Data.Sequence as Seq
-import qualified Data.Text as Text
+import System.FilePath (FilePath)
+import qualified Data.Text.Lazy as TL
 
 import Language.TCT.Cell
 import Language.TCT.Elem
 
 
+
+
+
+
+{-
+-- * Type 'TCT'
+type TCT = Tree (Padded Key) Tokens
+
+-- * Type 'Key'
+data Key
+ =   KeyColon !Name !White     -- ^ @name: @
+ |   KeyEqual !Name !White     -- ^ @name=@
+ |   KeyBar   !Name !White     -- ^ @name|@
+ |   KeyGreat !Name !White     -- ^ @name>@
+ |   KeyLower !Name !ElemAttrs -- ^ @<name a=b@
+ |   KeyDot   !Name            -- ^ @1. @
+ |   KeyDash                   -- ^ @- @
+ |   KeyDashDash               -- ^ @-- @
+ |   KeySection  !LevelSection -- ^ @# @
+ |   KeyBrackets !Name         -- ^ @[name]@
+ |   KeyDotSlash !PathFile     -- ^ @./file @
+ |   KeyPara
+ deriving (Eq, Ord, Show)
+
+-- ** Type 'Name'
+type Name = Text
+
+-- ** Type 'Value'
+type Value = Text
+
+-- ** Type 'PathFile'
+type PathFile = FP.FilePath
+
+-- ** Type 'LevelSection'
+type LevelSection = Int
+
+-- * Type 'Token'
+-- | NOTE: the 'Cell' spans the opening, the content and the closing.
+type Token = Tree (Padded TokenKey) TokenValue
+
+-- ** Type 'Tokens'
+type Tokens = Seq Token
+
+-- ** Type 'TokenKey'
+type TokenKey = Pair
+data Pair
+ =   PairElem !ElemName !ElemAttrs -- ^ @<elem n0=v0 n1=v1>value</elem>@
+ |   PairHash        -- ^ @#value#@
+ |   PairStar        -- ^ @*value*@
+ |   PairSlash       -- ^ @/value/@
+ |   PairUnderscore  -- ^ @_value_@
+ |   PairDash        -- ^ @-value-@
+ |   PairBackquote   -- ^ @`value`@
+ |   PairSinglequote -- ^ @'value'@
+ |   PairDoublequote -- ^ @"value"@
+ |   PairFrenchquote -- ^ @«value»@
+ |   PairParen       -- ^ @(value)@
+ |   PairBrace       -- ^ @{value}@
+ |   PairBracket     -- ^ @[value]@
+ deriving (Eq,Ord,Show)
+
+-- ** Type 'TokenValue'
+data TokenValue
+ =   TokenPhrases !Phrases
+ |   TokenEscape  !Char
+ |   TokenTag     !Tag
+ |   TokenLink    !Link
+ |   TokenTree    !TCT
+ |   TokenRaw     !TL.Text
+ deriving (Eq,Show)
+
+-- * Type 'Phrases'
+type Phrases = Seq (Padded Phrase)
+
+-- ** Type 'Phrase'
+data Phrase
+ =   PhraseWord  !Text
+ |   PhraseWhite !Text
+ |   PhraseOther !Text
+ deriving (Eq,Ord,Show)
+
+-- * Type 'Tag'
+type Tag = TL.Text
+-- newtype Tag = Tag Text
+
+type family Sourced a :: *
+type instance Sourced (Padded a) = Padded (Sourced a)
+type instance Sourced [a]        = [Sourced a]
+type instance Sourced (Seq a)    = Seq (Sourced a)
+type instance Sourced (Tree k a) = Tree (Sourced k) (Sourced a)
+type instance Sourced Key        = Cell Key
+type instance Sourced Value      = Cell Value
+type instance Sourced TokenKey   = Cell TokenKey
+type instance Sourced TokenValue = TokenValue
+type instance Sourced Phrase     = Cell Phrase
+
+-- * Type Pos
+class Sourcify a where
+       sourcify :: a -> Sourced a
+instance Sourced a => Sourced [a] where
+       type Sourced = [At a]
+       sourcify = (sourcify <$>)
+-}
+
+{-
 instance Buildable Token where
        build (TokenPlain t)   = build t
        build (TokenTag t)     = "#"<>build t
@@ -56,5 +152,3 @@ instance IsList Tokens where
 unTokens :: Tokens -> Seq Token
 unTokens (Tokens ts) = ts
 -}
-
-
index 1678a4b570f3c6272acca63b247bd09764d439d4..f2eb4ec5a1b14fbd85d636cb8a0fb3f24ab582bb 100644 (file)
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE OverloadedLists #-}
+{-# LANGUAGE NoOverloadedLists #-}
+{-# LANGUAGE PatternSynonyms #-}
 {-# LANGUAGE ViewPatterns #-}
-module Language.TCT.Tree
- ( module Language.TCT.Tree
- , Tree(..)
- , Trees
- ) where
+module Language.TCT.Tree where
 
 import Control.Monad (Monad(..))
+import Data.Bool
+import Data.Char (Char)
 import Data.Eq (Eq(..))
+import Data.Foldable (Foldable(..))
 import Data.Function (($))
+import Data.Int (Int)
 import Data.Maybe (Maybe(..))
+import Data.Monoid (Monoid(..))
 import Data.Ord (Ordering(..), Ord(..))
 import Data.Semigroup (Semigroup(..))
-import Data.Sequence ((|>))
-import Data.Text (Text)
+import Data.Sequence ((|>), (<|), ViewR(..))
 import Data.TreeSeq.Strict (Tree(..), Trees)
-import Prelude (undefined, Int, Num(..))
+import Prelude (undefined, Num(..))
+import System.FilePath (FilePath)
 import Text.Show (Show(..))
 import qualified Data.List as List
-import qualified Data.Text as Text
-import qualified System.FilePath as FP
 import qualified Data.Sequence as Seq
+import qualified Data.Text.Lazy as TL
 
 import Language.TCT.Cell
 import Language.TCT.Elem
-import Language.TCT.Read.Token
 -- import Language.TCT.Token
 
+-- ** Type 'TCT'
+type Root  = Tree  Node
+type Roots = Trees Node
+
+pattern Tree0 :: a -> Tree a
+pattern Tree0 a <- Tree a (null -> True)
+ where  Tree0 a = Tree a mempty
+
+-- ** Type 'Node'
+data Node
+ =   NodeHeader !Header
+ |   NodePair   !Pair
+ |   NodeToken  !Token
+ |   NodeText   !TL.Text
+ |   NodeLower  !Name !ElemAttrs -- ^ @<name a=b@
+ |   NodePara
+ |   NodeGroup
+ deriving (Eq,Show)
+
+-- ** Type 'Header'
+data Header
+ =   HeaderColon !Name !White     -- ^ @name: @
+ |   HeaderEqual !Name !White     -- ^ @name=@
+ |   HeaderBar   !Name !White     -- ^ @name|@
+ |   HeaderGreat !Name !White     -- ^ @name>@
+ |   HeaderDot   !Name            -- ^ @1. @
+ |   HeaderDash                   -- ^ @- @
+ |   HeaderDashDash               -- ^ @-- @
+ |   HeaderSection  !LevelSection -- ^ @# @
+ |   HeaderBrackets !Name         -- ^ @[name]@
+ |   HeaderDotSlash !FilePath     -- ^ @./file @
+ deriving (Eq, Ord, Show)
+
+-- *** Type 'Name'
+type Name = TL.Text
+
+-- *** Type 'LevelSection'
+type LevelSection = Int
+
+-- ** Type 'Pair'
+data Pair
+ =   PairElem !ElemName !ElemAttrs -- ^ @<elem n0=v0 n1=v1>value</elem>@
+ |   PairHash        -- ^ @#value#@
+ |   PairStar        -- ^ @*value*@
+ |   PairSlash       -- ^ @/value/@
+ |   PairUnderscore  -- ^ @_value_@
+ |   PairDash        -- ^ @-value-@
+ |   PairBackquote   -- ^ @`value`@
+ |   PairSinglequote -- ^ @'value'@
+ |   PairDoublequote -- ^ @"value"@
+ |   PairFrenchquote -- ^ @«value»@
+ |   PairParen       -- ^ @(value)@
+ |   PairBrace       -- ^ @{value}@
+ |   PairBracket     -- ^ @[value]@
+ deriving (Eq,Ord,Show)
+
+-- ** Type 'Token'
+data Token
+ =   TokenText   !TL.Text
+ |   TokenEscape !Char
+ |   TokenLink   !Link
+ |   TokenTag    !Tag
+ deriving (Eq,Show)
+
+-- *** Type 'Tag'
+type Tag = TL.Text
+
+-- *** Type 'Link'
+type Link = TL.Text
+
+-- * Type 'Row'
+-- | In normal order: a list of 'Header's, maybe ended by 'Value', all read on the same line.
+type Row = [Tree (Cell Node)]
+
+-- ** Type 'Rows'
+-- | In reverse order: a list of nodes in scope
+-- (hence to which the next line can append to).
+type Rows = [Tree (Cell Node)]
 
 -- | @appendRow rows row@ appends @row@ to @rows@.
 --
@@ -35,149 +113,109 @@ import Language.TCT.Read.Token
 -- [@row@]  next 'Row', from leftest column to rightest (non-stricly ascending)
 appendRow :: Rows -> Row -> Rows
 appendRow [] row = List.reverse row
-appendRow parents [] = parents
-appendRow rows@(parent:parents) row@(cell:cells) =
-       trac ("appendRow: rows=" <> show rows) $
-       trac ("appendRow: row=" <> show row) $
+appendRow rows [] = rows
+appendRow rows@(old@(Tree (Cell bo eo o) os):olds)
+           row@(new@(Tree (Cell bn en n) ns):news) =
+       debug "appendRow" "row"  row $
+       debug "appendRow" "rows" rows $
        dbg "appendRow" $
-       let colParent = columnPos $ posTree parent in
-       let colRow    = columnPos $ posTree cell in
-       case dbg "colParent" colParent `compare`
-            dbg "colRow"    colRow of
-        LT ->
-               case (dbg "parent" parent,dbg "cell" cell) of
-                (Tree0{}, TreeN{}) -> eq
-                -- (Tree0 p, Tree0{}) | Text.null (unCell p) -> eq -- FIXME: useful?
-                -- (TreeN (unCell -> KeyPara) p, Tree0 r) -> appendTree0 p r
-                -- (Tree0 p, Tree0 r) -> appendTree0 p r
-                _ | Just x <- appendPara -> x
-                _ -> lt
+       case dbg "colOld" (pos_column bo) `compare`
+            dbg "colNew" (pos_column bn) of
+        LT -> mergeNodeText lt
         EQ ->
-               case (dbg "parent" parent,dbg "cell" cell) of
-                _ | Just x <- appendPara -> x
-                (_, TreeN (unCell -> KeySection sectionRow) _)
-                 | Just (sectionParent, secPar:secPars) <- collapseSection colRow rows ->
-                       case dbg "sectionParent" sectionParent `compare`
-                            dbg "sectionRow"    sectionRow of
-                        LT -> appendRow (cell:secPar:secPars) cells
-                        EQ -> appendRow (cell:insertChild secPar secPars) cells
+               mergeNodeText $
+               case (o,n) of
+                (_, NodeHeader (HeaderSection secNew))
+                 | Just (secOld, s0:ss) <- collapseSection (pos_column bn) rows ->
+                       case dbg "secOld" secOld `compare`
+                            dbg "secNew" secNew of
+                        LT -> appendRow (new:s0:ss) news
+                        EQ -> appendRow (new:appendChild ss s0) news
                         GT -> gt
-                (TreeN (unCell -> KeySection{}) _, Tree0{}) -> lt
-                (TreeN (unCell -> KeySection{}) _, TreeN{}) -> lt
-                (Tree0{}, TreeN{}) -> eq
-                (TreeN{}, TreeN{}) -> eq
-                (TreeN{}, Tree0{}) -> eq
+                (NodeHeader HeaderSection{}, _) -> lt
+                (_, NodeText tn) | TL.null tn -> gt
+                (NodePara, _) | not newPara -> lt
+                _ | newPara -> gt
+                _ -> eq
         GT -> gt
        where
-       appendPara :: Maybe Rows
-       appendPara =
-               case (parent, cell) of
-                ( TreeN (Cell posPar posEndPar KeyPara) pars
-                 , Tree0 (Cell posRow posEndRow _c) ) ->
-                       Just $
-                       if linePos posRow - linePos posEndPar <= 1
-                       then appendRow (merged : parents) cells
-                       else appendRow (cell : insertChild parent parents) cells
-                       where merged = TreeN (Cell posPar posEndRow KeyPara) $ pars |> cell
-                ( Tree0 (Cell posPar posEndPar _p)
-                 , Tree0 (Cell posRow posEndRow _c) ) ->
-                       Just $
-                       if linePos posRow - linePos posEndPar <= 1
-                       then appendRow (merged : parents) cells
-                       else appendRow (cell : insertChild parent parents) cells
-                       where merged = TreeN (Cell posPar posEndRow KeyPara) [parent, cell]
-                _ -> Nothing
+       newPara = pos_line bn - pos_line eo > 1
+       lt = debug "appendRow" "action" ("lt"::TL.Text) $ List.reverse row <> rows
+       eq = debug "appendRow" "action" ("eq"::TL.Text) $ appendRow (new : appendChild olds old) news
+       gt = debug "appendRow" "action" ("gt"::TL.Text) $ appendRow (      appendChild olds old) row
        
-       {-
-       appendTree0 p r =
-               case appendCellValue p r of
-                Nothing -> appendRow (Tree0 r : insertChild (Tree0 p) parents) cells
-                Just t  -> appendRow (t : parents) cells
-       -}
-       lt = appendRow [] row <> rows
-       eq = appendRow (cell : insertChild parent parents) cells
-       gt = appendRow (insertChild parent parents) row
        -- | Find the first section (if any), returning its level, and the path collapsed upto it.
-       collapseSection :: Column -> Rows -> Maybe (Int,Rows)
-       collapseSection col xxs@(x:xs) | columnPos (posTree x) == col =
+       collapseSection :: ColNum -> Rows -> Maybe (LevelSection,Rows)
+       collapseSection col xxs@(x:xs) | pos_column (cell_begin (unTree x)) == col =
                case x of
-                TreeN (unCell -> KeySection lvl) _ -> Just (lvl, xxs)
+                Tree (unCell -> NodeHeader (HeaderSection lvl)) _ -> Just (lvl, xxs)
                 _ -> do
                        (lvl, cs) <- collapseSection col xs
-                       return (lvl, insertChild x cs)
+                       return (lvl, appendChild cs x)
        collapseSection _ _ = Nothing
+       
+       mergeNodeText :: Rows -> Rows
+       mergeNodeText rs
+        | newPara = rs
+        | otherwise =
+               case (o,n) of
+                (NodeText to, NodeText tn)
+                       | null os
+                       , not (TL.null to)
+                       , not (TL.null tn) ->
+                       -- debug "appendRow" "action" ("mergeNodeText"::TL.Text) $
+                       dbg "mergeNodeText" $
+                       appendRow (merged : olds) news
+                       where
+                       merged = Tree (Cell bo en $ NodeText $ to<>tp<>tn) ns
+                       tp = fromPad Pos
+                                { pos_line   = pos_line   bn - pos_line   eo
+                                , pos_column = pos_column bn - pos_column bo
+                                }
+                _ -> rs
 
-{-
-appendCellValue :: Cell Value -> Cell Value -> Tree (Cell Key) (Cell Value)
-appendCellValue par@(Cell posPar posEndPar p) row@(Cell posRow posEndRow r) =
-       trac ("appendCellValue: p="<>show p) $
-       trac ("appendCellValue: r="<>show r) $
-       dbg "appendCellValue" $
-       case linePos posRow - linePos posEndPar of
-        0 ->
-               TreeN (Cell posPar posEndRow KeyPara)
-                [ Tree0 par
-                , Tree0 row
-                ]
-        1 ->
-               TreeN (Cell posPar posEndRow KeyPara)
-                [ Tree0 par
-                , Tree0 row
-                ]
-        _ -> []
-       where
-       padding x y = Text.replicate (y - x) " "
-       {-
-       where
-       pad =
-               -- return $ LexemeWhite $ Cell posEndPar posRow $
-               -- padding (columnPos posEndPar) (columnPos posRow)
-       -}
-       {-
-       -- return $ Cell posPar posEndRow $ p <> pad <> r
-       -- return $ Cell posPar posEndRow $ p <> pad <> r
-       where
-       pad =
-               -- return $ LexemeWhite $ Cell posEndPar posRow $
-               -- "\n" <>
-               padding (columnPos posPar) (columnPos posRow)
-       -}
--}
-
-insertChild :: Tree (Cell Key) (Cell Value) -> Rows -> Rows
-insertChild child ps@[] =
-       trac ("insertChild: child="<>show child) $
-       trac ("insertChild: ps="<>show ps) $
-       dbg "insertChild" $
-       [child]
-insertChild c@(Tree0 (Cell _bp ep _))
-            (p@(Tree0 (Cell bp _ep _)):parents) =
-       TreeN (Cell bp ep KeyPara) [p, c] : parents
-insertChild (TreeN (Cell _bp ep _) cs)
-            (p@(Tree0 (Cell bp _ep _)):parents) =
-       TreeN (Cell bp ep KeyPara) (p Seq.<| cs) : parents
-       {-
-       undefined
-       -- FIXME: this case may be removed.
-       case dbg "colParent" (columnCell parent)`compare`dbg "colChild" (columnPos $ posTree child) of
-        LT -> TreeN KeyMix (Seq.fromList [Tree0 v, child] treesParent |> child) : parents
-        EQ -> TreeN KeyMix (Seq.fromList [Tree0 v, child] treesParent |> child) : parents
-        GT -> undefined
-       -}
-insertChild child ps@(TreeN parent treesParent:parents) =
-       trac ("insertChild: child="<>show child) $
-       trac ("insertChild: ps="<>show ps) $
-       dbg "insertChild" $
-       -- FIXME: this case may be removed.
-       case dbg "colParent" (columnCell parent)`compare`dbg "colChild" (columnPos $ posTree child) of
-        LT -> TreeN parent (treesParent |> child) : parents
-        EQ -> TreeN parent (treesParent |> child) : parents
-        GT -> undefined
-
-collapseRows :: Rows -> Tree (Cell Key) (Cell Value)
-collapseRows []              = undefined
-collapseRows [child]         = dbg "collapseRows" $ child
-collapseRows (child:parents) = dbg "collapseRows" $ collapseRows $ insertChild child parents
-
-
+appendChild :: Rows -> Tree (Cell Node) -> Rows
+appendChild rows new@(Tree (Cell bn en n) ns) =
+       debug "appendChild" "new" new $
+       debug "appendChild" "rows" rows $
+       dbg "appendChild" $
+       case rows of
+        [] -> [new]
+        old@(Tree (Cell bo eo o) os) : olds ->
+               (: olds) $
+               if newPara
+               then
+                       case (o,n) of
+                        (NodePara,NodePara) -> Tree (Cell bo en NodeGroup) $ Seq.fromList [old,new]
+                        (NodePara,_)        -> Tree (Cell bo en NodeGroup) $ Seq.fromList [old,Tree (Cell bn en NodePara) $ return new]
+                        (_,NodePara)        -> Tree (Cell bo en o) $ os|>new
+                        (NodeText{},_)      -> Tree (Cell bo en NodeGroup) $ Seq.fromList [old,new]
+                        _                   -> Tree (Cell bo en o) $ os|>Tree (Cell bn en NodePara) (return new)
+               else
+                       case (o,n) of
+                        (NodePara,NodePara) -> Tree (Cell bo en NodePara) $ os<>ns
+                        (NodePara,_)        -> Tree (Cell bo en NodePara) $ os|>new
+                        (_,NodePara)        -> Tree (Cell bo en NodePara) $ old<|ns
+                        (NodeText{},_)      -> Tree (Cell bo en NodeGroup) $ Seq.fromList [old,new]
+                        _ ->
+                               case Seq.viewr os of
+                                EmptyR ->
+                                       Tree (Cell bo en o) $
+                                               os |> Tree (Cell bn en NodePara) (return new)
+                                ls :> Tree (Cell br _er r) rs ->
+                                       case r of
+                                        NodePara ->
+                                               if pos_column br == pos_column bn
+                                               then Tree (Cell bo en o) $ ls |> Tree (Cell br en NodePara) (rs |> new)
+                                               else Tree (Cell bo en o) $ os |> Tree (Cell bn en NodePara) (return new)
+                                        _ ->  Tree (Cell bo en o) $ os |> new
+               where newPara = pos_line bn - pos_line eo > 1
 
+collapseRows :: Rows -> Tree (Cell Node)
+collapseRows rs =
+       debug "collapseRows" "rs" rs $
+       dbg "collapseRows" $
+       case rs of
+        [] -> undefined
+        [child] -> child
+        child:parents -> collapseRows $ appendChild parents child
index cb05e90125eef00e3a4bcf125d6efb297202c9ca..0b4a3f54f8687f8d55e205bf9d6caa78332fa334 100644 (file)
@@ -3,6 +3,7 @@
 {-# LANGUAGE ViewPatterns #-}
 module Language.TCT.Write.HTML5 where
 
+import Control.Applicative (Applicative(..))
 import Control.Monad (Monad(..), forM_, mapM_, when)
 import Data.Bool
 import Data.Char (Char)
@@ -37,6 +38,27 @@ import Text.Blaze.Utils
 import Language.TCT
 import qualified Language.TCT.Write.Plain as Plain
 
+html5Document :: TCTs -> Html
+html5Document body = do
+       H.docType
+       H.html $ do
+               H.head $ do
+                       H.meta ! HA.httpEquiv "Content-Type"
+                              ! HA.content "text/html; charset=UTF-8"
+                       whenJust (tokensTitle body) $ \ts ->
+                               H.title $
+                                       H.toMarkup $ Plain.text def $ List.head $ toList ts
+                       -- link ! rel "Chapter" ! title "SomeTitle">
+                       H.link ! HA.rel "stylesheet"
+                              ! HA.type_ "text/css"
+                              ! HA.href "style/tct-html5.css"
+               let (html5Body, State{}) =
+                       runStateMarkup def $
+                       html5ify body
+               H.body $ do
+                       H.a ! HA.id ("line-1") $ return ()
+                       html5Body
+
 -- * Type 'Html5'
 type Html5 = StateMarkup State ()
 
@@ -67,26 +89,6 @@ instance Html5ify TL.Text where
        html5ify = html5ify . H.toMarkup
 instance Html5ify String where
        html5ify = html5ify . H.toMarkup
-html5Document :: TCTs -> Html
-html5Document body = do
-       H.docType
-       H.html $ do
-               H.head $ do
-                       H.meta ! HA.httpEquiv "Content-Type"
-                              ! HA.content "text/html; charset=UTF-8"
-                       whenJust (tokensTitle body) $ \ts ->
-                               H.title $
-                                       H.toMarkup $ Plain.text def $ List.head $ toList ts
-                       -- link ! rel "Chapter" ! title "SomeTitle">
-                       H.link ! HA.rel "stylesheet"
-                              ! HA.type_ "text/css"
-                              ! HA.href "style/tct-html5.css"
-               let (html5Body, State{}) =
-                       runStateMarkup def $
-                       html5ify body
-               H.body $ do
-                       H.a ! HA.id ("line-1") $ return ()
-                       html5Body
 instance Html5ify (Trees (Cell Key) Tokens) where
        html5ify = mapM_ html5ify
 instance Html5ify (Tree (Cell Key) Tokens) where
@@ -184,12 +186,12 @@ instance Html5ify Token where
                                H.span ! HA.class_ "elem-name" $$
                                        html5ify name
                        lenName = Text.length name
-                       lenAttrs = sum $ (<$> attrs) $ \(attr_white,Attr{..}) ->
-                               Text.length attr_white +
-                               Text.length attr_name +
-                               Text.length attr_open +
-                               Text.length attr_value +
-                               Text.length attr_close
+                       lenAttrs = sum $ (<$> attrs) $ \(elemAttr_white,ElemAttr{..}) ->
+                               Text.length elemAttr_white +
+                               Text.length elemAttr_name +
+                               Text.length elemAttr_open +
+                               Text.length elemAttr_value +
+                               Text.length elemAttr_close
                        (lenO,lenC) | Seq.null ts = (1+lenName+lenAttrs+2,0)
                                    | otherwise   = (1+lenName+lenAttrs+1,2+lenName+1)
                        o,c :: Html5
@@ -207,10 +209,11 @@ instance Html5ify Token where
                                H.span ! HA.class_ "pair-content" $$ html5ify ts
                                html5ify $ Cell ep{columnPos = columnPos ep - Text.length c} ep ()
                                H.span ! HA.class_ "pair-close"   $$ html5ify c
-       html5ify (Tree0 (Cell bp ep t)) = do
-               html5ify $ Cell bp ep ()
-               case t of
-                TokenPlain txt -> html5ify txt
+       html5ify (Tree0 tok) = do
+               -- html5ify $ Cell bp ep ()
+               case tok of
+                TokenPhrases ps -> html5ify ps
+                TokenRaw t -> html5ify t
                        {-do
                        lin <- S.get
                        let lines = Text.splitOn "\n" txt
@@ -230,21 +233,30 @@ instance Html5ify Token where
                                H.span ! HA.class_ "tag-open" $$
                                        html5ify '#'
                                html5ify v
-                TokenEscape c -> html5ify ['\\',c]
-                TokenLink lnk ->
+                TokenEscape c -> html5ify $ ('\\' :) . pure <$> c
+                TokenLink (Cell bp ep lnk) -> do
+                       html5ify $ Cell bp ep ()
                        H.a ! HA.href (attrify lnk) $$
                                html5ify lnk
-instance Html5ify Attrs where
+instance Html5ify Phrases where
+       html5ify = mapM_ html5ify
+instance Html5ify Phrase where
+       html5ify p =
+               case p of
+                PhraseWord  t -> html5ify t
+                PhraseWhite t -> html5ify t
+                PhraseOther t -> html5ify t
+instance Html5ify ElemAttrs where
        html5ify = mapM_ html5ify
-instance Html5ify (White,Attr) where
-       html5ify (attr_white,Attr{..}) = do
-               html5ify attr_white
+instance Html5ify (White,ElemAttr) where
+       html5ify (elemAttr_white,ElemAttr{..}) = do
+               html5ify elemAttr_white
                H.span ! HA.class_ "attr-name" $$
-                       html5ify attr_name
-               html5ify attr_open
+                       html5ify elemAttr_name
+               html5ify elemAttr_open
                H.span ! HA.class_ "attr-value" $$
-                       html5ify attr_value
-               html5ify attr_close
+                       html5ify elemAttr_value
+               html5ify elemAttr_close
 
 -- * Utilities
 
index 2ab35c181c7acfd5dda0e922643b73c5a5f0343c..fb373998c50ca66eb37690a669ea9ff277369b30 100644 (file)
@@ -4,8 +4,8 @@
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Language.TCT.Write.Plain where
 
-import Control.Applicative (liftA2)
-import Control.Monad (Monad(..))
+import Control.Applicative (Applicative(..), liftA2)
+import Control.Monad (Monad(..), mapM)
 import Data.Bool
 import Data.Char (Char)
 import Data.Default.Class (Default(..))
@@ -14,10 +14,11 @@ import Data.Foldable (Foldable(..))
 import Data.Function (($), (.))
 import Data.Functor ((<$>))
 import Data.Int (Int64)
+import Data.Maybe (Maybe(..))
 import Data.Monoid (Monoid(..))
 import Data.Ord (Ord(..))
 import Data.Semigroup (Semigroup(..))
-import Data.Sequence (ViewL(..))
+import Data.Sequence (Seq, ViewL(..))
 import Data.String (String, IsString(..))
 import Data.Text (Text)
 import Data.TreeSeq.Strict (Tree(..),Trees)
@@ -31,7 +32,7 @@ import qualified Data.Text.Lazy as TL
 import qualified Data.Text.Lazy.Builder as TLB
 
 -- import Language.TCT.Tree
--- import Language.TCT.Token
+import Language.TCT.Token
 import Language.TCT.Cell
 import Language.TCT.Elem
 import Language.TCT.Read.Token
@@ -70,6 +71,8 @@ instance Default State where
 -- * Class 'Plainify'
 class Plainify a where
        plainify :: a -> Plain
+instance Plainify () where
+       plainify = mempty
 instance Plainify Char where
        plainify = return . TLB.singleton
 instance Plainify String where
@@ -83,14 +86,15 @@ instance Plainify a => Plainify (Cell a) where
                Pos lineLast colLast <- S.gets state_pos
                case () of
                 _ | lineLast < line -> do
-                       plainify $ Text.replicate (line - lineLast - 1) "\n"
-                       plainify $ Text.replicate (col - 1) " "
+                       S.modify $ \s -> s{state_pos=ep}
+                       plainify (Text.replicate (line - lineLast - 1) "\n")
+                        <> plainify (Text.replicate (col - 1) " ")
+                        <> plainify a
                 _ | lineLast == line && colLast <= col -> do
-                       plainify $ Text.replicate (col - colLast) " "
+                       S.modify $ \s -> s{state_pos=ep}
+                       plainify (Text.replicate (col - colLast) " ")
+                        <> plainify a
                 _ -> undefined
-               -- S.modify $ \s -> s{state_pos=bp}
-               S.modify $ \s -> s{state_pos=ep}
-               plainify a
 instance Plainify (Trees (Cell Key) Tokens) where
        plainify = foldMap plainify
 instance Plainify (Tree (Cell Key) Tokens) where
@@ -112,7 +116,7 @@ instance Plainify (Key, Trees (Cell Key) Tokens) where
                        plainify attrs <>
                        plainify ts
                 KeySection lvl ->
-                       plainify (TL.replicate (int64 lvl) "#") <> " " <>
+                       plainify (TL.replicate (int64 lvl) "#") <>
                        case Seq.viewl ts of
                         Tree0 title :< ts' ->
                                plainify title <>
@@ -133,41 +137,49 @@ instance Plainify Tokens where
        plainify = foldMap plainify
 instance Plainify Token where
        plainify = \case
-        TreeN (Cell bp ep k) ts -> plainify (Cell bp ep (k,ts))
-        Tree0 ts -> plainify ts
-instance Plainify (TokenKey, Tokens) where
-       plainify (k,ts) =
+        TreeN (Cell bp ep k) ts ->
+               plainify (Cell bp ep ()) <>
                plainify o <> plainify ts <> plainify c
                where (o,c) = pairBorders k ts
-instance Plainify TokenValue where
-       plainify = \case
-        TokenPlain txt -> plainify txt
-               {- TODO: remove
-               lnum <- S.get
-               let lines = Text.splitOn "\n" txt
-               S.put (lnum - 1 + List.length lines)
-               return $
-                       case lines of
-                        [] -> undefined
-                        (l0:ls) -> plainify l0 <> mconcat ((\l -> "\n"<>indent<>plainify l)<$>ls)
-               -}
-        TokenTag v -> plainify '#'<>plainify v
-        TokenEscape c -> do
-               esc <- S.gets state_escape
-               if esc
-                then plainify ['\\',c]
-                else plainify c
-        TokenLink lnk -> plainify lnk
-instance Plainify Attrs where
+        Tree0 tok ->
+               -- plainify (Cell bp ep ()) <>
+               case tok of
+                TokenPhrases p -> plainify p
+                TokenRaw t -> plainify t
+                       {- TODO: remove
+                       lnum <- S.get
+                       let lines = Text.splitOn "\n" txt
+                       S.put (lnum - 1 + List.length lines)
+                       return $
+                               case lines of
+                                [] -> undefined
+                                (l0:ls) -> plainify l0 <> mconcat ((\l -> "\n"<>indent<>plainify l)<$>ls)
+                       -}
+                TokenTag v -> plainify $ ("#"<>) <$> v
+                TokenEscape c -> do
+                       esc <- S.gets state_escape
+                       if esc
+                        then plainify $ (('\\' :) . pure) <$> c
+                        else plainify c
+                TokenLink lnk -> plainify lnk
+instance Plainify Phrases where
        plainify = foldMap plainify
-instance Plainify (Text,Attr) where
-       plainify (attr_white,Attr{..}) =
+instance Plainify Phrase where
+       plainify p =
+               case p of
+                PhraseWord  t -> plainify t
+                PhraseWhite t -> plainify t
+                PhraseOther t -> plainify t
+instance Plainify ElemAttrs where
+       plainify = foldMap plainify
+instance Plainify (Text,ElemAttr) where
+       plainify (elemAttr_white,ElemAttr{..}) =
                mconcat $ plainify <$>
-                [ attr_white
-                , attr_name
-                , attr_open
-                , attr_value
-                , attr_close
+                [ elemAttr_white
+                , elemAttr_name
+                , elemAttr_open
+                , elemAttr_value
+                , elemAttr_close
                 ]
 
 {-
@@ -192,6 +204,34 @@ instance Textify Token where
                 TokenLink lnk  -> plainify lnk
 -}
 
+-- * Class 'RackUpLeft'
+class RackUpLeft a where
+       rackUpLeft :: a -> S.State (Maybe Pos) a
+instance RackUpLeft Pos where
+       rackUpLeft pos@Pos{..} = do
+               S.get >>= \case
+                Nothing -> return pos
+                Just (Pos l0 c0) ->
+                       return Pos
+                        { linePos   = linePos   - l0 + 1
+                        , columnPos = columnPos - c0 + 1
+                        }
+instance RackUpLeft (Cell a) where
+       rackUpLeft (Cell bp ep a) = do
+               S.modify $ \case
+                Nothing -> Just bp
+                p -> p
+               Cell
+                <$> rackUpLeft bp
+                <*> rackUpLeft ep
+                <*> pure a
+instance RackUpLeft a => RackUpLeft (Seq a) where
+       rackUpLeft = mapM rackUpLeft
+instance (RackUpLeft k, RackUpLeft a) => RackUpLeft (Tree k a) where
+       rackUpLeft = \case
+        Tree0 a    -> Tree0 <$> rackUpLeft a
+        TreeN k ts -> TreeN <$> rackUpLeft k <*> rackUpLeft ts
+
 {-
 -- * Utilities
 plainifyIndentCell :: (Pos,Pos) -> Plain
@@ -206,21 +246,6 @@ plainifyIndentCell (Pos lineLast colLast,Pos line col)
  | otherwise = undefined
 
 -- ** 'Tree'
-treeRackUpLeft :: Tree (Cell k) (Cell a) -> Tree (Cell k) (Cell a)
-treeRackUpLeft t = go t
-       where
-       Pos l0 c0 = posTree t
-       rackUpLeft pos =
-               Pos
-                (linePos pos - l0 + 1)
-                (columnPos pos - c0 + 1)
-       go :: Tree (Cell k) (Cell a) -> Tree (Cell k) (Cell a)
-       go (Tree0 (Cell pos posEnd c)) =
-               Tree0 $ Cell (rackUpLeft pos) (rackUpLeft posEnd) c
-       go (TreeN (Cell pos posEnd c) ts) =
-               TreeN
-                (Cell (rackUpLeft pos) (rackUpLeft posEnd) c)
-                (go <$> ts)
 
 treePosLastCell ::
  Trees (Cell k) Tokens ->
index 1c5c0784771e6feca94b73757efd1d34d60160fa..2c790ce03171ee442bdc8626dca630b71e235020 100644 (file)
@@ -28,6 +28,7 @@ import qualified Data.List as List
 import qualified Data.Sequence as Seq
 import qualified Data.Text as Text
 import qualified Data.Text.Lazy as TL
+import qualified Control.Monad.Trans.State as S
 import qualified Language.TCT.Write.Plain as Plain
 import qualified System.FilePath as FP
 
@@ -36,6 +37,53 @@ import Language.TCT hiding (Parser)
 import Language.XML
 import qualified Data.TreeSeq.Strict as TreeSeq
 
+import Debug.Trace (trace)
+import Text.Show (show)
+
+xmlDocument :: TCTs -> XMLs
+xmlDocument trees =
+       -- (`S.evalState` def) $
+       case Seq.viewl trees of
+        TreeN (unCell -> KeySection{}) vs :< ts ->
+               case spanlTokens vs of
+                (titles@(Seq.viewl -> (Seq.viewl -> (posTree -> bp) :< _) :< _), vs') ->
+                       let vs'' =
+                               case Seq.findIndexL
+                                (\case
+                                TreeN (unCell -> KeyColon "about" _) _ -> True
+                                _ -> False) vs' of
+                                Nothing -> TreeN (Cell bp bp $ KeyColon "about" "") mempty <| vs'
+                                Just{} -> vs' in
+                       xmlify def
+                        { inh_titles = titles
+                        , inh_figure = True
+                        , inh_tree0  = List.repeat xmlPara
+                        } vs'' <>
+                       xmlify def ts
+                _ -> xmlify def trees
+        _ -> xmlify def trees
+
+{-
+-- * Type 'Xmls'
+type Xmls = S.State State XMLs
+type Xml  = S.State State XML
+instance Semigroup Xmls where
+       (<>) = liftA2 (<>)
+instance Monoid Xmls where
+       mempty  = return mempty
+       mappend = (<>)
+
+-- * Type 'State'
+data State
+ =   State
+ {   state_pos :: Pos
+ }
+instance Default State where
+       def = State
+        { state_pos = pos1
+        }
+-}
+
 -- * Type 'Inh'
 data Inh
  =   Inh
@@ -64,7 +112,7 @@ instance Xmlify TCTs where
                          , not (null body) ->
                                (<| go inh ts) $
                                TreeN (Cell bp ep "artwork") $
-                                       maybe id (\v -> (Tree0 (Cell bp ep (XmlAttr "type" v)) <|)) (mimetype n) $
+                                       maybe id (\v -> (Tree0 (XmlAttr (Cell bp ep ("type", v))) <|)) (mimetype n) $
                                        body >>= xmlify inh{inh_tree0=[]}
                        
                         TreeN key@(unCell -> KeyColon n _) cs :< ts
@@ -171,15 +219,17 @@ instance Xmlify Token where
                case p of
                 PairBracket | to <- Plain.text def ts
                             , TL.all (\c -> Char.isAlphaNum c || Char.isSymbol c) to ->
-                       Seq.singleton $
+                       Seq.singleton .
                        TreeN (cell "rref") $
                                xmlAttrs [cell ("to",TL.toStrict to)]
-                PairStar      -> Seq.singleton $ TreeN (cell "b") $ xmlify inh ts
-                PairSlash     -> Seq.singleton $ TreeN (cell "i") $ xmlify inh ts
-                PairBackquote -> Seq.singleton $ TreeN (cell "code") $ xmlify inh ts
+                PairStar      -> Seq.singleton . TreeN (cell "b")    $ xmlify inh ts
+                PairSlash     -> Seq.singleton . TreeN (cell "i")    $ xmlify inh ts
+                PairBackquote -> Seq.singleton . TreeN (cell "code") $ xmlify inh ts
                 PairFrenchquote ->
-                       Seq.singleton $
+                       Seq.singleton .
                        TreeN (cell "q") $
+                       xmlify inh ts
+                       {-
                        case ts of
                         (Seq.viewl -> Tree0 (Cell bl el (TokenPlain l)) :< ls) ->
                                case Seq.viewr ls of
@@ -194,35 +244,47 @@ instance Xmlify Token where
                                xmlify inh $
                                        rs |> Tree0 (Cell br er (TokenPlain (Text.dropAround Char.isSpace r)))
                         _ -> xmlify inh ts
+                        -}
                 PairHash ->
-                       Seq.singleton $
+                       Seq.singleton .
                        TreeN (cell "ref") $
                                xmlAttrs [cell ("to",TL.toStrict $ Plain.text def ts)]
                 PairElem name attrs ->
-                       Seq.singleton $
+                       Seq.singleton .
                        TreeN (cell $ xmlLocalName name) $
-                               xmlAttrs (Seq.fromList $ (\(_wh,Attr{..}) ->
-                                       cell (xmlLocalName attr_name,attr_value)) <$> attrs) <>
+                               xmlAttrs (Seq.fromList $ (\(_wh,ElemAttr{..}) ->
+                                       cell (xmlLocalName elemAttr_name,elemAttr_value)) <$> attrs) <>
                                xmlify inh ts
                 _ ->
                        let (o,c) = pairBorders p ts in
-                       Seq.singleton (Tree0 $ Cell bp bp $ XmlText o) `unionXml`
+                       Seq.singleton (Tree0 $ XmlPhrases $ phrasify $ Cell bp bp o) `unionXml`
                        xmlify inh ts `unionXml`
-                       Seq.singleton (Tree0 $ Cell ep ep $ XmlText c)
+                       Seq.singleton (Tree0 $ XmlPhrases $ phrasify $ Cell ep ep c)
                where
                cell :: a -> Cell a
                cell = Cell bp ep
-       xmlify _inh (Tree0 (Cell bp ep tok)) =
+       xmlify inh (Tree0 tok) = do
                case tok of
-                TokenPlain t  -> Seq.singleton $ Tree0 $ cell $ XmlText t
+                TokenPhrases ps -> xmlify inh $ ps
+                TokenEscape c -> Seq.singleton $ Tree0 $ XmlPhrases $ phrasify c
+                TokenRaw t    -> Seq.singleton $ Tree0 $ XmlText t
                 TokenTag t    -> Seq.singleton $ TreeN (cell "ref") $ xmlAttrs [cell ("to",t)]
-                TokenEscape c -> Seq.singleton $ Tree0 $ cell $ XmlText $ Text.singleton c
-                TokenLink lnk -> Seq.singleton $
-                       TreeN (cell "eref") $
-                               xmlAttrs [cell ("to",lnk)]
+                TokenLink (Cell bp ep lnk) ->
+                       xmlify (Cell bp ep ()) <>
+                       Seq.singleton (TreeN (cell "eref") $ xmlAttrs [cell ("to",lnk)])
                where
                cell :: a -> Cell a
                cell = Cell bp ep
+               {-
+               whites :: Pos -> Pos -> Seq XmlText
+               whites (Pos bLine bCol) (Pos eLine eCol) =
+                       case bLine`compate`eLine of
+                        LT -> verts <> 
+                        EQ -> horiz bCol eCol
+                        GT ->
+               -}
+instance Xmlify (Cell Phrase) where
+       xmlify _inh t = Seq.singleton $ Tree0 $ XmlPhrases $ Seq.singleton t
 
 mimetype :: Text -> Maybe Text
 mimetype "hs"          = Just "text/x-haskell"
@@ -238,31 +300,9 @@ xmlPara = xmlPhantom "para"
 xmlTitle :: Pos -> XMLs -> XML
 xmlTitle = xmlPhantom "title"
 xmlName :: Pos -> XMLs -> XML
-xmlName bp (toList -> [Tree0 (unCell -> XmlText t)]) = Tree0 (Cell bp bp $ XmlAttr "name" t)
+xmlName bp (toList -> [Tree0 (XmlText (unCell -> t))]) = Tree0 (XmlAttr $ Cell bp bp ("name", t))
 xmlName bp ts = xmlPhantom "name" bp ts
 
-xmlDocument :: TCTs -> XMLs
-xmlDocument trees =
-       case Seq.viewl trees of
-        TreeN (unCell -> KeySection{}) vs :< ts ->
-               case spanlTokens vs of
-                (titles@(Seq.viewl -> (Seq.viewl -> (posTree -> bp) :< _) :< _), vs') ->
-                       let vs'' =
-                               case Seq.findIndexL
-                                (\case
-                                TreeN (unCell -> KeyColon "about" _) _ -> True
-                                _ -> False) vs' of
-                                Nothing -> TreeN (Cell bp bp $ KeyColon "about" "") mempty <| vs'
-                                Just{} -> vs' in
-                       xmlify def
-                        { inh_titles = titles
-                        , inh_figure = True
-                        , inh_tree0  = List.repeat xmlPara
-                        } vs'' <>
-                       xmlify def ts
-                _ -> xmlify def trees
-        _ -> xmlify def trees
-
 xmlAbout ::
  Inh ->
  Cell Key -> Seq (Cell (XmlName, Text)) ->
@@ -287,17 +327,21 @@ xmlKey inh (Cell bp ep key) attrs ts =
         KeyBar   n _wh -> d_key n
         KeyDot _n   -> TreeN (cell "li") $ xmlify inh ts
         KeyDash     -> TreeN (cell "li") $ xmlify inh ts
-        KeyDashDash -> Tree0 $ cell $ XmlComment $ TL.toStrict com
+        KeyDashDash -> Tree0 $ XmlComment $ cell $ TL.toStrict com
                where
                com :: TL.Text
                com =
-                       Plain.text def $
+                       trace ("TS: "<>show ts) $
+                       trace ("RS: "<>show (S.evalState (Plain.rackUpLeft ts) Nothing)) $
+                       Plain.text def $ S.evalState (Plain.rackUpLeft ts) Nothing
+                       {-
                        TreeSeq.mapAlsoNode
                         (cell1 . unCell)
                         (\_k -> fmap $
                                TreeSeq.mapAlsoNode
                                 (cell1 . unCell)
                                 (\_k' -> cell1 . unCell)) <$> ts
+                       -}
         KeyLower n as -> TreeN (cell "artwork") $ xmlify inh ts
         KeyBrackets ident ->
                let inh' = inh{inh_figure = False} in
@@ -319,7 +363,7 @@ xmlKey inh (Cell bp ep key) attrs ts =
                        xmlify inh ts
 
 xmlAttrs :: Seq (Cell (XmlName,Text)) -> XMLs
-xmlAttrs = ((\(Cell bp ep (n,v)) -> Tree0 (Cell bp ep $ XmlAttr n v)) <$>)
+xmlAttrs = (Tree0 . XmlAttr <$>)
 
 -- | Unify two 'XMLs', merging border 'XmlText's if any.
 unionXml :: XMLs -> XMLs -> XMLs
@@ -327,9 +371,15 @@ unionXml x y =
        case (Seq.viewr x, Seq.viewl y) of
         (xs :> x0, y0 :< ys) ->
                case (x0,y0) of
-                (Tree0 (Cell bx _ex (XmlText tx)), Tree0 (Cell _by ey (XmlText ty))) ->
+                (  Tree0 (XmlPhrases tx)
+                 , Tree0 (XmlPhrases ty) ) ->
+                       xs `unionXml`
+                       Seq.singleton (Tree0 $ XmlPhrases $ tx <> ty) `unionXml`
+                       ys
+                (  Tree0 (XmlText tx)
+                 , Tree0 (XmlText ty) ) ->
                        xs `unionXml`
-                       Seq.singleton (Tree0 $ Cell bx ey $ XmlText $ tx <> ty) `unionXml`
+                       Seq.singleton (Tree0 $ XmlText $ tx <> ty) `unionXml`
                        ys
                 _ -> x <> y
         (Seq.EmptyR, _) -> y
@@ -352,6 +402,7 @@ spanlItems liKey ts =
        let (lis, ts') = spanLIs ts in
        foldl' accumLIs (mempty,ts') lis
        where
+       spanLIs :: TCTs -> (TCTs, TCTs)
        spanLIs = Seq.spanl $ \case
                 TreeN (unCell -> liKey -> True) _ -> True
                 Tree0 toks ->
@@ -364,22 +415,26 @@ spanlItems liKey ts =
                         _ -> False
                        -}
                 _ -> False
+       accumLIs :: (TCTs,TCTs) -> TCT -> (TCTs,TCTs)
        accumLIs acc@(oks,kos) t =
                case t of
                 TreeN (unCell -> liKey -> True) _ -> (oks|>t,kos)
                 Tree0 toks ->
                        let (ok,ko) =
                                (`Seq.spanl` toks) $ \case
-                                        TreeN (unCell -> PairElem "li" _) _ -> True
-                                        Tree0 (unCell -> TokenPlain txt) -> Char.isSpace`Text.all`txt
-                                        _ -> False in
-                       ( if null ok then oks else oks|>Tree0 (rmTokenPlain ok)
+                                TreeN (unCell -> PairElem "li" _) _ -> True
+                                -- (isTokenWhite -> True) -> True -- TODO: see if this is still useful
+                                _ -> False in
+                       ( if null ok then oks else oks|>Tree0 (rmTokenWhite ok)
                        , if null ko then kos else Tree0 ko<|kos )
                 _ -> acc
-       rmTokenPlain =
+       {-
+       rmTokenWhite :: Tokens -> Tokens
+       rmTokenWhite =
                Seq.filter $ \case
-                (Tree0 (unCell -> TokenPlain{})) -> False
+                (isTokenWhite -> False) -> True
                 _ -> True
+       -}
 
 spanlKeyColon :: Name -> TCTs -> (TCTs, TCTs)
 spanlKeyColon name =
index 45be9e3ff149847af3f9f797ba51a561ca2cb986..b7811307b7bf3ef95119eb203adac4eb4c620bf5 100644 (file)
@@ -20,11 +20,12 @@ import Prelude (error, pred, succ)
 import Text.Show (Show(..), showsPrec, showChar, showString)
 import qualified Data.List as List
 import qualified Data.Text as Text
+import qualified Data.Text.Lazy as TL
 
 import Language.TCT.Cell
 
 -- * Type 'XML'
-type XML  = Tree (Cell XmlName) (Cell XmlLeaf)
+type XML  = Tree (Cell XmlNode)
 type XMLs = Seq XML
 
 -- ** Type 'XmlName'
@@ -60,14 +61,16 @@ instance IsString XmlName where
 xmlLocalName :: Text -> XmlName
 xmlLocalName = XmlName "" ""
 
--- ** Type 'XmlLeaf'
-data XmlLeaf
- =   XmlAttr    XmlName Text
- |   XmlComment Text
- |   XmlText    Text
+-- ** Type 'XmlNode'
+data XmlNode
+ =   XmlElem    XmlName
+ |   XmlAttr    XmlName TL.Text
+ |   XmlComment TL.Text
+ |   XmlText    TL.Text
  deriving (Eq,Ord,Show)
 
 -- * Type 'Rank'
+-- | nth child
 type Rank = Int
 
 -- * Type 'Nat'
@@ -118,7 +121,7 @@ newtype MayText
 instance Semigroup MayText where
        MayText "" <> y = y
        x <> MayText "" = x
-       _x <> y          = y
+       _x <> y         = y
 
 whenMayText :: Applicative m => MayText -> (MayText -> m ()) -> m ()
 whenMayText (MayText "") _f = pure ()
index 4dc1b361433e3c8c8ae810c47496d8bcc3ea3410..e8f1984f40343fc23f727a106c9b62f330324077 100644 (file)
@@ -28,6 +28,7 @@ import qualified Data.List as List
 import qualified Data.Map.Strict as Map
 import qualified Data.Text as Text
 import qualified Data.Text.IO as Text
+import qualified Data.Text.Lazy as TL
 import qualified System.Environment as Env
 import qualified Text.Blaze.Renderer.Utf8 as Blaze
 import qualified Text.Blaze.Utils as Blaze
@@ -43,10 +44,10 @@ import qualified Language.DTC.Write.XML   as DTC.Write.XML
 import qualified Text.Blaze.DTC   as Blaze.DTC
 import qualified Text.Blaze.HTML5 as Blaze.HTML5
 -}
-import qualified Language.RNC.Write as RNC
+-- import qualified Language.RNC.Write as RNC
 import qualified Language.TCT as TCT
-import qualified Language.TCT.Write.HTML5 as TCT.Write.HTML5
-import qualified Language.TCT.Write.XML   as TCT.Write.XML
+-- import qualified Language.TCT.Write.HTML5 as TCT.Write.HTML5
+-- import qualified Language.TCT.Write.XML   as TCT.Write.XML
 import qualified Text.Megaparsec  as P
 
 import Read
@@ -76,12 +77,13 @@ main = do
 mainWithCommand :: Command -> IO ()
 mainWithCommand (CommandTCT ArgsTCT{..}) =
        readFile input $ \_fp txt ->
-               case TCT.readTCTs input txt of
+               case TCT.readTrees input $ TL.fromStrict txt of
                 Left err -> error $ P.parseErrorPretty err
                 Right tct -> do
                        when (trace_TCT trace) $ do
                                hPutStrLn stderr "### TCT ###"
                                hPrint stderr $ Tree.Pretty tct
+                       {-
                        when (trace_XML trace) $ do
                                hPutStrLn stderr "### XML ###"
                                let xml = TCT.Write.XML.xmlDocument tct
@@ -90,6 +92,7 @@ mainWithCommand (CommandTCT ArgsTCT{..}) =
                         TctFormatHTML5 ->
                                Blaze.renderMarkupToByteStringIO BS.putStr $
                                TCT.Write.HTML5.html5Document tct
+                       -}
 {-
 mainWithCommand (CommandDTC ArgsDTC{..}) =
        readFile input $ \_fp txt ->