packages feed

apple-0.1.0.0: src/A.hs

{-# LANGUAGE DeriveFunctor     #-}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE FlexibleContexts  #-}
{-# LANGUAGE OverloadedStrings #-}

-- | AST
module A ( T (..)
         , (~>)
         , I (..), Sh (..)
         , C (..)
         , E (..)
         , Idiom (..)
         , Builtin (..)
         , ResVar (..)
         , prettyTyped
         , prettyC
         , rLi
         ) where

import           Control.DeepSeq   (NFData)
import qualified Data.IntMap       as IM
import           GHC.Generics      (Generic)
import           Nm
import           Prettyprinter     (Doc, Pretty (..), braces, brackets, colon, comma, encloseSep, flatAlt, group, hsep, lbrace, lbracket, parens, pipe, punctuate, rbrace, rbracket,
                                    tupled, (<+>))
import           Prettyprinter.Ext

instance Pretty (I a) where pretty=ps 0

instance PS (I a) where
    ps _ (Ix _ i)        = pretty i
    ps _ (IVar _ n)      = pretty n
    ps d (StaPlus _ i j) = parensp (d>5) (ps 6 i <+> "+" <+> ps 6 j)
    ps d (StaMul _ i j)  = parensp (d>7) (ps 8 i <+> "*" <+> ps 8 j)
    ps _ (IEVar _ n)     = "#" <> pretty n

data I a = Ix { ia :: a, ii :: !Int }
         | IVar { ia :: a, ixn :: Nm a }
         | IEVar { ia :: a , ie :: Nm a } -- existential
         | StaPlus { ia :: a, ix0, ix1 :: I a }
         | StaMul { ia :: a, ix0, ix1 :: I a }
         deriving (Functor, Generic)

instance Show (I a) where
    show = show . pretty

data C = IsNum | IsOrd -- implies eq
       | HasBits deriving (Generic, Eq, Ord)

instance NFData C where

instance Pretty C where pretty IsNum = "IsNum"; pretty IsOrd = "IsOrd"; pretty HasBits = "HasBits"

instance Show C where show=show.pretty

tupledArr = group . encloseSep (flatAlt "⟨ " "⟨") (flatAlt " ⟩" "⟩") ", "

data Sh a = Nil
          | SVar (Nm a)
          | Cons (I a) (Sh a)
          | Rev (Sh a)
          | Cat (Sh a) (Sh a)
          | Π (Sh a)
          deriving (Functor, Generic)

infixr 8 `Cons`

instance Show (Sh a) where show=show.pretty

instance Pretty (Sh a) where pretty=ps 0

unroll Nil         = Just []
unroll (Cons i sh) = (i:)<$>unroll sh
unroll _           = Nothing

instance PS (Sh a) where
    ps _ (SVar n)    = pretty n
    ps _ sh@Cons{}   | Just is <- unroll sh = tupledBy " × " (pretty <$> is)
    ps d (Cons i sh) = parensp (d>6) (pretty i <+> "`Cons`" <+> pretty sh)
    ps _ Nil         = "Nil"
    ps d (Cat s s')  = parensp (d>5) (ps 6 s <+> "⧺" <+> ps 6 s')
    ps d (Rev s)     = parensp (d>appPrec) ("rev" <+> ps (appPrec+1) s)
    ps d (Π s)       = parensp (d>appPrec) ("Π" <+> ps (appPrec+1) s)

appPrec=10

infixr 0 ~>
(~>) = Arrow

data T a = Arr (Sh a) (T a)
         | F -- | double
         | I -- | int
         | B -- | bool
         | Li (I a)
         | TVar (Nm a) -- | Kind \(*\)
         | Arrow (T a) (T a)
         | P [T a]
         | Ρ (TyNm a) (IM.IntMap (T a))
         deriving (Functor, Generic)

instance Show (T a) where show=show.pretty

instance Pretty (T a) where pretty=ps 0

instance PS (T a) where
    ps d (Arr (i `Cons` Nil) t) = parensp (d>appPrec) ("Vec" <+> ps (appPrec+1) i <+> ps (appPrec+1) t)
    ps d (Arr i t)              = parensp (d>appPrec) ("Arr" <+> ps (appPrec+1) i <+> ps (appPrec+1) t)
    ps _ F                      = "float"
    ps _ I                      = "int"
    ps _ (Li i)                 = "int" <> parens (pretty i)
    ps _ B                      = "bool"
    ps _ (TVar n)               = pretty n
    ps d (Arrow t0 t1)          = parensp (d>0) (ps 1 t0 <+> "→" <+> ps 0 t1)
    ps _ (P ts)                 = tupledBy " * " (pretty <$> ts)
    ps _ (Ρ n fs)               = braces (pretty n <+> pipe <+> prettyFields (IM.toList fs))

rLi :: T a -> T a
rLi Li{}          = I
rLi (Arrow t0 t1) = Arrow (rLi t0) (rLi t1)
rLi (Arr sh t)    = Arr sh (rLi t)
rLi (Ρ n ts)      = Ρ n (rLi <$> ts)
rLi (P ts)        = P (rLi <$> ts)
rLi t             = t

prettyFields :: [(Int, T a)] -> Doc ann
prettyFields = mconcat . punctuate "," . fmap g where g (i, t) = pretty i <> ":" <+> pretty t

prettyRank :: (Int, Maybe [Int]) -> Doc ann
prettyRank (i, Nothing) = pretty i
prettyRank (i, Just as) = pretty i <+> "∘" <+> encloseSep lbracket rbracket comma (pretty<$>as)

instance Pretty Builtin where
    pretty Plus      = "+"
    pretty Fold      = "/"
    pretty FoldS     = "/ₒ"
    pretty FoldA     = "/*"
    pretty Times     = "*"
    pretty FRange    = "𝒻"
    pretty IRange    = "⍳"
    pretty Floor     = "⌊"
    pretty Minus     = "-"
    pretty Max       = "⋉"
    pretty Min       = "⋊"
    pretty Map       = "'"
    pretty Zip       = "`"
    pretty Div       = "%"
    pretty IntExp    = "^"
    pretty Exp       = "**"
    pretty ItoF      = "ℝ"
    pretty Neg       = "_"
    pretty Sqrt      = "√"
    pretty Log       = "_."
    pretty Re        = "re:"
    pretty Size      = ":"
    pretty (Rank as) = "`" <> encloseSep lbrace rbrace comma (prettyRank<$>as)
    pretty IDiv      = "/."
    pretty Scan      = "Λ"
    pretty ScanS     = "Λₒ"
    pretty (DI i)    = "\\`" <> pretty i
    pretty (Conv ns) = "⨳" <+> encloseSep lbrace rbrace comma (pretty<$>ns)
    pretty (TAt i)   = parens ("->" <> pretty i)
    pretty Gen       = "gen."
    pretty Last      = "}."
    pretty LastM     = "}.?"
    pretty Head      = "{."
    pretty HeadM     = "{.?"
    pretty Tail      = "{:"
    pretty Init      = "}:"
    pretty ConsE     = "⊲"
    pretty Snoc      = "⊳"
    pretty Mul       = "%."
    pretty VMul      = "%:"
    pretty Iter      = "^:"
    pretty Succ      = "\\~"
    pretty T         = "|:"
    pretty Fib       = "𝓕"
    pretty Dim       = "𝓉"
    pretty Sin       = "sin."
    pretty Cos       = "cos."
    pretty Tan       = "tan."
    pretty Gte       = "≥"
    pretty Gt        = ">"
    pretty Lt        = "<"
    pretty Eq        = "="
    pretty Neq       = "≠"
    pretty Lte       = "≤"
    pretty CatE      = "⧺"
    pretty R         = "𝔯"
    pretty Rot       = "⊖"
    pretty Cyc       = "⊙"
    pretty A1        = "˙"
    pretty Even      = "even."
    pretty Odd       = "odd."
    pretty Mod       = "mod"
    pretty IOf       = "@."
    pretty Filt      = "§"
    pretty Abs       = "abs."
    pretty Di        = "di."
    pretty RevE      = "~"
    pretty Flat      = "♭"
    pretty AddDim    = "♮"
    pretty Xor       = "⊻"
    pretty And       = "∧"
    pretty Or        = "∨"
    pretty N         = "¬"
    pretty Ices      = "℘"
    pretty Eye       = "👁️"
    pretty Sr        = ">>"
    pretty Sl        = "<<"

data Builtin = Plus | Minus | Times | Div | IntExp | Exp | Log
             | Eq | Neq | Gt | Lt | Gte | Lte | CatE | IDiv | Mod
             | Max | Min | Neg | Sqrt | T | Di
             | Flat | AddDim | Ices | Filt | Eye
             | IRange | FRange
             | Map | FoldA | Zip
             | Rank [(Int, Maybe [Int])]
             | Fold | FoldS | Foldl | Floor | ItoF | Iter
             | Scan | ScanS | Size | Dim | Re | Gen | Fib | Succ
             | DI !Int -- dyadic infix
             | Conv [Int] | TAt !Int | Last | LastM | ConsE | Snoc
             | Mul | VMul | Outer | R | Head | HeadM | Tail | Init | RevE
             | Sin | Cos | Rot | Tan | Cyc | A1 | Even | Odd | IOf | Abs
             | And | Or | Xor | N | Sr | Sl
             deriving (Generic)
             -- TODO: window (feuilleter, stagger, ...) functions, reshape...?

ptName :: Nm (T a) -> Doc ann
ptName n@(Nm _ _ t) = parens (pretty n <+> ":" <+> pretty t)

prettyC :: (T (), [(Nm a, C)]) -> Doc ann
prettyC (t, []) = pretty t
prettyC (t, cs) = tupled (pc<$>cs) <+> ":=>" <+> pretty t
    where pc (n, c) = pretty c <+> pretty n

-- TODO: constraints
prettyTyped :: E (T a) -> Doc ann
prettyTyped (Var t n)                                             = parens (pretty n <+> ":" <+> pretty t)
prettyTyped (Builtin t b)                                         = parens (pretty b <+> ":" <+> pretty t)
prettyTyped (ILit t n)                                            = parens (pretty n <+> ":" <+> pretty t)
prettyTyped (FLit t x)                                            = parens (pretty x <+> ":" <+> pretty t)
prettyTyped (BLit t True)                                         = parens ("#t" <+> colon <+> pretty t)
prettyTyped (BLit t False)                                        = parens ("#f" <+> colon <+> pretty t)
prettyTyped (Cond t p e0 e1)                                      = parens ("?" <+> prettyTyped p <+> ",." <+> prettyTyped e0 <+> prettyTyped e1) <+> colon <+> pretty t
prettyTyped (Lam _ n@(Nm _ _ xt) e)                               = parens ("λ" <> parens (pretty n <+> ":" <+> pretty xt) <> "." <+> prettyTyped e)
prettyTyped (EApp _ (EApp _ (EApp _ (Builtin _ FoldS) e0) e1) e2) = parens (prettyTyped e0 <> "/ₒ" <+> prettyTyped e1 <+> prettyTyped e2)
prettyTyped (EApp _ (EApp _ (EApp _ (Builtin _ FoldA) e0) e1) e2) = parens (prettyTyped e0 <> "/*" <+> prettyTyped e1 <+> prettyTyped e2)
prettyTyped (EApp _ (EApp _ (EApp _ (Builtin _ Foldl) e0) e1) e2) = parens (prettyTyped e0 <> "/l" <+> prettyTyped e1 <+> prettyTyped e2)
prettyTyped (EApp t (EApp _ (EApp _ (Builtin _ Outer) e0) e1) e2) = parens (prettyTyped e1 <+> pretty e0 <> "⊗" <+> prettyTyped e2 <+> ":" <+> pretty t)
prettyTyped (EApp _ e0@(Builtin _ op) e1) | isBinOp op            = parens (prettyTyped e1 <+> prettyTyped e0)
prettyTyped (EApp _ e0 e1)                                        = parens (prettyTyped e0 <+> prettyTyped e1)
prettyTyped (Let t (n, e) e')                                     = parens (braces (ptName n <+> "←" <+> prettyTyped e <> ";" <+> prettyTyped e') <+> pretty t)
prettyTyped (LLet t (n, e) e')                                    = parens (braces (ptName n <+> "⟜" <+> prettyTyped e <> ";" <+> prettyTyped e') <+> pretty t)
prettyTyped (Def t (n, e) e')                                     = parens (braces (ptName n <+> "⇐" <+> prettyTyped e <> ";" <+> prettyTyped e') <+> pretty t)
prettyTyped (Tup _ es)                                            = tupled (prettyTyped <$> es)
prettyTyped e@(ALit t _)                                          = parens (pretty e <+> ":" <+> pretty t)

mPrec :: Builtin -> Maybe Int
mPrec Plus   = Just 6
mPrec Minus  = Just 6
mPrec Times  = Just 7
mPrec Div    = Just 7
mPrec IDiv   = Just 7
mPrec Exp    = Just 8
mPrec IntExp = Just 8
mPrec Mod    = Just 7
mPrec Succ   = Just 9
mPrec Fold   = Just 9
mPrec Map    = Just 5
mPrec ConsE  = Just 4
mPrec Snoc   = Just 4
mPrec CatE   = Just 5
mPrec Sr     = Just 8
mPrec Sl     = Just 8
mPrec Xor    = Just 6
mPrec And    = Just 3
mPrec Or     = Just 2
mPrec Eq     = Just 4
mPrec Neq    = Just 4
mPrec Gt     = Just 4
mPrec Lt     = Just 4
mPrec Gte    = Just 4
mPrec Lte    = Just 4
mPrec _      = Nothing

isBinOp :: Builtin -> Bool
isBinOp Plus   = True
isBinOp Minus  = True
isBinOp Times  = True
isBinOp Div    = True
isBinOp IDiv   = True
isBinOp Exp    = True
isBinOp IntExp = True
isBinOp DI{}   = True
isBinOp Conv{} = True
isBinOp Mul    = True
isBinOp VMul   = True
isBinOp Rot    = True
isBinOp ConsE  = True
isBinOp Snoc   = True
isBinOp Scan   = True
isBinOp Fold   = True
isBinOp Map    = True
isBinOp Cyc    = True
isBinOp A1     = True
isBinOp Mod    = True
isBinOp IOf    = True
isBinOp And    = True
isBinOp Or     = True
isBinOp Xor    = True
isBinOp Filt   = True
isBinOp Ices   = True
isBinOp Sr     = True
isBinOp Sl     = True
isBinOp _      = False

instance Pretty (E a) where pretty=ps 0

instance PS (E a) where
    ps d (Lam _ n e)                                              = parensp (d>1) ("λ" <> pretty n <> "." <+> ps 2 e)
    ps _ (Var _ n)                                                = pretty n
    ps _ (Builtin _ op) | isBinOp op                              = parens (pretty op)
    ps _ (Builtin _ b)                                            = pretty b
    ps d (EApp _ (Builtin _ (TAt i)) e)                           = parensp (d>9) (ps 10 e <> "->" <> pretty i)
    ps _ (EApp _ (Builtin _ op) e0) | isBinOp op                  = parens (pretty e0 <+> pretty op)
    ps d (EApp _ (EApp _ (Builtin _ op) e0) e1) | Just d' <- mPrec op = parensp (d>d') (ps (d'+1) e0 <+> pretty op <+> ps (d'+1) e1)
    ps _ (EApp _ (EApp _ (Builtin _ op) e0) e1) | isBinOp op      = parens (ps 10 e0 <+> pretty op <+> ps 10 e1)
    ps _ (EApp _ (EApp _ (EApp _ (Builtin _ Iter) e0) e1) e2)     = parens (ps 10 e0 <> "^:" <+> ps 10 e1 <+> ps 11 e2)
    ps _ (EApp _ (EApp _ (EApp _ (Builtin _ FoldS) e0) e1) e2)    = parens (pretty e0 <> "/ₒ" <+> pretty e1 <+> pretty e2)
    ps _ (EApp _ (EApp _ (EApp _ (Builtin _ Foldl) e0) e1) e2)    = parens (pretty e0 <> "/l" <+> pretty e1 <+> pretty e2)
    ps _ (EApp _ (EApp _ (EApp _ (Builtin _ FoldA) e0) e1) e2)    = parens (pretty e0 <> "/*" <+> pretty e1 <+> pretty e2)
    ps _ (EApp _ (EApp _ (EApp _ (Builtin _ ScanS) e0) e1) e2)    = parens (pretty e0 <+> "Λₒ" <+> pretty e1 <+> pretty e2)
    ps _ (EApp _ (EApp _ (EApp _ (Builtin _ Zip) e0) e1) e2)      = parens (pretty e0 <+> "`" <+> pretty e1 <+> pretty e2)
    ps _ (EApp _ (EApp _ (EApp _ (Builtin _ Outer) e0) e1) e2)    = parens (pretty e1 <+> ps 10 e0 <+> "⊗" <+> pretty e2)
    ps _ (EApp _ (EApp _ (Builtin _ op@Rank{}) e0) e1)            = parens (pretty e0 <+> pretty op <+> pretty e1)
    ps _ (EApp _ (EApp _ (Builtin _ op@Conv{}) e0) e1)            = parens (pretty e0 <+> pretty op <+> pretty e1)
    ps _ (EApp _ (EApp _ (Builtin _ (DI i)) e0) e1)               = parens (pretty e0 <+> "\\`" <> pretty i <+> pretty e1)
    ps _ (EApp _ (EApp _ (Builtin _ Succ) e0) e1)                 = parens (pretty e0 <+> "\\~" <+> pretty e1)
    ps d (EApp _ e0 e1)                                           = parensp (d>10) (ps 10 e0 <+> ps 11 e1)
    ps _ (FLit _ x)                                               = pretty x
    ps _ (ILit _ n)                                               = pretty n
    ps _ (BLit _ True)                                            = "#t"
    ps _ (BLit _ False)                                           = "#f"
    ps _ (Dfn _ e)                                                = brackets (pretty e)
    ps _ (ResVar _ x)                                             = pretty x
    ps _ (Parens _ e)                                             = parens (pretty e)
    ps _ (Let _ (n, e) e')                                        = braces (pretty n <+> "←" <+> pretty e <> ";" <+> pretty e')
    ps _ (Def _ (n, e) e')                                        = braces (pretty n <+> "⇐" <+> pretty e <> ";" <+> pretty e')
    ps _ (LLet _ (n, e) e')                                       = braces (pretty n <+> "⟜" <+> pretty e <> ";" <+> pretty e')
    ps _ (Id _ idm)                                               = pretty idm
    ps _ (Tup _ es)                                               = tupled (pretty <$> es)
    ps _ (ALit _ es)                                              = tupledArr (pretty <$> es)
    ps d (Ann _ e t)                                              = parensp (d>1) (ps 2 e <+> "::" <+> ps 1 t)
    ps d (Cond _ p e₀ e₁)                                         = "?" <> pretty p <> ",." <+> ps d e₀ <+> ",." <+> ps d e₁

instance Show (E a) where show=show.pretty

data ResVar = X | Y deriving (Generic)

instance Pretty ResVar where
    pretty X = "x"; pretty Y = "y"

data Idiom = FoldSOfZip { seedI, opI :: E (T ()), esI :: [E (T ())] }
           | FoldOfZip { zopI, opI :: E (T ()), esI :: [E (T ())] }
           | FoldGen { seedG, ufG, fG, nG :: E (T ()) }
           | AShLit { litSh :: [Int], esLit :: [E (T ())] }
           deriving (Generic)

instance Pretty Idiom where
    pretty (FoldSOfZip seed op es) = parens ("foldS-of-zip" <+> pretty seed <+> pretty op <+> pretty es)
    pretty (FoldOfZip zop op es)   = parens ("fold-of-zip" <+> pretty zop <+> pretty op <+> pretty es)
    pretty (FoldGen seed g f n)    = parens ("fold-gen" <+> brackets (pretty seed) <+> parens (pretty g) <+> parens (pretty f) <+> parens (pretty n))
    pretty (AShLit re es)          = parens ("re" <+> hsep (pretty <$> re) <+> "|" <+> pretty es)

instance Show Idiom where show=show.pretty

data E a = ALit { eAnn :: a, arrLit :: [E a] } -- TODO: include shape?
         -- TODO: bool array
         | Var { eAnn :: a, eVar :: Nm a }
         | Builtin { eAnn :: a, eBuiltin :: !Builtin }
         | EApp { eAnn :: a, eF, eArg :: E a }
         | Lam { eAnn :: a, eVar :: Nm a, eIn :: E a }
         | ILit { eAnn :: a, eILit :: !Integer }
         | FLit { eAnn :: a, eFLit :: !Double }
         | BLit { eAnn :: a, eBLit :: !Bool }
         | Cond { eAnn :: a, prop, ifBranch, elseBranch :: E a }
         | Let { eAnn :: a, eBnd :: (Nm a, E a), eIn :: E a }
         | Def { eAnn :: a, eBnd :: (Nm a, E a), eIn :: E a }
         | LLet { eAnn :: a, eBnd :: (Nm a, E a), eIn :: E a }
         | Dfn { eAnn :: a, eIn :: E a }
         | ResVar { eAnn :: a, eXY :: ResVar }
         | Parens { eAnn :: a, eExp :: E a }
         | Ann { eAnn :: a, eEe :: E a, eTy :: T a }
         | Tup { eAnn :: a, eEs :: [E a] }
         | Id { eAnn :: a, eIdiom :: Idiom }
         deriving (Functor, Generic)

instance NFData Builtin where
instance NFData ResVar where
instance NFData Idiom where
instance NFData a => NFData (E a) where
instance NFData a => NFData (I a) where
instance NFData a => NFData (Sh a) where
instance NFData a => NFData (T a) where