packages feed

descript-lang-0.2.0.0: src/Descript/Sugar/Data/InjFunc.hs

module Descript.Sugar.Data.InjFunc
  ( InjFunc
  , lookupFunc
  , forceLookupFunc
  ) where

import Descript.Sugar.Data.Atom
import Data.Monoid
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Prelude hiding (subtract, compare)
import qualified Prelude (compare)

-- | A function which operates on primtives, which can be accessed in
-- Descript. Returns 'Nothing' when given the wrong type of primitives.
type InjFunc = [Prim ()] -> Maybe (Prim ())

-- | All injected functions, with their corresponding identifiers.
-- (Identifiers not in 'InjSymbol' for convenience).
allFuncs :: Map String InjFunc
allFuncs = Map.fromList
  [ ("Add", add)
  , ("Subtract", subtract)
  , ("Multiply", multiply)
  , ("Compare", compare)
  , ("Append", append)
  , ("App3", app3)
  ]

-- | Gets the injected function corresponding to the given identifer.
-- Returns `Nothing` if the function doesn't exist.
lookupFunc :: InjSymbol an -> Maybe InjFunc
lookupFunc (InjSymbol _ funcId) = allFuncs Map.!? funcId

-- | Gets the injected function corresponding to the given identifer.
-- Fails if the function doesn't exist.
forceLookupFunc :: InjSymbol an -> InjFunc
forceLookupFunc (InjSymbol _ funcId) = allFuncs Map.! funcId

add :: InjFunc
add [PrimNumber () x, PrimNumber () y] = Just $ PrimNumber () $ x + y
add _ = Nothing

subtract :: InjFunc
subtract [PrimNumber () x, PrimNumber () y] = Just $ PrimNumber () $ x - y
subtract _ = Nothing

multiply :: InjFunc
multiply [PrimNumber () x, PrimNumber () y] = Just $ PrimNumber () $ x * y
multiply _ = Nothing

compare :: InjFunc
compare [PrimNumber () x, PrimNumber () y] = Just $ PrimNumber () $ x `compareNum` y
compare _ = Nothing

append :: InjFunc
append [PrimText () x, PrimText () y] = Just $ PrimText () $ x <> y
append _ = Nothing

app3 :: InjFunc
app3 [PrimText () x, PrimText () y, PrimText () z]
  = Just $ PrimText () $ x <> y <> z
app3 _ = Nothing

compareNum :: Rational -> Rational -> Rational
x `compareNum` y
  = case x `Prelude.compare` y of
         LT -> -1
         GT -> 1
         EQ -> 0