content: 
  {-# LANGUAGE TemplateHaskell #-}
  {-# LANGUAGE UndecidableInstances #-}
  
  module Cubix.Language.Parametric.Syntax.Function (
    -- Function calls
      FunctionCallAttrsL
    , FunctionExpL
    , FunctionArgumentsL
    , FunctionCallL
    , FunctionCall(..)
    , EmptyFunctionCallAttrs(..)
    , FunctionIdent(..)
  
    , FunctionArgumentL
    , FunctionArgumentList(..)
    , ReceiverL
    , ReceiverArg(..)
    , PositionalArgExpL
    , PositionalArgument(..)
  
    , pattern FunctionCall'
    ,        iFunctionCall
    ,        jFunctionCall
    , pattern EmptyFunctionCallAttrs'
    ,        iEmptyFunctionCallAttrs
    ,        jEmptyFunctionCallAttrs
    , pattern FunctionIdent'
    ,        iFunctionIdent
    ,        jFunctionIdent
    , pattern FunctionArgumentList'
    ,        iFunctionArgumentList
    ,        jFunctionArgumentList
    , pattern ReceiverArg'
    ,        iReceiverArg
    ,        jReceiverArg
    , pattern PositionalArgument'
    ,        iPositionalArgument
    ,        jPositionalArgument
  
    -- Function decls
  
    , FunctionDeclAttrsL
    , FunctionParameterDeclL
    , FunctionParameterDeclAttrsL
    , FunctionDeclL
    , FunctionDecl(..)
    , EmptyFunctionDeclAttrs(..)
    , SelfParameterDecl(..)
    , PositionalParameterDeclOptionalIdent(..)
    , PositionalParameterDeclWithIdent(..)
  
    , pattern FunctionDecl'
    ,        iFunctionDecl
    ,        jFunctionDecl
    , pattern EmptyFunctionDeclAttrs'
    ,        iEmptyFunctionDeclAttrs
    ,        jEmptyFunctionDeclAttrs
    , pattern SelfParameterDecl'
    ,        iSelfParameterDecl
    ,        jSelfParameterDecl
    , pattern PositionalParameterDeclOptionalIdent'
    ,        iPositionalParameterDeclOptionalIdent
    ,        jPositionalParameterDeclOptionalIdent
    , pattern PositionalParameterDeclWithIdent'
    ,        iPositionalParameterDeclWithIdent
    ,        jPositionalParameterDeclWithIdent
  
    -- Function defns
  
    , FunctionDefAttrsL
    , FunctionParameterL
    , FunctionBodyL
    , FunctionDefL
    , FunctionDef(..)
    , EmptyFunctionDefAttrs(..)
    , SelfParameter(..)
    , ParameterAttrsL
    , PositionalParameter(..)
    , EmptyParameterAttrs(..)
  
    , pattern FunctionDef'
    ,        iFunctionDef
    ,        jFunctionDef
    , pattern EmptyFunctionDefAttrs'
    ,        iEmptyFunctionDefAttrs
    ,        jEmptyFunctionDefAttrs
    , pattern SelfParameter'
    ,        iSelfParameter
    ,        jSelfParameter
    , pattern PositionalParameter'
    ,        iPositionalParameter
    ,        jPositionalParameter
    , pattern EmptyParameterAttrs'
    ,        iEmptyParameterAttrs
    ,        jEmptyParameterAttrs
  
    ) where
  
  import Data.Comp.Multi ( Node )
  
  import Cubix.Language.Parametric.Derive
  import Cubix.Language.Parametric.Syntax.VarDecl
  
  ---------------------------------------------------------------------------------
  ---------------------------              Function Calls         -----------------
  ---------------------------------------------------------------------------------
  
  data FunctionCallAttrsL
  data FunctionExpL
  data FunctionArgumentsL
  
  
  -- | Upon evaluating a FunctionCall node, the following occurs:
  --  1) The FunctionExp is evaluated.
  --  2) The function call attrs are evaluated.
  --  3) The arguments are evaluated, in unspecified order. (Remember, we model C, which has unspecified order)
  --  4) A function is looked up based on the function exp and the arguments, and is then invoked with the given arguments.
  --
  --  1 and 2 happpen in unspecified order. 1 and 2 happen before 3, which happens before 4.
  --
  --  All positional arguments in the invocation and the function definition are matched up sequentially
  --  If argument types do not line up (e.g.: pass a positional arg at a receiver position), this is undefined;
  --  said positional argument is ignored in the above computation
  data FunctionCallL
  data FunctionCall e l where
    FunctionCall :: e FunctionCallAttrsL -> e FunctionExpL -> e FunctionArgumentsL -> FunctionCall e FunctionCallL
  
  deriveAll [''FunctionCall]
  
  data EmptyFunctionCallAttrs :: Node where
    EmptyFunctionCallAttrs :: EmptyFunctionCallAttrs e FunctionCallAttrsL
  
  deriveAll [''EmptyFunctionCallAttrs]
  
  data FunctionIdent e l where
    FunctionIdent :: e IdentL -> FunctionIdent e FunctionExpL
  
  deriveAll [''FunctionIdent]
  
  -- | Additional non-syntactic assumptions:
  -- * At most one argument is receiver, and
  --     it's at the front of the list if exists.
  -- * Positional and receiver args are before other args
  data FunctionArgumentL
  data FunctionArgumentList :: Node where
    FunctionArgumentList :: e [FunctionArgumentL] -> FunctionArgumentList e FunctionArgumentsL
  
  deriveAll [''FunctionArgumentList]
  
  data ReceiverL
  data ReceiverArg e l where
    ReceiverArg :: e ReceiverL -> ReceiverArg e FunctionArgumentL
  
  deriveAll [''ReceiverArg]
  
  data PositionalArgExpL
  data PositionalArgument :: Node where
    PositionalArgument :: e PositionalArgExpL -> PositionalArgument e FunctionArgumentL
  
  deriveAll [''PositionalArgument]
  
  ---------------------------------------------------------------------------------
  ---------------------------          Function Decls             -----------------
  ---------------------------------------------------------------------------------
  
  data FunctionDeclAttrsL
  data FunctionParameterDeclL
  
  data FunctionDeclL
  data FunctionDecl e l where
    FunctionDecl :: e FunctionDeclAttrsL -> e IdentL -> e [FunctionParameterDeclL] -> FunctionDecl e FunctionDeclL
  
  deriveAll [''FunctionDecl]
  
  data EmptyFunctionDeclAttrs :: Node where
    EmptyFunctionDeclAttrs :: EmptyFunctionDeclAttrs e FunctionDeclAttrsL
  
  deriveAll [''EmptyFunctionDeclAttrs]
  
  data SelfParameterDecl :: Node where
    SelfParameterDecl :: SelfParameterDecl e FunctionParameterDeclL
  
  deriveAll [''SelfParameterDecl]
  
  data FunctionParameterDeclAttrsL
  
  data PositionalParameterDeclOptionalIdent e l where
    PositionalParameterDeclOptionalIdent :: e FunctionParameterDeclAttrsL -> e (Maybe IdentL) -> PositionalParameterDeclOptionalIdent e FunctionParameterDeclL
  
  deriveAll [''PositionalParameterDeclOptionalIdent]
  
  data PositionalParameterDeclWithIdent e l where
    PositionalParameterDeclWithIdent :: e FunctionParameterDeclAttrsL -> e IdentL -> PositionalParameterDeclWithIdent e FunctionParameterDeclL
  
  deriveAll [''PositionalParameterDeclWithIdent]
  
  
  ---------------------------------------------------------------------------------
  ---------------------------          Function Defns             -----------------
  ---------------------------------------------------------------------------------
  
  data FunctionDefAttrsL
  data FunctionParameterL
  data FunctionBodyL
  data FunctionDefL
  data FunctionDef e l where
    FunctionDef :: e FunctionDefAttrsL -> e IdentL -> e [FunctionParameterL] -> e FunctionBodyL -> FunctionDef e FunctionDefL
  
  deriveAll [''FunctionDef]
  
  data EmptyFunctionDefAttrs :: Node where
    EmptyFunctionDefAttrs :: EmptyFunctionDefAttrs e FunctionDefAttrsL
  
  deriveAll [''EmptyFunctionDefAttrs]
  
  data SelfParameter :: Node where
    SelfParameter :: SelfParameter e FunctionParameterL
  
  deriveAll [''SelfParameter]
  
  data ParameterAttrsL
  data PositionalParameter e l where
    PositionalParameter :: e ParameterAttrsL -> e IdentL -> PositionalParameter e FunctionParameterL
  
  deriveAll [''PositionalParameter]
  
  data EmptyParameterAttrs :: Node where
    EmptyParameterAttrs :: EmptyParameterAttrs e ParameterAttrsL
  
  deriveAll [''EmptyParameterAttrs]
  