packages feed

glsl-0.0.1.0: src/Language/GLSL/AST.hs

{-# LANGUAGE DeriveFunctor     #-}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StrictData        #-}
module Language.GLSL.AST where

import           Control.Applicative              (Applicative (..))
import           Data.Attoparsec.ByteString.Char8 (Parser)
import qualified Data.Text.Lazy.Builder           as LTB
import           GHC.Generics                     (Generic)


data GLSL a = GLSL Version [TopDecl a]
  deriving (Generic, Show, Eq, Functor, Foldable, Traversable)

newtype Version = Version Int
  deriving (Generic, Show, Eq)

data TopDecl a
  = LayoutDecl LayoutSpec GlobalDecl
  | GlobalDecl GlobalDecl
  | ProcDecl ProcName [ParamDecl] [StmtAnnot a]
  deriving (Generic, Show, Eq, Functor, Foldable, Traversable)

data ProcName
  = ProcMain
  | ProcName NameId
  deriving (Generic, Show, Eq)

data LayoutSpec
  = LayoutStd140
  | LayoutLocation Int
  deriving (Generic, Show, Eq)

data ParamDecl
  = Param ParamKind LocalDecl
  deriving (Generic, Show, Eq)

data ParamKind
  = PkIn
  | PkOut
  | PkInout
  deriving (Generic, Show, Eq)

data LocalDecl
  = LDecl Type NameId (Maybe Expr)
  deriving (Generic, Show, Eq)

data GlobalDecl
  = GDecl GDeclKind Type Name
  deriving (Generic, Show, Eq)

data GDeclKind
  = GkIn
  | GkOut
  | GkUniform
  deriving (Generic, Show, Eq)

data Type
  = TyBool
  | TyFloat
  | TySampler2D
  | TyVec Int
  | TyMat Int Int
  | TyStruct NameId [(Type, NameId)]
  deriving (Generic, Show, Eq)

newtype NameId = NameId Int
  deriving (Generic, Show, Eq)

data Name
  = Name Namespace NameId
  deriving (Generic, Show, Eq)

data Namespace
  = NsT
  | NsS
  | NsU
  | NsVF
  | NsIn
  | NsOut
  deriving (Generic, Show, Eq)

data FunName
  = PrimAbs
  | PrimAsin
  | PrimAtan
  | PrimCos
  | PrimCross
  | PrimDot
  | PrimFloor
  | PrimFract
  | PrimLength
  | PrimMat3x3
  | PrimMat4x4
  | PrimMod
  | PrimNormalize
  | PrimPow
  | PrimSin
  | PrimSmoothstep
  | PrimSqrt
  | PrimStep
  | PrimTan
  | PrimVec2
  | PrimVec3
  | PrimVec4
  deriving (Generic, Show, Eq)

data Swizzle
  = X | Y | Z | W
  deriving (Generic, Show, Eq)

data NameExpr
  = NameExpr Name
  | UniformExpr NameId NameId
  deriving (Generic, Show, Eq)

data Cast
  = Cast
  | NoCast
  deriving (Generic, Show, Eq)

data ExprAtom
  = LitIntExpr Cast Int
  | LitFloatExpr Cast Float
  | IdentifierExpr NameExpr
  | SwizzleExpr NameId Swizzle
  | VecIndexExpr NameExpr Swizzle
  | MatIndexExpr NameExpr Swizzle Swizzle
  deriving (Generic, Show, Eq)

data Expr
  = UnaryExpr UnaryOp ExprAtom
  | BinaryExpr ExprAtom BinaryOp ExprAtom
  | FunCallExpr FunName [ExprAtom]
  | TextureExpr ExprAtom ExprAtom ExprAtom
  | AtomExpr ExprAtom
  deriving (Generic, Show, Eq)

data BinaryOp
  = BOpPlus
  | BOpMinus
  | BOpMul
  | BOpDiv
  | BOpGE
  | BOpGT
  | BOpLE
  | BOpLT
  | BOpAnd
  | BOpOr
  deriving (Generic, Show, Eq)

data UnaryOp
  = UOpMinus
  | UOpNot
  deriving (Generic, Show, Eq)

data StmtAnnot a = SA
  { annot   :: a
  , unAnnot :: Stmt a
  }
  deriving (Generic, Show, Eq, Functor, Foldable, Traversable)

instance Applicative StmtAnnot where
  pure a = SA a (pure a)
  liftA2 f a b = SA (f (annot a) (annot b)) $ liftA2 f (unAnnot a) (unAnnot b)

data Stmt a
  = AssignStmt Name Expr
  | DeclStmt LocalDecl
  | EmitStmt Emit
  | IfStmt NameId [StmtAnnot a] [StmtAnnot a]
  deriving (Generic, Show, Eq, Functor, Foldable, Traversable)

instance Applicative Stmt where
  -- Arbitrary decision because "pure" doesn't really make sense.
  pure _ = EmitStmt EmitFragDepth

  liftA2 f (IfStmt n t1 e1) (IfStmt _ t2 e2) = IfStmt n
    ((zipWith . liftA2) f t1 t2)
    ((zipWith . liftA2) f e1 e2)
  liftA2 _ (AssignStmt n e) _ = AssignStmt n e
  liftA2 _ (DeclStmt d) _ = DeclStmt d
  liftA2 _ (EmitStmt e) _ = EmitStmt e
  liftA2 _ (IfStmt n _ _) _ = IfStmt n [] []


data Emit
  = EmitPosition Expr
  | EmitFragDepth
  deriving (Generic, Show, Eq)


class Annot a where
  parseAnnot :: Parser a
  ppAnnot :: a -> Maybe LTB.Builder

instance Annot () where
  parseAnnot = pure ()
  ppAnnot = const Nothing

instance (Annot a, Annot b) => Annot (a, b) where
  parseAnnot = error "not implemented"
  ppAnnot (a, b) = do
    ppA <- ppAnnot a
    ppB <- ppAnnot b
    return $ "(" <> ppA <> ", " <> ppB <> ")"

----------------------------------

argCountForFunName :: FunName -> Int
argCountForFunName PrimAbs        = 1
argCountForFunName PrimAsin       = 1
argCountForFunName PrimAtan       = 2
argCountForFunName PrimCos        = 1
argCountForFunName PrimCross      = 2
argCountForFunName PrimDot        = 2
argCountForFunName PrimFloor      = 1
argCountForFunName PrimFract      = 1
argCountForFunName PrimLength     = 1
argCountForFunName PrimMat3x3     = 3
argCountForFunName PrimMat4x4     = 4
argCountForFunName PrimMod        = 2
argCountForFunName PrimNormalize  = 1
argCountForFunName PrimPow        = 2
argCountForFunName PrimSin        = 1
argCountForFunName PrimSmoothstep = 3
argCountForFunName PrimSqrt       = 1
argCountForFunName PrimStep       = 2
argCountForFunName PrimTan        = 1
argCountForFunName PrimVec2       = 2
argCountForFunName PrimVec3       = 3
argCountForFunName PrimVec4       = 4

isLitExpr :: ExprAtom -> Bool
isLitExpr LitFloatExpr{} = True
isLitExpr LitIntExpr{}   = True
isLitExpr _              = False

isIdentifierExpr :: ExprAtom -> Bool
isIdentifierExpr IdentifierExpr{} = True
isIdentifierExpr _                = False