<commit_before>{-# LANGUAGE TemplateHaskell, TupleSections #-}
module Language.Drasil.Code.ExtLibImport (ExtLibState(..), auxMods, defs, 
  imports, modExports, steps, genExternalLibraryCall) where

import Language.Drasil

import Language.Drasil.Chunk.Code (CodeVarChunk, CodeFuncChunk, codeName, 
  ccObjVar)
import Language.Drasil.CodeExpr (new, newWithNamedArgs, msgWithNamedArgs)
import Language.Drasil.Mod (Class, StateVariable, Func(..), Mod, Name, 
  packmodRequires, classDef, classImplements, FuncStmt(..), funcDef, ctorDef)
import Language.Drasil.Code.ExternalLibrary (ExternalLibrary, Step(..), 
  FunctionInterface(..), Result(..), Argument(..), ArgumentInfo(..), 
  Parameter(..), ClassInfo(..), MethodInfo(..), FuncType(..))
import Language.Drasil.Code.ExternalLibraryCall (ExternalLibraryCall,
  StepGroupFill(..), StepFill(..), FunctionIntFill(..), ArgumentFill(..),
  ParameterFill(..), ClassInfoFill(..), MethodInfoFill(..))

import Control.Lens (makeLenses, (^.), over)
import Control.Monad (zipWithM)
import Control.Monad.State (State, execState, get, modify)
import Data.List (nub, partition)
import Data.List.NonEmpty (NonEmpty(..), (!!), toList)
import Data.Maybe (isJust)
import Prelude hiding ((!!))

data ExtLibState = ELS {
  _auxMods :: [Mod],
  _defs :: [FuncStmt],
  _defined :: [Name],
  _imports :: [String],
  _modExports :: [(String, String)],
  _steps :: [FuncStmt]
}
makeLenses ''ExtLibState

initELS :: ExtLibState
initELS = ELS {
  _auxMods = [],
  _defs = [],
  _defined = [],
  _imports = [],
  _modExports = [],
  _steps = []
}

-- State Modifiers

addMod :: Mod -> ExtLibState -> ExtLibState
addMod m = over auxMods (m:)

addDef :: Expr -> CodeVarChunk -> ExtLibState -> ExtLibState
addDef e c s = if n `elem` (s ^. defined) then s else over defs (++ [FDecDef c 
  e]) (addDefined n s)
  where n = codeName c

addFieldAsgs :: CodeVarChunk -> [CodeVarChunk] -> [Expr] -> ExtLibState -> 
  ExtLibState
addFieldAsgs o cs es = over defs (++ zipWith FAsg (map (ccObjVar o) cs) es)

addDefined :: String -> ExtLibState -> ExtLibState
addDefined n = over defined (n:)

addImports :: [String] -> ExtLibState -> ExtLibState
addImports is = over imports (\l -> nub $ l ++ is)

addModExport :: (String, String) -> ExtLibState -> ExtLibState
addModExport e = over modExports (e:)

addSteps :: [FuncStmt] -> ExtLibState -> ExtLibState
addSteps fs = over steps (++fs)

refreshLocal :: ExtLibState -> ExtLibState
refreshLocal s = s {_defs = [], _defined = [], _imports = []}

returnLocal :: ExtLibState -> ExtLibState -> ExtLibState
returnLocal oldS newS = newS {_defs = oldS ^. defs, 
                              _defined = oldS ^. defined, 
                              _imports = oldS ^. imports}

-- Generators

genExternalLibraryCall :: ExternalLibrary -> ExternalLibraryCall -> 
  ExtLibState
genExternalLibraryCall el elc = execState (genExtLibCall el elc) initELS

genExtLibCall :: ExternalLibrary -> ExternalLibraryCall ->
  State ExtLibState ()
genExtLibCall [] [] = return ()
genExtLibCall (sg:el) (SGF n sgf:elc) = let s = sg!!n in 
  if length s /= length sgf then error stepNumberMismatch else do
    fs <- zipWithM genStep s sgf
    modify (addSteps fs)
    genExtLibCall el elc
genExtLibCall _ _ = error stepNumberMismatch

genStep :: Step -> StepFill -> State ExtLibState FuncStmt
genStep (Call fi) (CallF fif) = genFI fi fif
genStep (Loop fis f ss) (LoopF fifs ccList sfs) = do
  es <- zipWithM genFIVal (toList fis) (toList fifs)
  fs <- zipWithM genStep (toList ss) (toList sfs)
  return $ FWhile (foldl1 ($&&) es $&& f ccList) fs
genStep (Statement f) (StatementF ccList exList) = return $ f ccList exList
genStep _ _ = error stepTypeMismatch

genFIVal :: FunctionInterface -> FunctionIntFill -> State ExtLibState Expr
genFIVal (FI (r:|rs) ft f as _) (FIF afs) = do
  args <- genArguments as afs
  let isNamed = isJust . fst 
      (nas, ars) = partition isNamed args
  modify (addImports (r:rs) . addModExport (codeName f, r))
  return $ getCallFunc ft f (map snd ars) (map (\(n, e) -> 
    maybe (error "defective isNamed") (,e) n) nas) 
  where getCallFunc Function = applyWithNamedArgs 
        getCallFunc (Method o) = msgWithNamedArgs o 
        getCallFunc Constructor = newWithNamedArgs

genFI :: FunctionInterface -> FunctionIntFill -> State ExtLibState FuncStmt
genFI fi@(FI _ _ _ _ r) fif = do
  fiEx <- genFIVal fi fif
  return $ maybeGenAssg r fiEx 

genArguments :: [Argument] -> [ArgumentFill] -> 
  State ExtLibState [(Maybe NamedArgument, Expr)]
genArguments (Arg n (LockedArg e):as) afs = fmap ((n,e):) (genArguments as afs)
genArguments as (UserDefinedArgF n e:afs) = fmap ((n,e):) (genArguments as afs)
genArguments (Arg n (Basic _ v):as) (BasicF e:afs) = do
  modify (maybe id (addDef e) v)
  fmap ((n,e):) (genArguments as afs)
-- FIXME: funcexpr needs to be defined, a function-valued expression
-- Uncomment the below when funcexpr is added
genArguments (Arg n (Fn c _ _{-ps s-}):as) (FnF _ _{-pfs sf-}:afs) = -- do
  -- let prms = genParameters ps pfs<commit_msg>Fix generation of pre-defined args<commit_after>{-# LANGUAGE TemplateHaskell, TupleSections #-}
module Language.Drasil.Code.ExtLibImport (ExtLibState(..), auxMods, defs, 
  imports, modExports, steps, genExternalLibraryCall) where

import Language.Drasil

import Language.Drasil.Chunk.Code (CodeVarChunk, CodeFuncChunk, codeName, 
  ccObjVar)
import Language.Drasil.CodeExpr (new, newWithNamedArgs, msgWithNamedArgs)
import Language.Drasil.Mod (Class, StateVariable, Func(..), Mod, Name, 
  packmodRequires, classDef, classImplements, FuncStmt(..), funcDef, ctorDef)
import Language.Drasil.Code.ExternalLibrary (ExternalLibrary, Step(..), 
  FunctionInterface(..), Result(..), Argument(..), ArgumentInfo(..), 
  Parameter(..), ClassInfo(..), MethodInfo(..), FuncType(..))
import Language.Drasil.Code.ExternalLibraryCall (ExternalLibraryCall,
  StepGroupFill(..), StepFill(..), FunctionIntFill(..), ArgumentFill(..),
  ParameterFill(..), ClassInfoFill(..), MethodInfoFill(..))

import Control.Lens (makeLenses, (^.), over)
import Control.Monad (zipWithM)
import Control.Monad.State (State, execState, get, modify)
import Data.List (nub, partition)
import Data.List.NonEmpty (NonEmpty(..), (!!), toList)
import Data.Maybe (isJust)
import Prelude hiding ((!!))

data ExtLibState = ELS {
  _auxMods :: [Mod],
  _defs :: [FuncStmt],
  _defined :: [Name],
  _imports :: [String],
  _modExports :: [(String, String)],
  _steps :: [FuncStmt]
}
makeLenses ''ExtLibState

initELS :: ExtLibState
initELS = ELS {
  _auxMods = [],
  _defs = [],
  _defined = [],
  _imports = [],
  _modExports = [],
  _steps = []
}

-- State Modifiers

addMod :: Mod -> ExtLibState -> ExtLibState
addMod m = over auxMods (m:)

addDef :: Expr -> CodeVarChunk -> ExtLibState -> ExtLibState
addDef e c s = if n `elem` (s ^. defined) then s else over defs (++ [FDecDef c 
  e]) (addDefined n s)
  where n = codeName c

addFieldAsgs :: CodeVarChunk -> [CodeVarChunk] -> [Expr] -> ExtLibState -> 
  ExtLibState
addFieldAsgs o cs es = over defs (++ zipWith FAsg (map (ccObjVar o) cs) es)

addDefined :: String -> ExtLibState -> ExtLibState
addDefined n = over defined (n:)

addImports :: [String] -> ExtLibState -> ExtLibState
addImports is = over imports (\l -> nub $ l ++ is)

addModExport :: (String, String) -> ExtLibState -> ExtLibState
addModExport e = over modExports (e:)

addSteps :: [FuncStmt] -> ExtLibState -> ExtLibState
addSteps fs = over steps (++fs)

refreshLocal :: ExtLibState -> ExtLibState
refreshLocal s = s {_defs = [], _defined = [], _imports = []}

returnLocal :: ExtLibState -> ExtLibState -> ExtLibState
returnLocal oldS newS = newS {_defs = oldS ^. defs, 
                              _defined = oldS ^. defined, 
                              _imports = oldS ^. imports}

-- Generators

genExternalLibraryCall :: ExternalLibrary -> ExternalLibraryCall -> 
  ExtLibState
genExternalLibraryCall el elc = execState (genExtLibCall el elc) initELS

genExtLibCall :: ExternalLibrary -> ExternalLibraryCall ->
  State ExtLibState ()
genExtLibCall [] [] = return ()
genExtLibCall (sg:el) (SGF n sgf:elc) = let s = sg!!n in 
  if length s /= length sgf then error stepNumberMismatch else do
    fs <- zipWithM genStep s sgf
    modify (addSteps fs)
    genExtLibCall el elc
genExtLibCall _ _ = error stepNumberMismatch

genStep :: Step -> StepFill -> State ExtLibState FuncStmt
genStep (Call fi) (CallF fif) = genFI fi fif
genStep (Loop fis f ss) (LoopF fifs ccList sfs) = do
  es <- zipWithM genFIVal (toList fis) (toList fifs)
  fs <- zipWithM genStep (toList ss) (toList sfs)
  return $ FWhile (foldl1 ($&&) es $&& f ccList) fs
genStep (Statement f) (StatementF ccList exList) = return $ f ccList exList
genStep _ _ = error stepTypeMismatch

genFIVal :: FunctionInterface -> FunctionIntFill -> State ExtLibState Expr
genFIVal (FI (r:|rs) ft f as _) (FIF afs) = do
  args <- genArguments as afs
  let isNamed = isJust . fst 
      (nas, ars) = partition isNamed args
  modify (addImports (r:rs) . addModExport (codeName f, r))
  return $ getCallFunc ft f (map snd ars) (map (\(n, e) -> 
    maybe (error "defective isNamed") (,e) n) nas) 
  where getCallFunc Function = applyWithNamedArgs 
        getCallFunc (Method o) = msgWithNamedArgs o 
        getCallFunc Constructor = newWithNamedArgs

genFI :: FunctionInterface -> FunctionIntFill -> State ExtLibState FuncStmt
genFI fi@(FI _ _ _ _ r) fif = do
  fiEx <- genFIVal fi fif
  return $ maybeGenAssg r fiEx 

genArguments :: [Argument] -> [ArgumentFill] -> 
  State ExtLibState [(Maybe NamedArgument, Expr)]
genArguments (Arg n (LockedArg e):as) afs = fmap ((n,e):) (genArguments as afs)
genArguments as (UserDefinedArgF n e:afs) = fmap ((n,e):) (genArguments as afs)
genArguments (Arg n (Basic _ Nothing):as) (BasicF e:afs) = fmap ((n,e):) 
  (genArguments as afs)
genArguments (Arg n (Basic _ (Just v)):as) (BasicF e:afs) = do
  modify (addDef e v)
  fmap ((n,sy v):) (genArguments as afs)
-- FIXME: funcexpr needs to be defined, a function-valued expression
-- Uncomment the below when funcexpr is added
genArguments (Arg n (Fn c _ _{-ps s-}):as) (FnF _ _{-pfs sf-}:afs) = -- do
  -- let prms = genParameters ps pfs
{'fraction_non_alphanumeric': 0.13181639858768143, 'fraction_numerical': 0.00019615535504119262, 'mean_word_length': 3.9142168674698796, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 71, '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': '5102897', 'n_tokens_mistral': 3530, 'n_tokens_neox': 3466, 'n_words': 1047}