noise-0.0.1: src/Text/Noise/Compiler/Function.hs
{-# LANGUAGE TypeSynonymInstances #-}
module Text.Noise.Compiler.Function
( Function
, Value(..)
, FromValue(..)
, FunctionError(..)
, requireArg
, acceptArg
, acceptBlockArgs
, throw
, call
) where
import Control.Applicative
import Control.Monad
import Text.Noise.Compiler.Error (FunctionError(..))
import qualified Text.Noise.Compiler.Document as D
import qualified Text.Noise.Compiler.Document.Color as Color
type Keyword = String
data Value = NumberValue D.Number
| ColorValue String
| StringValue String
| ElementValue D.Element
| GradientValue D.Gradient
| PathCommandValue D.PathCommand
data ArgStack = ArgStack [Value] [(Keyword,Value)] [Value]
data Result a = Success a ArgStack | Failure FunctionError
data Function a = Function { runFunction :: ArgStack -> Result a }
instance Functor Function where
fmap = liftM
instance Applicative Function where
pure = return
(<*>) = ap
instance Monad Function where
return x = Function $ \args -> Success x args
Function r >>= f = Function $ \args ->
case r args of
Failure err -> Failure err
Success x args' ->
let Function r' = f x
in r' args'
call :: Function a -> [Value] -> [(Keyword,Value)] -> [Value] -> Either FunctionError a
call function posArgs kwArgs blockArgs = case result of
Failure err -> Left err
Success _ (ArgStack (_:_) _ _) -> Left TooManyArgumentsError
Success ret _ -> Right ret
where result = runFunction function (ArgStack posArgs kwArgs blockArgs)
class FromValue a where
fromValue :: Value -> Maybe a
instance FromValue Value where
fromValue = Just
instance FromValue D.Number where
fromValue (NumberValue x) = Just x
fromValue _ = Nothing
instance FromValue D.Paint where
fromValue (ColorValue x) = D.ColorPaint <$> Color.fromHex x
fromValue (GradientValue x) = Just (D.GradientPaint x)
fromValue _ = Nothing
instance FromValue D.Color where
fromValue (ColorValue x) = Color.fromHex x
fromValue _ = Nothing
instance FromValue D.IRI where
fromValue (StringValue x) = D.fileIRI x
fromValue _ = Nothing
instance FromValue D.Element where
fromValue (ElementValue x) = Just x
fromValue _ = Nothing
instance FromValue D.PathCommand where
fromValue (PathCommandValue x) = Just x
fromValue _ = Nothing
getArg :: (FromValue a) => Keyword -> Maybe a -> Function a
getArg keyword maybeDefault = Function $ \args -> case args of
ArgStack (value:xs) kwArgs blockArgs -> case fromValue value of
Just x -> case lookup keyword kwArgs of
Nothing -> Success x (ArgStack xs kwArgs blockArgs)
Just _ -> Failure (RedundantKeywordArgError keyword)
Nothing -> Failure (ArgumentTypeError keyword)
ArgStack [] kwArgs blockArgs -> case lookup keyword kwArgs of
Just value -> case fromValue value of
Just x -> Success x (ArgStack [] kwArgs blockArgs)
Nothing -> Failure (ArgumentTypeError keyword)
Nothing -> case maybeDefault of
Just default' -> Success default' (ArgStack [] kwArgs blockArgs)
Nothing -> Failure (MissingArgumentError keyword)
requireArg :: (FromValue a) => Keyword -> Function a
requireArg keyword = getArg keyword Nothing
acceptArg :: (FromValue a) => Keyword -> a -> Function a
acceptArg keyword default' = getArg keyword (Just default')
acceptBlockArgs :: (FromValue a) => Function [a]
acceptBlockArgs = Function $ \args@(ArgStack _ _ xs) ->
case mapM fromValue xs of
Just xs' -> Success xs' args
Nothing -> Failure BlockStatementTypeError
throw :: FunctionError -> Function a
throw err = Function $ \_ -> Failure err