packages feed

deka-0.6.0.0: dectest/Directives.hs

{-# LANGUAGE OverloadedStrings #-}
module Directives where

import qualified Parse as P
import qualified Deka.Context as C
import Data.Char (toLower)
import qualified Data.ByteString.Char8 as BS8
import Data.Monoid
import TestLog
import Util
import Data.String
import qualified Data.Sequence as S
import Data.Sequence(ViewR(..))

data Directives = Directives
  { dsPrecision :: Maybe P.Value
  , dsRounding :: Maybe P.Value
  , dsEmax :: Maybe P.Value
  , dsEmin :: Maybe P.Value
  , dsExtended :: Maybe P.Value
  , dsClamp :: Maybe P.Value
  , dsVersion :: Maybe P.Value
  } deriving Show

type Getter = Directives -> Maybe P.Value
type Setter = P.Value -> Directives -> Directives

dirFields
  :: IsString a
  => [(a, (Getter, Setter))]
dirFields =
  [ ("precision", (dsPrecision, \v d -> d { dsPrecision = Just v }))
  , ("rounding", (dsRounding, \v d -> d { dsRounding = Just v }))
  , ("maxexponent", (dsEmax, \v d -> d { dsEmax = Just v }))
  , ("minexponent", (dsEmin, \v d -> d { dsEmin = Just v }))
  , ("extended", (dsExtended, \v d -> d { dsExtended = Just v }))
  , ("clamp", (dsClamp, \v d -> d { dsClamp = Just v }))
  , ("version", (dsVersion, \v d -> d { dsVersion = Just v }))
  ]

emptyDirectives :: Directives
emptyDirectives = Directives Nothing Nothing Nothing Nothing
  Nothing Nothing Nothing

plusDirective
  :: (P.Keyword, P.Value)
  -> Directives
  -> TestLog Directives
plusDirective (kw, vl) d = case lookup k dirFields of
  Nothing -> flunk $ "could not find directive: " <> BS8.pack k
  Just p -> add p
  where
    (k, v) = (map toLower . BS8.unpack . P.unKeyword $ kw,
              P.unValue vl)
    add (get, set) = case get d of
      Nothing -> do
        tell $ "using directive " <> BS8.pack k <> " with value " <> v
        return $ set vl d
      Just _ -> do
        tell $ "ignoring old directive " <> BS8.pack k
          <> " with value " <> v
        return d

plusDirectives
  :: S.Seq (P.Keyword, P.Value)
  -> TestLog Directives
plusDirectives = go emptyDirectives
  where
    go ds sq = case S.viewr sq of
      EmptyR -> return ds
      sq' :> p -> do
        ds' <- plusDirective p ds
        go ds' sq'

directivesToCtx :: Directives -> TestLog (C.Ctx ())
directivesToCtx ds = do

  rnd <- case dsRounding ds of
    Nothing -> return (return ())
    Just (P.Value r) -> do
      let dflt = flunk $ "could not set rounding: " <> r
          mayRnd = lookup r allRounds
      rnd <- maybe dflt return mayRnd
      tell $ "setting rounding to " <> r
      return (C.setRound rnd)

  clmp <- case dsClamp ds of
    Nothing -> return (return ())
    Just (P.Value r) -> case readNumberBS r >>= parseBool of
      Nothing -> flunk $ "could not set clamp: " <> r
      Just p -> do
        tell $ "setting clamp to " <> BS8.pack (show p)
        return (C.setClamp p)

  tri <- do
    pcsn <- case dsPrecision ds of
      Nothing -> flunk "precision not present in directives"
      Just (P.Value r) -> case readNumberBS r >>= C.precision of
        Nothing -> flunk $ "could not set precision: " <> r
        Just p -> do
          tell $ "using for precision: " <> r
          return p

    emx <- case dsEmax ds of
      Nothing -> flunk "emax not present in directives"
      Just (P.Value r) -> case readNumberBS r >>= C.emax of
        Nothing -> flunk $ "could not set emax: " <> r
        Just x -> do
          tell $ "using for Emax: " <> r
          return x

    emn <- case dsEmin ds of
      Nothing -> flunk "emin not present in directives"
      Just (P.Value r) -> case readNumberBS r >>= C.emin of
        Nothing -> flunk $ "could not set emin: " <> r
        Just x -> do
          tell $ "using for Emin: " <> r
          return x

    case C.trio pcsn emx emn of
      Nothing -> flunk $ "failed to set trio"
      Just t -> return $ C.setTrio t

  return $ rnd >> clmp >> tri

parseDirectives
  :: S.Seq (P.Keyword, P.Value)
  -> TestLog (C.Ctx ())
parseDirectives sq = plusDirectives sq >>= directivesToCtx

allRounds :: IsString a => [(a, C.Round)]
allRounds =
  [ ("ceiling", C.roundCeiling)
  , ("up", C.roundUp)
  , ("half_up", C.roundHalfUp)
  , ("half_even", C.roundHalfEven)
  , ("half_down", C.roundHalfDown)
  , ("down", C.roundDown)
  , ("floor", C.roundFloor)
  , ("05up", C.round05Up)
  ]