module Symantic.Parser.Grammar.View where

import Data.Function (($), (.), id)
import Data.Semigroup (Semigroup(..))
import Data.String (String, IsString(..))
import Text.Show (Show(..))
import qualified Control.Applicative as Fct
import qualified Data.Tree as Tree
import qualified Data.List as List

import Symantic.Univariant.Letable
import Symantic.Parser.Grammar.Combinators

-- * Type 'ViewGrammar'
newtype ViewGrammar a = ViewGrammar { unViewGrammar :: Tree.Tree String }

viewGrammar :: ViewGrammar a -> ViewGrammar a
viewGrammar = id

instance Show (ViewGrammar a) where
  show = drawTree . unViewGrammar
    where
    drawTree :: Tree.Tree String -> String
    drawTree  = List.unlines . draw
    draw :: Tree.Tree String -> [String]
    draw (Tree.Node x ts0) = List.lines x <> drawSubTrees ts0
      where
      drawSubTrees [] = []
      drawSubTrees [t] = shift "` " "  " (draw t)
      drawSubTrees (t:ts) = shift "+ " "| " (draw t) <> drawSubTrees ts
      shift first other = List.zipWith (<>) (first : List.repeat other)
instance IsString (ViewGrammar a) where
  fromString s = ViewGrammar $ Tree.Node (fromString s) []

instance Show letName => Letable letName ViewGrammar where
  def name x = ViewGrammar $
    Tree.Node ("def "<>show name) [unViewGrammar x]
  ref rec name = ViewGrammar $
    Tree.Node
      ( (if rec then "rec " else "ref ")
      <> show name
      ) []
instance Applicable ViewGrammar where
  _f <$> x = ViewGrammar $ Tree.Node "<$>" [unViewGrammar x]
  pure a = ViewGrammar $ Tree.Node ("pure "<>showsPrec 10 a "") []
  x <*> y = ViewGrammar $ Tree.Node "<*>" [unViewGrammar x, unViewGrammar y]
  x <* y = ViewGrammar $ Tree.Node "<*" [unViewGrammar x, unViewGrammar y]
  x *> y = ViewGrammar $ Tree.Node "*>" [unViewGrammar x, unViewGrammar y]
instance Alternable ViewGrammar where
  empty = ViewGrammar $ Tree.Node "empty" []
  x <|> y = ViewGrammar $ Tree.Node "<|>" [unViewGrammar x, unViewGrammar y]
  try x = ViewGrammar $ Tree.Node "try" [unViewGrammar x]
instance Satisfiable ViewGrammar tok where
  satisfy _es _p = ViewGrammar $ Tree.Node "satisfy" []
instance Selectable ViewGrammar where
  branch lr l r = ViewGrammar $ Tree.Node "branch"
    [ unViewGrammar lr, unViewGrammar l, unViewGrammar r ]
instance Matchable ViewGrammar where
  conditional a _ps bs b = ViewGrammar $ Tree.Node "conditional"
    [ unViewGrammar a
    , Tree.Node "bs" (unViewGrammar Fct.<$> bs)
    , unViewGrammar b
    ]
instance Lookable ViewGrammar where
  look x = ViewGrammar $ Tree.Node "look" [unViewGrammar x]
  negLook x = ViewGrammar $ Tree.Node "negLook" [unViewGrammar x]
  eof = ViewGrammar $ Tree.Node "eof" []
instance Foldable ViewGrammar where
  chainPre f x = ViewGrammar $ Tree.Node "chainPre" [unViewGrammar f, unViewGrammar x]
  chainPost x f = ViewGrammar $ Tree.Node "chainPost" [unViewGrammar x, unViewGrammar f]