packages feed

descript-lang-0.2.0.0: src/Descript/Misc/Build/Write/Print/Printable.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE FlexibleContexts #-}

module Descript.Misc.Build.Write.Print.Printable
  ( Printable (..)
  , FwdPrintable (..)
  ) where

import Descript.Misc.Build.Write.Print.APrint
import Descript.Misc.Ann
import Descript.Misc.Summary
import Data.Proxy

-- | An AST node which can be printed back into source text.
--
-- Note: The 'Summary' dependency is for convenience, because most (if
-- not all) prints make good summaries. With it, you can implement
-- 'Summary' using:
--
-- > summaryRec = pprintSummaryRec
class (Ann a, Summary (a ())) => Printable a where
  {-# MINIMAL aprint | aprintRec #-}

  -- | Pretty-prints this node into an abstract form.
  aprint :: (APrint r) => a an -> r
  aprint = aprintRec aprint

  -- | Pretty-prints this node into an abstract form,
  -- printing children using the given function.
  aprintRec :: (APrint r)
            => (forall b. (Printable b) => b an -> r)
            -> a an
            -> r
  aprintRec _ = aprint

  -- | Whether this node needs to be completely reprinted or patched if
  -- tainted (a child changes). Defaults to 'False' for convenience.
  needsFullReprint :: Proxy (a an) -> Bool
  needsFullReprint _ = False

-- | An "rough" AST node which can be printed back into source text. The
-- difference between this and 'Print' is that this doesn't need 'Ann',
-- which allows for (probably only use) 'Maybe' values to be printed.
--
-- If an instance is also 'Printable', the implementation should always be:
--
-- > afprintRec = id
--
-- (calls @sub@ on itself).
--
-- When printing a child instance, "forward" @sub@, e.g.:
--
-- > aprintRec sub (Add aPrintableChild aFwdPrintableChild)
-- >   = sub aPrintableChild <> " + " <> afprintRec sub aFwdPrintableChild
class (Functor a, Foldable a, Traversable a, Summary (a ())) => FwdPrintable a where
  -- | Pretty-prints this node into an abstract form,
  -- printing children using the given function.
  afprintRec :: (APrint r)
             => (forall b. (Printable b) => b an -> r)
             -> a an
             -> r