glsl-0.0.1.0: src/Language/GLSL/PrettyPrint.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StrictData #-}
module Language.GLSL.PrettyPrint where
import Data.List (intersperse)
import qualified Data.Text.Lazy as LT
import qualified Data.Text.Lazy.Builder as LTB
import qualified Data.Text.Lazy.Builder.Int as LTB
import qualified Data.Text.Lazy.Builder.RealFloat as LTB
import Language.GLSL.AST
printShader :: Annot a => GLSL a -> LT.Text
printShader = LTB.toLazyText . ppGLSL
-- | Pretty-print GLSL
ppGLSL :: Annot a => GLSL a -> LTB.Builder
ppGLSL (GLSL v decls) =
ppVersion v
<> "\n" <> ppL ppTopDecl decls
-- | Pretty-print Version
ppVersion :: Version -> LTB.Builder
ppVersion (Version v) = "#version " <> ppInt v
-- | Pretty-print TopDecl
ppTopDecl :: Annot a => TopDecl a -> LTB.Builder
ppTopDecl (LayoutDecl e d) = "layout(" <> ppLayoutSpec e <> ") " <> ppGlobalDecl d
ppTopDecl (GlobalDecl d) = ppGlobalDecl d
ppTopDecl (ProcDecl n a b) =
"void " <> ppProcName n
<> "(" <> ppS "," ppParamDecl a <> ") {\n"
<> ppL ppStmtAnnot b
<> "}\n"
-- | Pretty-print ProcName
ppProcName :: ProcName -> LTB.Builder
ppProcName ProcMain = "main"
ppProcName (ProcName n) = "p" <> ppNameId n
-- | Pretty-print LayoutSpec
ppLayoutSpec :: LayoutSpec -> LTB.Builder
ppLayoutSpec LayoutStd140 = "std140"
ppLayoutSpec (LayoutLocation l) = "location = " <> ppInt l
-- | Pretty-print ParamDecl
ppParamDecl :: ParamDecl -> LTB.Builder
ppParamDecl (Param k d) =
ppParamKind k <> " " <> ppLocalDecl d
-- | Pretty-print ParamKind
ppParamKind :: ParamKind -> LTB.Builder
ppParamKind PkIn = "in"
ppParamKind PkOut = "out"
ppParamKind PkInout = "inout"
-- | Pretty-print LocalDecl
ppLocalDecl :: LocalDecl -> LTB.Builder
ppLocalDecl (LDecl t n Nothing) =
ppType t
<> " t" <> ppNameId n <> ";\n"
ppLocalDecl (LDecl t n (Just e)) =
ppType t
<> " t" <> ppNameId n
<> " = " <> ppExpr e <> ";\n"
-- | Pretty-print GlobalDecl
ppGlobalDecl :: GlobalDecl -> LTB.Builder
ppGlobalDecl (GDecl k t n) =
ppGDeclKind k
<> " " <> ppType t
<> " " <> ppName n <> ";\n"
-- | Pretty-print GDeclKind
ppGDeclKind :: GDeclKind -> LTB.Builder
ppGDeclKind GkIn = "in"
ppGDeclKind GkOut = "out"
ppGDeclKind GkUniform = "uniform"
-- | Pretty-print Type
ppType :: Type -> LTB.Builder
ppType TyBool = "bool"
ppType TyFloat = "float"
ppType TySampler2D = "sampler2D"
ppType (TyVec n) = "vec" <> ppInt n
ppType (TyMat n m) = "mat" <> ppInt n <> "x" <> ppInt m
ppType (TyStruct n ms) =
"uBlock" <> ppNameId n
<> " {\n" <> ppL ppStructMember ms <> "}"
where ppStructMember (t, m) = ppType t <> " u" <> ppNameId m <> ";\n"
-- | Pretty-print NameId
ppNameId :: NameId -> LTB.Builder
ppNameId (NameId n) = ppInt n
-- | Pretty-print Name
ppName :: Name -> LTB.Builder
ppName (Name ns n) = ppNamespace ns <> ppNameId n
-- | Pretty-print Namespace
ppNamespace :: Namespace -> LTB.Builder
ppNamespace NsT = "t"
ppNamespace NsS = "s"
ppNamespace NsU = "u"
ppNamespace NsVF = "vf"
ppNamespace NsIn = "in"
ppNamespace NsOut = "out"
-- | Pretty-print FunName
ppFunName :: FunName -> LTB.Builder
ppFunName PrimAbs = "abs"
ppFunName PrimAsin = "asin"
ppFunName PrimAtan = "atan"
ppFunName PrimCos = "cos"
ppFunName PrimCross = "cross"
ppFunName PrimDot = "dot"
ppFunName PrimFloor = "floor"
ppFunName PrimFract = "fract"
ppFunName PrimLength = "length"
ppFunName PrimMat3x3 = "mat3x3"
ppFunName PrimMat4x4 = "mat4x4"
ppFunName PrimMod = "mod"
ppFunName PrimNormalize = "normalize"
ppFunName PrimPow = "pow"
ppFunName PrimSin = "sin"
ppFunName PrimSmoothstep = "smoothstep"
ppFunName PrimSqrt = "sqrt"
ppFunName PrimStep = "step"
ppFunName PrimTan = "tan"
ppFunName PrimVec2 = "vec2"
ppFunName PrimVec3 = "vec3"
ppFunName PrimVec4 = "vec4"
-- | Pretty-print Swizzle
ppSwizzle :: Swizzle -> LTB.Builder
ppSwizzle X = "x"
ppSwizzle Y = "y"
ppSwizzle Z = "z"
ppSwizzle W = "w"
-- | Pretty-print VecIndex (Swizzle)
ppVecIndex :: Swizzle -> LTB.Builder
ppVecIndex X = "0"
ppVecIndex Y = "1"
ppVecIndex Z = "2"
ppVecIndex W = "3"
-- | Pretty-print NameExpr
ppNameExpr :: NameExpr -> LTB.Builder
ppNameExpr (NameExpr n) = ppName n
ppNameExpr (UniformExpr n m) = "u" <> ppNameId n <> ".u" <> ppNameId m
-- | Pretty-print ExprAtom
ppExprAtom :: ExprAtom -> LTB.Builder
ppExprAtom (LitIntExpr Cast i) = "int(" <> ppInt i <> ")"
ppExprAtom (LitIntExpr NoCast i) = ppInt i
ppExprAtom (LitFloatExpr Cast n) = "float(" <> ppFloat n <> ")"
ppExprAtom (LitFloatExpr NoCast r) = ppFloat r
ppExprAtom (IdentifierExpr n) = ppNameExpr n
ppExprAtom (SwizzleExpr n m) = "t" <> ppNameId n <> "." <> ppSwizzle m
ppExprAtom (VecIndexExpr n i) = ppNameExpr n <> "[" <> ppVecIndex i <> "]"
ppExprAtom (MatIndexExpr n i j) = ppNameExpr n <> "[" <> ppVecIndex i <> "]" <> "[" <> ppVecIndex j <> "]"
-- | Pretty-print Expr
ppExpr :: Expr -> LTB.Builder
ppExpr (AtomExpr e) = ppExprAtom e
ppExpr (UnaryExpr o e) = "(" <> ppUnaryOp o <> ppExprAtom e <> ")"
ppExpr (BinaryExpr l o r) = "(" <> ppExprAtom l <> ppBinaryOp o <> ppExprAtom r <> ")"
ppExpr (FunCallExpr n args) = ppFunName n <> "(" <> ppS "," ppExprAtom args <> ")"
ppExpr (TextureExpr t x y) = "texture(" <> ppExprAtom t <> ",vec2(" <> ppExprAtom x <> "," <> ppExprAtom y <> "))"
-- | Pretty-print BinaryOp
ppBinaryOp :: BinaryOp -> LTB.Builder
ppBinaryOp BOpPlus = "+"
ppBinaryOp BOpMinus = "-"
ppBinaryOp BOpMul = "*"
ppBinaryOp BOpDiv = "/"
ppBinaryOp BOpGE = ">="
ppBinaryOp BOpGT = ">"
ppBinaryOp BOpLE = "<="
ppBinaryOp BOpLT = "<"
ppBinaryOp BOpAnd = "&&"
ppBinaryOp BOpOr = "||"
-- | Pretty-print UnaryOp
ppUnaryOp :: UnaryOp -> LTB.Builder
ppUnaryOp UOpMinus = "-"
ppUnaryOp UOpNot = "!"
-- | Pretty-print StmtAnnot
ppStmtAnnot :: Annot a => StmtAnnot a -> LTB.Builder
ppStmtAnnot (SA a s) =
maybe "" (\ltb -> "// " <> ltb <> "\n") (ppAnnot a) <> ppStmt s
-- | Pretty-print Stmt
ppStmt :: Annot a => Stmt a -> LTB.Builder
ppStmt (AssignStmt n e) = ppName n <> " = " <> ppExpr e <> ";\n"
ppStmt (DeclStmt d) = ppLocalDecl d
ppStmt (EmitStmt e) = ppEmit e
ppStmt (IfStmt c t e) =
"if(t" <> ppNameId c <> "){\n"
<> ppL ppStmtAnnot t
<> "} else {\n"
<> ppL ppStmtAnnot e
<> "}\n"
-- | Pretty-print Emit
ppEmit :: Emit -> LTB.Builder
ppEmit (EmitPosition e) = "gl_Position = " <> ppExpr e <> ";\n"
ppEmit EmitFragDepth = "gl_FragDepth = gl_FragCoord[2];\n"
-- | Pretty-printing utility
ppInt :: Int -> LTB.Builder
ppInt = LTB.decimal
ppFloat :: Float -> LTB.Builder
ppFloat = LTB.realFloat
ppL :: (a -> LTB.Builder) -> [a] -> LTB.Builder
ppL printer = mconcat . map printer
ppS :: LTB.Builder -> (a -> LTB.Builder) -> [a] -> LTB.Builder
ppS sep printer = mconcat . intersperse sep . map printer
----------------------------------
-- Pretty-printing to String
pp :: (a -> LTB.Builder) -> a -> String
pp printer = LT.unpack . LTB.toLazyText . printer
ppl :: (a -> LTB.Builder) -> [a] -> String
ppl printer = LT.unpack . LTB.toLazyText . ppL printer
pps :: LTB.Builder -> (a -> LTB.Builder) -> [a] -> String
pps sep printer = LT.unpack . LTB.toLazyText . ppS sep printer