diff --git a/ChangeLog b/ChangeLog
new file mode 100644
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,40 @@
+version 0.6.0.2:
+
+* changed build system to use cartel.
+
+* moved tests to separate package, deka-tests
+
+version 0.6.0.0:
+
+* switch to mpdecimal for the underlying C library.  This allows
+higher limits on exponents and precision.  All arithmetic is now
+(practically speaking) arbitrary precision.  This also allows more
+operations, such as logarithms and all exponents.  As a possible
+disadvantage, this might be slower than decNumber (but I have not
+benchmarked this.)
+
+version 0.4.0.4:
+
+* test with GHC 7.8.2
+
+* bundle in decNumber for easier building.
+
+version 0.4.0.2:
+
+* remove version upper bounds
+
+* lower version lower bounds to allow building with GHC 7.4
+
+* add Sunlight tests
+
+version 0.4.0.0:
+
+* removed bindings-dsl; see comments in git log
+
+* made Quad an instance of Eq and Ord
+
+version 0.2.0.2:
+
+* updated .travis.yml for decnumber dependency
+
+* Removed spurious dependencies from .cabal file
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,68 @@
+License for deka:
+
+Copyright (c) 2014, Omari Norman
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Omari Norman nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Deka includes code from the decNumber C library.  The license
+for decNumber is as follows:
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1995-2005 International Business Machines Corporation and others
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above
+copyright notice(s) and this permission notice appear in all copies of
+the Software and that both the above copyright notice(s) and this
+permission notice appear in supporting documentation.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in this Software without prior written authorization
+of the copyright holder.
+
+--------------------------------------------------------------------------------
+All trademarks and registered trademarks mentioned herein are the property of their respective owners.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,63 @@
+# deka
+
+deka provides correctly rounded decimal arithmetic for Haskell.
+
+The core of deka is a binding to the C library mpdecimal.  You need
+to install mpdecimal; otherwise, your executables will not link.
+mpdecimal is available here:
+
+http://www.bytereef.org/mpdecimal/index.html
+
+mpdecimal has also been packaged for some Linux distributions, such
+as Debian (libmpdec-dev) and Arch (mpdecimal).  deka has been tested
+with mpdecimal version 2.4.0.
+
+As the author of deka, I have no association with the author of
+mpdecimal, and any errors in this library are mine and should be
+reported to omari@smileystation.com or to the Github tracker at
+
+http://www.github.com/massysett/deka
+
+You will want to understand the General Decimal Arithmetic
+Specification in order to fully understand deka.  The specification
+is at
+
+http://speleotrove.com/decimal/decarith.html
+
+and more about decimal arithmetic generally at
+
+http://speleotrove.com/decimal/
+
+## Dependencies
+
+The main deka library depends only on `base`, `bytestring`, and
+`parsec`, so it shouldn't be difficult to build.  The tests use
+[tasty](http://documentup.com/feuerbach/tasty) and
+[QuickCheck](http://hackage.haskell.org/package/QuickCheck).
+
+## Test status
+
+deka is tested using the tests available on the General Decimal
+Arithmetic website:
+
+http://speleotrove.com/decimal/dectest.html
+
+Some of these tests currently fail.  The failures are in edge cases
+that should not affect most usage.  Diagnosing these failures is on
+the TODO list.
+
+## More documentation
+
+Much more documentation is available in the Haddock comments in the
+source files.  There is also a file of examples to get you started.
+It has copious comments.  It is written in literate Haskell, so the
+compiler keeps me honest with the example code.  Unfortunately
+Haddock does not play very nice with literate Haskell.  However, the
+file is easy to view on Github:
+
+[Examples](lib/Data/Deka/Docs/Examples.lhs)
+
+## License
+
+deka is licensed under the BSD license, see the LICENSE file.
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/current-versions.txt b/current-versions.txt
new file mode 100644
--- /dev/null
+++ b/current-versions.txt
@@ -0,0 +1,53 @@
+This package was tested to work with these dependency
+versions and compiler version.
+These are the default versions fetched by cabal install.
+Tested as of: 2014-07-16 13:56:43.863793 UTC
+Path to compiler: ghc-7.8.3
+Compiler description: 7.8.3
+
+/opt/ghc/7.8.3/lib/ghc-7.8.3/package.conf.d:
+    Cabal-1.18.1.3
+    array-0.5.0.0
+    base-4.7.0.1
+    bin-package-db-0.0.0.0
+    binary-0.7.1.0
+    rts-1.0
+    bytestring-0.10.4.0
+    containers-0.5.5.1
+    deepseq-1.3.0.2
+    directory-1.2.1.0
+    filepath-1.3.0.2
+    (ghc-7.8.3)
+    ghc-prim-0.3.1.0
+    haskeline-0.7.1.2
+    (haskell2010-1.1.2.0)
+    (haskell98-2.0.0.3)
+    hoopl-3.10.0.1
+    hpc-0.6.0.1
+    integer-gmp-0.5.1.0
+    old-locale-1.0.0.6
+    old-time-1.1.0.2
+    pretty-1.1.1.1
+    process-1.2.0.0
+    template-haskell-2.9.0.0
+    terminfo-0.4.0.0
+    time-1.4.2
+    transformers-0.3.0.0
+    unix-2.7.0.1
+    xhtml-3000.2.1
+
+/home/massysett/deka/tests/sunlight-19453/db:
+    QuickCheck-2.7.6
+    deka-0.6.0.2
+    deka-tests-0.6.0.2
+    mmorph-1.0.3
+    mtl-2.2.1
+    parsec-3.1.5
+    pipes-4.1.2
+    primitive-0.5.3.0
+    quickpull-0.2.0.0
+    random-1.0.1.1
+    text-1.1.1.3
+    tf-random-0.5
+    transformers-0.4.1.0
+
diff --git a/dectest/Arity.hs b/dectest/Arity.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Arity.hs
@@ -0,0 +1,131 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | Use functions in here to test any testcase except toSci,
+-- toEng, or apply.  Those have special rules for operand parsing.
+module Arity where
+
+import TestLog
+import qualified Data.ByteString.Char8 as BS8
+import qualified Deka.Dec as D
+import qualified Deka.Context as C
+import Control.Monad
+import Data.Monoid
+import Operand
+import Result
+import Types
+import Directives
+import TestHelpers
+
+type Unary = D.Dec -> C.Ctx D.Dec
+type Binary = D.Dec -> D.Dec -> C.Ctx D.Dec
+type Ternary = D.Dec -> D.Dec -> D.Dec -> C.Ctx D.Dec
+
+unary :: Unary -> Test
+unary f dirs ops rslt conds = runTestLog $ do
+  ic <- parseDirectives dirs
+  op <- case ops of
+    x:[] -> operand ic x
+    _ -> flunk $ "one operand expected, got " <>
+      (BS8.pack . show . length $ ops)
+  mayRslt <- result rslt
+  let k = ic >> f op
+      (r, fl) = C.runCtxStatus k
+  testConditions conds fl
+  testDec r mayRslt
+  pass "conditions and result match targets"
+
+binary :: Binary -> Test
+binary f dirs ops rslt conds = runTestLog $ do
+  ic <- parseDirectives dirs
+  (opX, opY) <- case ops of
+    x:y:[] -> do
+      ox <- operand ic x
+      oy <- operand ic y
+      return (ox, oy)
+    _ -> flunk $ "two operands expected, got " <>
+      (BS8.pack . show . length $ ops)
+  mayRslt <- result rslt
+  let k = ic >> f opX opY
+      (r, fl) = C.runCtxStatus k
+  testConditions conds fl
+  testDec r mayRslt
+  pass "conditions and result match targets"
+
+comparer :: (D.Dec -> D.Dec -> Ordering) -> Test
+comparer f dirs ops rslt conds = runTestLog $ do
+  when (not . null $ conds) . flunk $
+    "comparer: conditions not null, which makes no sense "
+    <> "for this kind of test."
+  ic <- parseDirectives dirs
+  (opX, opY) <- case ops of
+    x:y:[] -> do
+      ox <- operand ic x
+      oy <- operand ic y
+      return (ox, oy)
+    _ -> flunk $ "two operands expected, got " <>
+      (BS8.pack . show . length $ ops)
+  rsltO <- resultOrd rslt
+  let r = f opX opY
+  if rsltO == r
+    then pass "conditions and result match targets"
+    else flunk $ "expected: " <> (BS8.pack . show $ rsltO)
+          <> " got: " <> (BS8.pack . show $ r)
+
+binaryTest :: (D.Dec -> D.Dec -> Bool) -> Test
+binaryTest f dirs ops rslt conds = runTestLog $ do
+  when (not . null $ conds) . flunk $
+    "binaryTest: conditions not null, which makes no sense "
+    <> "for this kind of test."
+  ic <- parseDirectives dirs
+  (opX, opY) <- case ops of
+    x:y:[] -> do
+      ox <- operand ic x
+      oy <- operand ic y
+      return (ox, oy)
+    _ -> flunk $ "two operands expected, got " <>
+      (BS8.pack . show . length $ ops)
+  rsltB <- resultBool rslt
+  let r = f opX opY
+  if rsltB == r
+    then pass "conditions and result match targets"
+    else flunk $ "expected: " <> (BS8.pack . show $ rsltB)
+          <> " got: " <> (BS8.pack . show $ r)
+
+
+decAndIntegral
+  :: (D.Dec -> D.Signed -> C.Ctx D.Dec) -> Test
+
+decAndIntegral f dirs ops rslt conds = runTestLog $ do
+  ic <- parseDirectives dirs
+  (opX, opY) <- case ops of
+    x:y:[] -> do
+      ox <- operand ic x
+      oy <- operandIntegral y
+      return (ox, oy)
+    _ -> flunk $ "two operands expected, got " <>
+      (BS8.pack . show . length $ ops)
+  let k = ic >> f opX opY
+      (r, fl) = C.runCtxStatus k
+  mayRslt <- result rslt
+  testConditions conds fl
+  testDec r mayRslt
+  pass "conditions and results match targets"
+
+ternary :: Ternary -> Test
+ternary f dirs ops rslt conds = runTestLog $ do
+  ic <- parseDirectives dirs
+  (opX, opY, opZ) <- case ops of
+    x:y:z:[] -> do
+      ox <- operand ic x
+      oy <- operand ic y
+      oz <- operand ic z
+      return (ox, oy, oz)
+    _ -> flunk $ "three operands expected, got " <>
+      (BS8.pack . show . length $ ops)
+  mayRslt <- result rslt
+  let k = ic >> f opX opY opZ
+      (r, fl) = C.runCtxStatus k
+  testConditions conds fl
+  testDec r mayRslt
+  pass "conditions and result match targets"
+
diff --git a/dectest/Conditions.hs b/dectest/Conditions.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Conditions.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Conditions where
+
+import qualified Data.ByteString.Char8 as BS8
+import TestLog
+import Data.String
+import qualified Deka.Context as C
+import Data.Monoid
+import Data.Char (toLower)
+import Data.List (sort)
+
+-- | Parses and sorts a list of conditions.
+
+parseConditions :: [BS8.ByteString] -> TestLog [C.Flag]
+parseConditions = fmap sort . mapM parseCondition
+
+parseCondition :: BS8.ByteString -> TestLog C.Flag
+parseCondition str = case lookup s allConditions of
+  Nothing -> flunk $ "could not parse condition: " <> str
+  Just f -> tell ("parsed condition: " <> str) >> return f
+  where
+    s = map toLower . BS8.unpack $ str
+
+allConditions :: IsString a => [(a, C.Flag)]
+allConditions =
+  [ ("clamped", C.clamped)
+  , ("conversion_syntax", C.conversionSyntax)
+  , ("division_by_zero", C.divisionByZero)
+  , ("division_impossible", C.divisionImpossible)
+  , ("division_undefined", C.divisionUndefined)
+  , ("inexact", C.inexact)
+
+  -- insufficient_storage not present in mpdecimal - not used in the
+  -- tests
+  -- , ("insufficient_storage", C.insufficientStorage)
+
+  , ("invalid_context", C.invalidContext)
+  , ("invalid_operation", C.invalidOperation)
+
+  -- lost_digits - not present in mpdecimal - but also not in the
+  -- decNumber tests
+  --, ("lost_digits", C.lostDigits)
+
+  , ("overflow", C.overflow)
+  , ("rounded", C.rounded)
+  , ("subnormal", C.subnormal)
+  , ("underflow", C.underflow)
+  ]
+ 
diff --git a/dectest/Directives.hs b/dectest/Directives.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Directives.hs
@@ -0,0 +1,142 @@
+{-# 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)
+  ]
+
diff --git a/dectest/NumTests.hs b/dectest/NumTests.hs
new file mode 100644
--- /dev/null
+++ b/dectest/NumTests.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE OverloadedStrings, NoImplicitPrelude #-}
+
+module NumTests where
+
+import Arity
+import Types
+import Specials
+import Deka.Dec
+import qualified Data.ByteString.Char8 as BS8
+
+testLookups :: [(BS8.ByteString, Test)]
+testLookups =
+  [ ("abs", unary abs)
+  , ("add", binary add)
+  , ("and", binary and)
+  , ("apply", apply)
+  -- skip: canonical
+  , ("class", decClass)
+  , ("compare", binary compare)
+  , ("comparesig", binary compareSignal)
+  , ("comparetotal", comparer compareTotal)
+  , ("comparetotalmag", comparer compareTotalMag)
+  -- skip: copy, copyabs, copynegate, copysign
+  , ("divide", binary divide)
+  , ("divideint", binary divideInteger)
+  , ("exp", unary exp)
+  , ("fma", ternary fma)
+  , ("invert", unary invert)
+  , ("ln", unary ln)
+  , ("log10", unary log10)
+  , ("logb", unary logB)
+  , ("max", binary max)
+  , ("min", binary min)
+  , ("maxmag", binary maxMag)
+  , ("minmag", binary minMag)
+  , ("minus", unary minus)
+  , ("multiply", binary multiply)
+  , ("nextminus", unary nextMinus)
+  , ("nextplus", unary nextPlus)
+  , ("nexttoward", binary nextToward)
+  , ("or", binary or)
+  , ("plus", unary plus)
+  , ("power", binary power)
+  , ("quantize", binary quantize)
+  , ("reduce", unary reduce)
+  , ("remainder", binary remainder)
+  , ("remaindernear", binary remainderNear)
+  , ("rescale", decAndIntegral rescale)
+  , ("rotate", binary rotate)
+  , ("samequantum", binaryTest sameQuantum)
+  , ("scaleb", binary scaleB)
+  , ("shift", binary shift)
+  , ("squareroot", unary squareRoot)
+  , ("subtract", binary subtract)
+  , ("toEng", toEng)
+  , ("tointegral", unary toIntegralValue)
+  , ("toIntegralx", unary toIntegralExact)
+  , ("toSci", toSci)
+  -- skip: trim
+  , ("xor", binary xor)
+  ]
diff --git a/dectest/Operand.hs b/dectest/Operand.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Operand.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Operand where
+
+import TestLog
+import qualified Data.ByteString.Char8 as BS8
+import qualified Deka.Dec as D
+import qualified Deka.Context as C
+import Data.Monoid
+import Util
+
+-- | Parses an operand.  Do not use this function for @toSci@,
+-- @toEng@, or @apply@ as those have special rules for handling the
+-- context.
+--
+-- Bypasses if the operand contains any octothorpe.
+
+operand
+  :: C.Ctx ()
+  -- ^ Initial context to use
+  -> BS8.ByteString
+  -- ^ Parse this token
+  -> TestLog D.Dec
+operand ic bs
+  | '#' `BS8.elem` bs =
+      bypass $ "operand contains an octothorpe: " <> bs
+  | otherwise = do
+      tell $ "parsing operand token: " <> bs
+      let k = do
+            ic
+            p <- fmap C.unPrecision C.setMaxPrecision
+            s <- D.fromByteString bs
+            return (p, s)
+      let (p, r) = C.runCtx k
+      tell $ "operand parse result: " <> D.toByteString r
+        <> " parsed at precision: " <> BS8.pack (show p)
+      return r
+
+-- | Parses an operand into a context.  Use this function for
+-- @toSci@, @toEng@, and @apply@.  Bypasses if the operand contains
+-- any octothorpe.
+operandSciEngAp
+  :: C.Ctx ()
+  -- ^ Initial context to use
+  -> BS8.ByteString
+  -- ^ Parse this token
+  -> TestLog (C.Ctx D.Dec)
+operandSciEngAp ic bs
+  | '#' `BS8.elem` bs =
+      bypass $ "operand contains an octothorpe: " <> bs
+  | otherwise = do
+      tell $ "parsing operand token: " <> bs
+      let k = ic >> D.fromByteString bs
+      return k
+
+-- | Parses a signed integral operand.
+operandIntegral
+  :: BS8.ByteString
+  -> TestLog D.Signed
+operandIntegral bs
+  | '#' `BS8.elem` bs =
+      bypass $ "operand contains an octothorpe: " <> bs
+
+  | otherwise = case readNumberBS bs of
+      Nothing -> flunk $ "could not parse integral operand: " <> bs
+      Just r -> do
+        tell $ "parsed integral operand: " <> bs
+        return r
diff --git a/dectest/Parse.hs b/dectest/Parse.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Parse.hs
@@ -0,0 +1,99 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Parse where
+
+import Parse.Tokens
+import qualified Data.ByteString.Char8 as BS8
+
+-- | Remove the comments from a line of tokens.  Any unquoted token that
+-- starts with two dashes is removed.  Also, any token that comes
+-- after such a token is also removed.
+removeComments :: [Token] -> [Token]
+removeComments toks = go toks
+  where
+    go [] = []
+    go (t:ts)
+      | quoted t = t : go ts
+      | BS8.take 2 (unToken t) == "--" = []
+      | otherwise = t : go ts
+
+newtype Keyword = Keyword { unKeyword :: BS8.ByteString }
+  deriving (Eq, Show)
+
+newtype Value = Value { unValue :: BS8.ByteString }
+  deriving (Eq, Show)
+
+data TestSpec = TestSpec
+  { testId :: BS8.ByteString
+  , testOperation :: BS8.ByteString
+  , testOperands :: [BS8.ByteString]
+  , testResult :: BS8.ByteString
+  , testConditions :: [BS8.ByteString]
+  } deriving Show
+
+data Instruction
+  = Blank
+  | Directive Keyword Value
+  | Test TestSpec
+  deriving Show
+
+data File = File
+  { fileName :: BS8.ByteString
+  , fileContents :: [Either File Instruction]
+  } deriving Show
+
+directive :: [Token] -> (Keyword, Value)
+directive ts = case ts of
+  x:y:[] -> ( Keyword . BS8.init . unToken $ x,
+              Value (unToken y) )
+  _ -> error "directive: bad token count"
+
+lineToContent :: [Token] -> IO (Either File Instruction)
+lineToContent ts
+  | null ts = return . Right $ Blank
+  | length ts == 2 && kw == "dectest" = fmap Left $ parseFile fn
+  | length ts == 2 = return . Right $ Directive akw avl
+  | otherwise = return . Right . Test . mkTestSpec $ ts
+  where
+    (akw@(Keyword kw), avl@(Value val)) = directive ts
+    fn = val `BS8.append` ".decTest"
+  
+mkTestSpec :: [Token] -> TestSpec
+mkTestSpec ts
+  | length ts < 5 = error "mkTestSpec: list too short"
+  | otherwise = TestSpec
+      { testId = unToken . head $ ts
+      , testOperation = unToken . head . drop 1 $ ts
+      , testOperands = map unToken
+          . takeWhile (not . resultsIn)
+          . drop 2
+          $ ts
+      , testResult = unToken
+          . safeHead
+          . drop 1
+          . dropWhile (not . resultsIn)
+          . drop 2
+          $ ts
+      , testConditions = map unToken
+          . drop 2
+          . dropWhile (not . resultsIn)
+          . drop 2
+          $ ts
+      }
+  where
+    resultsIn t = unToken t == "->" && not (quoted t)
+    safeHead x = case x of
+      [] -> error "mkTestSpec: list too short"
+      y:_ -> y
+
+rawToContent :: Raw -> IO [Either File Instruction]
+rawToContent
+  = mapM lineToContent
+  . map removeComments
+  . map processLine
+  . splitLines
+
+parseFile :: BS8.ByteString -> IO File
+parseFile fn = do
+  rw <- raw (BS8.unpack fn)
+  ctnt <- rawToContent rw
+  return $ File fn ctnt
diff --git a/dectest/Parse/Tokenizer.hs b/dectest/Parse/Tokenizer.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Parse/Tokenizer.hs
@@ -0,0 +1,220 @@
+{-# LANGUAGE OverloadedStrings #-}
+-- | A finite state machine to break a single line of text into
+-- tokens.
+--
+-- The machine has three main states, some of which have sub-states:
+--
+-- * inside of a token. Here, the machine can be in a @plain@ (that
+-- is, unquoted) word, or it can be inside of a quoted word.  When
+-- inside of a quoted word, if a closing quotation mark is seen, the
+-- machine transitions to being in a @pending@ state.  The next
+-- character determines what happens next: if it's an identical
+-- quotation mark, then a single quotation mark is added to the
+-- current token, and the machine stays in a quoted word state.  If
+-- the character is anything else, the machine outputs the previous
+-- token and begins a new one.
+--
+-- * between tokens.
+--
+-- * in a comment.  Before a token is output, the tokenizer examines
+-- it to determine whether it is both (1) unquoted, and (2) begins
+-- with two dashes.  If so, it's a comment token.  The token is not
+-- output, and the machine shifts to being in a comment state, which
+-- swallows all remaining characters that are input.
+--
+-- To use the tokenizer:
+--
+-- * turn it on with 'start'.
+--
+-- * Feed it characters from the line using 'feed'.  Occasionally
+-- this will output a single 'Token'.  It always outputs a new
+-- 'Tokenizer' that will accept further characters.
+--
+-- * when done, be sure to turn it off with 'finish'.  This will
+-- eject any characters in the tokenizer that have not been spit out
+-- yet.
+
+module Parse.Tokenizer
+  ( Tokenizer
+  , Token(..)
+  , start           -- :: Tokenizer
+  , feed            -- :: Char -> Tokenizer -> (Tokenizer, Maybe Token)
+  , finish          -- :: Tokenizer -> Maybe Token
+  ) where
+
+import qualified Data.ByteString.Char8 as BS8
+
+-- | Set to True when a single close quote character has been
+-- parsed.  Since double quote characters indicates an enclosed
+-- quote, we don't know until the next character whether to close
+-- the quote or just include a quote in the token.
+type Pending = Bool
+
+data QuoteType = Single | Double
+  deriving (Eq, Show)
+
+toQuot :: QuoteType -> Char
+toQuot Single = '\''
+toQuot Double = '"'
+
+data InTok
+  = PlainWord
+  | Quoted QuoteType Pending
+  deriving Show
+
+data Accepting
+  = InTok InTok BS8.ByteString
+  | BetweenToks
+  deriving Show
+
+-- The Tokenizer holds a Maybe Accepting, which is Nothing if the
+-- Tokenizer is no longer accepting new characters because it is in
+-- an comment, or is Just if accepting new characters.
+
+data Tokenizer = Tokenizer (Maybe Accepting)
+  deriving Show
+
+data Token = Token
+  { unToken :: BS8.ByteString
+  , quoted :: Bool
+  } deriving (Eq, Ord, Show)
+
+-- | Turns the tokenizer on.
+
+start :: Tokenizer
+start = Tokenizer . Just $ BetweenToks
+
+-- | Feeds a character to the tokenizer.
+feed :: Char -> Tokenizer -> (Tokenizer, Maybe Token)
+feed c (Tokenizer t) = case t of
+  Nothing -> (Tokenizer Nothing, Nothing)
+
+  Just a -> case a of
+    InTok tokType curr -> case tokType of
+
+      PlainWord ->
+        let mnt q = mint (InTok (Quoted q False) BS8.empty)
+                          curr False
+        in case c of
+            '"' -> mnt Double
+            '\'' -> mnt Single
+            ' ' -> mint BetweenToks curr False
+            _ -> stayInTok c curr PlainWord
+
+      Quoted qType pend
+        | pend -> acceptQuotedWithPending c curr qType
+        | otherwise -> acceptQuotedNoPending c curr qType
+
+    BetweenToks -> case c of
+      ' ' -> (Tokenizer (Just BetweenToks), Nothing)
+      '"' -> newTok (Left Double)
+      '\'' -> newTok (Left Single)
+      _ -> newTok (Right c)
+
+-- | Creates a new token, if called for.  Checks to see if the token
+-- that would be produced would be a comment token.  If so, do not
+-- emit a token, and return a Tokenizer that does not accept new
+-- characters.  Otherwise, emit the token, and return an accepting
+-- Tokenizer.
+
+mint
+  :: Accepting
+  -- ^ If a token is produced because the Tokenizer did not output a
+  -- comment, this becomes the new state of the Tokenizer.
+  -> BS8.ByteString
+  -- ^ What to output
+  -> Bool
+  -- ^ True if the token is quoted; False if not
+  -> (Tokenizer, Maybe Token)
+mint a o q
+  | q = nt
+  | otherwise =
+      if BS8.take 2 o == "--"
+      then (Tokenizer Nothing, Nothing)
+      else nt
+  where
+    nt = (Tokenizer (Just a), Just (Token o q))
+
+-- | Accepts a new character without producing a token.
+
+stayInTok
+  :: Char
+  -- ^ Character to add to the storehouse of characters in the
+  -- current token
+  -> BS8.ByteString
+  -- ^ Storehouse of current characters
+  -> InTok
+  -> (Tokenizer, Maybe Token)
+  -- ^ snd is always False, fst is a Tokenizer that is InTok
+stayInTok c s i = (tzr, Nothing)
+  where
+    tzr = Tokenizer (Just ac)
+    ac = InTok i (s `BS8.snoc` c)
+
+-- | Accepts a character while within a quote and there is not a
+-- pending character.
+
+acceptQuotedNoPending
+  :: Char
+  -- ^ Character to accept
+  -> BS8.ByteString
+  -- ^ Storehouse of current characters
+  -> QuoteType
+  -- ^ Type of quote we're currently inside of
+  -> (Tokenizer, Maybe Token)
+  -- ^ snd is always False, fst is a Tokenizer that is InTok
+acceptQuotedNoPending c s q = (tzr, Nothing)
+  where
+    tzr = Tokenizer (Just ac)
+    ac = InTok (Quoted q pnd) s'
+    (s', pnd)
+      | c == toQuot q = (s, True)
+      | otherwise = (s `BS8.snoc` c, False)
+
+-- | Accepts a character while within a quote and there is a pending
+-- character.
+acceptQuotedWithPending
+  :: Char
+  -- ^ Character to accept
+  -> BS8.ByteString
+  -- ^ Storehouse of current characters
+  -> QuoteType
+  -- ^ Type of quote we're currently inside of
+  -> (Tokenizer, Maybe Token)
+  -- ^ snd is always False, fst is a Tokenizer that is InTok
+acceptQuotedWithPending c s q
+  | c == toQuot q = stayInTok c s (Quoted q False)
+  | otherwise = case c of
+      ' ' -> mnt BetweenToks
+      '"' -> mnt (InTok (Quoted Double False) BS8.empty)
+      '\'' -> mnt (InTok (Quoted Single False) BS8.empty)
+      _ -> mnt (InTok PlainWord (BS8.singleton c))
+  where
+    mnt a = mint a s True
+
+-- | Starts a new token.
+newTok
+  :: Either QuoteType Char
+  -- ^ If Left, start a new quoted token.  If Right, start a new
+  -- plain token with the given character.
+  -> (Tokenizer, Maybe Token)
+  -- ^ snd is always False, fst if an accepting Tokenizer
+newTok e = (Tokenizer (Just (InTok i s)), Nothing)
+  where
+    (i, s) = case e of
+      Left q -> (Quoted q False, BS8.empty)
+      Right c -> (PlainWord, BS8.singleton c)
+
+-- | Finishes any remaining tokens in the machine.  Applies 'error'
+-- if there is a quoted token in the machine that has not been
+-- finished yet.
+finish :: Tokenizer -> Maybe Token
+finish (Tokenizer ma) = case ma of
+  Nothing -> Nothing
+  Just a -> case a of
+    BetweenToks -> Nothing
+    InTok i s -> case i of
+      PlainWord -> Just (Token s False)
+      Quoted _ pnd
+        | pnd -> Just (Token s True)
+        | otherwise -> error "finish: quoted token still in machine"
diff --git a/dectest/Parse/Tokens.hs b/dectest/Parse/Tokens.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Parse/Tokens.hs
@@ -0,0 +1,70 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Parse.Tokens
+  ( Raw(unRaw)
+  , Line(..)
+  , T.Token(..)
+  , splitLines
+  , processLine
+  , raw
+  ) where
+
+import qualified Data.ByteString.Char8 as BS8
+import qualified Parse.Tokenizer as T
+
+-- | Raw file, parsed in from disk.
+newtype Raw = Raw { unRaw :: BS8.ByteString }
+  deriving Show
+
+raw :: FilePath -> IO Raw
+raw = fmap Raw . BS8.readFile
+
+-- | A line from a Raw.  Does not contain any newlines.
+newtype Line = Line { unLine :: BS8.ByteString }
+  deriving Show
+
+-- | Splits a Raw into a list of Line.  First, eliminates any
+-- MS-DOS carriage returns (ASCII character 0d).  Then, uses the
+-- ByteString lines function.
+splitLines :: Raw -> [Line]
+splitLines = map Line . BS8.lines . BS8.filter (/= '\r') . unRaw
+
+--
+-- Parsing a Line into Tokens
+--
+
+data HighLevelLine = HighLevelLine
+  { llState :: T.Tokenizer
+  , llToks :: [T.Token]
+  } deriving Show
+
+highLevelProc :: HighLevelLine -> Char -> HighLevelLine
+highLevelProc h c = HighLevelLine l' ts'
+  where
+    (l', mayT) = T.feed c (llState h)
+    ts' = case mayT of
+      Nothing -> llToks h
+      Just t' -> t' : llToks h
+
+eject :: HighLevelLine -> [T.Token]
+eject h = reverse toks
+  where
+    toks = case T.finish (llState h) of
+      Nothing -> llToks h
+      Just t -> t : llToks h
+
+processLine :: Line -> [T.Token]
+processLine
+  = eject
+  . BS8.foldl highLevelProc z
+  . unLine
+  where
+    z = HighLevelLine T.start []
+
+_testProcessLine :: String -> IO ()
+_testProcessLine
+  = mapM_ BS8.putStrLn
+  . map T.unToken
+  . processLine
+  . Line
+  . BS8.pack
+
diff --git a/dectest/Result.hs b/dectest/Result.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Result.hs
@@ -0,0 +1,74 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Result where
+
+import TestLog
+import qualified Data.ByteString.Char8 as BS8
+import qualified Deka.Dec as D
+import qualified Deka.Context as C
+import Data.Monoid
+
+-- | Parses a result token.  Returns Nothing if the result token was
+-- a question mark, as this indicates that the result is undefined.
+-- Bypasses if the token contains an octothorpe.  Otherwise, returns
+-- the Dec.
+--
+-- Probably the easiest way to do the comparison is going to be to
+-- take the output of the test function, apply @toByteString@ to it,
+-- and then test that for equality with the result of applying
+-- @toByteString@ to the result returned from here.
+
+result
+  :: BS8.ByteString
+  -> TestLog (Maybe D.Dec)
+result bs
+  | '#' `BS8.elem` bs =
+      bypass $ "result contains an octothorpe: " <> bs
+
+  | '?' `BS8.elem` bs = do
+      tell "result token contains a question mark"
+      return Nothing
+
+  | otherwise = do
+      tell $ "parsing result token: " <> bs
+      let r = C.runCtx (D.fromByteString bs)
+      tell $ "result parse result: " <> D.toByteString r
+      return . Just $ r
+
+-- | Parses result token where the function is expecting an
+-- Ordering.
+
+resultOrd
+  :: BS8.ByteString
+  -> TestLog Ordering
+resultOrd bs
+  | '#' `BS8.elem` bs =
+      bypass $ "result contains an octothorpe: " <> bs
+
+  | '?' `BS8.elem` bs =
+      flunk "result token contains a question mark"
+
+  | otherwise = do
+      tell $ "parsing result token: " <> bs
+      case bs of
+        "-1" -> return LT
+        "0" -> return EQ
+        "1" -> return GT
+        _ -> flunk $ "unrecognized Ord result: " <> bs
+
+resultBool
+  :: BS8.ByteString
+  -> TestLog Bool
+resultBool bs
+  | '#' `BS8.elem` bs =
+      bypass $ "result contains an octothorpe: " <> bs
+
+  | '?' `BS8.elem` bs =
+      flunk "result token contains a question mark"
+
+  | otherwise = do
+      tell $ "parsing result token: " <> bs
+      case bs of
+        "1" -> return True
+        "0" -> return False
+        _ -> flunk $ "unrecognized Bool result: " <> bs
+
diff --git a/dectest/Runner.hs b/dectest/Runner.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Runner.hs
@@ -0,0 +1,164 @@
+{-# LANGUAGE OverloadedStrings, BangPatterns #-}
+module Runner (runAndExit) where
+
+import qualified Parse as P
+import qualified Data.ByteString.Char8 as BS8
+import Data.Monoid
+import Data.List (intersperse)
+import System.Exit
+import Data.Foldable (toList)
+import qualified Data.Sequence as S
+import Data.Sequence ((|>))
+import Pipes
+import Pipes.Prelude (fold)
+import NumTests (testLookups)
+import Types
+
+produceFile :: MonadIO m => Pipe BS8.ByteString P.File m ()
+produceFile = do
+  bs <- await
+  f <- liftIO $ P.parseFile bs
+  yield f
+
+order :: Monad m => Pipe P.File Order m ()
+order = do
+  f <- await
+  go S.empty (P.fileContents f)
+  where
+    go !sq ls = case ls of
+      [] -> return ()
+      x:xs -> case x of
+        Left inner -> go S.empty (P.fileContents inner)
+        Right i -> case i of
+          P.Blank -> go sq xs
+          P.Directive k v ->
+            let sq' = sq |> (k, v)
+            in go sq' xs
+          P.Test spec -> do
+            yield (Order sq spec)
+            go sq xs
+
+output :: Monad m => Pipe Order TestOutput m ()
+output = do
+  o <- await
+  case lookup (P.testOperation . ordSpec $ o) testLookups of
+    Nothing -> yield (noOperation . ordSpec $ o)
+    Just t -> yield (runTest o t)
+  output
+
+
+printTest
+  :: MonadIO m
+  => Pipe TestOutput (Maybe Bool) m ()
+printTest = do
+  o <- await
+  liftIO . BS8.putStr . showResult $ o
+  yield (outResult o)
+  printTest
+
+pipeline :: MonadIO m => Pipe BS8.ByteString (Maybe Bool) m ()
+pipeline =
+  produceFile
+  >-> order
+  >-> output
+  >-> printTest
+
+totals :: Monad m => Producer (Maybe Bool) m () -> m Counts
+totals = fold tally mempty id
+
+runAndExit :: [String] -> IO ()
+runAndExit ss = do
+  let bs = map BS8.pack ss
+      pip = each bs >-> pipeline
+  tot <- totals pip
+  putStr . showCounts $ tot
+  exit tot
+
+noOperation :: P.TestSpec -> TestOutput
+noOperation ts = TestOutput
+  { outSpec = ts
+  , outResult = Nothing
+  , outLog = S.singleton "no matching operation; skipping"
+  }
+
+data Order = Order
+  { _ordDirectives :: S.Seq (P.Keyword, P.Value)
+  , ordSpec :: P.TestSpec
+  }
+
+runTest
+  :: Order
+  -> Test
+  -> TestOutput
+runTest (Order ds ts) t = TestOutput
+  { outSpec = ts
+  , outResult = r
+  , outLog = l
+  }
+  where
+    (r, l) = t ds (P.testOperands ts) (P.testResult ts)
+      (P.testConditions ts)
+
+data TestOutput = TestOutput
+  { outSpec :: P.TestSpec
+  , outResult :: Maybe Bool
+  , outLog :: S.Seq BS8.ByteString
+  }
+
+data Counts = Counts
+  { _nPass :: !Int
+  , nFail :: !Int
+  , _nSkip :: !Int
+  } deriving Show
+
+tally :: Counts -> Maybe Bool -> Counts
+tally (Counts p f s) mb = case mb of
+  Nothing -> Counts p f (s + 1)
+  Just True -> Counts (p + 1) f s
+  Just False -> Counts p (f + 1) s
+
+instance Monoid Counts where
+  mempty = Counts 0 0 0
+  (Counts x1 y1 z1) `mappend` (Counts x2 y2 z2) =
+    Counts (x1 + x2) (y1 + y2) (z1 + z2)
+
+showCounts :: Counts -> String
+showCounts (Counts p f s) = unlines
+  [ "pass: " ++ show p
+  , "fail: " ++ show f
+  , "skip: " ++ show s
+  , "total: " ++ show (p + f + s)
+  ]
+
+exit :: Counts -> IO ()
+exit c
+  | nFail c > 0 = exitFailure
+  | otherwise = exitSuccess
+
+showResult
+  :: TestOutput
+  -> BS8.ByteString
+showResult (TestOutput t r sq) = BS8.unlines $ l1:lr
+  where
+    l1 = pf <+> showSpec t
+    pf = case r of
+      Nothing -> "[skip]"
+      Just True -> "[pass]"
+      Just False -> "[FAIL]"
+    lr = map ("    " <>) . toList $ sq
+
+showSpec :: P.TestSpec -> BS8.ByteString
+showSpec t =
+  P.testId t
+  <+> P.testOperation t
+  <+> BS8.concat (intersperse " " . P.testOperands $ t)
+  <+> "->"
+  <+> P.testResult t
+  <+> BS8.concat (intersperse " " . P.testConditions $ t)
+
+(<+>) :: BS8.ByteString -> BS8.ByteString -> BS8.ByteString
+l <+> r
+  | BS8.null l && BS8.null r = ""
+  | BS8.null l || BS8.null r = l <> r
+  | otherwise = l <> " " <> r
+
diff --git a/dectest/Specials.hs b/dectest/Specials.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Specials.hs
@@ -0,0 +1,85 @@
+{-# LANGUAGE OverloadedStrings #-}
+-- | Handling special cases: toSci, toEng, apply, class.
+
+module Specials where
+
+import qualified Data.ByteString.Char8 as BS8
+import TestLog
+import qualified Deka.Context as C
+import qualified Deka.Dec as D
+import Types
+import Operand
+import Directives
+import TestHelpers
+import Data.Monoid
+import Result
+import Data.Char (toLower)
+import Control.Arrow (first)
+
+toSciOrEng :: (D.Dec -> BS8.ByteString) -> Test
+toSciOrEng fn dirs opS rsS cdS = runTestLog $ do
+  ic <- parseDirectives dirs
+  getOp <- case opS of
+    x:[] -> operandSciEngAp ic x
+    _ -> flunk $ "expected 1 operand, got " <>
+      (BS8.pack . show . length $ opS)
+  let (rConv, fl) = C.runCtxStatus getOp
+      r = fn rConv
+  testConditions cdS fl
+  if r == rsS
+    then pass $ "string " <> r <> " matches expected result"
+    else flunk $ "string " <> r <> " does not match expected "
+            <> "result of " <> rsS
+
+toSci :: Test
+toSci = toSciOrEng D.toByteString
+
+toEng :: Test
+toEng = toSciOrEng D.toEngByteString
+
+apply :: Test
+apply dirs opS rsS cdS = runTestLog $ do
+  ic <- parseDirectives dirs
+  getOp <- case opS of
+    x:[] -> operandSciEngAp ic x
+    _ -> flunk $ "expected 1 operand, got " <>
+      (BS8.pack . show . length $ opS)
+  let k = getOp >>= D.plus
+      (rConv, fl) = C.runCtxStatus k
+      r = D.toByteString rConv
+  tgt <- result rsS
+  testConditions cdS fl
+  case tgt of
+    Nothing -> flunk $ "target result of apply is undefined; "
+      <> "this makes no sense"
+    Just t
+      | D.toByteString t == r -> pass "result is as expected"
+      | otherwise -> flunk $ "result of " <> r
+          <> " does not match expected result of "
+          <> D.toByteString t
+
+parseClass :: BS8.ByteString -> TestLog D.Class
+parseClass bs = case lookup lwr ls of
+  Nothing -> flunk $ "could not parse class: " <> bs
+  Just r -> do
+    tell $ "parsed class: " <> bs
+    return r
+  where
+    lwr = map toLower . BS8.unpack $ bs
+    ls = map (first (map toLower)) D.strToClass
+
+decClass :: Test
+decClass dirs opS rsS cdS = runTestLog $ do
+  ic <- parseDirectives dirs
+  op <- case opS of
+    x:[] -> operand ic x
+    _ -> flunk $ "expected 1 operand, got " <>
+      (BS8.pack . show . length $ opS)
+  tgt <- parseClass rsS
+  let k = ic >> D.numClass op
+      (r, fl) = C.runCtxStatus k
+  testConditions cdS fl
+  if r == tgt
+    then pass "result is as expected"
+    else flunk $ "unexpected class: result is " <>
+            (BS8.pack . show $ r)
diff --git a/dectest/TestHelpers.hs b/dectest/TestHelpers.hs
new file mode 100644
--- /dev/null
+++ b/dectest/TestHelpers.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE OverloadedStrings #-}
+module TestHelpers where
+
+import TestLog
+import qualified Data.ByteString.Char8 as BS8
+import qualified Deka.Dec as D
+import qualified Deka.Context as C
+import Data.Monoid
+import Conditions
+import Data.List (sort)
+
+testConditions
+  :: [BS8.ByteString]
+  -- ^ List of conditions
+  -> C.Flags
+  -- ^ Actual conditions from test
+  -> TestLog ()
+testConditions bs flgs = do
+  cs <- parseConditions bs
+  let fs = sort . C.unpackFlags $ flgs
+  if sort fs == sort cs
+    then tell "conditions are as expected"
+    else flunk $ "conditions not as expected: " <>
+          (BS8.pack . show $ fs)
+
+testDec :: D.Dec -> Maybe D.Dec -> TestLog ()
+testDec x y = case y of
+  Nothing -> tell "target result is undefined" >> return ()
+  Just r ->
+    let sx = D.toByteString x
+        sr = D.toByteString r
+        res | sx == sr = tell "result is as expected"
+            | otherwise =
+                flunk $ "output: " <> sx <> " expected result: " <> sr
+    in res
diff --git a/dectest/TestLog.hs b/dectest/TestLog.hs
new file mode 100644
--- /dev/null
+++ b/dectest/TestLog.hs
@@ -0,0 +1,64 @@
+module TestLog
+  ( TestLog
+  , tell
+  , bypass
+  , flunk
+  , Done
+  , pass
+  , runTestLog
+  ) where
+
+import qualified Data.Sequence as S
+import Control.Applicative
+import Control.Monad
+import qualified Data.ByteString.Char8 as BS8
+import Data.Monoid
+
+data State a
+  = Good a
+  | Failed
+  | Bypass
+  deriving Show
+
+newtype TestLog a = TestLog
+  { unTestLog :: (S.Seq BS8.ByteString, State a) }
+  deriving Show
+
+instance Monad TestLog where
+  return a = TestLog (S.empty, Good a)
+  (TestLog (ss, st)) >>= f = TestLog $ case st of
+    Failed -> (ss, Failed)
+    Bypass -> (ss, Bypass)
+    Good a -> let (ss', st') = unTestLog $ f a in
+      (ss <> ss', st')
+
+instance Applicative TestLog where
+  pure = return
+  (<*>) = ap
+
+instance Functor TestLog where
+  fmap = liftM
+
+tell :: BS8.ByteString -> TestLog ()
+tell bs = TestLog (S.singleton bs, Good ())
+
+bypass :: BS8.ByteString -> TestLog a
+bypass bs = TestLog (S.singleton bs, Bypass)
+
+flunk :: BS8.ByteString -> TestLog a
+flunk bs = TestLog (S.singleton bs, Failed)
+
+data Done = Done
+  deriving Show
+
+pass :: BS8.ByteString -> TestLog Done
+pass bs = TestLog (S.singleton bs, Good Done)
+
+runTestLog :: TestLog Done -> (Maybe Bool, S.Seq BS8.ByteString)
+runTestLog (TestLog (ss, st)) = (r, ss)
+  where
+    r = case st of
+      Good Done -> Just True
+      Failed -> Just False
+      Bypass -> Nothing
+
diff --git a/dectest/Types.hs b/dectest/Types.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Types.hs
@@ -0,0 +1,36 @@
+module Types where
+
+import qualified Data.ByteString.Char8 as BS8
+import qualified Parse as P
+import Data.Sequence
+
+-- | All tests must conform to this interface.
+
+type Test
+
+  = Seq (P.Keyword, P.Value)
+  -- ^ All directives in force when the test is run.  Oldest
+  -- directives are on the left side of the Seq; newest ones, on
+  -- the right side.
+
+  -> [BS8.ByteString]
+  -- ^ Operands
+
+  -> BS8.ByteString
+  -- ^ Result
+
+  -> [BS8.ByteString]
+  -- ^ Conditions.  These are already sorted.
+
+  -> (Maybe Bool, Seq BS8.ByteString)
+  -- ^ The test returns a Maybe Bool to indicate the test result.
+  -- Passage is Just True, failure is Just False, skip is Nothing.
+  -- Use Nothing for inputs that the implementation does not
+  -- support, such as null operands.  For all other failures
+  -- (including programmer errors or test configuration errors such
+  -- as mismatches in the number of operands), use Just False.
+  --
+  -- Also returned is a list of ByteString.  These are narratives.
+  -- Put one pice of data in each line.  For example  you might
+  -- include information on how the operands parsed, how the result
+  -- parsed, what information the test function returned, etc.
diff --git a/dectest/Util.hs b/dectest/Util.hs
new file mode 100644
--- /dev/null
+++ b/dectest/Util.hs
@@ -0,0 +1,28 @@
+module Util where
+
+import qualified Data.ByteString.Char8 as BS8
+
+switch :: a -> [(Bool, a)] -> a
+switch dflt [] = dflt
+switch dflt ((bl, a):xs)
+  | bl = a
+  | otherwise = switch dflt xs
+
+parseBool :: Int -> Maybe Bool
+parseBool i
+  | i == 0 = Just False
+  | i == 1 = Just True
+  | otherwise = Nothing
+
+safeRead :: Read a => String -> Maybe a
+safeRead a = case reads a of
+  (x, ""):[] -> Just x
+  _ -> Nothing
+
+readNumber :: Read a => String -> Maybe a
+readNumber a = case a of
+  [] -> Nothing
+  x:xs -> if x == '+' then safeRead xs else safeRead (x:xs)
+
+readNumberBS :: Read a => BS8.ByteString -> Maybe a
+readNumberBS bs = readNumber (BS8.unpack bs)
diff --git a/dectest/deka-dectest.hs b/dectest/deka-dectest.hs
new file mode 100644
--- /dev/null
+++ b/dectest/deka-dectest.hs
@@ -0,0 +1,7 @@
+module Main where
+
+import Runner
+import System.Environment
+
+main :: IO ()
+main = getArgs >>= runAndExit
diff --git a/deka-tests.cabal b/deka-tests.cabal
new file mode 100644
--- /dev/null
+++ b/deka-tests.cabal
@@ -0,0 +1,135 @@
+-- This Cabal file generated using the Cartel library.
+-- Cartel is available at:
+-- http://www.github.com/massysett/cartel
+--
+-- Script name used to generate: genCabal.hs
+-- Generated on: 2014-07-16 09:29:20.116107 EDT
+-- Cartel library version: 0.10.0.2
+name: deka-tests
+version: 0.6.0.2
+cabal-version: >= 1.14
+build-type: Simple
+license: BSD3
+license-file: LICENSE
+copyright: Copyright 2014 Omari Norman
+author: Omari Norman
+maintainer: Omari Norman, omari@smileystation.com
+stability: Experimental
+homepage: https://github.com/massysett/deka
+bug-reports: https://github.com/massysett/deka/issues
+synopsis: Tests for deka, decimal floating point arithmetic
+description:
+  deka provides decimal floating point arithmetic.  It is based on
+  mpdecimal, the C library used to provide support for the Decimal
+  module in Python 3.
+  .
+  You will need to install mpdecimal to use deka; otherwise your
+  executables will not link.  It is available at
+  .
+   <http://www.bytereef.org/mpdecimal/>
+  .
+  mpdecimal has also been packaged for some Linux distributions,
+  such as Debian (libmpdec-dev - available in Jessie and later) and
+  Arch (mpdecimal).
+  .
+  mpdecimal, in turn, implements the General Decimal Arithmetic
+  Specification, which is available at
+  .
+  <http://speleotrove.com/decimal/>
+  .
+  For more on deka, please see the Github home page at
+  .
+  <https://github.com/massysett/deka>
+  .
+  This package contains only tests, so that other packages
+  may also use the tests.
+category: Math
+tested-with: GHC == 7.4.1, GHC == 7.6.3, GHC == 7.8.3
+extra-source-files:
+    README.md
+  , ChangeLog
+  , current-versions.txt
+  , minimum-versions.txt
+
+source-repository head
+  type: git
+  location: https://github.com/massysett/deka.git
+
+Library
+  exposed-modules:
+      Deka.Dec.Coarbitrary
+    , Deka.Dec.Generators
+    , Deka.Dec.Shrinkers
+    , Deka.Native.Abstract.Coarbitrary
+    , Deka.Native.Abstract.Generators
+    , Deka.Native.Abstract.Shrinkers
+    , Deka.Tests.Util
+  hs-source-dirs:
+      lib
+  build-depends:
+      base ((> 4.5.0.0 || == 4.5.0.0) && < 4.8)
+    , bytestring ((> 0.9.2.1 || == 0.9.2.1) && < 0.11)
+    , deka == 0.6.0.2
+    , QuickCheck ((> 2.7.3 || == 2.7.3) && < 2.8)
+  ghc-options:
+      -Wall
+  default-language: Haskell2010
+
+Executable deka-dectest
+  build-depends:
+      base ((> 4.5.0.0 || == 4.5.0.0) && < 4.8)
+    , bytestring ((> 0.9.2.1 || == 0.9.2.1) && < 0.11)
+    , deka == 0.6.0.2
+    , QuickCheck ((> 2.7.3 || == 2.7.3) && < 2.8)
+    , transformers ((> 0.3.0.0 || == 0.3.0.0) && < 0.5)
+    , parsec ((> 3.1.2 || == 3.1.2) && < 3.2)
+    , containers ((> 0.4.2.1 || == 0.4.2.1) && < 0.6)
+    , pipes ((> 4.1.1 || == 4.1.1) && < 4.2)
+  hs-source-dirs:
+      dectest
+  other-modules:
+      Arity
+    , Conditions
+    , Directives
+    , NumTests
+    , Operand
+    , Parse
+    , Parse.Tokenizer
+    , Parse.Tokens
+    , Result
+    , Runner
+    , Specials
+    , TestHelpers
+    , TestLog
+    , Types
+    , Util
+  main-is: deka-dectest.hs
+  default-language: Haskell2010
+  ghc-options:
+      -Wall
+
+Test-Suite deka-native
+  build-depends:
+      base ((> 4.5.0.0 || == 4.5.0.0) && < 4.8)
+    , bytestring ((> 0.9.2.1 || == 0.9.2.1) && < 0.11)
+    , deka == 0.6.0.2
+    , QuickCheck ((> 2.7.3 || == 2.7.3) && < 2.8)
+    , quickpull ((> 0.2.0.0 || == 0.2.0.0) && < 0.3)
+  type: exitcode-stdio-1.0
+  main-is: deka-native.hs
+  hs-source-dirs:
+      native
+    , lib
+  other-modules:
+      Deka.Dec.Coarbitrary
+    , Deka.Dec.Generators
+    , Deka.Dec.Shrinkers
+    , Deka.Native.Abstract.Coarbitrary
+    , Deka.Native.Abstract.Generators
+    , Deka.Native.Abstract.Shrinkers
+    , Deka.Tests.Util
+    , Decrees
+    , Properties
+  default-language: Haskell2010
+  ghc-options:
+      -Wall
diff --git a/lib/Deka/Dec/Coarbitrary.hs b/lib/Deka/Dec/Coarbitrary.hs
new file mode 100644
--- /dev/null
+++ b/lib/Deka/Dec/Coarbitrary.hs
@@ -0,0 +1,15 @@
+module Deka.Dec.Coarbitrary where
+
+import qualified Deka.Dec as D
+import Test.QuickCheck
+import Deka.Tests.Util
+
+posNeg :: D.PosNeg -> Gen a -> Gen a
+posNeg a = case a of
+  D.Pos -> varInt 0
+  D.Neg -> varInt 1
+
+sign :: D.Sign -> Gen a -> Gen a
+sign a = case a of
+  D.Sign0 -> varInt 0
+  D.Sign1 -> varInt 1
diff --git a/lib/Deka/Dec/Generators.hs b/lib/Deka/Dec/Generators.hs
new file mode 100644
--- /dev/null
+++ b/lib/Deka/Dec/Generators.hs
@@ -0,0 +1,10 @@
+module Deka.Dec.Generators where
+
+import Test.QuickCheck
+import qualified Deka.Dec as D
+
+posNeg :: Gen D.PosNeg
+posNeg = elements [ D.Pos, D.Neg ]
+
+sign :: Gen D.Sign
+sign = elements [ D.Sign0, D.Sign1 ]
diff --git a/lib/Deka/Dec/Shrinkers.hs b/lib/Deka/Dec/Shrinkers.hs
new file mode 100644
--- /dev/null
+++ b/lib/Deka/Dec/Shrinkers.hs
@@ -0,0 +1,13 @@
+module Deka.Dec.Shrinkers where
+
+import qualified Deka.Dec as D
+
+posNeg :: D.PosNeg -> [D.PosNeg]
+posNeg x = case x of
+  D.Neg -> [D.Pos]
+  _ -> []
+
+sign :: D.Sign -> [D.Sign]
+sign x = case x of
+  D.Sign1 -> [D.Sign0]
+  _ -> []
diff --git a/lib/Deka/Native/Abstract/Coarbitrary.hs b/lib/Deka/Native/Abstract/Coarbitrary.hs
new file mode 100644
--- /dev/null
+++ b/lib/Deka/Native/Abstract/Coarbitrary.hs
@@ -0,0 +1,72 @@
+module Deka.Native.Abstract.Coarbitrary where
+
+import qualified Deka.Native.Abstract as D
+import Test.QuickCheck
+import Deka.Tests.Util
+import Deka.Dec.Coarbitrary
+import Prelude hiding (exponent)
+
+novem :: D.Novem -> Gen a -> Gen a
+novem d = case d of
+  D.D1 -> v 0
+  D.D2 -> v 1
+  D.D3 -> v 2
+  D.D4 -> v 3
+  D.D5 -> v 4
+  D.D6 -> v 5
+  D.D7 -> v 6
+  D.D8 -> v 7
+  D.D9 -> v 8
+  where
+    v = varInt
+
+decem :: D.Decem -> Gen a -> Gen a
+decem d = case d of
+  D.D0 -> varInt 0
+  D.Nonem n -> varInt 1 . novem n
+
+decuple :: D.Decuple -> Gen a -> Gen a
+decuple (D.Decuple n ds) = novem n . coarbitraryList decem ds
+
+aut :: D.Aut -> Gen a -> Gen a
+aut a = case a of
+  D.Nil -> varInt 0
+  D.Plenus d -> varInt 1 . decuple d
+
+firmado :: D.Firmado -> Gen a -> Gen a
+firmado a = case a of
+  D.Cero -> varInt 0
+  D.Completo p d -> varInt 1 . posNeg p . decuple d
+
+coefficient :: D.Coefficient -> Gen a -> Gen a
+coefficient (D.Coefficient c) = aut c
+
+exponent :: D.Exponent -> Gen a -> Gen a
+exponent (D.Exponent c) = firmado c
+
+diagnostic :: D.Diagnostic -> Gen a -> Gen a
+diagnostic (D.Diagnostic d) = decuple d
+
+noisy :: D.Noisy -> Gen a -> Gen a
+noisy d = case d of
+  D.Quiet -> varInt 0
+  D.Signaling -> varInt 1
+
+nonNum :: D.NonNum -> Gen a -> Gen a
+nonNum (D.NonNum n d) = noisy n . varD d
+  where
+    varD x = case x of
+      Nothing -> varInt 0
+      Just j -> varInt 1 . diagnostic j
+
+value :: D.Value -> Gen a -> Gen a
+value v = case v of
+  D.Finite c e -> varInt 0 . coefficient c . exponent e
+  D.Infinite -> varInt 1
+  D.NotANumber n -> varInt 2 . nonNum n
+
+abstract :: D.Abstract -> Gen a -> Gen a
+abstract (D.Abstract s v) = sign s . value v
+
+adjustedExp :: D.AdjustedExp -> Gen a -> Gen a
+adjustedExp (D.AdjustedExp i) = variant i
diff --git a/lib/Deka/Native/Abstract/Generators.hs b/lib/Deka/Native/Abstract/Generators.hs
new file mode 100644
--- /dev/null
+++ b/lib/Deka/Native/Abstract/Generators.hs
@@ -0,0 +1,53 @@
+module Deka.Native.Abstract.Generators where
+
+import Test.QuickCheck
+import Deka.Dec.Generators
+import qualified Deka.Native.Abstract as A
+import Control.Monad
+import Prelude hiding (exponent)
+
+novem :: Gen A.Novem
+novem = elements
+  [ A.D1, A.D2, A.D3, A.D4, A.D5, A.D6, A.D7, A.D8, A.D9 ]
+
+decem :: Gen A.Decem
+decem = frequency [(1, return A.D0), (5, fmap A.Nonem novem)]
+
+decuple :: Gen A.Decuple
+decuple = liftM2 A.Decuple novem (listOf decem)
+
+aut :: Gen A.Aut
+aut = frequency [(1, return A.Nil), (5, fmap A.Plenus decuple)]
+
+firmado :: Gen A.Firmado
+firmado = frequency [ (1, return A.Cero),
+                      (5, liftM2 A.Completo posNeg decuple) ]
+
+coefficient :: Gen A.Coefficient
+coefficient = fmap A.Coefficient aut
+
+exponent :: Gen A.Exponent
+exponent = fmap A.Exponent firmado
+
+diagnostic :: Gen A.Diagnostic
+diagnostic = fmap A.Diagnostic decuple
+
+noisy :: Gen A.Noisy
+noisy = elements [ A.Quiet, A.Signaling ]
+
+nonNum :: Gen A.NonNum
+nonNum = liftM2 A.NonNum noisy
+  (frequency [(1, return Nothing), (5, fmap Just diagnostic)])
+
+value :: Gen A.Value
+value = frequency
+  [ (4, liftM2 A.Finite coefficient exponent)
+  , (1, return A.Infinite)
+  , (1, fmap A.NotANumber nonNum)
+  ]
+
+abstract :: Gen A.Abstract
+abstract = liftM2 A.Abstract sign value
+
+adjustedExp :: Gen A.AdjustedExp
+adjustedExp = fmap A.AdjustedExp arbitrarySizedIntegral
diff --git a/lib/Deka/Native/Abstract/Shrinkers.hs b/lib/Deka/Native/Abstract/Shrinkers.hs
new file mode 100644
--- /dev/null
+++ b/lib/Deka/Native/Abstract/Shrinkers.hs
@@ -0,0 +1,75 @@
+module Deka.Native.Abstract.Shrinkers where
+
+import Deka.Dec.Shrinkers
+import qualified Deka.Native.Abstract as D
+import Test.QuickCheck
+import Prelude hiding (exponent)
+
+novem :: D.Novem -> [D.Novem]
+novem d = case d of
+  D.D1 -> []
+  D.D2 -> [D.D1]
+  D.D3 -> [D.D1 .. D.D2]
+  D.D4 -> [D.D1 .. D.D3]
+  D.D5 -> [D.D1 .. D.D4]
+  D.D6 -> [D.D1 .. D.D5]
+  D.D7 -> [D.D1 .. D.D6]
+  D.D8 -> [D.D1 .. D.D7]
+  D.D9 -> [D.D1 .. D.D8]
+
+decem :: D.Decem -> [D.Decem]
+decem d = case d of
+  D.D0 -> []
+  D.Nonem nv -> D.D0 : map D.Nonem (novem nv)
+
+decuple :: D.Decuple -> [D.Decuple]
+decuple (D.Decuple n d) =
+  [ D.Decuple n' d' | n' <- novem n,
+                      d' <- shrinkList decem d ]
+
+aut :: D.Aut -> [D.Aut]
+aut a = case a of
+  D.Nil -> []
+  D.Plenus d -> D.Nil : map D.Plenus (decuple d)
+
+firmado :: D.Firmado -> [D.Firmado]
+firmado a = case a of
+  D.Cero -> []
+  D.Completo p d ->
+    [ D.Completo p' d' | p' <- posNeg p, d' <- decuple d ]
+
+coefficient :: D.Coefficient -> [D.Coefficient]
+coefficient = map D.Coefficient . aut . D.unCoefficient
+
+exponent :: D.Exponent -> [D.Exponent]
+exponent = map D.Exponent . firmado . D.unExponent
+
+diagnostic :: D.Diagnostic -> [D.Diagnostic]
+diagnostic = map D.Diagnostic . decuple . D.unDiagnostic
+
+noisy :: D.Noisy -> [D.Noisy]
+noisy a = case a of
+  D.Quiet -> []
+  D.Signaling -> [D.Quiet]
+
+nonNum :: D.NonNum -> [D.NonNum]
+nonNum (D.NonNum n d) = [ D.NonNum n' d'
+  | n' <- noisy n, d' <- shrinkMaybe d ]
+  where
+    shrinkMaybe m = case m of
+      Nothing -> []
+      Just x -> Nothing : map Just (diagnostic x)
+
+value :: D.Value -> [D.Value]
+value a = case a of
+  D.Finite c e -> [ D.Finite c' e' | c' <- coefficient c,
+                                     e' <- exponent e ]
+  D.Infinite -> []
+  D.NotANumber n -> [ D.NotANumber n' | n' <- nonNum n ]
+
+abstract :: D.Abstract -> [D.Abstract]
+abstract (D.Abstract s v) =
+  [ D.Abstract s' v' | s' <- sign s, v' <- value v ]
+
+adjustedExp :: D.AdjustedExp -> [D.AdjustedExp]
+adjustedExp (D.AdjustedExp i) = map D.AdjustedExp $ shrinkIntegral i
diff --git a/lib/Deka/Tests/Util.hs b/lib/Deka/Tests/Util.hs
new file mode 100644
--- /dev/null
+++ b/lib/Deka/Tests/Util.hs
@@ -0,0 +1,11 @@
+module Deka.Tests.Util where
+
+import Test.QuickCheck
+
+varInt :: Int -> Gen b -> Gen b
+varInt = variant
+
+coarbitraryList :: (a -> Gen b -> Gen b) -> [a] -> Gen b -> Gen b
+coarbitraryList f ls = case ls of
+  [] -> varInt 0
+  x:xs -> varInt 1 . f x . coarbitraryList f xs
diff --git a/minimum-versions.txt b/minimum-versions.txt
new file mode 100644
--- /dev/null
+++ b/minimum-versions.txt
@@ -0,0 +1,50 @@
+This package was tested to work with these dependency
+versions and compiler version.
+These are the minimum versions given in the .cabal file.
+Tested as of: 2014-07-16 13:56:43.863793 UTC
+Path to compiler: ghc-7.4.1
+Compiler description: 7.4.1
+
+/opt/ghc/7.4.1/lib/ghc-7.4.1/package.conf.d:
+    Cabal-1.14.0
+    array-0.4.0.0
+    base-4.5.0.0
+    bin-package-db-0.0.0.0
+    binary-0.5.1.0
+    bytestring-0.9.2.1
+    containers-0.4.2.1
+    deepseq-1.3.0.0
+    directory-1.1.0.2
+    extensible-exceptions-0.1.1.4
+    filepath-1.3.0.0
+    (ghc-7.4.1)
+    ghc-prim-0.2.0.0
+    (haskell2010-1.1.0.1)
+    (haskell98-2.0.0.1)
+    hoopl-3.8.7.3
+    hpc-0.5.1.1
+    integer-gmp-0.4.0.0
+    old-locale-1.0.0.4
+    old-time-1.1.0.0
+    pretty-1.1.1.0
+    process-1.1.0.1
+    rts-1.0
+    template-haskell-2.7.0.0
+    time-1.4
+    unix-2.5.1.0
+
+/home/massysett/deka/tests/sunlight-19453/db:
+    QuickCheck-2.7.3
+    deka-0.6.0.2
+    deka-tests-0.6.0.2
+    mmorph-1.0.3
+    mtl-2.1.3.1
+    parsec-3.1.2
+    pipes-4.1.1
+    primitive-0.5.3.0
+    quickpull-0.2.0.0
+    random-1.0.1.1
+    text-0.11.3.1
+    tf-random-0.5
+    transformers-0.3.0.0
+
diff --git a/native/Decrees.hs b/native/Decrees.hs
new file mode 100644
--- /dev/null
+++ b/native/Decrees.hs
@@ -0,0 +1,15 @@
+-- | This module generated by the Quickpull package.
+-- Quickpull is available at:
+-- <http://www.github.com/massysett/quickpull>
+
+module Decrees where
+
+import Quickpull
+import qualified Properties
+
+decrees :: [Decree]
+decrees =
+
+  [ Decree ( Meta {modDesc = ModDesc {modPath = "native/Properties.hs", modName = ["Properties"]}, linenum = 9, qName = "prop_abstractToStringToAbstract"} ) ( Single Properties.prop_abstractToStringToAbstract )
+  , Decree ( Meta {modDesc = ModDesc {modPath = "native/Properties.hs", modName = ["Properties"]}, linenum = 15, qName = "prop_decToAbstractToDec"} ) ( Single Properties.prop_decToAbstractToDec )
+  ]
diff --git a/native/Properties.hs b/native/Properties.hs
new file mode 100644
--- /dev/null
+++ b/native/Properties.hs
@@ -0,0 +1,21 @@
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+module Properties where
+
+import qualified Deka.Native.Abstract.Generators as G
+import qualified Deka.Native as N
+import Test.QuickCheck
+import qualified Deka.Dec as D
+
+prop_abstractToStringToAbstract =
+  forAll G.abstract $ \a ->
+  case N.stringToAbstract . N.abstractToString $ a of
+    Left _ -> property False
+    Right a' -> a === a'
+
+prop_decToAbstractToDec =
+  forAll G.abstract $ \a ->
+  let (d, flgs) = N.abstractToDec a
+      a' = N.decToAbstract d
+      (d'', flgs') = N.abstractToDec a'
+  in flgs == D.emptyFlags && flgs' == D.emptyFlags
+     ==> D.compareTotal d d'' == EQ
diff --git a/native/deka-native.hs b/native/deka-native.hs
new file mode 100644
--- /dev/null
+++ b/native/deka-native.hs
@@ -0,0 +1,7 @@
+module Main where
+
+import Decrees
+import Quickpull
+
+main :: IO ()
+main = defaultMain decrees
