blob: f2fa8a254f615207db72af158f37833e62ac96eb [file]
-- |
-- Module : Minigent.Syntax.PrettyPrint
-- Copyright : (c) Data61 2018-2019
-- Commonwealth Science and Research Organisation (CSIRO)
-- ABN 41 687 119 230
-- License : BSD3
--
-- This module is a fairly straightforward pretty-printing module.
-- Each function corresponds to a syntactic class from the parser.
--
-- It uses the @prettyprinter@ library and produces ANSI-coloured
-- output.
--
-- It expects to be imported unqualified.
{-# LANGUAGE OverloadedStrings #-}
module Minigent.Syntax.PrettyPrint where
import qualified Minigent.Syntax.PrettyPrint.Styles as S
import Minigent.Syntax
import Minigent.Syntax.Utils
import qualified Minigent.Syntax.Utils.Row as Row
import Minigent.Environment
import Data.Text.Prettyprint.Doc
import Data.Text.Prettyprint.Doc.Render.Terminal
import qualified Data.Text as T
import qualified Data.Map as M
import Minigent.TC.Assign
prettyPrimType t = annotate S.primType (viaShow (t :: PrimType))
prettyREntry (Entry v x tk)
= annotate S.field (pretty v)
<+> annotate S.sym ":"
<+> prettyType x
<> if tk then space <> annotate S.keyword "take"
else mempty
prettyVEntry (Entry v x tk)
= annotate S.con (pretty v)
<+> prettyType x
<> if tk then space <> annotate S.keyword "take"
else mempty
prettySigil ReadOnly = annotate S.sigil "!"
prettySigil Unboxed = annotate S.sigil "#"
prettySigil (UnknownSigil s) = annotate S.sigil (pretty s)
prettySigil _ = mempty
prettyRecPar None = mempty
prettyRecPar (Rec x) = annotate S.typeVar (annotate S.keyword "rec" <+> pretty x) <+> mempty
prettyRecPar (UnknownParameter x) = annotate S.unifVar (pretty x) <+> mempty
prettyVRow r@(Row _ Nothing) = encloseSep langle rangle pipe (map prettyVEntry (Row.entries r))
prettyVRow r@(Row _ (Just v)) = encloseSep langle rangle pipe (map prettyVEntry (Row.entries r)
++ [annotate S.var (pretty (v ++ "..."))])
prettyRRow r@(Row _ Nothing) = encloseSep lbrace rbrace comma (map prettyREntry (Row.entries r))
prettyRRow r@(Row _ (Just v)) = encloseSep lbrace rbrace comma (map prettyREntry (Row.entries r)
++ [annotate S.var (pretty (v ++ "...")) ])
prettyType ty = case ty of
Function t1 t2 -> align (sep [pretty' t1, annotate S.sym "->" <+> prettyType t2])
Bang t -> annotate S.typeOp "bang" <+> prettyA t
_ -> pretty' ty
where
prettyA (TypeVar n) = annotate S.typeVar (pretty n)
prettyA (RecPar n _) = annotate S.keyword "rec" <+> annotate S.typeVar (pretty n)
prettyA (UnifVar n) = annotate S.unifVar (pretty n)
prettyA (TypeVarBang n) = annotate S.typeVar (pretty n) <> annotate S.sigil "!"
prettyA (RecParBang n _) = annotate S.keyword "rec" <+> annotate S.typeVar (pretty n) <> annotate S.sigil "!"
prettyA (PrimType t) = prettyPrimType t
prettyA (Record n r s) = prettyRecPar n <> align (prettyRRow r) <> prettySigil s
prettyA (Variant r) = align (prettyVRow r)
prettyA (AbsType n s []) = annotate S.absType (pretty n) <> prettySigil s
prettyA ty = parens (prettyType ty)
pretty' ty = case ty of
AbsType n s ts | not (null ts) -> annotate S.absType (pretty n) <> prettySigil s
<+> align (sep (map prettyA ts))
_ -> prettyA ty
prettyOp o | Just v <- lookup o (map (\(a,b) -> (b,a)) operators)
= annotate S.op (pretty v)
prettyExp (Sig e t) = prettyExp e <+> annotate S.sym ":" <+> prettyType t
prettyExp e = prettyBool e
prettyBool (PrimOp o [e1,e2])
| o `elem` boolOps = prettyBool e1 <+> prettyOp o <+> prettyComp e2
prettyBool e = prettyComp e
prettyComp (PrimOp o [e1,e2])
| o `elem` compOps = prettySum e1 <+> prettyOp o <+> prettySum e2
prettyComp e = prettySum e
prettySum (PrimOp o [e1,e2])
| o `elem` sumOps = prettySum e1 <+> prettyOp o <+> prettyProd e2
prettySum e = prettyProd e
prettyProd (PrimOp o [e1,e2])
| o `elem` prodOps = prettyProd e1 <+> prettyOp o <+> prettyApp e2
prettyProd e = prettyApp e
prettyApp (Apply e1 e2) = prettyApp e1 <+> prettyAtom e2
prettyApp (Con c e) = annotate S.con (pretty c) <+> prettyAtom e
prettyApp (PrimOp Not [e]) = annotate S.op "~" <+> prettyAtom e
prettyApp e = prettyAtom e
prettyAtom (Literal l) = prettyLiteral l
prettyAtom (Var v) = annotate S.var (pretty v)
prettyAtom (TypeApp f ts) = annotate S.func (pretty f) <> align (list (map prettyType ts))
prettyAtom (If e1 e2 e3)
= align (sep [ annotate S.keyword "if" <+> prettyExp e1
, annotate S.keyword "then" <+> prettyExp e2
, annotate S.keyword "else" <+> prettyExp e3
, annotate S.keyword "end" ])
prettyAtom (Let v e1 e2)
= align (sep [ annotate S.keyword "let" <+> annotate S.var (pretty v)
<+> annotate S.sym "="
<+> prettyExp e1
, annotate S.keyword "in" <+> prettyExp e2
, annotate S.keyword "end" ])
prettyAtom (LetBang vs v e1 e2)
= align (sep [ annotate S.keyword "let" <> annotate S.sigil "!"
<+> align (tupled (map (annotate S.var . pretty) vs))
<+> annotate S.var (pretty v)
<+> annotate S.sym "="
<+> prettyExp e1
, annotate S.keyword "in" <+> prettyExp e2
, annotate S.keyword "end" ])
prettyAtom (Struct fs) = align . encloseSep lbrace rbrace comma
$ map (\(f, e) -> annotate S.field (pretty f)
<+> annotate S.sym "="
<+> prettyExp e) fs
prettyAtom (Case e c v1 e1 v2 e2)
= align (sep [ annotate S.keyword "case" <+> prettyExp e <+> annotate S.keyword "of",
indent 2 (annotate S.con (pretty c) <+> annotate S.var (pretty v1)
<+> annotate S.sym "->"
<+> prettyExp e1)
, annotate S.sym "|" <+> hang 2 (annotate S.var (pretty v2 )
<+> annotate S.sym "->"
<+> prettyExp e2)
, annotate S.keyword "end"
])
prettyAtom (Esac e c v1 e1)
= align (sep [ annotate S.keyword "case" <+> prettyExp e <+> annotate S.keyword "of",
indent 2 (annotate S.con (pretty c) <+> annotate S.var (pretty v1)
<+> annotate S.sym "->"
<+> prettyExp e1)
, annotate S.keyword "end"
])
prettyAtom (Take r f v e1 e2)
= align (sep [ annotate S.keyword "take" <+> annotate S.var (pretty r)
<+> lbrace
<+> annotate S.field (pretty f)
<+> annotate S.sym "="
<+> annotate S.var (pretty v)
<+> rbrace
<+> annotate S.sym "="
<+> prettyExp e1
, annotate S.keyword "in" <+> prettyExp e2
, annotate S.keyword "end" ])
prettyAtom (Put e1 f e2 )
= align (sep [ annotate S.keyword "put" <+> prettyExp e1
<> annotate S.sym "."
<> annotate S.field (pretty f)
<+> annotate S.sym ":="
<+> prettyExp e2
, annotate S.keyword "end" ])
prettyAtom (Member e f) = prettyAtom e <> annotate S.sym "." <> annotate S.field (pretty f)
prettyAtom e = parens (prettyExp e)
prettyLiteral (BoolV b) = annotate S.literal (viaShow b)
prettyLiteral (IntV i) = annotate S.literal (viaShow i)
prettyLiteral (UnitV) = annotate S.literal "Unit"
prettyToplevel (TypeSig f t) = annotate S.func (pretty f)
<+> annotate S.sym ":"
<+> prettyPolyType t
<> annotate S.sym ";"
prettyToplevel (Equation f x t) = annotate S.func (pretty f)
<+> annotate S.var (pretty x)
<+> annotate S.sym "="
<+> prettyExp t
<> annotate S.sym ";"
prettyGlobalEnvs (GlobalEnvs defns types)
= align . vsep . map prettyToplevel
. flip concatMap (M.toList types) $
\(f,t) -> TypeSig f t : case M.lookup f defns of
Just (x,e) -> [Equation f x e]
Nothing -> []
prettySimpleConstraint c = case c of
(Share p) -> annotate S.constraintKeyword "Share" <+> prettyType p
(Drop p) -> annotate S.constraintKeyword "Drop" <+> prettyType p
(Escape p) -> annotate S.constraintKeyword "Escape" <+> prettyType p
(Exhausted p) -> annotate S.constraintKeyword "Exhausted" <+> prettyType p
(Solved p) -> annotate S.constraintKeyword "Solved" <+> prettyType p
(t1 :< t2) -> prettyType t1 <+> annotate S.constraintKeyword ":<" <+> prettyType t2
(i :<=: t) -> annotate S.literal (viaShow i)
<+> annotate S.constraintKeyword ":<=:"
<+> prettyType t
(t1 :=: t2) -> prettyType t1 <+> annotate S.constraintKeyword ":=:" <+> prettyType t2
(Sat) -> annotate S.constraintKeyword "Sat"
(Unsat) -> annotate S.constraintKeyword "Unsat"
(UnboxedNoRecurse rp s)
-> annotate S.constraintKeyword "UnboxedNoRecurse" <+> parens (prettyRecPar rp) <+> parens (prettySigil s)
_ -> error "prettySimpleConstraint called on non-simple constraint"
prettyConstraint cs = vsep (punctuate (space <> annotate S.constraintKeyword ":&:")
(map prettySimpleConstraint (flattenConstraint cs)))
prettyAssertion c = case c of
(a :<: b) -> pretty a <+> annotate S.constraintKeyword ":<:" <+> pretty b
(a :~: b) -> pretty a <+> annotate S.constraintKeyword ":~:" <+> pretty b
prettyPolyType (Forall [] [] t) = prettyType t
prettyPolyType (Forall ts c t) = align (sep [ list (map (prettyType . TypeVar) ts)
, sep (punctuate comma (map prettyConstraint c))
<> annotate S.sym "."
, prettyType t ] )
debugAssigns
= T.unpack . renderStrict
. layoutPretty defaultLayoutOptions
. vcat . map (newl . prettyAssign)
where
prettyAssign (TyAssign v t)
= parens $ annotate S.con "TyAssign" <+> annotate S.unifVar (pretty v) <+> prettyType t
prettyAssign (RowAssign v r)
= parens $ annotate S.con "RowAssign" <+> annotate S.unifVar (pretty v) <+> prettyRRow r
prettyAssign (SigilAssign v s)
= parens $ annotate S.con "SigilAssign" <+> annotate S.unifVar (pretty v) <+> prettySigil s
prettyAssign (RecParAssign v rp)
= parens $ annotate S.con "RecParAssign" <+> annotate S.unifVar (pretty v) <+> prettyRecPar rp
newl s = s <> pretty (",\n" :: String)
debugPrettyAssertions
= T.unpack . renderStrict
. layoutPretty defaultLayoutOptions
. vcat . map prettyAssertion
debugPrettyGoals
= T.unpack . renderStrict
. layoutPretty defaultLayoutOptions
. vcat . map (\x ->
case x of
Nothing -> pretty ("Nothing" :: String)
Just x' -> pretty (x' :: String)
)
debugPrettyType
= T.unpack . renderStrict
. layoutPretty defaultLayoutOptions
. prettyType
debugPrettyConstraints
= T.unpack . renderStrict
. layoutPretty defaultLayoutOptions
. vcat . map prettyConstraint
testPrettyToplevel
= T.unpack . renderStrict . unAnnotateS
. layoutPretty defaultLayoutOptions
. prettyToplevel
-- For debugging - a print/show combination that escape unicode characters.
-- Taken from https://stackoverflow.com/a/14461928
uprint :: Show a => a -> IO ()
uprint = putStrLn . ushow
ushow :: Show a => a -> String
ushow x = con (show x) where
con :: String -> String
con [] = []
con li@(x:xs) | x == '\"' = '\"':str++"\""++(con rest)
| x == '\'' = '\'':char:'\'':(con rest')
| otherwise = x:con xs where
(str,rest):_ = reads li
(char,rest'):_ = reads li