diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,9 +1,2 @@
 import Distribution.Simple
-import System.Cmd
-main = defaultMainWithHooks $ simpleUserHooks { runTests = run, preClean = clean }
-    where run _ _ _ _ = do
-            system "dist/build/yaml2yeast-test/yaml2yeast-test tests"
-            return ()
-          clean _ _ = do
-            system "rm -f tests/*.error"
-            return (Nothing, [])
+main = defaultMain
diff --git a/Text/Yaml/Reference.hs b/Text/Yaml/Reference.hs
--- a/Text/Yaml/Reference.hs
+++ b/Text/Yaml/Reference.hs
@@ -139,8 +139,8 @@
     UTF8    -> undoUTF8 bytes 0
     UTF16LE -> combinePairs $ undoUTF16LE bytes 0
     UTF16BE -> combinePairs $ undoUTF16BE bytes 0
-    UTF32LE -> combinePairs $ undoUTF32LE bytes 0
-    UTF32BE -> combinePairs $ undoUTF32BE bytes 0
+    UTF32LE -> undoUTF32LE bytes 0
+    UTF32BE -> undoUTF32BE bytes 0
 
 -- ** UTF-32 decoding
 
@@ -682,6 +682,15 @@
 unexpectedReply state = case state|>sInput of
                              ((_, char):_) -> failReply state $ "Unexpected '" ++ [char] ++ "'"
                              []            -> failReply state "Unexpected end of input"
+
+-- | Needed due to the Applicative Monad Proposal.
+instance Functor Parser where
+  fmap = liftM
+
+-- | Needed due to the Applicative Monad Proposal.
+instance Applicative Parser where
+  pure = return
+  (<*>) = ap
 
 -- | Allow using the @do@ notation for our parsers, which makes for short and
 -- sweet @do@ syntax when we want to examine the results (we typically don't).
diff --git a/YamlReference.cabal b/YamlReference.cabal
--- a/YamlReference.cabal
+++ b/YamlReference.cabal
@@ -1,14 +1,14 @@
 Name:                YamlReference
-Version:             0.9.3
-Cabal-Version:       >= 1.6
+Version:             0.10.0
+Cabal-Version:       >= 1.8
 License:             LGPL
 License-File:        lgpl.txt
-Copyright:           Oren Ben-Kiki 2007, 2008
+Copyright:           Oren Ben-Kiki 2007, 2008, 2016
 Author:              Oren Ben-Kiki
 Maintainer:          yaml-oren@ben-kiki.org
 Stability:           alpha
 Homepage:            http://www.ben-kiki.org/oren/YamlReference
-Package-Url:         http://www.ben-kiki.org/oren/YamlReference/YamlReference-0.9.2.tar.gz
+Package-Url:         http://www.ben-kiki.org/oren/YamlReference/YamlReference-0.10.0.tar.gz
 Category:            Text
 Synopsis:            YAML reference implementation
 Build-Type:          Custom
@@ -158,10 +158,10 @@
                      tests/c-flow-mapping.n=4.c=flow-in.spaced.output
                      tests/c-flow-sequence.n=4.c=flow-in.compact.input
                      tests/c-flow-sequence.n=4.c=flow-in.compact.output
-                     tests/c-flow-sequence.n=4.c=flow-in.::.input
+                     tests/c-flow-sequence.n=4.c=flow-in.colons.input
                      tests/c-flow-sequence.n=4.c=flow-in.invalid.input
                      tests/c-flow-sequence.n=4.c=flow-in.invalid.output
-                     tests/c-flow-sequence.n=4.c=flow-in.::.output
+                     tests/c-flow-sequence.n=4.c=flow-in.colons.output
                      tests/c-flow-sequence.n=4.c=flow-in.spaced.input
                      tests/c-flow-sequence.n=4.c=flow-in.spaced.output
                      tests/c-folded.input tests/c-folded.output
@@ -868,14 +868,14 @@
                      tests/ns-plain.n=1.c=flow-key.dc.output
                      tests/ns-plain.n=1.c=flow-key.ds.input
                      tests/ns-plain.n=1.c=flow-key.ds.output
-                     tests/ns-plain.n=1.c=flow-key.::.input
+                     tests/ns-plain.n=1.c=flow-key.colons.input
                      tests/ns-plain.n=1.c=flow-key.ka.input
                      tests/ns-plain.n=1.c=flow-key.ka.output
                      tests/ns-plain.n=1.c=flow-key.kc.input
                      tests/ns-plain.n=1.c=flow-key.kc.output
                      tests/ns-plain.n=1.c=flow-key.ks.input
                      tests/ns-plain.n=1.c=flow-key.ks.output
-                     tests/ns-plain.n=1.c=flow-key.::.output
+                     tests/ns-plain.n=1.c=flow-key.colons.output
                      tests/ns-plain.n=1.c=flow-key.va.input
                      tests/ns-plain.n=1.c=flow-key.va.output
                      tests/ns-plain.n=1.c=flow-key.vc.input
@@ -1229,41 +1229,29 @@
                      tests/s-white.sp.output tests/s-white.tab.input
                      tests/s-white.tab.output
 
-Flag small_base
-    Description:         Choose the new smaller, split-up base package.
-
 Library
     Exposed-Modules:     Text.Yaml.Reference
-    if flag(small_base)
-        Build-Depends:   base >= 3, containers, bytestring
-    else
-        Build-Depends:   base < 3
-    Build-Depends:       HUnit >= 1.1, regex-compat >= 0.71, dlist >= 0.2
-    if impl(ghc >= 6.10.0)
-        Extensions:      CPP, MultiParamTypeClasses, FunctionalDependencies,
-                         FlexibleInstances, TypeSynonymInstances, PostfixOperators
-    else
-        Extensions:      CPP, MultiParamTypeClasses, FunctionalDependencies,
-                         FlexibleInstances, TypeSynonymInstances
+    Build-Depends:       base >= 4 && < 5, containers, bytestring,
+                         regex-compat >= 0.71, dlist >= 0.2
+    Extensions:          CPP, MultiParamTypeClasses, FunctionalDependencies,
+                         FlexibleInstances, TypeSynonymInstances, PostfixOperators,
+                         FlexibleContexts
 
 Executable yaml2yeast
     Hs-Source-Dirs:      yaml2yeast .
+    Build-Depends:       base >= 4 && < 5, containers, bytestring,
+                         regex-compat >= 0.71, dlist >= 0.2
     Main-Is:             Main.hs
-    if impl(ghc >= 6.10.0)
-        Extensions:      CPP, MultiParamTypeClasses, FunctionalDependencies,
-                         FlexibleInstances, TypeSynonymInstances, PostfixOperators
-    else
-        Extensions:      CPP, MultiParamTypeClasses, FunctionalDependencies,
-                         FlexibleInstances, TypeSynonymInstances
+    Extensions:          CPP, MultiParamTypeClasses, FunctionalDependencies,
+                         FlexibleInstances, TypeSynonymInstances, PostfixOperators,
+                         FlexibleContexts
 
-Executable yaml2yeast-test
+Test-Suite yaml2yeast-test
+    Type:                exitcode-stdio-1.0
     Hs-Source-Dirs:      yaml2yeast-test .
     Main-Is:             Main.hs
-    if impl(ghc >= 6.10.0)
-        Extensions:      CPP, MultiParamTypeClasses, FunctionalDependencies,
-                         FlexibleInstances, TypeSynonymInstances, PostfixOperators
-    else
-        Extensions:      CPP, MultiParamTypeClasses, FunctionalDependencies,
-                         FlexibleInstances, TypeSynonymInstances
-    if flag(small_base)
-        Build-Depends:   directory
+    Build-Depends:       base >= 4 && < 5, containers, directory, hashmap, mtl,
+                         bytestring, regex-compat >= 0.71, dlist >= 0.2, HUnit >= 1.1
+    Extensions:          CPP, MultiParamTypeClasses, FunctionalDependencies,
+                         FlexibleInstances, TypeSynonymInstances, PostfixOperators,
+                         FlexibleContexts
diff --git a/tests/c-flow-sequence.n=4.c=flow-in.::.input b/tests/c-flow-sequence.n=4.c=flow-in.::.input
deleted file mode 100644
--- a/tests/c-flow-sequence.n=4.c=flow-in.::.input
+++ /dev/null
@@ -1,1 +0,0 @@
-[ ::std::vector ]
diff --git a/tests/c-flow-sequence.n=4.c=flow-in.::.output b/tests/c-flow-sequence.n=4.c=flow-in.::.output
deleted file mode 100644
--- a/tests/c-flow-sequence.n=4.c=flow-in.::.output
+++ /dev/null
@@ -1,24 +0,0 @@
-# B: 0, C: 0, L: 1, c: 0
-Q
-# B: 0, C: 0, L: 1, c: 0
-I[
-# B: 1, C: 1, L: 1, c: 1
-!Commit to 'node' was made outside it
-# B: 1, C: 1, L: 1, c: 1
-w 
-# B: 2, C: 2, L: 1, c: 2
-N
-# B: 2, C: 2, L: 1, c: 2
-S
-# B: 2, C: 2, L: 1, c: 2
-T::std::vector
-# B: 15, C: 15, L: 1, c: 15
-s
-# B: 15, C: 15, L: 1, c: 15
-n
-# B: 15, C: 15, L: 1, c: 15
-w 
-# B: 16, C: 16, L: 1, c: 16
-I]
-# B: 17, C: 17, L: 1, c: 17
-q
diff --git a/tests/c-flow-sequence.n=4.c=flow-in.colons.input b/tests/c-flow-sequence.n=4.c=flow-in.colons.input
new file mode 100644
--- /dev/null
+++ b/tests/c-flow-sequence.n=4.c=flow-in.colons.input
@@ -0,0 +1,1 @@
+[ ::std::vector ]
diff --git a/tests/c-flow-sequence.n=4.c=flow-in.colons.output b/tests/c-flow-sequence.n=4.c=flow-in.colons.output
new file mode 100644
--- /dev/null
+++ b/tests/c-flow-sequence.n=4.c=flow-in.colons.output
@@ -0,0 +1,24 @@
+# B: 0, C: 0, L: 1, c: 0
+Q
+# B: 0, C: 0, L: 1, c: 0
+I[
+# B: 1, C: 1, L: 1, c: 1
+!Commit to 'node' was made outside it
+# B: 1, C: 1, L: 1, c: 1
+w 
+# B: 2, C: 2, L: 1, c: 2
+N
+# B: 2, C: 2, L: 1, c: 2
+S
+# B: 2, C: 2, L: 1, c: 2
+T::std::vector
+# B: 15, C: 15, L: 1, c: 15
+s
+# B: 15, C: 15, L: 1, c: 15
+n
+# B: 15, C: 15, L: 1, c: 15
+w 
+# B: 16, C: 16, L: 1, c: 16
+I]
+# B: 17, C: 17, L: 1, c: 17
+q
diff --git a/tests/ns-plain.n=1.c=flow-key.::.input b/tests/ns-plain.n=1.c=flow-key.::.input
deleted file mode 100644
--- a/tests/ns-plain.n=1.c=flow-key.::.input
+++ /dev/null
@@ -1,1 +0,0 @@
-::std::vector
diff --git a/tests/ns-plain.n=1.c=flow-key.::.output b/tests/ns-plain.n=1.c=flow-key.::.output
deleted file mode 100644
--- a/tests/ns-plain.n=1.c=flow-key.::.output
+++ /dev/null
@@ -1,8 +0,0 @@
-# B: 0, C: 0, L: 1, c: 0
-S
-# B: 1, C: 1, L: 1, c: 1
-!Commit to 'node' was made outside it
-# B: 0, C: 0, L: 1, c: 0
-T::std::vector
-# B: 13, C: 13, L: 1, c: 13
-s
diff --git a/tests/ns-plain.n=1.c=flow-key.colons.input b/tests/ns-plain.n=1.c=flow-key.colons.input
new file mode 100644
--- /dev/null
+++ b/tests/ns-plain.n=1.c=flow-key.colons.input
@@ -0,0 +1,1 @@
+::std::vector
diff --git a/tests/ns-plain.n=1.c=flow-key.colons.output b/tests/ns-plain.n=1.c=flow-key.colons.output
new file mode 100644
--- /dev/null
+++ b/tests/ns-plain.n=1.c=flow-key.colons.output
@@ -0,0 +1,8 @@
+# B: 0, C: 0, L: 1, c: 0
+S
+# B: 1, C: 1, L: 1, c: 1
+!Commit to 'node' was made outside it
+# B: 0, C: 0, L: 1, c: 0
+T::std::vector
+# B: 13, C: 13, L: 1, c: 13
+s
diff --git a/yaml2yeast-test/Main.hs b/yaml2yeast-test/Main.hs
--- a/yaml2yeast-test/Main.hs
+++ b/yaml2yeast-test/Main.hs
@@ -36,8 +36,10 @@
 module Main (main) where
 
 import           Control.Monad
+import           Control.Monad.State
+import           Control.Monad.Trans
 import qualified Data.ByteString.Lazy.Char8 as C
-import qualified Data.HashTable as Hash
+import qualified Data.HashMap as Hash
 import           System.Directory
 import           System.Environment
 import           System.Exit
@@ -47,19 +49,15 @@
 import           Text.Yaml.Reference
 
 -- | Map each tokenizer name to whether a test for it was seen.
-type Seen = Hash.HashTable String Bool
+type Seen = Hash.Map String Bool
 
--- | @allTokenizers@ returns a hash table populated with all known tokenizers
--- where each has the initial value of @False@.
-allTokenizers :: IO Seen
-allTokenizers = do hash <- Hash.new (==) Hash.hashString
-                   mapM (\name -> Hash.insert hash name False) tokenizerNames
-                   return hash
+-- | The type of the test runner program.
+type TestsRunner = StateT Seen IO
 
 -- | @reportMissing seen@ reports the productions (tokenizers) which were not
 -- /seen/ and returns their number.
 reportMissing :: Seen -> IO Int
-reportMissing seen = do list <- Hash.toList seen
+reportMissing seen = do let list = Hash.toList seen
                         missing <- foldM reportTest 0 list
                         if missing > 0
                            then hPutStrLn stderr $ "Missing: " ++ (show missing)
@@ -93,8 +91,8 @@
 
 -- | @isTestInputFile file@ returns whether the specified /file/ is a test
 -- input file (ends with \"@.input@\").
-isTestInputFile :: FilePath -> IO Bool
-isTestInputFile file = do isFile <- doesFileExist file
+isTestInputFile :: FilePath -> TestsRunner Bool
+isTestInputFile file = do isFile <- (lift . doesFileExist) file
                           if not isFile
                              then return False
                              else case matchRegex (mkRegex "\\.input$") file of
@@ -181,40 +179,44 @@
 
 -- | @fileTest seen file@ wraps @assertTest@ in a test case named after the
 -- /file/ and marks it as /seen/.
-fileTest :: Seen -> FilePath -> IO Test
-fileTest seen file = do Hash.update seen (testProduction file) True
-                        return $ TestLabel file $ TestCase $ assertTest file
+fileTest :: FilePath -> TestsRunner Test
+fileTest file = do seen <- get
+                   put $ Hash.adjust (const True) (testProduction file) seen
+                   return $ TestLabel file $ TestCase $ assertTest file
 
 -- | @directoryTestInputFiles directory@ returns the list of test input files
 -- contained in the /directory/.
-directoryTestInputFiles :: String -> IO [FilePath]
-directoryTestInputFiles directory = do entries <- getDirectoryContents directory
+directoryTestInputFiles :: String -> TestsRunner [FilePath]
+directoryTestInputFiles directory = do entries <- (lift . getDirectoryContents) directory
                                        filterM isTestInputFile $ map ((directory ++) . ("/" ++)) entries
 
 -- | @directoryTests seen directory@ returns the list of test cases contained
 -- in the /directory/, wrapped in a test case named after it, and updates the
 -- /seen/ hash.
-directoryTests :: Seen -> String -> IO Test
-directoryTests seen directory = do files <- directoryTestInputFiles directory
-                                   tests <- mapM (fileTest seen) files
-                                   return $ TestLabel directory $ TestList tests
+directoryTests :: String -> TestsRunner Test
+directoryTests directory = do files <- directoryTestInputFiles directory
+                              tests <- mapM fileTest files
+                              return $ TestLabel directory $ TestList tests
 
 -- | @allTests seen directories@ returns the list of test cases contained in
 -- the /directories/ (or \"@.@\" if none is specified), wrapped in a test case
 -- named @all@ if there is more than one directory, updating the /seen/ hash.
-allTests :: Seen -> [String] -> IO Test
-allTests seen directories = do case directories of
-                                    [] -> directoryTests seen "."
-                                    [directory] -> directoryTests seen directory
-                                    _ -> do tests <- mapM (directoryTests seen) directories
-                                            return $ TestLabel "all" $ TestList tests
+allTests :: [String] -> TestsRunner Test
+allTests directories = do case directories of
+                               [] -> directoryTests "."
+                               [directory] -> directoryTests directory
+                               _ -> do tests <- mapM directoryTests directories
+                                       return $ TestLabel "all" $ TestList tests
 
 -- | @main@ executes all the tests contained in the directories specified in
 -- the command line (or \"@.@\" if none is specified).
 main :: IO ()
-main = do directories <- getArgs
-          seen <- allTokenizers
-          tests <- allTests seen directories
+main = do argDirectories <- getArgs
+          let directories = if argDirectories == []
+                            then [ "tests" ]
+                            else argDirectories
+          let notSeen = Hash.fromList $ zip tokenizerNames $ repeat False
+          (tests, seen) <- runStateT (allTests directories) notSeen
           missing <- reportMissing seen
           results <- runTestTT tests
           case missing + (errors results) + (failures results) of
