{-# LANGUAGE GADTs, TemplateHaskell #-}
{-# LANGUAGE InstanceSigs #-}
-- | Defines the CodeSpec structure and related functions.
module Language.Drasil.CodeSpec where

import Prelude hiding (const)
import Control.Lens ((^.), makeLenses, Lens', makeClassyFor, set)
import Data.List (nub, (\\))
import qualified Data.Map as Map
import Data.Maybe (mapMaybe)

import Drasil.Build.Artifacts (RelativeFile)
import Language.Drasil hiding (None)
import Language.Drasil.Display (Symbol(Variable))
import Drasil.Database (ChunkDB, UID, HasUID(..), insertAll)
import Drasil.Code.CodeExpr.Development (expr, eNamesRI, eDep)
import qualified Drasil.System as S
import Drasil.System (HasSmithEtAlSRS(..), HasSystemMeta(..), programName)
import Theory.Drasil (DataDefinition, qdEFromDD, getEqModQdsFromIm)
import Utils.Drasil (subsetOf)

import Drasil.Code.CodeVar (CodeChunk, CodeIdea(codeChunk), CodeVarChunk)
import Language.Drasil.Chunk.ConstraintMap (ConstraintCEMap, ConstraintCE, constraintMap)
import Language.Drasil.Chunk.CodeDefinition (CodeDefinition, qtov, qtoc, odeDef)
import Language.Drasil.Choices (Choices(..), Maps(..), ODE(..), ExtLib(..),
  odeLibReqs, odeInfoReqs)
import Language.Drasil.Chunk.CodeBase (quantvar, codevars, varResolve)
import Language.Drasil.Mod (Func(..), FuncData(..), FuncDef(..), Mod(..), Name)
import Language.Drasil.ICOSolutionSearch (Def, solveExecOrder)

-- | Program input.
type Input = CodeVarChunk
-- | Program output.
type Output = CodeVarChunk
-- | Constants in the problem.
type Const = CodeDefinition
-- | Derived inputs.
type Derived = CodeDefinition
-- | Maps constants to their respective 'CodeDefinition'.
type ConstantMap = Map.Map UID CodeDefinition

-- | Old Code specifications. Holds information needed to generate code.
data OldCodeSpec = OldCodeSpec {
  -- | Program name.
  OldCodeSpec -> Name
_pName :: Name,
  -- | Authors.
  OldCodeSpec -> People
_authors :: People,
  -- | All inputs.
  OldCodeSpec -> [CodeVarChunk]
_inputs :: [Input],
  -- | Explicit inputs (values to be supplied by a file).
  OldCodeSpec -> [CodeVarChunk]
_extInputs :: [Input],
  -- | Derived inputs (each calculated from explicit inputs in a single step).
  OldCodeSpec -> [Const]
_derivedInputs :: [Derived],
  -- | All outputs.
  OldCodeSpec -> [CodeVarChunk]
_outputs :: [Output],
  -- | List of files that must be in same directory for running the executable.
  OldCodeSpec -> [RelativeFile]
_configFiles :: [RelativeFile],
  -- | Mathematical definitions, ordered so that they form a path from inputs to
  -- outputs.
  OldCodeSpec -> [Const]
_execOrder :: [Def],
  -- | Map from 'UID's to constraints for all constrained chunks used in the problem.
  OldCodeSpec -> ConstraintCEMap
_cMap :: ConstraintCEMap,
  -- | List of all constants used in the problem.
  OldCodeSpec -> [Const]
_constants :: [Const],
  -- | Map containing all constants used in the problem.
  OldCodeSpec -> ConstantMap
_constMap :: ConstantMap,
  -- | Additional modules required in the generated code, which Drasil cannot yet
  -- automatically define.
  OldCodeSpec -> [Mod]
_mods :: [Mod],  -- medium hack
  -- | The database of all chunks used in the problem.
  OldCodeSpec -> ChunkDB
_systemdb :: ChunkDB
  }

makeClassyFor "HasOldCodeSpec" "oldCodeSpec"
  [   ("_pName", "pNameO")
    , ("_authors", "authorsO")
    , ("_inputs", "inputsO")
    , ("_extInputs", "extInputsO")
    , ("_derivedInputs", "derivedInputsO")
    , ("_outputs", "outputsO")
    , ("_configFiles", "configFilesO")
    , ("_execOrder", "execOrderO")
    , ("_cMap", "cMapO")
    , ("_constants", "constantsO")
    , ("_constMap", "constMapO")
    , ("_mods", "modsO")
    , ("_systemdb", "systemdbO")
    ] ''OldCodeSpec

-- | New Code Specification. Holds system information and a reference to `OldCodeSpec`.
data CodeSpec = CS {
  CodeSpec -> SmithEtAlSRS
_system' :: S.SmithEtAlSRS,
  CodeSpec -> OldCodeSpec
_oldCode :: OldCodeSpec
}
makeLenses ''CodeSpec

instance HasSmithEtAlSRS CodeSpec where
  smithEtAlSRS :: Lens' CodeSpec S.SmithEtAlSRS
  smithEtAlSRS :: Lens' CodeSpec SmithEtAlSRS
smithEtAlSRS = (SmithEtAlSRS -> f SmithEtAlSRS) -> CodeSpec -> f CodeSpec
Lens' CodeSpec SmithEtAlSRS
system'

instance HasSystemMeta CodeSpec where
  systemMeta :: Lens' CodeSpec SystemMeta
systemMeta = (SmithEtAlSRS -> f SmithEtAlSRS) -> CodeSpec -> f CodeSpec
Lens' CodeSpec SmithEtAlSRS
system' ((SmithEtAlSRS -> f SmithEtAlSRS) -> CodeSpec -> f CodeSpec)
-> ((SystemMeta -> f SystemMeta) -> SmithEtAlSRS -> f SmithEtAlSRS)
-> (SystemMeta -> f SystemMeta)
-> CodeSpec
-> f CodeSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SystemMeta -> f SystemMeta) -> SmithEtAlSRS -> f SmithEtAlSRS
forall c. HasSystemMeta c => Lens' c SystemMeta
Lens' SmithEtAlSRS SystemMeta
systemMeta

instance HasOldCodeSpec CodeSpec where
  oldCodeSpec :: Lens' CodeSpec OldCodeSpec
  oldCodeSpec :: Lens' CodeSpec OldCodeSpec
oldCodeSpec = (OldCodeSpec -> f OldCodeSpec) -> CodeSpec -> f CodeSpec
Lens' CodeSpec OldCodeSpec
oldCode

-- | Converts a list of chunks that have 'UID's to a Map from 'UID' to the associated chunk.
assocToMap :: HasUID a => [a] -> Map.Map UID a
assocToMap :: forall a. HasUID a => [a] -> Map UID a
assocToMap = [(UID, a)] -> Map UID a
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(UID, a)] -> Map UID a)
-> ([a] -> [(UID, a)]) -> [a] -> Map UID a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> (UID, a)) -> [a] -> [(UID, a)]
forall a b. (a -> b) -> [a] -> [b]
map (\a
x -> (a
x a -> Getting UID a UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID a UID
forall c. HasUID c => Getter c UID
Getter a UID
uid, a
x))

-- | Get ODE from ExtLib
getODE :: [ExtLib] -> Maybe ODE
getODE :: [ExtLib] -> Maybe ODE
getODE [] = Maybe ODE
forall a. Maybe a
Nothing
getODE (Math ODE
ode: [ExtLib]
_) = ODE -> Maybe ODE
forall a. a -> Maybe a
Just ODE
ode
-- getODE (_:xs) = getODE xs

-- | Maps ODE to their respective 'CodeDefinition'.
mapODE :: Maybe ODE -> [CodeDefinition]
mapODE :: Maybe ODE -> [Const]
mapODE Maybe ODE
Nothing = []
mapODE (Just ODE
ode) = (ODEInfo -> Const) -> [ODEInfo] -> [Const]
forall a b. (a -> b) -> [a] -> [b]
map ODEInfo -> Const
odeDef ([ODEInfo] -> [Const]) -> [ODEInfo] -> [Const]
forall a b. (a -> b) -> a -> b
$ ODE -> [ODEInfo]
odeInfo ODE
ode

-- | Creates a 'CodeSpec' using the provided 'System', 'Choices', and 'Mod's.
-- The 'CodeSpec' consists of the system information and a corresponding 'OldCodeSpec'.
codeSpec :: S.SmithEtAlSRS -> Choices -> CodeSpec
codeSpec :: SmithEtAlSRS -> Choices -> CodeSpec
codeSpec SmithEtAlSRS
si Choices
chs = CS {
  _system' :: SmithEtAlSRS
_system' = SmithEtAlSRS
si',
  _oldCode :: OldCodeSpec
_oldCode = SmithEtAlSRS -> Choices -> OldCodeSpec
oldcodeSpec SmithEtAlSRS
si' Choices
chs
}
  where
    els :: [ExtLib]
els = Choices -> [ExtLib]
extLibs Choices
chs
    libReqs :: [DefinedQuantityDict]
libReqs = (ExtLib -> [DefinedQuantityDict])
-> [ExtLib] -> [DefinedQuantityDict]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ExtLib -> [DefinedQuantityDict]
odeLibReqs [ExtLib]
els
    infoReqs :: [DefinedQuantityDict]
infoReqs = (ExtLib -> [DefinedQuantityDict])
-> [ExtLib] -> [DefinedQuantityDict]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ExtLib -> [DefinedQuantityDict]
odeInfoReqs [ExtLib]
els
    db' :: ChunkDB
db' = [DefinedQuantityDict] -> ChunkDB -> ChunkDB
forall a. TypeableChunk a => [a] -> ChunkDB -> ChunkDB
insertAll ([DefinedQuantityDict]
libReqs [DefinedQuantityDict]
-> [DefinedQuantityDict] -> [DefinedQuantityDict]
forall a. [a] -> [a] -> [a]
++ [DefinedQuantityDict]
infoReqs) (ChunkDB -> ChunkDB) -> ChunkDB -> ChunkDB
forall a b. (a -> b) -> a -> b
$ SmithEtAlSRS
si SmithEtAlSRS -> Getting ChunkDB SmithEtAlSRS ChunkDB -> ChunkDB
forall s a. s -> Getting a s a -> a
^. Getting ChunkDB SmithEtAlSRS ChunkDB
forall c. HasSystemMeta c => Lens' c ChunkDB
Lens' SmithEtAlSRS ChunkDB
systemdb
    si' :: SmithEtAlSRS
si' = ASetter SmithEtAlSRS SmithEtAlSRS ChunkDB ChunkDB
-> ChunkDB -> SmithEtAlSRS -> SmithEtAlSRS
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter SmithEtAlSRS SmithEtAlSRS ChunkDB ChunkDB
forall c. HasSystemMeta c => Lens' c ChunkDB
Lens' SmithEtAlSRS ChunkDB
systemdb ChunkDB
db' SmithEtAlSRS
si

-- | Generates an 'OldCodeSpec' from 'SmithEtAlSRS', 'Choices', and a list of
-- 'Mod's. This function extracts various components (e.g., inputs, outputs,
-- constraints, etc.) from 'SmithEtAlSRS' to populate the 'OldCodeSpec'
-- structure.
oldcodeSpec :: S.SmithEtAlSRS -> Choices -> OldCodeSpec
oldcodeSpec :: SmithEtAlSRS -> Choices -> OldCodeSpec
oldcodeSpec sys :: SmithEtAlSRS
sys@S.ICO{ _inputs :: ()
S._inputs = [h]
ins
                     , _outputs :: ()
S._outputs = [i]
outs
                     , _constraints :: ()
S._constraints = [j]
cs
                     , _constants :: SmithEtAlSRS -> [ConstQDef]
S._constants = [ConstQDef]
cnsts } Choices
chs =
  let ddefs :: [DataDefinition]
ddefs = SmithEtAlSRS
sys SmithEtAlSRS
-> Getting [DataDefinition] SmithEtAlSRS [DataDefinition]
-> [DataDefinition]
forall s a. s -> Getting a s a -> a
^. Getting [DataDefinition] SmithEtAlSRS [DataDefinition]
forall c. HasSmithEtAlSRS c => Lens' c [DataDefinition]
Lens' SmithEtAlSRS [DataDefinition]
dataDefns
      n :: Name
n = SmithEtAlSRS
sys SmithEtAlSRS -> Getting Name SmithEtAlSRS Name -> Name
forall s a. s -> Getting a s a -> a
^. Getting Name SmithEtAlSRS Name
forall c. HasSmithEtAlSRS c => Lens' c Name
Lens' SmithEtAlSRS Name
programName
      db :: ChunkDB
db = SmithEtAlSRS
sys SmithEtAlSRS -> Getting ChunkDB SmithEtAlSRS ChunkDB -> ChunkDB
forall s a. s -> Getting a s a -> a
^. Getting ChunkDB SmithEtAlSRS ChunkDB
forall c. HasSystemMeta c => Lens' c ChunkDB
Lens' SmithEtAlSRS ChunkDB
systemdb
      inputs' :: [CodeVarChunk]
inputs' = (h -> CodeVarChunk) -> [h] -> [CodeVarChunk]
forall a b. (a -> b) -> [a] -> [b]
map h -> CodeVarChunk
forall c.
(Quantity c, MayHaveUnit c, Concept c) =>
c -> CodeVarChunk
quantvar [h]
ins
      const' :: [Const]
const' = (ConstQDef -> Const) -> [ConstQDef] -> [Const]
forall a b. (a -> b) -> [a] -> [b]
map ConstQDef -> Const
forall e. CanGenCode e => QDefinition e -> Const
qtov ((ConstQDef -> Bool) -> [ConstQDef] -> [ConstQDef]
forall a. (a -> Bool) -> [a] -> [a]
filter ((UID -> Map UID [CodeConcept] -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.notMember` Maps -> Map UID [CodeConcept]
conceptMatch (Choices -> Maps
maps Choices
chs)) (UID -> Bool) -> (ConstQDef -> UID) -> ConstQDef -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ConstQDef -> Getting UID ConstQDef UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID ConstQDef UID
forall c. HasUID c => Getter c UID
Getter ConstQDef UID
uid))
        [ConstQDef]
cnsts)
      derived :: [Const]
derived = (QDefinition Expr -> Const) -> [QDefinition Expr] -> [Const]
forall a b. (a -> b) -> [a] -> [b]
map QDefinition Expr -> Const
forall e. CanGenCode e => QDefinition e -> Const
qtov ([QDefinition Expr] -> [Const]) -> [QDefinition Expr] -> [Const]
forall a b. (a -> b) -> a -> b
$ [DataDefinition]
-> [CodeVarChunk] -> [Const] -> ChunkDB -> [QDefinition Expr]
getDerivedInputs [DataDefinition]
ddefs [CodeVarChunk]
inputs' [Const]
const' ChunkDB
db
      rels :: [Const]
rels = ((QDefinition Expr -> Const) -> [QDefinition Expr] -> [Const]
forall a b. (a -> b) -> [a] -> [b]
map QDefinition Expr -> Const
forall (q :: * -> *).
(Quantity (q Expr), MayHaveUnit (q Expr), DefiningExpr q,
 Concept (q Expr)) =>
q Expr -> Const
qtoc ([InstanceModel] -> [QDefinition Expr]
getEqModQdsFromIm (SmithEtAlSRS
sys SmithEtAlSRS
-> Getting [InstanceModel] SmithEtAlSRS [InstanceModel]
-> [InstanceModel]
forall s a. s -> Getting a s a -> a
^. Getting [InstanceModel] SmithEtAlSRS [InstanceModel]
forall c. HasSmithEtAlSRS c => Lens' c [InstanceModel]
Lens' SmithEtAlSRS [InstanceModel]
instModels) [QDefinition Expr] -> [QDefinition Expr] -> [QDefinition Expr]
forall a. [a] -> [a] -> [a]
++ (DataDefinition -> Maybe (QDefinition Expr))
-> [DataDefinition] -> [QDefinition Expr]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe DataDefinition -> Maybe (QDefinition Expr)
qdEFromDD [DataDefinition]
ddefs) [Const] -> [Const] -> [Const]
forall a. Eq a => [a] -> [a] -> [a]
\\ [Const]
derived)
        [Const] -> [Const] -> [Const]
forall a. [a] -> [a] -> [a]
++ Maybe ODE -> [Const]
mapODE ([ExtLib] -> Maybe ODE
getODE ([ExtLib] -> Maybe ODE) -> [ExtLib] -> Maybe ODE
forall a b. (a -> b) -> a -> b
$ Choices -> [ExtLib]
extLibs Choices
chs)
        [Const] -> [Const] -> [Const]
forall a. [a] -> [a] -> [a]
++ (QDefinition Expr -> Const) -> [QDefinition Expr] -> [Const]
forall a b. (a -> b) -> [a] -> [b]
map QDefinition Expr -> Const
forall (q :: * -> *).
(Quantity (q Expr), MayHaveUnit (q Expr), DefiningExpr q,
 Concept (q Expr)) =>
q Expr -> Const
qtoc (Choices -> [QDefinition Expr]
handWiredDefs Choices
chs)
      -- TODO: When we have better DEModels, we should be deriving our ODE information
      --       directly from the instance models (ims) instead of directly from the choices.
      outs' :: [CodeVarChunk]
outs' = (i -> CodeVarChunk) -> [i] -> [CodeVarChunk]
forall a b. (a -> b) -> [a] -> [b]
map i -> CodeVarChunk
forall c.
(Quantity c, MayHaveUnit c, Concept c) =>
c -> CodeVarChunk
quantvar [i]
outs
      allInputs :: [CodeVarChunk]
allInputs = [CodeVarChunk] -> [CodeVarChunk]
forall a. Eq a => [a] -> [a]
nub ([CodeVarChunk] -> [CodeVarChunk])
-> [CodeVarChunk] -> [CodeVarChunk]
forall a b. (a -> b) -> a -> b
$ [CodeVarChunk]
inputs' [CodeVarChunk] -> [CodeVarChunk] -> [CodeVarChunk]
forall a. [a] -> [a] -> [a]
++ (Const -> CodeVarChunk) -> [Const] -> [CodeVarChunk]
forall a b. (a -> b) -> [a] -> [b]
map Const -> CodeVarChunk
forall c.
(Quantity c, MayHaveUnit c, Concept c) =>
c -> CodeVarChunk
quantvar [Const]
derived
      exOrder :: [Const]
exOrder = [Const] -> [CodeVarChunk] -> [CodeVarChunk] -> ChunkDB -> [Const]
solveExecOrder [Const]
rels ([CodeVarChunk]
allInputs [CodeVarChunk] -> [CodeVarChunk] -> [CodeVarChunk]
forall a. [a] -> [a] -> [a]
++ (ConstQDef -> CodeVarChunk) -> [ConstQDef] -> [CodeVarChunk]
forall a b. (a -> b) -> [a] -> [b]
map ConstQDef -> CodeVarChunk
forall c.
(Quantity c, MayHaveUnit c, Concept c) =>
c -> CodeVarChunk
quantvar [ConstQDef]
cnsts) [CodeVarChunk]
outs' ChunkDB
db
  in OldCodeSpec {
        _pName :: Name
_pName = Name
n,
        _authors :: People
_authors = SmithEtAlSRS
sys SmithEtAlSRS -> Getting People SmithEtAlSRS People -> People
forall s a. s -> Getting a s a -> a
^. Getting People SmithEtAlSRS People
forall c. HasSystemMeta c => Lens' c People
Lens' SmithEtAlSRS People
authors,
        _inputs :: [CodeVarChunk]
_inputs = [CodeVarChunk]
allInputs,
        _extInputs :: [CodeVarChunk]
_extInputs = [CodeVarChunk]
inputs',
        _derivedInputs :: [Const]
_derivedInputs = [Const]
derived,
        _outputs :: [CodeVarChunk]
_outputs = [CodeVarChunk]
outs',
        _configFiles :: [RelativeFile]
_configFiles = Choices -> [RelativeFile]
defaultConfigFiles Choices
chs,
        _execOrder :: [Const]
_execOrder = [Const]
exOrder,
        _cMap :: ConstraintCEMap
_cMap = [j] -> ConstraintCEMap
forall c. (HasUID c, Constrained c) => [c] -> ConstraintCEMap
constraintMap [j]
cs,
        _constants :: [Const]
_constants = [Const]
const',
        _constMap :: ConstantMap
_constMap = [Const] -> ConstantMap
forall a. HasUID a => [a] -> Map UID a
assocToMap [Const]
const',
        _mods :: [Mod]
_mods = Choices -> [Mod]
extraMods Choices
chs,
        _systemdb :: ChunkDB
_systemdb = ChunkDB
db
      }

-- medium hacks ---

-- | Convert a 'Func' to an implementation-stage 'DefinedQuantityDict' representing the
-- function.
asVC :: Func -> DefinedQuantityDict
asVC :: Func -> DefinedQuantityDict
asVC (FDef (FuncDef Name
n Name
d [ParameterChunk]
_ Space
_ Maybe Name
_ [FuncStmt]
_)) = ConceptChunk -> Symbol -> Space -> DefinedQuantityDict
dqdNoUnit (Name -> NP -> Name -> ConceptChunk
dcc Name
n (Name -> NP
nounPhraseSP Name
n) Name
d) (Name -> Symbol
Variable Name
n) Space
Real
asVC (FDef (CtorDef Name
n Name
d [ParameterChunk]
_ [Initializer]
_ [FuncStmt]
_))   = ConceptChunk -> Symbol -> Space -> DefinedQuantityDict
dqdNoUnit (Name -> NP -> Name -> ConceptChunk
dcc Name
n (Name -> NP
nounPhraseSP Name
n) Name
d) (Name -> Symbol
Variable Name
n) Space
Real
asVC (FData (FuncData Name
n Name
d DataDesc
_))     = ConceptChunk -> Symbol -> Space -> DefinedQuantityDict
dqdNoUnit (Name -> NP -> Name -> ConceptChunk
dcc Name
n (Name -> NP
nounPhraseSP Name
n) Name
d) (Name -> Symbol
Variable Name
n) Space
Real

-- | Get a 'UID' of a chunk corresponding to a 'Func'.
funcUID :: Func -> UID
funcUID :: Func -> UID
funcUID Func
f = Func -> DefinedQuantityDict
asVC Func
f DefinedQuantityDict -> Getting UID DefinedQuantityDict UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID DefinedQuantityDict UID
forall c. HasUID c => Getter c UID
Getter DefinedQuantityDict UID
uid

-- | Determines the derived inputs, which can be immediately calculated from the
-- knowns (inputs and constants). If there are DDs, the derived inputs will
-- come from those. If there are none, then the 'QDefinition's are used instead.
getDerivedInputs :: [DataDefinition] -> [Input] -> [Const] ->
  ChunkDB -> [SimpleQDef]
getDerivedInputs :: [DataDefinition]
-> [CodeVarChunk] -> [Const] -> ChunkDB -> [QDefinition Expr]
getDerivedInputs [DataDefinition]
ddefs [CodeVarChunk]
ins [Const]
cnsts ChunkDB
sm =
  (QDefinition Expr -> Bool)
-> [QDefinition Expr] -> [QDefinition Expr]
forall a. (a -> Bool) -> [a] -> [a]
filter (([CodeVarChunk] -> [CodeVarChunk] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`subsetOf` [CodeVarChunk]
refSet) ([CodeVarChunk] -> Bool)
-> (QDefinition Expr -> [CodeVarChunk]) -> QDefinition Expr -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CodeExpr -> ChunkDB -> [CodeVarChunk])
-> ChunkDB -> CodeExpr -> [CodeVarChunk]
forall a b c. (a -> b -> c) -> b -> a -> c
flip CodeExpr -> ChunkDB -> [CodeVarChunk]
codevars ChunkDB
sm (CodeExpr -> [CodeVarChunk])
-> (QDefinition Expr -> CodeExpr)
-> QDefinition Expr
-> [CodeVarChunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr -> CodeExpr
expr (Expr -> CodeExpr)
-> (QDefinition Expr -> Expr) -> QDefinition Expr -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (QDefinition Expr -> Getting Expr (QDefinition Expr) Expr -> Expr
forall s a. s -> Getting a s a -> a
^. Getting Expr (QDefinition Expr) Expr
forall e. Lens' (QDefinition e) e
forall (c :: * -> *) e. DefiningExpr c => Lens' (c e) e
defnExpr)) ((DataDefinition -> Maybe (QDefinition Expr))
-> [DataDefinition] -> [QDefinition Expr]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe DataDefinition -> Maybe (QDefinition Expr)
qdEFromDD [DataDefinition]
ddefs)
  where refSet :: [CodeVarChunk]
refSet = [CodeVarChunk]
ins [CodeVarChunk] -> [CodeVarChunk] -> [CodeVarChunk]
forall a. [a] -> [a] -> [a]
++ (Const -> CodeVarChunk) -> [Const] -> [CodeVarChunk]
forall a b. (a -> b) -> [a] -> [b]
map Const -> CodeVarChunk
forall c.
(Quantity c, MayHaveUnit c, Concept c) =>
c -> CodeVarChunk
quantvar [Const]
cnsts

-- | Get a list of 'Constraint's for a list of 'CodeChunk's.
getConstraints :: (HasUID c) => ConstraintCEMap -> [c] -> [ConstraintCE]
getConstraints :: forall c. HasUID c => ConstraintCEMap -> [c] -> [ConstraintCE]
getConstraints ConstraintCEMap
cm [c]
cs = [[ConstraintCE]] -> [ConstraintCE]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[ConstraintCE]] -> [ConstraintCE])
-> [[ConstraintCE]] -> [ConstraintCE]
forall a b. (a -> b) -> a -> b
$ (c -> Maybe [ConstraintCE]) -> [c] -> [[ConstraintCE]]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (\c
c -> UID -> ConstraintCEMap -> Maybe [ConstraintCE]
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (c
c c -> Getting UID c UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID c UID
forall c. HasUID c => Getter c UID
Getter c UID
uid) ConstraintCEMap
cm) [c]
cs

-- | Get a list of 'CodeChunk's from a constraint.
constraintvars :: ConstraintCE -> ChunkDB -> [CodeChunk]
constraintvars :: ConstraintCE -> ChunkDB -> [CodeChunk]
constraintvars (Range ConstraintReason
_ RealInterval CodeExpr CodeExpr
ri) ChunkDB
m =
  (UID -> CodeChunk) -> [UID] -> [CodeChunk]
forall a b. (a -> b) -> [a] -> [b]
map (CodeVarChunk -> CodeChunk
forall c. CodeIdea c => c -> CodeChunk
codeChunk (CodeVarChunk -> CodeChunk)
-> (UID -> CodeVarChunk) -> UID -> CodeChunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ChunkDB -> UID -> CodeVarChunk
varResolve ChunkDB
m) ([UID] -> [CodeChunk]) -> [UID] -> [CodeChunk]
forall a b. (a -> b) -> a -> b
$ [UID] -> [UID]
forall a. Eq a => [a] -> [a]
nub ([UID] -> [UID]) -> [UID] -> [UID]
forall a b. (a -> b) -> a -> b
$ RealInterval CodeExpr CodeExpr -> [UID]
eNamesRI RealInterval CodeExpr CodeExpr
ri
constraintvars (Elem ConstraintReason
_ CodeExpr
ri) ChunkDB
m =
  (UID -> CodeChunk) -> [UID] -> [CodeChunk]
forall a b. (a -> b) -> [a] -> [b]
map (CodeVarChunk -> CodeChunk
forall c. CodeIdea c => c -> CodeChunk
codeChunk (CodeVarChunk -> CodeChunk)
-> (UID -> CodeVarChunk) -> UID -> CodeChunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ChunkDB -> UID -> CodeVarChunk
varResolve ChunkDB
m) ([UID] -> [CodeChunk]) -> [UID] -> [CodeChunk]
forall a b. (a -> b) -> a -> b
$ CodeExpr -> [UID]
eDep CodeExpr
ri