packages feed

fir-0.1.0.0: src/FIR/Module.hs

{-# OPTIONS_HADDOCK ignore-exports #-}

{-# LANGUAGE DataKinds              #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE GADTs                  #-}
{-# LANGUAGE InstanceSigs           #-}
{-# LANGUAGE PatternSynonyms        #-}
{-# LANGUAGE ScopedTypeVariables    #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE TypeOperators          #-}
{-# LANGUAGE UndecidableInstances   #-}

{-|
Module: FIR.Module

Utility wrapper types for programs.

A program essentially consists of a value of type @Codensity AST (AST a := j) i@,
but with additional type-level information pertaining to the program inputs/outputs,
similar to the interface for a shader module in @OpenGL@ or @Vulkan@.

See "FIR.ProgramState" which defines the type-level data that programs keep track of.
-}

module FIR.Module
  ( Program
  , Module(Module)
  , ShaderModule(ShaderModule)
  )
  where

-- base
import Data.Kind
  ( Type )
import GHC.TypeLits
  ( Symbol )

-- fir
import Control.Monad.Indexed
  ( (:=)(AtKey), Codensity(..) )
import Data.Type.Map
  ( (:->) )
import FIR.AST
  ( AST, Code
  , Syntactic(..), SyntacticVal, InternalType
  , pattern (:$), pattern Bind, pattern Return
  )
import FIR.AST.Type
  ( Eff )
import FIR.Definition
  ( Definition, KnownDefinitions
  , StartState
  )
import FIR.ProgramState
  ( ProgramState )
import FIR.Validation.Definitions
  ( ValidDefinitions )
import qualified SPIRV.Stage  as SPIRV
  ( Shader )

--------------------------------------------------------------------------
-- * Program type synonym
--
-- $wrappers
-- Wrapper for the main internal representation
-- @Codensity AST (a := j) i@

type Program (i :: ProgramState) (j :: ProgramState) (a :: Type)
  = Codensity AST (a := j) i

instance SyntacticVal a => Syntactic (Program i j a) where
  type Internal (Codensity AST (a := j) i) = Eff i j (InternalType a)

  toAST :: Codensity AST (a := j) i -> AST ( Eff i j (InternalType a) )
  toAST (Codensity k) = k ( \(AtKey a) -> Return :$ toAST a )

  fromAST :: AST ( Eff i j (InternalType a) ) -> Codensity AST (a := j) i
  fromAST a = Codensity ( \k -> Bind :$ toAST a :$ toAST (k . AtKey) )

--------------------------------------------------------------------------
-- * Module type

-- | A 'Module' wraps a value-level program with additional
-- 'Definition's which specify the interface of the module,
-- such as memory layout of input and output data.
--
-- Corresponds to the concept of a SPIR-V module.
data Module
      ( defs :: [ Symbol :-> Definition ] )
    :: Type where
  Module  :: forall defs endState
          .  ( KnownDefinitions defs, ValidDefinitions defs )
          => Program (StartState defs) endState (Code ())
          -> Module defs

--------------------------------------------------------------------------
-- * Shader stage type

-- | Value-level wrapper for a shader stage.
--
-- Takes a module (which may have multiple shaders defined),
-- and specifies (using name + stage) which shader
-- is being referred to (e.g. for use in a shader pipeline).
--
-- Keeps track of the final indexed monadic state of the shader,
-- which is used to perform type-level validation.
data ShaderModule
        ( name     :: Symbol                  )
        ( stage    :: SPIRV.Shader            )
        ( defs     :: [Symbol :-> Definition] )
        ( endState :: ProgramState            )
        where
  ShaderModule
    :: forall name stage defs endState
    .  ( KnownDefinitions defs, ValidDefinitions defs )
    => Program (StartState defs) endState (Code ())
    -> ShaderModule name stage defs endState