flaw-graphics/Flaw/Graphics/Program/Internal.hs

Summary

Maintainability
Test Coverage
{-|
Module: Flaw.Graphics.Program.Internal
Description: Internals for shader program support.
License: MIT
-}

{-# LANGUAGE DeriveGeneric, GADTs, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, RankNTypes, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TypeFamilies, UndecidableInstances #-}

module Flaw.Graphics.Program.Internal
  ( ScalarType(..)
  , Dimension(..)
  , ValueType(..)
  , valueTypeScalarsCount
  , OfScalarType(..)
  , OfVectorType
  , OfValueType(..)
  , OfAttributeType(..)
  , AttributeFormat(..)
  , AttributeType(..)
  , Normalization(..)
  , State(..)
  , Attribute(..)
  , Uniform(..)
  , Sampler(..)
  , SamplerDimension(..)
  , Target(..)
  , Stage(..)
  , Temp(..)
  , Node(..)
  , SamplerNode(..)
  , SampleNodeLod(..)
  , nodeValueType
  , nodeArrayValueType
  , Program
  , runProgram
  ) where

import Control.Monad
import Control.Monad.Reader
import Data.Char
import Data.Int
import Data.Word
import Data.IORef
import qualified Data.Serialize as S
import GHC.Generics(Generic)
import Language.Haskell.TH

import Flaw.Math
import Flaw.Math.Internal

-- | Supported scalar types in programs.
data ScalarType
  = ScalarFloat
  | ScalarDouble
  | ScalarInt
  | ScalarUint
  | ScalarBool
  deriving (Eq, Ord, Show, Generic)
instance S.Serialize ScalarType

-- | Supported dimensions in programs.
data Dimension
  = Dimension1
  | Dimension2
  | Dimension3
  | Dimension4
  deriving (Eq, Ord, Show, Generic)
instance S.Serialize Dimension

-- | Supported types in programs.
data ValueType
  = ScalarValueType !ScalarType
  | VectorValueType !Dimension !ScalarType
  | MatrixValueType !Dimension !Dimension !ScalarType
  deriving (Eq, Ord, Show, Generic)
instance S.Serialize ValueType

-- | Number of scalars in type.
valueTypeScalarsCount :: ValueType -> Int
valueTypeScalarsCount vt = case vt of
  ScalarValueType _ -> 1
  VectorValueType d _ -> dim d
  MatrixValueType d1 d2 _ -> dim d1 * dim d2
  where
    dim d = case d of
      Dimension1 -> 1
      Dimension2 -> 2
      Dimension3 -> 3
      Dimension4 -> 4

-- | Class of scalar types which can be used in program.
class OfValueType a => OfScalarType a where
  -- | Get program scalar type.
  -- Argument is not used.
  scalarType :: a -> ScalarType

instance OfScalarType Float where
  scalarType _ = ScalarFloat
instance OfScalarType Double where
  scalarType _ = ScalarDouble
instance OfScalarType Int32 where
  scalarType _ = ScalarInt
instance OfScalarType Word32 where
  scalarType _ = ScalarUint
instance OfScalarType Bool where
  scalarType _ = ScalarBool

-- | Class of types which can be used in program.
class Show a => OfValueType a where
  valueType :: a -> ValueType
  valueToShowList :: a -> [String]
  valueToShowList v = [show v]

instance OfValueType Float where
  valueType _ = ScalarValueType ScalarFloat
instance OfValueType Double where
  valueType _ = ScalarValueType ScalarDouble
instance OfValueType Int32 where
  valueType _ = ScalarValueType ScalarInt
instance OfValueType Word32 where
  valueType _ = ScalarValueType ScalarUint
instance OfValueType Bool where
  valueType _ = ScalarValueType ScalarBool

-- instance (OfScalarType a, Vectorized a) => OfValueType (Vec{1..4} a)
fmap concat $ forM [1..maxVecDimension] $ \c -> do
  let name = mkName $ "Vec" ++ [intToDigit c]
  let t = conT name
  let d = conE $ mkName $ "Dimension" ++ [intToDigit c]
  ps <- forM [1..c] $ \p -> newName ['p', intToDigit p]
  [d|
    instance (OfScalarType a, Vectorized a) => OfValueType ($t a) where
      valueType _ = VectorValueType $d $ scalarType (undefined :: a)
      valueToShowList $(conP name $ map varP ps) = $(listE $ map (\p -> appE (varE 'show) $ varE p) ps)
    |]

-- instance (OfScalarType a, Vectorized a) => OfValueType (Mat{1..4}x{1..4} a)
fmap concat $ forM matDimensions $ \(ci, cj) -> do
  let name = mkName $ "Mat" ++ [intToDigit ci, 'x', intToDigit cj]
  let t = conT name
  let di = conE $ mkName $ "Dimension" ++ [intToDigit ci]
  let dj = conE $ mkName $ "Dimension" ++ [intToDigit cj]
  ps <- forM [(intToDigit i, intToDigit j) | i <- [1..ci], j <- [1..cj]] $ \(i, j) -> newName ['p', i, j]
  [d|
    instance (OfScalarType a, Vectorized a) => OfValueType ($t a) where
      valueType _ = MatrixValueType $di $dj $ scalarType (undefined :: a)
      valueToShowList $(conP name $ map varP ps) = $(listE $ map (\p -> appE (varE 'show) $ varE p) ps)
    |]

-- | Class of vector types which can be used in program.
class (OfValueType a, Vec a, OfScalarType (VecElement a)) => OfVectorType a

instance (OfScalarType a, Vectorized a) => OfVectorType (Vec1 a)
instance (OfScalarType a, Vectorized a) => OfVectorType (Vec2 a)
instance (OfScalarType a, Vectorized a) => OfVectorType (Vec3 a)
instance (OfScalarType a, Vectorized a) => OfVectorType (Vec4 a)

-- | Class of types which can be used in vertex attribute.
class OfValueType a => OfAttributeType a where
  -- | Typed attibute format.
  data AttributeFormat a :: *
  attributeFormatToType :: AttributeFormat a -> AttributeType

-- | Attribute format ids.
data AttributeType
  = ATFloat32
  | ATFloat16
  | ATInt32 !Normalization
  | ATInt16 !Normalization
  | ATInt8 !Normalization
  | ATUint32 !Normalization
  | ATUint16 !Normalization
  | ATUint8 !Normalization
  | ATVec1 !AttributeType
  | ATVec2 !AttributeType
  | ATVec3 !AttributeType
  | ATVec4 !AttributeType
  | ATMat1x1 !AttributeType
  | ATMat1x2 !AttributeType
  | ATMat1x3 !AttributeType
  | ATMat1x4 !AttributeType
  | ATMat2x1 !AttributeType
  | ATMat2x2 !AttributeType
  | ATMat2x3 !AttributeType
  | ATMat2x4 !AttributeType
  | ATMat3x1 !AttributeType
  | ATMat3x2 !AttributeType
  | ATMat3x3 !AttributeType
  | ATMat3x4 !AttributeType
  | ATMat4x1 !AttributeType
  | ATMat4x2 !AttributeType
  | ATMat4x3 !AttributeType
  | ATMat4x4 !AttributeType
  deriving (Eq, Ord, Show, Generic)
instance S.Serialize AttributeType

-- | Normalization mode.
data Normalization
  = NonNormalized
  | Normalized
  deriving (Eq, Ord, Show, Generic)
instance S.Serialize Normalization

instance OfAttributeType Float where
  data AttributeFormat Float
    = AttributeFloat32
    | AttributeFloat16
    | AttributeFloatInt32 !Normalization
    | AttributeFloatInt16 !Normalization
    | AttributeFloatInt8 !Normalization
    | AttributeFloatUint32 !Normalization
    | AttributeFloatUint16 !Normalization
    | AttributeFloatUint8 !Normalization
  attributeFormatToType f = case f of
    AttributeFloat32 -> ATFloat32
    AttributeFloat16 -> ATFloat16
    AttributeFloatInt32 n -> ATInt32 n
    AttributeFloatInt16 n -> ATInt16 n
    AttributeFloatInt8 n -> ATInt8 n
    AttributeFloatUint32 n -> ATUint32 n
    AttributeFloatUint16 n -> ATUint16 n
    AttributeFloatUint8 n -> ATUint8 n

instance OfAttributeType Int32 where
  data AttributeFormat Int32
    = AttributeInt32
    | AttributeInt16
    | AttributeInt8
  attributeFormatToType f = case f of
    AttributeInt32 -> ATInt32 NonNormalized
    AttributeInt16 -> ATInt16 NonNormalized
    AttributeInt8 -> ATInt8 NonNormalized

instance OfAttributeType Word32 where
  data AttributeFormat Word32
    = AttributeUint32
    | AttributeUint16
    | AttributeUint8
  attributeFormatToType f = case f of
    AttributeUint32 -> ATUint32 NonNormalized
    AttributeUint16 -> ATUint16 NonNormalized
    AttributeUint8 -> ATUint8 NonNormalized

-- instance (OfScalarType a, Vectorized a, OfAttributeType a) => OfAttributeType (Vec{1..4} a)
forM ['1'..'4'] $ \c -> do
  let v = mkName $ "Vec" ++ [c]
  a <- newName "a"
  let conName = mkName $ "AttributeVec" ++ [c]
  b <- newName "b"
  instanceD (sequence [ [t| OfScalarType $(varT a) |], [t| Vectorized $(varT a) |], [t| OfAttributeType $(varT a) |] ]) (appT (conT ''OfAttributeType) $ appT (conT v) $ varT a)
    [ newtypeInstD (return []) ''AttributeFormat [appT (conT v) $ varT a] Nothing (normalC conName [return (Bang NoSourceUnpackedness NoSourceStrictness, AppT (ConT ''AttributeFormat) $ VarT a)]) []
    , funD 'attributeFormatToType [clause [conP conName [varP b]] (normalB [| $(conE $ mkName $ "ATVec" ++ [c]) (attributeFormatToType $(varE b)) |]) []]
    ]

-- instance (OfScalarType a, Vectorized a, OfAttributeType a) => OfAttributeType (Mat{1..4}x{1..4} a)
forM matDimensions $ \(ci, cj) -> do
  let v = mkName $ "Mat" ++ [intToDigit ci, 'x', intToDigit cj]
  a <- newName "a"
  let conName = mkName $ "AttributeMat" ++ [intToDigit ci, 'x', intToDigit cj]
  b <- newName "b"
  instanceD (sequence [ [t| OfScalarType $(varT a) |], [t| Vectorized $(varT a) |], [t| OfAttributeType $(varT a) |] ]) (appT (conT ''OfAttributeType) $ appT (conT v) $ varT a)
    [ newtypeInstD (return []) ''AttributeFormat [appT (conT v) $ varT a] Nothing (normalC conName [return (Bang NoSourceUnpackedness NoSourceStrictness, AppT (ConT ''AttributeFormat) $ VarT a)]) []
    , funD 'attributeFormatToType [clause [conP conName [varP b]] (normalB [| $(conE $ mkName $ "ATMat" ++ [intToDigit ci, 'x', intToDigit cj]) (attributeFormatToType $(varE b)) |]) []]
    ]

-- | State of the program while constructing.
data State = State
  { stateStage :: !Stage
  , stateTemps :: [Temp]
  , stateTempsCount :: {-# UNPACK #-} !Int
  , stateTargets :: [Target]
  } deriving Show

data Attribute = Attribute
  { attributeSlot :: {-# UNPACK #-} !Int
  , attributeOffset :: {-# UNPACK #-} !Int
  , attributeDivisor :: {-# UNPACK #-} !Int
  , attributeType :: !AttributeType
  , attributeValueType :: !ValueType
  } deriving (Eq, Ord, Show, Generic)
instance S.Serialize Attribute

data Uniform = Uniform
  { uniformSlot :: {-# UNPACK #-} !Int
  , uniformOffset :: {-# UNPACK #-} !Int
  , uniformSize :: {-# UNPACK #-} !Int
  , uniformType :: !ValueType
  } deriving (Eq, Ord, Show, Generic)
instance S.Serialize Uniform

data Sampler = Sampler
  { samplerSlot :: {-# UNPACK #-} !Int
  , samplerDimension :: !SamplerDimension
  , samplerSampleType :: !ValueType
  , samplerCoordsType :: !ValueType
  } deriving (Eq, Ord, Show, Generic)
instance S.Serialize Sampler

data SamplerDimension
  = Sampler1D
  | Sampler2D
  | Sampler3D
  | SamplerCube
  deriving (Eq, Ord, Show, Generic)
instance S.Serialize SamplerDimension

data Target
  = PositionTarget (Node Float4)
  | ColorTarget !Int (Node Float4)
  | DualColorTarget (Node Float4) (Node Float4)
  | DepthTarget (Node Float)
  deriving Show

data Stage
  = VertexStage
  | PixelStage
  | EndStage
  deriving (Eq, Ord, Show)

data Temp = forall a. OfValueType a => Temp
  { tempIndex :: {-# UNPACK #-} !Int
  , tempNode :: !(Node a)
  , tempStage :: !Stage
  , tempType :: !ValueType
  }
deriving instance Show Temp

data Node a where
  AttributeNode :: Attribute -> Node a
  UniformNode :: Uniform -> Node a
  TempNode :: Int -> Node a
  ConstNode :: OfValueType a => ValueType -> a -> Node a
  IndexNode :: (OfValueType a, OfValueType b, Integral b) => ValueType -> ValueType -> Node [a] -> Node b -> Node a
  AddNode :: (OfValueType a, Num a) => ValueType -> Node a -> Node a -> Node a
  SubtractNode :: (OfValueType a, Num a) => ValueType -> Node a -> Node a -> Node a
  MultiplyNode :: (OfValueType a, Num a) => ValueType -> Node a -> Node a -> Node a
  DivideNode :: (OfValueType a, Fractional a) => ValueType -> Node a -> Node a -> Node a
  RecipNode :: (OfValueType a, Fractional a) => ValueType -> Node a -> Node a
  NegateNode :: (OfValueType a, Num a) => ValueType -> Node a -> Node a
  AbsNode :: (OfValueType a, Num a) => ValueType -> Node a -> Node a
  SignumNode :: (OfValueType a, Num a) => ValueType -> Node a -> Node a
  MinNode :: OfValueType a => ValueType -> Node a -> Node a -> Node a
  MaxNode :: OfValueType a => ValueType -> Node a -> Node a -> Node a
  ClampNode :: OfValueType a => ValueType -> Node a -> Node a -> Node a -> Node a
  LerpNode :: OfValueType a => ValueType -> Node a -> Node a -> Node a -> Node a
  EqualNode :: OfValueType a => ValueType -> Node a -> Node a -> Node Bool
  LessNode :: OfValueType a => ValueType -> Node a -> Node a -> Node Bool
  LessEqualNode :: OfValueType a => ValueType -> Node a -> Node a -> Node Bool
  IfNode :: OfValueType a => ValueType -> Node Bool -> Node a -> Node a -> Node a
  PiNode :: (OfValueType a, Floating a) => ValueType -> Node a
  ExpNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  SqrtNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  InvSqrtNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  LogNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  PowNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a -> Node a
  LogBaseNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a -> Node a
  SinNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  TanNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  CosNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  AsinNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  AtanNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  AcosNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  SinhNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  TanhNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  CoshNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  AsinhNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  AtanhNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  AcoshNode :: (OfValueType a, Floating a) => ValueType -> Node a -> Node a
  MulNode :: (OfValueType a, OfValueType b, Mul a b, OfValueType (MulResult a b)) => ValueType -> ValueType -> ValueType -> Node a -> Node b -> Node (MulResult a b)
  DotNode :: (OfVectorType v, OfScalarType (VecElement v), Dot v) => ValueType -> ValueType -> Node v -> Node v -> Node (VecElement v)
  CrossNode :: (OfVectorType v, Cross v) => ValueType -> Node v -> Node v -> Node v
  NormNode :: (OfVectorType v, OfScalarType (VecElement v), Norm v) => ValueType -> ValueType -> Node v -> Node (VecElement v)
  Norm2Node :: (OfVectorType v, OfScalarType (VecElement v), Norm v) => ValueType -> ValueType -> Node v -> Node (VecElement v)
  NormalizeNode :: (OfVectorType v, Normalize v) => ValueType -> Node v -> Node v
  DdxNode :: OfValueType a => ValueType -> Node a -> Node a
  DdyNode :: OfValueType a => ValueType -> Node a -> Node a
  FloorNode :: OfValueType a => ValueType -> Node a -> Node a
  InstanceIdNode :: Node Word32
  ComponentNode :: OfVectorType v => ValueType -> ValueType -> Char -> Node v -> Node (VecElement v)
  SwizzleNode :: (OfVectorType a, OfVectorType b) => ValueType -> ValueType -> String -> Node a -> Node b
  SampleNode :: (OfVectorType (v c), OfVectorType (v Int32)) =>
    { sampleNodeSamplerNode :: SamplerNode s (v c)
    , sampleNodeCoordsNode :: Node (v c)
    , sampleNodeOffsetNode :: Maybe (Node (v Int32))
    , sampleNodeLod :: SampleNodeLod v c
    } -> Node s
  CastNode :: (OfValueType a, OfValueType b) => ValueType -> ValueType -> Node a -> Node b
  Combine2VecNode :: (OfValueType a, OfValueType b, OfValueType r)
    => ValueType -> ValueType -> ValueType -> Node a -> Node b -> Node r
  Combine3VecNode :: (OfValueType a, OfValueType b, OfValueType c, OfValueType r)
    => ValueType -> ValueType -> ValueType -> ValueType -> Node a -> Node b -> Node c -> Node r
  Combine4VecNode :: (OfValueType a, OfValueType b, OfValueType c, OfValueType d, OfValueType r)
    => ValueType -> ValueType -> ValueType -> ValueType -> ValueType -> Node a -> Node b -> Node c -> Node d -> Node r
  ScreenToTextureNode :: OfValueType a => ValueType -> Node a -> Node a
  NormalizeSampledDepthNode :: Node Float -> Node Float
  FragCoordNode :: Node Float4

deriving instance Show (Node a)

newtype SamplerNode s c = SamplerNode Sampler deriving Show

data SampleNodeLod v a
  = SampleNodeAutoLod
  | SampleNodeLod (Node a)
  | SampleNodeBiasLod (Node a)
  | SampleNodeGradLod (Node (v a)) (Node (v a))
  deriving Show

nodeValueType :: OfValueType a => Node a -> ValueType
nodeValueType node = valueType $ (undefined :: (Node a -> a)) node

nodeArrayValueType :: OfValueType a => Node [a] -> ValueType
nodeArrayValueType node = valueType $ (undefined :: (Node [a] -> a)) node

instance OfVectorType v => Vec (Node v) where
  type VecElement (Node v) = Node (VecElement v)
  vecLength _ = vecLength (undefined :: v)
  vecToList _ = undefined
  vecFromScalar e = CastNode (nodeValueType e) (valueType (undefined :: v)) e

instance (OfValueType a, Num a) => Num (Node a) where
  (+) = AddNode $ valueType (undefined :: a)
  (*) = MultiplyNode $ valueType (undefined :: a)
  (-) = SubtractNode $ valueType (undefined :: a)
  negate = NegateNode $ valueType (undefined :: a)
  abs = AbsNode $ valueType (undefined :: a)
  signum = SignumNode $ valueType (undefined :: a)
  fromInteger = (ConstNode $ valueType (undefined :: a)) . fromInteger

instance (OfValueType a, Fractional a) => Fractional (Node a) where
  (/) = DivideNode $ valueType (undefined :: a)
  recip = RecipNode $ valueType (undefined :: a)
  fromRational = (ConstNode $ valueType (undefined :: a)) . fromRational

instance (OfValueType a, Floating a) => Floating (Node a) where
  pi = PiNode $ valueType (undefined :: a)
  exp = ExpNode $ valueType (undefined :: a)
  sqrt = SqrtNode $ valueType (undefined :: a)
  log = LogNode $ valueType (undefined :: a)
  (**) = PowNode $ valueType (undefined :: a)
  logBase = LogBaseNode $ valueType (undefined :: a)
  sin = SinNode $ valueType (undefined :: a)
  tan = TanNode $ valueType (undefined :: a)
  cos = CosNode $ valueType (undefined :: a)
  asin = AsinNode $ valueType (undefined :: a)
  atan = AtanNode $ valueType (undefined :: a)
  acos = AcosNode $ valueType (undefined :: a)
  sinh = SinhNode $ valueType (undefined :: a)
  tanh = TanhNode $ valueType (undefined :: a)
  cosh = CoshNode $ valueType (undefined :: a)
  asinh = AsinhNode $ valueType (undefined :: a)
  atanh = AtanhNode $ valueType (undefined :: a)
  acosh = AcoshNode $ valueType (undefined :: a)

instance (OfValueType a, OfValueType b, OfValueType (MulResult a b), Mul a b) => Mul (Node a) (Node b) where
  type MulResult (Node a) (Node b) = Node (MulResult a b)
  mul = MulNode (valueType (undefined :: a)) (valueType (undefined :: b)) (valueType (undefined :: MulResult a b))

instance (OfVectorType v, Dot v) => Dot (Node v) where
  dot = DotNode (valueType (undefined :: v)) (valueType (undefined :: VecElement v))

instance (OfVectorType v, Cross v) => Cross (Node v) where
  cross = CrossNode (valueType (undefined :: v))

instance (OfVectorType v, Norm v) => Norm (Node v) where
  norm = NormNode (valueType (undefined :: v)) (valueType (undefined :: VecElement v))
  norm2 = Norm2Node (valueType (undefined :: v)) (valueType (undefined :: VecElement v))

instance (OfVectorType v, Normalize v) => Normalize (Node v) where
  normalize = NormalizeNode (valueType (undefined :: v))

{- instance
  ( OfVectorType v
  , OfScalarType (VecElement v)
  , Vec{X..W} v
  ) => Vec{X..W} (Node v)
-}
forM "xyzw" $ \c -> do
  v <- newName "v"
  let vc = mkName $ "Vec" ++ [toUpper c]
  instanceD (sequence
    [ [t| OfVectorType $(varT v) |]
    , [t| $(conT vc) $(varT v) |]
    ]) [t| $(conT vc) (Node $(varT v)) |]
    [ funD (mkName $ [c, '_']) [clause [] (normalB [| ComponentNode (valueType (undefined :: $(varT v))) (valueType (undefined :: VecElement $(varT v))) $(litE $ charL c) |]) []]
    ]

{- instance
  ( OfVectorType v
  , OfVectorType (SwizzleVec{X..W}{1..4}Result v)
  , SwizzleVec{X..W}{1..4} v
  ) => SwizzleVec{X..W}{1..4} (Node v)
-}
forM [(maxComp, dim) | maxComp <- [1..4], dim <- [1..4]] $ \(maxComp, dim) -> do
  v <- newName "v"
  let
    components = take maxComp "xyzw"
    nameSuffix = [toUpper $ last components, intToDigit dim]
    sv = mkName $ "SwizzleVec" ++ nameSuffix
    resultTypeName = mkName $ "SwizzleVecResult" ++ nameSuffix
    variants = filter variantFilter $ genVariants dim where
      genVariants 0 = [""]
      genVariants len = [c : cs | c <- components, cs <- genVariants $ len - 1]
      variantFilter variant = all (\c -> elem c components) variant && elem (last components) variant
    funDecl variant = do
      funD (mkName $ variant ++ "__") [clause [] (normalB [| SwizzleNode (valueType (undefined :: $(varT v))) (valueType (undefined :: $(conT resultTypeName) $(varT v))) $(litE $ stringL variant) |]) []]
    resultTypeDecl = tySynInstD resultTypeName $ tySynEqn
      [ [t| Node $(varT v) |] ]
      [t| Node ($(conT resultTypeName) $(varT v)) |]
  instanceD (sequence
    [ [t| OfVectorType $(varT v) |]
    , [t| OfVectorType ($(conT $ mkName $ "SwizzleVecResult" ++ nameSuffix) $(varT v)) |]
    , [t| $(conT sv) $(varT v) |]
    ])
    [t| $(conT sv) (Node $(varT v)) |] $ resultTypeDecl : map funDecl variants

-- | Program monad.
type Program a = ReaderT (IORef State) IO a

runProgram :: Program () -> IO State
runProgram program = do
  stateVar <- newIORef State
    { stateTemps = []
    , stateTempsCount = 0
    , stateStage = VertexStage
    , stateTargets = []
    }
  runReaderT program stateVar
  state@State
    { stateStage = stage
    } <- readIORef stateVar
  if stage /= EndStage then fail "wrong program: stage should be end"
  else return ()
  return state