module Language.Egison.Pretty.Pattern
( prettyExpr
, module X
)
where
import Language.Egison.Pretty.Pattern.Error
as X
( Error(..) )
import Language.Egison.Pretty.Pattern.PrintMode
as X
( ExtPrinter
, PrintMode(..)
, PageMode(..)
, PrintFixity(..)
)
import Language.Egison.Syntax.Pattern.Fixity
as X
( Fixity(..)
, Associativity(..)
, Precedence(..)
)
import Data.Semigroup ( (<>) )
import Data.Text ( Text )
import Control.Monad.Except ( MonadError(..) )
import Language.Egison.Pretty.Pattern.Prim
( Doc
, hsep
, text
, parens
, (<+>)
, renderDoc
)
import Language.Egison.Pretty.Pattern.Error
( Error(UnknownInfixOperator) )
import Language.Egison.Pretty.Pattern.External
( name
, varName
, valueExpr
)
import Language.Egison.Pretty.Pattern.Print
( Print
, runPrint
, askContext
, withContext
, operatorOf
)
import Language.Egison.Pretty.Pattern.Context
( Context(..)
, Side(..)
)
import Language.Egison.Pretty.Pattern.Operator
( Operator(..) )
import qualified Language.Egison.Syntax.Pattern.Fixity.Primitive
as PrimOp
import Language.Egison.Syntax.Pattern ( Expr(..) )
smartParens :: Operator -> Doc -> Print n v e Doc
smartParens opr doc = do
ctx <- askContext
if check ctx opr then pure $ parens doc else pure doc
where
check World _ = False
check ConstructorArgument PrefixOp{} = False
check ConstructorArgument _ = True
check (Under uPrec side) InfixOp { precedence, associativity }
| uPrec > precedence = True
| uPrec == precedence && not (matching associativity side) = True
| otherwise = False
check (Under uPrec _) PrefixOp { precedence } | uPrec >= precedence = True
| otherwise = False
matching AssocRight RightSide = True
matching AssocLeft LeftSide = True
matching _ _ = False
expr :: Ord n => Expr n v e -> Print n v e Doc
expr Wildcard = pure "_"
expr (Variable v) = do
dv <- varName v
pure $ "$" <> dv
expr (Value e) = do
de <- valueExpr e
pure $ "#" <> de
expr (Predicate e) = do
de <- valueExpr e
pure $ "?" <> de
expr (And e1 e2) = do
d1 <- withContext (Under PrimOp.andPrecedence LeftSide) $ expr e1
d2 <- withContext (Under PrimOp.andPrecedence RightSide) $ expr e2
smartParens opr $ d1 <+> "&" <+> d2
where
opr = InfixOp { precedence = PrimOp.andPrecedence
, associativity = PrimOp.andAssociativity
, symbol = "&"
}
expr (Or e1 e2) = do
d1 <- withContext (Under PrimOp.orPrecedence LeftSide) $ expr e1
d2 <- withContext (Under PrimOp.orPrecedence RightSide) $ expr e2
smartParens opr $ d1 <+> "|" <+> d2
where
opr = InfixOp { precedence = PrimOp.orPrecedence
, associativity = PrimOp.orAssociativity
, symbol = "|"
}
expr (Not e) = do
d <- withContext (Under PrimOp.notPrecedence RightSide) $ expr e
smartParens opr $ "!" <> d
where opr = PrefixOp { precedence = PrimOp.notPrecedence, symbol = "!" }
expr (Infix n e1 e2) = do
opr <- operatorOf n
case opr of
InfixOp { precedence, symbol } -> do
d1 <- withContext (Under precedence LeftSide) $ expr e1
d2 <- withContext (Under precedence RightSide) $ expr e2
smartParens opr $ d1 <+> text symbol <+> d2
_ -> throwError $ UnknownInfixOperator n
expr (Pattern n []) = name n
expr (Pattern n es) = do
dn <- name n
ds <- withContext ConstructorArgument $ traverse expr es
pure . parens $ dn <+> hsep ds
prettyExpr
:: (MonadError (Error n) m, Ord n) => PrintMode n v e -> Expr n v e -> m Text
prettyExpr mode e = do
doc <- runPrint (expr e) mode
pure $ renderDoc mode doc