packages feed

HaGL-0.1.0.0: src/Graphics/HaGL/Print.hs

{-# OPTIONS_GHC -Wno-orphans #-}

module Graphics.HaGL.Print (printGLExpr) where

import Prelude hiding (id)
import Control.Monad.State.Lazy (State, execState, gets, modify)
import qualified Data.Set as Set

import Graphics.HaGL.GLExpr
import Graphics.HaGL.ExprID
import Graphics.HaGL.GLAst


-- GLAst printers for debugging purposes

printGLExpr :: IsGLDomain d => GLExpr d t -> String
printGLExpr = show . toGLAst

instance Show GLAst where
    show = runPrinter . printGLAst

instance Show GLDomain where
    show ConstDomain = "const"
    show HostDomain = "host"
    show VertexDomain = "vert"
    show FragmentDomain = "frag"

-- set to 0 for no limit
maxDepth = 16

data PrintState = PrintState {
    depth :: Int,
    traversedIds :: Set.Set ExprID,
    buf :: String
}

type Printer = State PrintState ()

runPrinter :: Printer -> String
runPrinter pr = buf $ execState pr 
    PrintState { depth = 0, traversedIds = Set.empty, buf = "" }

printGLAst :: GLAst -> Printer
printGLAst (GLAstAtom id ty (Const _)) =
    printNode id ty "const"
printGLAst (GLAstAtom id ty GenVar) =
    printNode id ty "genVar"
printGLAst (GLAstAtom id ty (Uniform x)) = do
    printNode id ty "uniform"
    ifNotTraversed id $
        indented $ printGLAst $ toGLAst x
printGLAst (GLAstAtom id ty (GenericUniform label)) = do
    printNode id ty ("user-def.: " ++ label)
printGLAst (GLAstAtom id ty (Inp _)) =
    printNode id ty "inp"
printGLAst (GLAstAtom id ty (Frag _ x)) = do
    printNode id ty "frag"
    ifNotTraversed id $
        indented $ printGLAst $ toGLAst x
printGLAst (GLAstAtom id ty (IOFloat _)) =
    printNode id ty "ioFloat"
printGLAst (GLAstAtom id ty (IODouble _)) =
    printNode id ty "ioDouble"
printGLAst (GLAstAtom id ty (IOInt _)) =
    printNode id ty "ioInt"
printGLAst (GLAstAtom id ty (IOUInt _)) =
    printNode id ty "ioUInt"
printGLAst (GLAstAtom id ty (IOBool _)) =
    printNode id ty "ioBool"
printGLAst (GLAstAtom id ty (IOPrec x0 x)) = do
    printNode id ty "ioPrec"
    ifNotTraversed id $ do
        indented $ printGLAst $ toGLAst x0
        indented $ printGLAst $ toGLAst x
printGLAst (GLAstAtom id ty _) =
    printNode id ty "glLift"
printGLAst (GLAstFunc id ty r params) = do
    printNode id ty "glFunc"
    ifNotTraversed id $ do
        indented $ printGLAst r
        indented $ mapM_ printGLAst params
printGLAst (GLAstFuncApp id ty fn args) = do
    printNode id ty "glFunc app"
    ifNotTraversed id $ do
        indented $ printGLAst fn
        indented $ mapM_ printGLAst args
printGLAst (GLAstExpr id ty op xs) = do
    printNode id ty op
    ifNotTraversed id $
        indented $ mapM_ printGLAst xs

printNode :: ExprID -> GLTypeInfo -> String -> Printer
printNode id ty str = do
    printLine $ str ++ " " ++ idLabel id ++ " : " ++ 
        show (shaderType ty) ++ " " ++ exprType ty

printStr :: String -> Printer
printStr s = do
    depth <- gets depth
    modify (\ps -> ps { buf = buf ps ++ replicate (2 * depth) ' ' ++ s })

printLine :: String -> Printer
printLine = printStr . (++ "\n")

indented :: Printer -> Printer
indented printer = do
    d <- gets depth
    if maxDepth > 0 && d > maxDepth then printLine "  ..." else do
        modify (\ps -> ps { depth = depth ps + 1 })
        printer
        modify (\ps -> ps { depth = depth ps - 1 })

ifNotTraversed :: ExprID -> Printer -> Printer
ifNotTraversed id printAction = do
    ids <- gets traversedIds
    if id `elem` ids then
        printLine "  ..."
    else do
        modify (\ps -> ps { traversedIds = Set.insert id (traversedIds ps) })
        printAction