<commit_before>-- | Machinery for making decisions about C++ level materialization for K3.
module Language.K3.Codegen.CPP.Materialization where

import Control.Monad.Identity (Identity(..), runIdentity)
import Control.Monad.State (StateT(..), MonadState(..), runState)

import qualified Data.Map as M
import qualified Data.IntMap as I

import Language.K3.Core.Common

data Method
  = ConstReferenced
  | Referenced
  | Moved
  | Copied
 deriving (Eq, Read, Show)

-- Decisions as pertaining to an identifier at a given expression specify how the binding is to be
-- populated (initialized), and how it is to be written back (finalized, if necessary).
data Decision = Decision { inD :: Method, outD :: Method } deriving (Eq, Read, Show)

-- The most conservative decision is to initialize a new binding by copying its initializer, and to
-- finalize it by copying it back. There might be a strictly better strategy, but this is the
-- easiest to write.
defaultDecision :: Decision
defaultDecision = Decision { inD = Copied, outD = Copied }

type Table = I.Map (M.Map Identifier Decision)

type MaterializationS = (Table, PIEnv)
type MaterializationM = StateT MaterializationS Identity

-- Table Construction/Attachment

runMaterializationM :: MaterializationM a -> MaterializationS -> (a, MaterializationS)
runMaterializationM = runIdentity . runStateT

materializationD :: K3 Declaration -> MaterializationM (K3 Declaration)
materializationD = undefined

materializationE :: K3 Expression -> MaterializationM (K3 Expression)
materializationE = undefined

-- Queries

anyM :: (Functor m, Applicative m, Monad m) => (a -> m Bool) -> [a] -> m Bool
anyM f xs = or <$> mapM xs

-- Determine if a piece of provenance 'occurs in' another. The answer can be influenced by 'width
-- flag', determining whether or not the provenance of superstructure occurs in the provenance of
-- its substructure.
occursIn :: Bool -> K3 Provenance -> K3 Provenance -> MaterializationM Bool
occursIn wide b a
  = case a of

      -- Everything occurs in itself.
      _ | a == b = True

      -- Something occurs in a bound variable if it occurs in anything that was used to initialize
      -- that bound variable, and that bound variable was initialized using a non-isolating method.
      (tag -> PBVar mv) -> do
             decision <- getDecision (pmvloc mv) (pmvn mv)
             if inD decision == Referenced || inD decision == ConstReferenced
               then fromMaybe (error "Dangling provenance pointer") (pLookup $ pmvptr mv) >>= occursIn wide b
               else return False

      -- Something occurs in substructure if it occurs in any superstructure, and wide effects are
      -- set.
      (tag -> POption) | wide -> anyM (occursIn wide b) (children a)
      (tag -> PIndirection) | wide -> anyM (occursIn wide b) (children a)
      (tag -> PTuple _) | wide -> anyM (occursIn wide b) (children a)
      (tag -> PProject _) | wide -> anyM (occursIn wide b) (children a)
      (tag -> PRecord _) | wide -> anyM (occursIn wide b) (children a)

      -- TODO: Add more intelligent handling of substructure + PData combinations.

      _ -> False

isReadIn :: K3 Expression -> K3 Expression -> MaterializationM Bool
isReadIn = undefined

isWrittenIn :: K3 Expression -> K3 Expression -> MaterializationM Bool
isWrittenIn = undefined

isMoveableIn :: K3 Expression -> K3 Expression -> MaterializationM Bool
isMoveableIn x c = undefined
<commit_msg>Add downstream component to Materialization state.<commit_after>-- | Machinery for making decisions about C++ level materialization for K3.
module Language.K3.Codegen.CPP.Materialization where

import Control.Monad.Identity (Identity(..), runIdentity)
import Control.Monad.State (StateT(..), MonadState(..), runState)

import qualified Data.Map as M
import qualified Data.IntMap as I

import Language.K3.Core.Common

data Method
  = ConstReferenced
  | Referenced
  | Moved
  | Copied
 deriving (Eq, Read, Show)

-- Decisions as pertaining to an identifier at a given expression specify how the binding is to be
-- populated (initialized), and how it is to be written back (finalized, if necessary).
data Decision = Decision { inD :: Method, outD :: Method } deriving (Eq, Read, Show)

-- The most conservative decision is to initialize a new binding by copying its initializer, and to
-- finalize it by copying it back. There might be a strictly better strategy, but this is the
-- easiest to write.
defaultDecision :: Decision
defaultDecision = Decision { inD = Copied, outD = Copied }

type Table = I.Map (M.Map Identifier Decision)

type MaterializationS = (Table, PIEnv, [K3 Expression])
type MaterializationM = StateT MaterializationS Identity

-- Table Construction/Attachment

runMaterializationM :: MaterializationM a -> MaterializationS -> (a, MaterializationS)
runMaterializationM = runIdentity . runStateT

materializationD :: K3 Declaration -> MaterializationM (K3 Declaration)
materializationD = undefined

materializationE :: K3 Expression -> MaterializationM (K3 Expression)
materializationE = undefined

-- Queries

anyM :: (Functor m, Applicative m, Monad m) => (a -> m Bool) -> [a] -> m Bool
anyM f xs = or <$> mapM xs

-- Determine if a piece of provenance 'occurs in' another. The answer can be influenced by 'width
-- flag', determining whether or not the provenance of superstructure occurs in the provenance of
-- its substructure.
occursIn :: Bool -> K3 Provenance -> K3 Provenance -> MaterializationM Bool
occursIn wide b a
  = case a of

      -- Everything occurs in itself.
      _ | a == b = True

      -- Something occurs in a bound variable if it occurs in anything that was used to initialize
      -- that bound variable, and that bound variable was initialized using a non-isolating method.
      (tag -> PBVar mv) -> do
             decision <- getDecision (pmvloc mv) (pmvn mv)
             if inD decision == Referenced || inD decision == ConstReferenced
               then fromMaybe (error "Dangling provenance pointer") (pLookup $ pmvptr mv) >>= occursIn wide b
               else return False

      -- Something occurs in substructure if it occurs in any superstructure, and wide effects are
      -- set.
      (tag -> POption) | wide -> anyM (occursIn wide b) (children a)
      (tag -> PIndirection) | wide -> anyM (occursIn wide b) (children a)
      (tag -> PTuple _) | wide -> anyM (occursIn wide b) (children a)
      (tag -> PProject _) | wide -> anyM (occursIn wide b) (children a)
      (tag -> PRecord _) | wide -> anyM (occursIn wide b) (children a)

      -- TODO: Add more intelligent handling of substructure + PData combinations.

      _ -> False

isReadIn :: K3 Expression -> K3 Expression -> MaterializationM Bool
isReadIn = undefined

isWrittenIn :: K3 Expression -> K3 Expression -> MaterializationM Bool
isWrittenIn = undefined

isMoveableIn :: K3 Expression -> K3 Expression -> MaterializationM Bool
isMoveableIn x c = undefined

{'fraction_non_alphanumeric': 0.08847262247838616, 'fraction_numerical': 0.0044668587896253605, 'mean_word_length': 3.418204964990452, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2642705', 'n_tokens_mistral': 1969, 'n_tokens_neox': 1899, 'n_words': 819}