{-# LANGUAGE LambdaCase #-}
-- | Defines a language for specifying external library use scenarios
module Language.Drasil.Code.ExternalLibrary (ExternalLibrary, Step(..), 
  FunctionInterface(..), Result(..), Argument(..), ArgumentInfo(..), 
  Parameter(..), ClassInfo(..), MethodInfo(..), FuncType(..), externalLib, 
  choiceSteps, choiceStep, mandatoryStep, mandatorySteps, callStep, 
  libFunction, libMethod, libFunctionWithResult, libMethodWithResult, 
  libConstructor, libConstructorMultiReqs, constructAndReturn, lockedArg, 
  lockedNamedArg, inlineArg, inlineNamedArg, preDefinedArg, preDefinedNamedArg, 
  functionArg, customObjArg, recordArg, lockedParam, unnamedParam, customClass, 
  implementation, constructorInfo, methodInfo, methodInfoNoReturn, 
  appendCurrSol, populateSolList, assignArrayIndex, assignSolFromObj, 
  initSolListFromArray, initSolListWithVal, solveAndPopulateWhile, 
  returnExprList, fixedReturn, initSolWithVal
) where

import Language.Drasil (Space, HasSpace(typ))
import Language.Drasil.Chunk.Code (CodeVarChunk, CodeFuncChunk, codeName)
import Language.Drasil.Chunk.Parameter (ParameterChunk, pcAuto)
import Language.Drasil.Chunk.NamedArgument (NamedArgument)
import Language.Drasil.Code.Expr.Development
import Language.Drasil.CodeExpr
import Language.Drasil.Mod (FuncStmt(..), Description)

import Control.Lens ((^.))
import Data.List.NonEmpty (NonEmpty(..), fromList)

-- | Condition for loops.
type Condition = CodeExpr

-- | Function require
type Requires = String

-- | External library is a group of 'Step's
type ExternalLibrary = [StepGroup]

-- | Function steps.
type StepGroup = NonEmpty [Step]

-- | A step can be a call to an external library function or method.
data Step = Call FunctionInterface 
  -- | A while loop.
  -- The function calls in the condition, other conditions, and steps for the body of the loop.
  | Loop (NonEmpty FunctionInterface) ([CodeExpr] -> Condition) (NonEmpty Step)
  -- For when a statement is needed, but does not interface with the external library.
  | Statement ([CodeVarChunk] -> [CodeExpr] -> FuncStmt)

-- | The first item in the 'Requires' list should be where the function being called is defined.
data FunctionInterface = FI (NonEmpty Requires) FuncType CodeFuncChunk [Argument] (Maybe Result)

-- | The result of a function call can be assigned to a variable or returned.
data Result = Assign CodeVarChunk | Return

-- | An argument may contain a named argument and argument information.
data Argument = Arg (Maybe NamedArgument) ArgumentInfo -- Maybe named argument

-- | Determines the context needed for an argument to work.
data ArgumentInfo = 
  -- | An argument not dependent on use case.
  LockedArg CodeExpr 
  -- | An argument dependent on the use case. Maybe is the variable if it needs
  --   to be declared and defined prior to calling.
  | Basic Space (Maybe CodeVarChunk) 
  -- | A function-type argument, with a single 'Step' for the body.
  | Fn CodeFuncChunk [Parameter] Step
  -- | An argument that is an object of a class that must be implemented in the 
  --   calling program.
  --   Parameters: Requires, description, object, constructor, class info.
  | Class [Requires] Description CodeVarChunk CodeFuncChunk ClassInfo
  -- | An argument that is an object of a record class defined by the external
  --   library, where some fields need to be set by the calling program.
  --   Parameters: Requires, constructor, object, fields. 
  --   First Require should be where the record type is defined.
  | Record (NonEmpty Requires) CodeFuncChunk CodeVarChunk [CodeVarChunk]

-- | Function parameter may or may not be dependent on use case.
data Parameter = LockedParam ParameterChunk | NameableParam Space

-- | For classes that need to be generated in the calling program. May be a
--   regular class or a class that implements an interface from the external
--   library.
data ClassInfo = Regular [MethodInfo] | Implements String [MethodInfo]

-- | Constructor: description, known parameters, body. (CodeFuncChunk for constructor is not here because it is higher up in the AST, at the 'Class' node).
data MethodInfo = CI Description [Parameter] [Step]
  -- | Method, description, known parameters, maybe return description, body.
  | MI CodeFuncChunk Description [Parameter] (Maybe Description) (NonEmpty Step)

-- | Function type may be a function, a method, or a constructor.
data FuncType = Function | Method CodeVarChunk | Constructor

-- | Specifies an external library.
externalLib :: [StepGroup] -> ExternalLibrary
externalLib :: [StepGroup] -> [StepGroup]
externalLib = [StepGroup] -> [StepGroup]
forall a. a -> a
id

-- | To be used when there are multiple options for a group of consecutive steps, 
--   where a single use-case-specific factor decides which step group to use.
choiceSteps :: [[Step]] -> StepGroup
choiceSteps :: [[Step]] -> StepGroup
choiceSteps [] = [Char] -> StepGroup
forall a. HasCallStack => [Char] -> a
error "choiceSteps should be called with a non-empty list"
choiceSteps sg :: [[Step]]
sg = [[Step]] -> StepGroup
forall a. [a] -> NonEmpty a
fromList [[Step]]
sg

-- | To be used when there are multiple options for a single step, where a 
--   use-case-specific factor decides which step to use.
choiceStep :: [Step] -> StepGroup
choiceStep :: [Step] -> StepGroup
choiceStep [] = [Char] -> StepGroup
forall a. HasCallStack => [Char] -> a
error "choiceStep should be called with a non-empty list"
choiceStep ss :: [Step]
ss = [[Step]] -> StepGroup
forall a. [a] -> NonEmpty a
fromList ([[Step]] -> StepGroup) -> [[Step]] -> StepGroup
forall a b. (a -> b) -> a -> b
$ (Step -> [Step]) -> [Step] -> [[Step]]
forall a b. (a -> b) -> [a] -> [b]
map (Step -> [Step] -> [Step]
forall a. a -> [a] -> [a]
: []) [Step]
ss

-- | Specifies a step which must exist in some form in every use case.
mandatoryStep :: Step -> StepGroup
mandatoryStep :: Step -> StepGroup
mandatoryStep f :: Step
f = [Step
f] [Step] -> [[Step]] -> StepGroup
forall a. a -> [a] -> NonEmpty a
:| []

-- | Specifies multiple consecutive steps that all must exist in some form in 
--   every use case.
mandatorySteps :: [Step] -> StepGroup
mandatorySteps :: [Step] -> StepGroup
mandatorySteps fs :: [Step]
fs = [Step]
fs [Step] -> [[Step]] -> StepGroup
forall a. a -> [a] -> NonEmpty a
:| []

-- Specifies a step that includes a call to an external library function or method.
callStep :: FunctionInterface -> Step
callStep :: FunctionInterface -> Step
callStep = FunctionInterface -> Step
Call

-- | Specifies a step where an external library function or method is called in a 
--   while-loop condition and in the loop body.
loopStep :: [FunctionInterface] -> ([CodeExpr] -> Condition) -> [Step] -> Step
loopStep :: [FunctionInterface] -> ([CodeExpr] -> CodeExpr) -> [Step] -> Step
loopStep [] _ _ = [Char] -> Step
forall a. HasCallStack => [Char] -> a
error "loopStep should be called with a non-empty list of FunctionInterface"
loopStep _ _ [] = [Char] -> Step
forall a. HasCallStack => [Char] -> a
error "loopStep should be called with a non-empty list of Step"
loopStep fis :: [FunctionInterface]
fis c :: [CodeExpr] -> CodeExpr
c ss :: [Step]
ss = NonEmpty FunctionInterface
-> ([CodeExpr] -> CodeExpr) -> NonEmpty Step -> Step
Loop ([FunctionInterface] -> NonEmpty FunctionInterface
forall a. [a] -> NonEmpty a
fromList [FunctionInterface]
fis) [CodeExpr] -> CodeExpr
c ([Step] -> NonEmpty Step
forall a. [a] -> NonEmpty a
fromList [Step]
ss)

-- | Specifies a call to an external library function.
libFunction :: Requires -> CodeFuncChunk -> [Argument] -> FunctionInterface
libFunction :: [Char] -> CodeFuncChunk -> [Argument] -> FunctionInterface
libFunction rq :: [Char]
rq f :: CodeFuncChunk
f ps :: [Argument]
ps = NonEmpty [Char]
-> FuncType
-> CodeFuncChunk
-> [Argument]
-> Maybe Result
-> FunctionInterface
FI ([Char]
rq [Char] -> [[Char]] -> NonEmpty [Char]
forall a. a -> [a] -> NonEmpty a
:| []) FuncType
Function CodeFuncChunk
f [Argument]
ps Maybe Result
forall a. Maybe a
Nothing

-- | Specifies a call to an external library method.
libMethod :: Requires -> CodeVarChunk -> CodeFuncChunk -> [Argument] -> 
  FunctionInterface
libMethod :: [Char]
-> CodeVarChunk -> CodeFuncChunk -> [Argument] -> FunctionInterface
libMethod rq :: [Char]
rq o :: CodeVarChunk
o m :: CodeFuncChunk
m ps :: [Argument]
ps = NonEmpty [Char]
-> FuncType
-> CodeFuncChunk
-> [Argument]
-> Maybe Result
-> FunctionInterface
FI ([Char]
rq [Char] -> [[Char]] -> NonEmpty [Char]
forall a. a -> [a] -> NonEmpty a
:| []) (CodeVarChunk -> FuncType
Method CodeVarChunk
o) CodeFuncChunk
m [Argument]
ps Maybe Result
forall a. Maybe a
Nothing

-- | Specifies a call to an external library function, where the result is 
--   assigned to a variable.
libFunctionWithResult :: Requires -> CodeFuncChunk -> [Argument] -> 
  CodeVarChunk -> FunctionInterface
libFunctionWithResult :: [Char]
-> CodeFuncChunk -> [Argument] -> CodeVarChunk -> FunctionInterface
libFunctionWithResult rq :: [Char]
rq f :: CodeFuncChunk
f ps :: [Argument]
ps r :: CodeVarChunk
r = NonEmpty [Char]
-> FuncType
-> CodeFuncChunk
-> [Argument]
-> Maybe Result
-> FunctionInterface
FI ([Char]
rq [Char] -> [[Char]] -> NonEmpty [Char]
forall a. a -> [a] -> NonEmpty a
:| []) FuncType
Function CodeFuncChunk
f [Argument]
ps (Result -> Maybe Result
forall a. a -> Maybe a
Just (Result -> Maybe Result) -> Result -> Maybe Result
forall a b. (a -> b) -> a -> b
$ CodeVarChunk -> Result
Assign CodeVarChunk
r)

-- | Specifies a call to an external library method, where the result is 
--   assigned to a variable.
libMethodWithResult :: Requires -> CodeVarChunk -> CodeFuncChunk -> [Argument] 
  -> CodeVarChunk -> FunctionInterface
libMethodWithResult :: [Char]
-> CodeVarChunk
-> CodeFuncChunk
-> [Argument]
-> CodeVarChunk
-> FunctionInterface
libMethodWithResult rq :: [Char]
rq o :: CodeVarChunk
o m :: CodeFuncChunk
m ps :: [Argument]
ps r :: CodeVarChunk
r = NonEmpty [Char]
-> FuncType
-> CodeFuncChunk
-> [Argument]
-> Maybe Result
-> FunctionInterface
FI ([Char]
rq [Char] -> [[Char]] -> NonEmpty [Char]
forall a. a -> [a] -> NonEmpty a
:| []) (CodeVarChunk -> FuncType
Method CodeVarChunk
o) CodeFuncChunk
m [Argument]
ps (Result -> Maybe Result
forall a. a -> Maybe a
Just (Result -> Maybe Result) -> Result -> Maybe Result
forall a b. (a -> b) -> a -> b
$ CodeVarChunk -> Result
Assign CodeVarChunk
r)

-- | Specifies a call to an external library constructor, where the result is 
--   assigned to a variable.
libConstructor :: Requires -> CodeFuncChunk -> [Argument] -> CodeVarChunk -> 
  FunctionInterface
libConstructor :: [Char]
-> CodeFuncChunk -> [Argument] -> CodeVarChunk -> FunctionInterface
libConstructor rq :: [Char]
rq c :: CodeFuncChunk
c as :: [Argument]
as r :: CodeVarChunk
r = NonEmpty [Char]
-> FuncType
-> CodeFuncChunk
-> [Argument]
-> Maybe Result
-> FunctionInterface
FI ([Char]
rq [Char] -> [[Char]] -> NonEmpty [Char]
forall a. a -> [a] -> NonEmpty a
:| []) FuncType
Constructor CodeFuncChunk
c [Argument]
as (Result -> Maybe Result
forall a. a -> Maybe a
Just (Result -> Maybe Result) -> Result -> Maybe Result
forall a b. (a -> b) -> a -> b
$ CodeVarChunk -> Result
Assign CodeVarChunk
r)

-- | Specifies a call to an external library function, where multiple modules from
--   the external library are required, and the result is assigned to a variable.
libConstructorMultiReqs :: [Requires] -> CodeFuncChunk -> [Argument] -> 
  CodeVarChunk -> FunctionInterface
libConstructorMultiReqs :: [[Char]]
-> CodeFuncChunk -> [Argument] -> CodeVarChunk -> FunctionInterface
libConstructorMultiReqs [] _ _ _ = [Char] -> FunctionInterface
forall a. HasCallStack => [Char] -> a
error ([Char] -> FunctionInterface) -> [Char] -> FunctionInterface
forall a b. (a -> b) -> a -> b
$ "libConstructorMultiReqs should" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
  " be called with a non-empty list of Requires"
libConstructorMultiReqs rqs :: [[Char]]
rqs c :: CodeFuncChunk
c as :: [Argument]
as r :: CodeVarChunk
r = NonEmpty [Char]
-> FuncType
-> CodeFuncChunk
-> [Argument]
-> Maybe Result
-> FunctionInterface
FI ([[Char]] -> NonEmpty [Char]
forall a. [a] -> NonEmpty a
fromList [[Char]]
rqs) FuncType
Constructor CodeFuncChunk
c [Argument]
as 
  (Result -> Maybe Result
forall a. a -> Maybe a
Just (Result -> Maybe Result) -> Result -> Maybe Result
forall a b. (a -> b) -> a -> b
$ CodeVarChunk -> Result
Assign CodeVarChunk
r)

-- | Specifies a call to an external library constructor, where the result is returned.
constructAndReturn :: Requires -> CodeFuncChunk -> [Argument] -> 
  FunctionInterface
constructAndReturn :: [Char] -> CodeFuncChunk -> [Argument] -> FunctionInterface
constructAndReturn rq :: [Char]
rq c :: CodeFuncChunk
c as :: [Argument]
as = NonEmpty [Char]
-> FuncType
-> CodeFuncChunk
-> [Argument]
-> Maybe Result
-> FunctionInterface
FI ([Char]
rq [Char] -> [[Char]] -> NonEmpty [Char]
forall a. a -> [a] -> NonEmpty a
:| []) FuncType
Constructor CodeFuncChunk
c [Argument]
as (Result -> Maybe Result
forall a. a -> Maybe a
Just Result
Return)

-- | Specifies an argument that is not use-case-dependent.
lockedArg :: CodeExpr -> Argument
lockedArg :: CodeExpr -> Argument
lockedArg = Maybe NamedArgument -> ArgumentInfo -> Argument
Arg Maybe NamedArgument
forall a. Maybe a
Nothing (ArgumentInfo -> Argument)
-> (CodeExpr -> ArgumentInfo) -> CodeExpr -> Argument
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CodeExpr -> ArgumentInfo
LockedArg

-- | Specifies a named argument that is not use-case-dependent.
lockedNamedArg :: NamedArgument -> CodeExpr -> Argument
lockedNamedArg :: NamedArgument -> CodeExpr -> Argument
lockedNamedArg n :: NamedArgument
n = Maybe NamedArgument -> ArgumentInfo -> Argument
Arg (NamedArgument -> Maybe NamedArgument
forall a. a -> Maybe a
Just NamedArgument
n) (ArgumentInfo -> Argument)
-> (CodeExpr -> ArgumentInfo) -> CodeExpr -> Argument
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CodeExpr -> ArgumentInfo
LockedArg

-- | Specifies a use-case-dependent argument whose value can be inlined in the 
--   call.
inlineArg :: Space -> Argument
inlineArg :: Space -> Argument
inlineArg t :: Space
t = Maybe NamedArgument -> ArgumentInfo -> Argument
Arg Maybe NamedArgument
forall a. Maybe a
Nothing (ArgumentInfo -> Argument) -> ArgumentInfo -> Argument
forall a b. (a -> b) -> a -> b
$ Space -> Maybe CodeVarChunk -> ArgumentInfo
Basic Space
t Maybe CodeVarChunk
forall a. Maybe a
Nothing

-- | Specifies a use-case-dependent named argument whose value can be inlined in 
--   the call.
inlineNamedArg :: NamedArgument ->  Space -> Argument
inlineNamedArg :: NamedArgument -> Space -> Argument
inlineNamedArg n :: NamedArgument
n t :: Space
t = Maybe NamedArgument -> ArgumentInfo -> Argument
Arg (NamedArgument -> Maybe NamedArgument
forall a. a -> Maybe a
Just NamedArgument
n) (ArgumentInfo -> Argument) -> ArgumentInfo -> Argument
forall a b. (a -> b) -> a -> b
$ Space -> Maybe CodeVarChunk -> ArgumentInfo
Basic Space
t Maybe CodeVarChunk
forall a. Maybe a
Nothing

-- | Specifies use-case-dependent argument whose value must be assigned to a 
--   variable before being passed in the call.
preDefinedArg :: CodeVarChunk -> Argument
preDefinedArg :: CodeVarChunk -> Argument
preDefinedArg v :: CodeVarChunk
v = Maybe NamedArgument -> ArgumentInfo -> Argument
Arg Maybe NamedArgument
forall a. Maybe a
Nothing (ArgumentInfo -> Argument) -> ArgumentInfo -> Argument
forall a b. (a -> b) -> a -> b
$ Space -> Maybe CodeVarChunk -> ArgumentInfo
Basic (CodeVarChunk
v CodeVarChunk -> Getting Space CodeVarChunk Space -> Space
forall s a. s -> Getting a s a -> a
^. Getting Space CodeVarChunk Space
forall c. HasSpace c => Lens' c Space
typ) (CodeVarChunk -> Maybe CodeVarChunk
forall a. a -> Maybe a
Just CodeVarChunk
v)

-- | Specifies use-case-dependent named argument whose value must be assigned to 
--   a variable before being passed in the call.
preDefinedNamedArg :: NamedArgument -> CodeVarChunk -> Argument
preDefinedNamedArg :: NamedArgument -> CodeVarChunk -> Argument
preDefinedNamedArg n :: NamedArgument
n v :: CodeVarChunk
v = Maybe NamedArgument -> ArgumentInfo -> Argument
Arg (NamedArgument -> Maybe NamedArgument
forall a. a -> Maybe a
Just NamedArgument
n) (ArgumentInfo -> Argument) -> ArgumentInfo -> Argument
forall a b. (a -> b) -> a -> b
$ Space -> Maybe CodeVarChunk -> ArgumentInfo
Basic (CodeVarChunk
v CodeVarChunk -> Getting Space CodeVarChunk Space -> Space
forall s a. s -> Getting a s a -> a
^. Getting Space CodeVarChunk Space
forall c. HasSpace c => Lens' c Space
typ) (CodeVarChunk -> Maybe CodeVarChunk
forall a. a -> Maybe a
Just CodeVarChunk
v)

-- | Specifies a function type argument, where the body consists of a single step.
functionArg :: CodeFuncChunk -> [Parameter] -> Step -> Argument
functionArg :: CodeFuncChunk -> [Parameter] -> Step -> Argument
functionArg f :: CodeFuncChunk
f ps :: [Parameter]
ps b :: Step
b = Maybe NamedArgument -> ArgumentInfo -> Argument
Arg Maybe NamedArgument
forall a. Maybe a
Nothing (CodeFuncChunk -> [Parameter] -> Step -> ArgumentInfo
Fn CodeFuncChunk
f [Parameter]
ps Step
b)

-- | Specifies an argument that is an object of a class that must be defined in 
--   the calling program.
customObjArg :: [Requires] -> Description -> CodeVarChunk -> CodeFuncChunk -> 
  ClassInfo -> Argument
customObjArg :: [[Char]]
-> [Char] -> CodeVarChunk -> CodeFuncChunk -> ClassInfo -> Argument
customObjArg rs :: [[Char]]
rs d :: [Char]
d o :: CodeVarChunk
o c :: CodeFuncChunk
c ci :: ClassInfo
ci = Maybe NamedArgument -> ArgumentInfo -> Argument
Arg Maybe NamedArgument
forall a. Maybe a
Nothing ([[Char]]
-> [Char]
-> CodeVarChunk
-> CodeFuncChunk
-> ClassInfo
-> ArgumentInfo
Class [[Char]]
rs [Char]
d CodeVarChunk
o CodeFuncChunk
c ClassInfo
ci)

-- | Specifies an argument that is an object of a class from the external library.
--   The list of [CodeVarChunk] represents fields of the object that must be set 
--   in the calling program.
recordArg :: Requires -> CodeFuncChunk -> CodeVarChunk -> [CodeVarChunk] -> 
  Argument
recordArg :: [Char]
-> CodeFuncChunk -> CodeVarChunk -> [CodeVarChunk] -> Argument
recordArg rq :: [Char]
rq c :: CodeFuncChunk
c o :: CodeVarChunk
o fs :: [CodeVarChunk]
fs = Maybe NamedArgument -> ArgumentInfo -> Argument
Arg Maybe NamedArgument
forall a. Maybe a
Nothing (NonEmpty [Char]
-> CodeFuncChunk -> CodeVarChunk -> [CodeVarChunk] -> ArgumentInfo
Record ([Char]
rq [Char] -> [[Char]] -> NonEmpty [Char]
forall a. a -> [a] -> NonEmpty a
:| []) CodeFuncChunk
c CodeVarChunk
o [CodeVarChunk]
fs)

-- | Specifies a use-case-independent parameter.
lockedParam :: CodeVarChunk -> Parameter
lockedParam :: CodeVarChunk -> Parameter
lockedParam = ParameterChunk -> Parameter
LockedParam (ParameterChunk -> Parameter)
-> (CodeVarChunk -> ParameterChunk) -> CodeVarChunk -> Parameter
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CodeVarChunk -> ParameterChunk
forall c. CodeIdea c => c -> ParameterChunk
pcAuto

-- | Specifies a parameter whose name depends on the use case.
unnamedParam :: Space -> Parameter
unnamedParam :: Space -> Parameter
unnamedParam = Space -> Parameter
NameableParam

-- | Specifies a class that must be implemented in the calling program.
customClass :: [MethodInfo] -> ClassInfo
customClass :: [MethodInfo] -> ClassInfo
customClass = [MethodInfo] -> ClassInfo
Regular

-- | Specifies an implementation of an interface from the external library.
implementation :: String -> [MethodInfo] -> ClassInfo
implementation :: [Char] -> [MethodInfo] -> ClassInfo
implementation = [Char] -> [MethodInfo] -> ClassInfo
Implements

-- | Specifies a constructor.
constructorInfo :: CodeFuncChunk -> [Parameter] -> [Step] -> MethodInfo
constructorInfo :: CodeFuncChunk -> [Parameter] -> [Step] -> MethodInfo
constructorInfo c :: CodeFuncChunk
c = [Char] -> [Parameter] -> [Step] -> MethodInfo
CI ("Constructor for " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ CodeFuncChunk -> [Char]
forall c. CodeIdea c => c -> [Char]
codeName CodeFuncChunk
c [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ " objects")

-- | Specifies a method.
methodInfo :: CodeFuncChunk -> Description -> [Parameter] -> Description -> 
  [Step] -> MethodInfo
methodInfo :: CodeFuncChunk
-> [Char] -> [Parameter] -> [Char] -> [Step] -> MethodInfo
methodInfo _ _ _ _ [] = [Char] -> MethodInfo
forall a. HasCallStack => [Char] -> a
error "methodInfo should be called with a non-empty list of Step"
methodInfo m :: CodeFuncChunk
m d :: [Char]
d ps :: [Parameter]
ps rd :: [Char]
rd ss :: [Step]
ss = CodeFuncChunk
-> [Char]
-> [Parameter]
-> Maybe [Char]
-> NonEmpty Step
-> MethodInfo
MI CodeFuncChunk
m [Char]
d [Parameter]
ps ([Char] -> Maybe [Char]
forall a. a -> Maybe a
Just [Char]
rd) ([Step] -> NonEmpty Step
forall a. [a] -> NonEmpty a
fromList [Step]
ss)

-- | Specifies a method that does not return anything.
methodInfoNoReturn :: CodeFuncChunk -> Description -> [Parameter] -> [Step] -> 
  MethodInfo
methodInfoNoReturn :: CodeFuncChunk -> [Char] -> [Parameter] -> [Step] -> MethodInfo
methodInfoNoReturn _ _ _ [] = [Char] -> MethodInfo
forall a. HasCallStack => [Char] -> a
error "methodInfoNoReturn should be called with a non-empty list of Step"
methodInfoNoReturn m :: CodeFuncChunk
m d :: [Char]
d ps :: [Parameter]
ps ss :: [Step]
ss = CodeFuncChunk
-> [Char]
-> [Parameter]
-> Maybe [Char]
-> NonEmpty Step
-> MethodInfo
MI CodeFuncChunk
m [Char]
d [Parameter]
ps Maybe [Char]
forall a. Maybe a
Nothing ([Step] -> NonEmpty Step
forall a. [a] -> NonEmpty a
fromList [Step]
ss)

-- | Specifies a statement where a current solution is appended to a solution list.
appendCurrSol :: CodeExpr -> Step
appendCurrSol :: CodeExpr -> Step
appendCurrSol curr :: CodeExpr
curr = ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep (\cdchs :: [CodeVarChunk]
cdchs es :: [CodeExpr]
es -> case ([CodeVarChunk]
cdchs, [CodeExpr]
es) of
    ([s :: CodeVarChunk
s], []) -> CodeExpr -> CodeVarChunk -> FuncStmt
appendCurrSolFS CodeExpr
curr CodeVarChunk
s
    (_,_) -> [Char] -> FuncStmt
forall a. HasCallStack => [Char] -> a
error "Fill for appendCurrSol should provide one CodeChunk and no Exprs")
  
-- | Specifies a statement where a solution list is populated by iterating 
--   through a solution array.
populateSolList :: CodeVarChunk -> CodeVarChunk -> CodeVarChunk -> [Step]
populateSolList :: CodeVarChunk -> CodeVarChunk -> CodeVarChunk -> [Step]
populateSolList arr :: CodeVarChunk
arr el :: CodeVarChunk
el fld :: CodeVarChunk
fld = [([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep (\cdchs :: [CodeVarChunk]
cdchs es :: [CodeExpr]
es -> case ([CodeVarChunk]
cdchs, [CodeExpr]
es) of
    ([s :: CodeVarChunk
s], []) -> CodeVarChunk -> CodeExpr -> FuncStmt
FAsg CodeVarChunk
s ([[CodeExpr]] -> CodeExpr
Matrix [[]])
    (_,_) -> [Char] -> FuncStmt
forall a. HasCallStack => [Char] -> a
error [Char]
popErr),
  ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep (\cdchs :: [CodeVarChunk]
cdchs es :: [CodeExpr]
es -> case ([CodeVarChunk]
cdchs, [CodeExpr]
es) of
    ([s :: CodeVarChunk
s], []) -> CodeVarChunk -> CodeExpr -> [FuncStmt] -> FuncStmt
FForEach CodeVarChunk
el (CodeVarChunk -> CodeExpr
forall r c. (ExprC r, HasUID c, HasSymbol c) => c -> r
sy CodeVarChunk
arr) [CodeExpr -> CodeVarChunk -> FuncStmt
appendCurrSolFS (CodeVarChunk -> CodeVarChunk -> CodeExpr
forall r. CodeExprC r => CodeVarChunk -> CodeVarChunk -> r
field CodeVarChunk
el CodeVarChunk
fld) CodeVarChunk
s]
    (_,_) -> [Char] -> FuncStmt
forall a. HasCallStack => [Char] -> a
error [Char]
popErr)]
  where popErr :: [Char]
popErr = "Fill for populateSolList should provide one CodeChunk and no Exprs"

-- | Specifies statements where every index of an array is assigned a value.
assignArrayIndex :: Step
assignArrayIndex :: Step
assignArrayIndex = ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep (\cdchs :: [CodeVarChunk]
cdchs es :: [CodeExpr]
es -> case ([CodeVarChunk]
cdchs, [CodeExpr]
es) of
  ([a :: CodeVarChunk
a],vs :: [CodeExpr]
vs) -> [FuncStmt] -> FuncStmt
FMulti ([FuncStmt] -> FuncStmt) -> [FuncStmt] -> FuncStmt
forall a b. (a -> b) -> a -> b
$ (Integer -> CodeExpr -> FuncStmt)
-> [Integer] -> [CodeExpr] -> [FuncStmt]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (CodeVarChunk -> Integer -> CodeExpr -> FuncStmt
FAsgIndex CodeVarChunk
a) [0..] [CodeExpr]
vs
  (_,_) -> [Char] -> FuncStmt
forall a. HasCallStack => [Char] -> a
error "Fill for assignArrayIndex should provide one CodeChunk")

-- | Specifies a statement where a solution is assigned from the field of an 
--   object.
assignSolFromObj :: CodeVarChunk -> Step
assignSolFromObj :: CodeVarChunk -> Step
assignSolFromObj o :: CodeVarChunk
o = ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep (\cdchs :: [CodeVarChunk]
cdchs es :: [CodeExpr]
es -> case ([CodeVarChunk]
cdchs, [CodeExpr]
es) of
  ([s :: CodeVarChunk
s],[]) -> CodeVarChunk -> CodeExpr -> FuncStmt
FAsg CodeVarChunk
s (CodeVarChunk -> CodeVarChunk -> CodeExpr
forall r. CodeExprC r => CodeVarChunk -> CodeVarChunk -> r
field CodeVarChunk
o CodeVarChunk
s)
  (_,_) -> [Char] -> FuncStmt
forall a. HasCallStack => [Char] -> a
error "Fill for assignSolFromObj should provide one CodeChunk and no Exprs")

-- | Specifies a statement where a solution list is initialized with the first 
--   element of an array.
initSolListFromArray :: CodeVarChunk -> Step
initSolListFromArray :: CodeVarChunk -> Step
initSolListFromArray a :: CodeVarChunk
a = ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep (\cdchs :: [CodeVarChunk]
cdchs es :: [CodeExpr]
es -> case ([CodeVarChunk]
cdchs, [CodeExpr]
es) of
  ([s :: CodeVarChunk
s],[]) -> CodeVarChunk -> CodeExpr -> FuncStmt
FAsg CodeVarChunk
s ([[CodeExpr]] -> CodeExpr
forall r. ExprC r => [[r]] -> r
matrix [[CodeExpr -> CodeExpr -> CodeExpr
forall r. ExprC r => r -> r -> r
idx (CodeVarChunk -> CodeExpr
forall r c. (ExprC r, HasUID c, HasSymbol c) => c -> r
sy CodeVarChunk
a) (Integer -> CodeExpr
forall r. LiteralC r => Integer -> r
int 0)]])
  (_,_) -> [Char] -> FuncStmt
forall a. HasCallStack => [Char] -> a
error "Fill for initSolListFromArray should provide one CodeChunk and no Exprs")

-- | Specifies a statement where a solution list is initialized with a value.
initSolListWithVal :: Step
initSolListWithVal :: Step
initSolListWithVal = ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep (\cdchs :: [CodeVarChunk]
cdchs es :: [CodeExpr]
es -> case ([CodeVarChunk]
cdchs, [CodeExpr]
es) of
  ([s :: CodeVarChunk
s],[v :: CodeExpr
v]) -> CodeVarChunk -> CodeExpr -> FuncStmt
FDecDef CodeVarChunk
s ([[CodeExpr]] -> CodeExpr
forall r. ExprC r => [[r]] -> r
matrix [[CodeExpr
v]])
  (_,_) -> [Char] -> FuncStmt
forall a. HasCallStack => [Char] -> a
error "Fill for initSolListWithVal should provide one CodeChunk and one Expr")

-- | A solve and populate loop. 'FunctionInterface' for loop condition, 'CodeChunk' for solution object, 
--   'CodeChunk' for independent var, 'FunctionInterface' for solving, 
--   'CodeChunk' for soln array to populate with.
solveAndPopulateWhile :: FunctionInterface -> CodeVarChunk -> CodeVarChunk -> 
  FunctionInterface -> CodeVarChunk -> Step
solveAndPopulateWhile :: FunctionInterface
-> CodeVarChunk
-> CodeVarChunk
-> FunctionInterface
-> CodeVarChunk
-> Step
solveAndPopulateWhile lc :: FunctionInterface
lc ob :: CodeVarChunk
ob iv :: CodeVarChunk
iv slv :: FunctionInterface
slv popArr :: CodeVarChunk
popArr = [FunctionInterface] -> ([CodeExpr] -> CodeExpr) -> [Step] -> Step
loopStep [FunctionInterface
lc] (\case 
  [ub :: CodeExpr
ub] -> CodeVarChunk -> CodeVarChunk -> CodeExpr
forall r. CodeExprC r => CodeVarChunk -> CodeVarChunk -> r
field CodeVarChunk
ob CodeVarChunk
iv CodeExpr -> CodeExpr -> CodeExpr
forall r. ExprC r => r -> r -> r
$< CodeExpr
ub
  _ -> [Char] -> CodeExpr
forall a. HasCallStack => [Char] -> a
error "Fill for solveAndPopulateWhile should provide one Expr") 
  [FunctionInterface -> Step
callStep FunctionInterface
slv, CodeExpr -> Step
appendCurrSol (CodeVarChunk -> CodeVarChunk -> CodeExpr
forall r. CodeExprC r => CodeVarChunk -> CodeVarChunk -> r
field CodeVarChunk
ob CodeVarChunk
popArr)]

-- | Specifies a statement where a list is returned, where each value of the list
-- is explicitly defined.
returnExprList :: Step
returnExprList :: Step
returnExprList = ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep (\cdchs :: [CodeVarChunk]
cdchs es :: [CodeExpr]
es -> case ([CodeVarChunk]
cdchs, [CodeExpr]
es) of
  ([], _) -> CodeExpr -> FuncStmt
FRet (CodeExpr -> FuncStmt) -> CodeExpr -> FuncStmt
forall a b. (a -> b) -> a -> b
$ [[CodeExpr]] -> CodeExpr
Matrix [[CodeExpr]
es]
  (_,_) -> [Char] -> FuncStmt
forall a. HasCallStack => [Char] -> a
error "Fill for returnExprList should provide no CodeChunks")

-- | A statement where a current solution is appended to a solution list.
appendCurrSolFS :: CodeExpr -> CodeVarChunk -> FuncStmt
appendCurrSolFS :: CodeExpr -> CodeVarChunk -> FuncStmt
appendCurrSolFS cs :: CodeExpr
cs s :: CodeVarChunk
s = CodeExpr -> CodeExpr -> FuncStmt
FAppend (CodeVarChunk -> CodeExpr
forall r c. (ExprC r, HasUID c, HasSymbol c) => c -> r
sy CodeVarChunk
s) (CodeExpr -> CodeExpr -> CodeExpr
forall r. ExprC r => r -> r -> r
idx CodeExpr
cs (Integer -> CodeExpr
forall r. LiteralC r => Integer -> r
int 0))

-- | Specifies a use-case-independent statement that returns a value.
fixedReturn :: CodeExpr -> Step
fixedReturn :: CodeExpr -> Step
fixedReturn = FuncStmt -> Step
lockedStatement (FuncStmt -> Step) -> (CodeExpr -> FuncStmt) -> CodeExpr -> Step
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CodeExpr -> FuncStmt
FRet

-- | Specifies a statement step.
statementStep :: ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep :: ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep = ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
Statement

-- | Specifies a statement that is not use-case-dependent.
lockedStatement :: FuncStmt -> Step
lockedStatement :: FuncStmt -> Step
lockedStatement s :: FuncStmt
s = ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
Statement (\_ _ -> FuncStmt
s)

-- | Specifies a statement where a single solution is initialized with a value.
initSolWithVal :: Step
initSolWithVal :: Step
initSolWithVal = ([CodeVarChunk] -> [CodeExpr] -> FuncStmt) -> Step
statementStep (\cdchs :: [CodeVarChunk]
cdchs es :: [CodeExpr]
es -> case ([CodeVarChunk]
cdchs, [CodeExpr]
es) of
  ([s :: CodeVarChunk
s],[v :: CodeExpr
v]) -> CodeVarChunk -> CodeExpr -> FuncStmt
FDecDef CodeVarChunk
s CodeExpr
v
  (_,_) -> [Char] -> FuncStmt
forall a. HasCallStack => [Char] -> a
error "Fill for initSolWithVal should provide one CodeChunk and one Expr")