M Graphics/Layout.hs => Graphics/Layout.hs +4 -4
@@ 4,11 4,11 @@ import Graphics.Layout.Box
 import Graphics.Layout.Grid
 
 data LayoutItem n x =
-    LayoutFlow x (PaddedBox n) [LayoutItem n]
-    | LayoutGrid x (Grid n) [(GridItem n, LayoutItem n)]
+    LayoutFlow x (PaddedBox n) [LayoutItem n x]
+    | LayoutGrid x (Grid n) [(GridItem n, LayoutItem n x)]
 -- More to come...
 
-sizeBound :: LayoutItem Length () -> LayoutItem Length ()
+{-sizeBound :: LayoutItem Length () -> LayoutItem Length ()
 size :: PaddedBox Double -> LayoutItem Length () -> LayoutItem Double ()
 position :: LayoutItem Double -> LayoutItem Double Size
-layout :: PaddedBox Double -> LayoutItem Length () -> Bool -> [LayoutItem Double Size]
+layout :: PaddedBox Double -> LayoutItem Length () -> Bool -> [LayoutItem Double Size]-}
 
M Graphics/Layout/Arithmetic.hs => Graphics/Layout/Arithmetic.hs +47 -30
@@ 1,12 1,13 @@
 {-# LANGUAGE OverloadedStrings #-}
 module Graphics.Layout.Arithmetic where
 
-import Data.CSS.Tokens (Token(..))
+import Data.CSS.Syntax.Tokens (Token(..), NumericValue(..))
 import Data.Scientific (toRealFloat)
 import GHC.Real (infinity)
 import Data.Text (unpack, Text)
+import qualified Data.Text as Txt
 
-data Opcode n = Comma | Add | Subtract | Multiply | Divide | Func Text | Num n
+data Opcode n = Seq | Add | Subtract | Multiply | Divide | Func Text | Num n deriving Show
 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
@@ 14,59 15,64 @@ parseCalc (Dimension _ n unit:toks) stack =
     Num (val2float n, unpack unit):parseCalc toks stack
 parseCalc (Ident "e":toks) stack = Num (exp 1, ""):parseCalc toks stack
 parseCalc (Ident "pi":toks) stack = Num (pi, ""):parseCalc toks stack
-parseCalc (Ident "infinity":toks) stack = Num (infinity, ""):parseCalc toks stack
-parseCalc (Ident "-infinity":toks) stack = Num (-infinity, ""):parseCalc toks stack
+parseCalc (Ident "infinity":toks) stack = Num (f infinity, ""):parseCalc toks stack
+parseCalc (Ident "-infinity":toks) stack =
+    Num (negate $ f infinity, ""):parseCalc toks stack
 parseCalc (Ident "NaN":toks) stack = Num (0/0, ""):parseCalc toks stack
 
-parseCalc (Func x:toks) stack = parseCalc toks (Func x:stack)
+parseCalc (Function x:toks) stack = parseCalc toks (Func x:stack)
 parseCalc (LeftParen:toks) stack = parseCalc toks (Func "calc":stack)
 parseCalc toks'@(Delim c:toks) (stack:stacks)
     | prec stack >= prec (op c) = stack:parseCalc toks' stacks
     | otherwise = parseCalc toks (op c:stack:stacks)
   where
-    prec Comma = 1
+    prec Seq = 1
     prec Add = 2
     prec Subtract = 2
     prec Multiply = 3
     prec Divide = 3
     prec (Func _) = 0
     prec (Num _) = error "Unexpected number on operand stack!"
-    op '+' = Add
-    op '-' = Subtract
-    op '*' = Multiply
-    op '/' = Divide
-    op ',' = Comma -- For function-calls.
+parseCalc (Delim c:toks) [] = parseCalc toks [op c]
 parseCalc (Comma:toks) stack = parseCalc (Delim ',':toks) stack
 parseCalc (RightParen:toks) (Func "calc":stack) = parseCalc toks stack
-parseCalc (RightParen:toks) (op@Func _:stack) = op:parseCalc toks stack
+parseCalc (RightParen:toks) (op@(Func _):stack) = op:parseCalc toks stack
 parseCalc toks@(RightParen:_) (op:stack) = op:parseCalc toks stack
+parseCalc (RightParen:toks) [] = parseCalc toks []
 parseCalc [] [] = []
 parseCalc [] stack = parseCalc [RightParen] stack
-parseCalc _ _ = [Func "invalid"]
+parseCalc toks stack = [Func "invalid"]
+
+op :: Char -> Opcode n
+op '+' = Add
+op '-' = Subtract
+op '*' = Multiply
+op '/' = Divide
+op ',' = Seq -- For function-calls.
 
 -- Do operands counts line up? Are we dividing by 0?
 -- Also I see concerns about whether units line up. Not bothering verifying that.
 verifyCalc :: [Opcode (Float, String)] -> [Bool] -> Bool
-verifyCalc (Comma:expr) stack = verifyCalc expr stack
+verifyCalc (Seq:expr) stack = verifyCalc expr stack
 verifyCalc (Add:expr) (_:_:stack) = verifyCalc expr (True:stack)
-verifyCalc (Minus:expr) (_:_:stack) = verifyCalc expr (True:stack)
+verifyCalc (Subtract:expr) (_:_:stack) = verifyCalc expr (True:stack)
 verifyCalc (Multiply:expr) (_:_:stack) = verifyCalc expr (True:stack)
 verifyCalc (Divide:expr) (False:_) = False
 verifyCalc (Divide:expr) (_:_:stack) = verifyCalc expr (True:stack)
 verifyCalc (Num (n, _):expr) stack = verifyCalc expr ((n == 0):stack)
 verifyCalc (Func x:expr) (_:stack)
-    | x `elem` words "abs acos asin atan atan2 cos exp log sign sin sqrt tan" =
+    | x `elem` Txt.words "abs acos asin atan cos exp log sign sin sqrt tan" =
         verifyCalc expr (True:stack)
 verifyCalc (Func x:expr) (_:_:stack)
-    | x `elem` words "max min mod pow rem" = verifyCalc expr (True:stack)
+    | x `elem` Txt.words "atan2 max min mod pow rem" = verifyCalc expr (True:stack)
 verifyCalc (Func "clamp":expr) (_:_:_:stack) = verifyCalc expr (True:stack)
 verifyCalc [] [_] = True
 verifyCalc _ _ = False
 
-evalCalc :: Num n => [Opcode n] -> [n] -> n
-evalCalc (Comma:expr) stack = evalCalc expr stack -- The function args off
+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)
-evalCalc (Minus:expr) (y:x:stack) = evalCalc expr ((x - y):stack)
+evalCalc (Subtract:expr) (y:x:stack) = evalCalc expr ((x - y):stack)
 evalCalc (Multiply:expr) (y:x:stack) = evalCalc expr ((x*y):stack)
 evalCalc (Divide:expr) (y:x:stack) = evalCalc expr ((x/y):stack)
 evalCalc (Num n:expr) stack = evalCalc expr (n:stack)
@@ 75,18 81,20 @@ evalCalc (Func "abs":expr) (x:stack) = evalCalc expr (abs x:stack)
 evalCalc (Func "acos":expr) (x:stack) = evalCalc expr (acos x:stack)
 evalCalc (Func "asin":expr) (x:stack) = evalCalc expr (asin x:stack)
 evalCalc (Func "atan":expr) (x:stack) = evalCalc expr (atan x:stack)
-evalCalc (Func "atan2":expr) (x:stack) = evalCalc expr (atan2 x:stack)
-evalCalc (Func "clamp":expr) (max:x:min:stack) =
-    evalCalc expr (clamp (min, max) x:stack)
+evalCalc (Func "atan2":expr) (y:x:stack) = evalCalc expr (atan2 x y:stack)
+evalCalc (Func "clamp":expr) (high:x:low:stack) =
+    evalCalc expr (min high (max low x):stack)
 evalCalc (Func "cos":expr) (x:stack) = evalCalc expr (cos x:stack)
 evalCalc (Func "exp":expr) (x:stack) = evalCalc expr (exp x:stack)
 evalCalc (Func "log":expr) (x:stack) = evalCalc expr (log x:stack)
-evalCalc (Func "max":expr) (y:x:stack) = evalCalc expr (maximum x y:stack)
-evalCalc (Func "min":expr) (y:x:stack) = evalCalc expr (minimum x y:stack)
-evalCalc (Func "mod":expr) (y:x:stack) = evalCalc expr (mod x y:stack)
+evalCalc (Func "max":expr) (y:x:stack) = evalCalc expr (max x y:stack)
+evalCalc (Func "min":expr) (y:x:stack) = evalCalc expr (min x y:stack)
+evalCalc (Func "mod":expr) (y:x:stack) =
+    evalCalc expr (toEnum (round x `mod` round y):stack)
 evalCalc (Func "pow":expr) (y:x:stack) = evalCalc expr (x ** y:stack)
-evalCalc (Func "rem":expr) (y:x:stack) = evalCalc expr (rem x y:stack)
-evalCalc (Func "sign":expr) (x:stack) = evalCalc expr (sign x:stack)
+evalCalc (Func "rem":expr) (y:x:stack) =
+    evalCalc expr (toEnum (round x `rem` round y):stack)
+evalCalc (Func "sign":expr) (x:stack) = evalCalc expr (signum x:stack)
 evalCalc (Func "sin":expr) (x:stack) = evalCalc expr (sin x:stack)
 evalCalc (Func "sqrt":expr) (x:stack) = evalCalc expr (sqrt x:stack)
 evalCalc (Func "tan":expr) (x:stack) = evalCalc expr (tan x:stack)
@@ 96,8 104,17 @@ evalCalc _ _ = error "Verification should have caught this error!"
 
 mapCalc :: (a -> b) -> [Opcode a] -> [Opcode b]
 mapCalc cb (Num x:toks) = Num (cb x):mapCalc cb toks
-mapCalc cb (tok:toks) = tok:mapCalc cb toks
+-- GHC demanded more verbosity...
+mapCalc cb (Seq:toks) = mapCalc cb toks -- we can drop these while we're at it...
+mapCalc cb (Add:toks) = Add:mapCalc cb toks
+mapCalc cb (Subtract:toks) = Subtract:mapCalc cb toks
+mapCalc cb (Multiply:toks) = Multiply:mapCalc cb toks
+mapCalc cb (Divide:toks) = Divide:mapCalc cb toks
+mapCalc cb (Func f:toks) = Func f:mapCalc cb toks
 mapCalc _ [] = []
 
 val2float (NVInteger n) = fromIntegral n
-val2float (NVScientific n) = toRealFloat n
+val2float (NVNumber n) = toRealFloat n
+
+f :: Rational -> Float
+f = fromRational
 
M Graphics/Layout/Box.hs => Graphics/Layout/Box.hs +1 -1
@@ 6,7 6,7 @@ data Border n = Border {
 }
 data Size n = Size {inline :: n, block :: n}
 
-data PaddedBox n = {
+data PaddedBox n = PaddedBox {
     min :: Size n,
     max :: Size n,
     size :: Size n,
 
M Graphics/Layout/CSS.hs => Graphics/Layout/CSS.hs +3 -3
@@ 5,13 5,13 @@ import Graphics.Layout
 
 data CSSBox = CSSBox {
     boxSizing :: BoxSizing,
-    cssBox :: PaddedBox (Double, String), -- Some units need to be resolved per font. calc()?
+    cssBox :: PaddedBox (Double, String) -- Some units need to be resolved per font. calc()?
     -- Other layout-mode specific properties?
     -- Resolve font here so we can resolve those units?
 }
 data BoxSizing = BorderBox | ContentBox
 
-instance PropertyParser CSSBox where
+{-instance PropertyParser CSSBox where
     ...
 
-finalizeCSS :: CSSBox -> LayoutItem Length
+finalizeCSS :: CSSBox -> LayoutItem Length-}
 
M Graphics/Layout/Grid.hs => Graphics/Layout/Grid.hs +8 -3
@@ 1,19 1,24 @@
 module Graphics.Layout.Grid where
 
+import Data.Text (Text)
+import Graphics.Layout.Box
+
 data Grid n = Grid {
     rows :: [(Name, Either n Double)],
     columns :: [(Name, Either n Double)],
     gap :: Size n,
     gridBox :: PaddedBox n
 }
-data GridItem n = Grid {
+data GridItem n = GridItem {
     startRow :: Int, endRow :: Int, startCol :: Int, endCol :: Int,
     gridItemBox :: PaddedBox n
 }
 
-sizeBoundGrid :: Grid Length -> [GridItem Length] -> Grid Length
+type Name = Text
+
+{-sizeBoundGrid :: Grid Length -> [GridItem Length] -> Grid Length
 sizeGrid :: PaddedBox Double -> Grid Length -> Grid Double
 sizeGridItem :: Grid Length -> GridItem Length -> Grid Double
 positionGrid :: Grid Double -> [GridItem Double] -> [Size]
 layoutGrid :: PaddedBox Double -> Grid Length -> [GridItem Length] -> Bool ->
-    [(Grid Double, [(Size, GridItem Double)])]
+    [(Grid Double, [(Size, GridItem Double)])]-}
 
M cattrap.cabal => cattrap.cabal +10 -2
@@ 17,11 17,12 @@ extra-source-files:  CHANGELOG.md
 cabal-version:       >=1.10
 
 library
-  exposed-modules:     Graphics.Layout, Graphics.Layout.CSS, Graphics.Layout.Flow,
+  exposed-modules:     Graphics.Layout, Graphics.Layout.CSS, 
+-- Graphics.Layout.Flow,
                         Graphics.Layout.Grid, Graphics.Layout.Box, Graphics.Layout.Arithmetic
   -- other-modules:
   -- other-extensions:
-  build-depends:       base >=4.12 && <4.16
+  build-depends:       base >=4.12 && <4.16, css-syntax, scientific, text, stylist-traits
   -- hs-source-dirs:
   default-language:    Haskell2010
 
@@ 32,3 33,10 @@ executable cattrap
   build-depends:       base >=4.12 && <4.16
   hs-source-dirs:      app
   default-language:    Haskell2010
+
+test-suite test-cattrap
+  hs-source-dirs:      test
+  default-language:    Haskell2010
+  type:                exitcode-stdio-1.0
+  main-is:             Test.hs
+  build-depends:       base, cattrap, hspec, QuickCheck, css-syntax
 
A test/Test.hs => test/Test.hs +27 -0
@@ 0,0 1,27 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import Test.Hspec
+
+import Graphics.Layout.Arithmetic
+import Data.CSS.Syntax.Tokens (tokenize, Token(..))
+import Debug.Trace (traceShowId)
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec = do
+    describe "canary" $ do
+        it "test framework works" $ do
+            True `shouldBe` True
+    describe "calc()" $ do
+        it "Can perform basic arithmatic" $ do
+            runMath "42" `shouldBe` 42
+            runMath "6 * 9" `shouldBe` 54
+--            runMath "6 * 9 - 42" `shouldBe` 12
+--            runMath "6 * (9 - 42)" `shouldBe` -198
+--            runMath "6 * calc(9 - 42)" `shouldBe` -198
+--            runMath "6 * abs(9 - 42)" `shouldBe` 198
+
+runMath = flip evalCalc [] . mapCalc fst . flip parseCalc [] . filter (/= Whitespace) . tokenize