packages feed

katydid-0.4.0.1: test/UserDefinedFuncs.hs

module UserDefinedFuncs (
    userLib
    , incExpr
    , concatExpr
    , isPrimeExpr
) where

import qualified Data.Text

import Data.Numbers.Primes (isPrime)

import Data.Katydid.Relapse.Expr

-- |
-- userLib is a library of user defined functions that can be passed to the parser.
userLib :: String -> [AnyExpr] -> Either String AnyExpr
userLib "inc" args = mkIncExpr args
userLib "concat" args = mkConcatExpr args
userLib "isPrime" args = mkIsPrime args
userLib n _ = Left $ "undefined function: " ++ n

-- |
-- mkIncExpr tries to create an incExpr from a variable number and dynamically types arguments.
-- This function is used by the Relapse parser to insert your user defined expression into the expression tree.
mkIncExpr :: [AnyExpr] -> Either String AnyExpr
mkIncExpr args = do {
    arg <- assertArgs1 "inc" args;
    mkIntExpr . incExpr <$> assertInt arg;
}

-- |
-- incExpr creates an expression that increases its input argument by 1.
-- This function is also useful if we want to build up our own well typed expression tree, 
-- bypassing the Relapse parser.
incExpr :: Expr Int -> Expr Int
incExpr intArg = trimInt Expr {
    desc = mkDesc "inc" [desc intArg]
    , eval = \fieldValue -> (+1) <$> eval intArg fieldValue
}

-- |
-- mkConcatExpr tries to create an concatExpr from a variable number and dynamically types arguments.
mkConcatExpr :: [AnyExpr] -> Either String AnyExpr
mkConcatExpr args = do {
    (arg1, arg2) <- assertArgs2 "inc" args;
    strArg1 <- assertString arg1;
    strArg2 <- assertString arg2;
    return $ mkStringExpr $ concatExpr strArg1 strArg2;
}

-- |
-- concatExpr creates an expression that concatenates two string together.
concatExpr :: Expr Data.Text.Text -> Expr Data.Text.Text -> Expr Data.Text.Text
concatExpr strExpr1 strExpr2 = trimString Expr {
    desc = mkDesc "concat" [desc strExpr1, desc strExpr2]
    , eval = \fieldValue -> do {
        str1 <- eval strExpr1 fieldValue;
        str2 <- eval strExpr2 fieldValue;
        return $ Data.Text.concat [str1,str2];
    }
}

-- |
-- mkIsPrimeExpr tries to create an isPrimeExpr from a variable number and dynamically types arguments.
mkIsPrime :: [AnyExpr] -> Either String AnyExpr
mkIsPrime args = do {
    arg <- assertArgs1 "isPrime" args;
    case arg of
    (AnyExpr _ (IntFunc _)) -> mkBoolExpr . isPrimeExpr <$> assertInt arg;
    (AnyExpr _ (UintFunc _)) ->  mkBoolExpr . isPrimeExpr <$> assertUint arg;
}

-- |
-- isPrime creates an expression checks whether a number is prime.
isPrimeExpr :: Integral a => Expr a -> Expr Bool
isPrimeExpr numExpr = trimBool Expr {
    desc = mkDesc "isPrime" [desc numExpr]
    , eval = \fieldValue -> isPrime <$> eval numExpr fieldValue
}