~alcinnz/CatTrap

84442e4e3a53b5c6140ce44a8ddad12541894509 — Adrian Cochrane 1 year, 5 months ago 3cbd097
Reference-document (unused) calc() implementation.
1 files changed, 16 insertions(+), 1 deletions(-)

M Graphics/Layout/Arithmetic.hs
M Graphics/Layout/Arithmetic.hs => Graphics/Layout/Arithmetic.hs +16 -1
@@ 7,8 7,11 @@ import Data.Scientific (toRealFloat)
import GHC.Real (infinity)
import Data.Text (unpack, Text)
import qualified Data.Text as Txt
import Debug.Trace (trace) -- For error reporting.

-- | Parsed calc() expression. As a postfix arithmatic expression.
data Opcode n = Seq | Add | Subtract | Multiply | Divide | Func Text | Num n deriving Show
-- | Parse a calc() expression.
parseCalc :: [Token] -> [Opcode (Float, String)] -> [Opcode (Float, String)]
parseCalc (Number _ n:toks) stack = Num (val2float n, ""):parseCalc toks stack
parseCalc (Percentage _ n:toks) stack = Num (val2float n, "%"):parseCalc toks stack


@@ 45,6 48,7 @@ parseCalc [] [] = []
parseCalc [] stack = parseCalc [RightParen] stack
parseCalc _ _ = [Func "invalid"]

-- | Parse an operator char.
op :: Char -> Opcode n
op '+' = Add
op '-' = Subtract


@@ 55,6 59,7 @@ op _ = Func "invalid"

-- Do operands counts line up? Are we dividing by 0?
-- Also I see concerns about whether units line up. Not bothering verifying that.
-- | Verify that a parsed math expression can be properly evaluated.
verifyCalc :: [Opcode (Float, String)] -> [Bool] -> Bool
verifyCalc (Seq:expr) stack = verifyCalc expr stack
verifyCalc (Add:expr) (_:_:stack) = verifyCalc expr (True:stack)


@@ 72,6 77,7 @@ verifyCalc (Func "clamp":expr) (_:_:_:stack) = verifyCalc expr (True:stack)
verifyCalc [] [_] = True
verifyCalc _ _ = False

-- | Evaluate a parsed calc() expression.
evalCalc :: [Opcode Float] -> [Float] -> Float
evalCalc (Seq:expr) stack = evalCalc expr stack -- The function args off
evalCalc (Add:expr) (y:x:stack) = evalCalc expr ((x + y):stack)


@@ 103,8 109,15 @@ evalCalc (Func "sqrt":expr) (x:stack) = evalCalc expr (sqrt x:stack)
evalCalc (Func "tan":expr) (x:stack) = evalCalc expr (tan x:stack)

evalCalc [] [ret] = ret
evalCalc _ _ = error "Verification should have caught this error!"
evalCalc [] stack@(ret:_) =
    trace ("Verification should have caught this error! " ++ show stack) ret
evalCalc [] [] = trace "Verification should have caught this error! Stack underflow!" 0
evalCalc (op:_) (ret:_) =
    trace ("Verification should have caught this error! Unsupported op " ++ show op) ret
evalCalc (op:_) [] =
    trace ("Verification should have caught this error! Unsupported op " ++ show op) 0

-- | Convert all numbers in an expression via the given callback.
mapCalc :: (a -> b) -> [Opcode a] -> [Opcode b]
mapCalc cb (Num x:toks) = Num (cb x):mapCalc cb toks
-- GHC demanded more verbosity...


@@ 116,9 129,11 @@ mapCalc cb (Divide:toks) = Divide:mapCalc cb toks
mapCalc cb (Func f':toks) = Func f':mapCalc cb toks
mapCalc _ [] = []

-- | Convert from a tokenized NumericValue to a Float.
val2float :: NumericValue -> Float
val2float (NVInteger n) = fromIntegral n
val2float (NVNumber n) = toRealFloat n

-- | Convert from a rational value to a float.
f :: Rational -> Float
f = fromRational