spade-0.1.0.10: src/Compiler/AST/FunctionDef.hs
module Compiler.AST.FunctionDef where
import Common
import Control.DeepSeq
import GHC.Generics
import Control.Applicative
import Data.List as L
import Data.List.NonEmpty as NE
import Data.Maybe
import Data.Text as T
import Compiler.AST.Common
import Compiler.AST.FunctionStatement
import Compiler.AST.Parser.Common
import Compiler.Lexer
import Parser.Lib
import Test.Common
data FunctionDef
= FunctionDef Bool Identifier [Identifier] (NonEmpty FunctionStatementWithLoc)
deriving (Show, Generic, Eq)
instance NFData FunctionDef
instance HasAstParser FunctionDef where
astParser = nameParser "Function Definition" $ do
surroundWs_ (parseKeyword KwProc)
fnName <- surroundWs parseIdentifier
args <- parseItemListInParen parseIdentifier
setGeneratorFlag False
stms <- mandatory (some (surroundWs (astParser @FunctionStatementWithLoc)))
mandatory $ surroundWs_ $ parseKeyword KwEndProc
isGenerator <- getGeneratorFlag
setGeneratorFlag False
pure $ FunctionDef isGenerator fnName (fromMaybe [] (NE.toList <$> args)) (NE.fromList stms)
instance ToSource FunctionDef where
toSourcePretty i (FunctionDef _ name args stms) =
T.concat $
[nlt, indent i, toSource KwProc, wst, toSource name, toSource DlParenOpen] <>
(L.intersperse (toSource DlComma <> " ") (toSource <$> args)) <>
[toSource DlParenClose] <> [nlt] <>
[toSourcePretty (i+1) (NE.toList stms)] <> [nlt, indent i, toSource KwEndProc]
instance HasGen FunctionDef where
getGen = do
isGen <- bool
stms <- case isGen of
True -> functionStmsWithYield
False -> functionStmsWithoutYield
(FunctionDef isGen) <$> getGen <*> getGen <*> (pure stms)
hasYield :: NonEmpty FunctionStatementWithLoc -> Bool
hasYield fustms = case fustms of
((FunctionStatementWithLoc stm _) :| []) -> hasYield' stm
((FunctionStatementWithLoc stm _) :| (h:t)) -> if hasYield' stm
then True
else hasYield (h :| t)
where
hasYield' = \case
Let _ _ _ -> False
Call _ _ _ -> False
If _ stms1 stms2 -> hasYield stms1 || hasYield stms2
IfThen _ stms -> hasYield stms
MultiIf _ stms1 (NE.map snd -> branches) mstms2 ->
hasYield stms1 || (or (hasYield <$> branches)) ||
(case mstms2 of
Nothing -> False
Just stms -> hasYield stms)
For _ _ _ stms _ -> hasYield stms
ForEach _ _ stms -> hasYield stms
While _ stms -> hasYield stms
Loop stms -> hasYield stms
Yield _ -> True
_ -> False
functionStmsWithoutYield :: Gen (NonEmpty FunctionStatementWithLoc)
functionStmsWithoutYield = do
stms <- nonEmptyGen getGen
if hasYield stms then functionStmsWithoutYield else pure stms
functionStmsWithYield :: Gen (NonEmpty FunctionStatementWithLoc)
functionStmsWithYield = do
stms <- nonEmptyGen getGen
if hasYield stms then pure stms else functionStmsWithYield