diff --git a/cli/Options.hs b/cli/Options.hs
--- a/cli/Options.hs
+++ b/cli/Options.hs
@@ -1,6 +1,7 @@
 module Options
 where
 
+import Data.Semigroup ( (<>) ) -- needed for GHC 8.0 and 8.2
 import Options.Applicative
 
 
diff --git a/ginger.cabal b/ginger.cabal
--- a/ginger.cabal
+++ b/ginger.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                ginger
-version:             0.10.1.0
+version:             0.10.2.0
 synopsis:            An implementation of the Jinja2 template language in Haskell
 description:         Ginger is Jinja, minus the most blatant pythonisms. Wants
                      to be feature complete, but isn't quite there yet.
@@ -43,6 +43,7 @@
                , aeson >=1.4.2.0 && <1.6
                , aeson-pretty >=0.8.7 && <0.9
                , bytestring >=0.10.8.2 && <0.11
+               , containers >=0.6.4 && <0.7
                , data-default >= 0.5
                , filepath >= 1.3
                , http-types >= 0.8 && (< 0.11 || >= 0.12)
@@ -63,6 +64,8 @@
   default-language:    Haskell2010
 
 executable ginger
+    if impl(ghcjs)
+        buildable: False
     main-is: GingerCLI.hs
     other-modules: Options
     hs-source-dirs: cli
@@ -93,7 +96,7 @@
                  , bytestring >=0.10.8.2 && <0.11
                  , data-default >=0.5
                  , mtl >=2.2.2 && <2.3
-                 , tasty >=1.2 && <1.3
+                 , tasty >=1.2 && <1.5
                  , tasty-hunit >=0.10.0.1 && <0.11
                  , tasty-quickcheck >=0.10 && <0.11
                  , text >=1.2.3.1 && <1.3
diff --git a/src/Text/Ginger/GVal.hs b/src/Text/Ginger/GVal.hs
--- a/src/Text/Ginger/GVal.hs
+++ b/src/Text/Ginger/GVal.hs
@@ -61,6 +61,8 @@
 import qualified Data.Aeson as JSON
 import qualified Data.HashMap.Strict as HashMap
 import Data.HashMap.Strict (HashMap)
+import qualified Data.Map.Strict as Map
+import Data.Map.Strict (Map)
 import qualified Data.Vector as Vector
 import Control.Monad ((<=<), forM, mapM)
 import Control.Monad.Trans (MonadTrans, lift)
@@ -355,6 +357,22 @@
                     , isNull = False
                     , asLookup = Just (`HashMap.lookup` xs)
                     , asDictItems = Just $ HashMap.toList xs
+                    }
+
+-- | 'Map' of 'Text' becomes a dictionary-like 'GVal'
+instance ToGVal m v => ToGVal m (Map Text v) where
+    toGVal xs = helper (Map.map toGVal xs)
+        where
+            helper :: Map Text (GVal m) -> GVal m
+            helper xs =
+                def
+                    { asHtml = mconcat . Prelude.map asHtml . Map.elems $ xs
+                    , asText = mconcat . Prelude.map asText . Map.elems $ xs
+                    , asBytes = mconcat . Prelude.map asBytes . Map.elems $ xs
+                    , asBoolean = not . Map.null $ xs
+                    , isNull = False
+                    , asLookup = Just (`Map.lookup` xs)
+                    , asDictItems = Just $ Map.toAscList xs
                     }
 
 instance ToGVal m Int where
diff --git a/src/Text/Ginger/Run.hs b/src/Text/Ginger/Run.hs
--- a/src/Text/Ginger/Run.hs
+++ b/src/Text/Ginger/Run.hs
@@ -109,6 +109,8 @@
 import Control.Applicative
 import qualified Data.HashMap.Strict as HashMap
 import Data.HashMap.Strict (HashMap)
+import qualified Data.Map.Strict as Map
+import Data.Map.Strict (Map)
 import Data.Scientific (Scientific, formatScientific)
 import qualified Data.Scientific as Scientific
 import Data.Default (def)
@@ -281,8 +283,6 @@
               , ToGVal (Run p m h) p
               , Monoid h
               , Monad m
-              , Applicative m
-              , Functor m
               )
            => GingerContext p m h
            -> Template p
@@ -302,8 +302,6 @@
                , ToGVal (Run p m h) p
                , Monoid h
                , Monad m
-               , Applicative m
-               , Functor m
                )
             => Template p
             -> Run p m h (GVal (Run p m h))
@@ -311,7 +309,7 @@
     runStatement . templateBody . baseTemplate
 
 -- | Run an action within a different template context.
-withTemplate :: (Monad m, Applicative m, Functor m)
+withTemplate :: Monad m
              => Template p
              -> Run p m h a
              -> Run p m h a
@@ -324,7 +322,7 @@
     return result
 
 -- | Run an action within a block context
-withBlockName :: (Monad m, Applicative m, Functor m)
+withBlockName :: Monad m
               => VarName
               -> Run p m h a
               -> Run p m h a
@@ -335,7 +333,7 @@
     modify (\s -> s { rsCurrentBlockName = oldBlockName })
     return result
 
-lookupBlock :: (Monad m, Applicative m, Functor m) => VarName -> Run p m h (Block p)
+lookupBlock :: Monad m => VarName -> Run p m h (Block p)
 lookupBlock blockName = do
     tpl <- gets rsCurrentTemplate
     let blockMay = resolveBlock blockName tpl
@@ -357,7 +355,6 @@
                 , ToGVal (Run p m h) p
                 , Monoid h
                 , Monad m
-                , Functor m
                 )
              => Statement p
              -> Run p m h (GVal (Run p m h))
@@ -371,7 +368,6 @@
                 , ToGVal (Run p m h) p
                 , Monoid h
                 , Monad m
-                , Functor m
                 )
              => Statement p
              -> Run p m h (GVal (Run p m h))
@@ -433,7 +429,7 @@
 
 runStatement' (ScopedS _ body) = withLocalScope runInner
     where
-        runInner :: (Functor m, Monad m) => Run p m h (GVal (Run p m h))
+        runInner :: Monad m => Run p m h (GVal (Run p m h))
         runInner = runStatement body
 
 runStatement' (ForS _ varNameIndex varNameValue itereeExpr body) = do
@@ -510,7 +506,6 @@
              . ( ToGVal (Run p m h) h
                , ToGVal (Run p m h) p
                , Monoid h
-               , Functor m
                , Monad m
                ) => Macro p -> GVal (Run p m h)
 macroToGVal (Macro argNames body) =
@@ -554,7 +549,7 @@
         l <- asText <$> runExpression a
         r <- runExpression b
         return (l, r)
-    return . toGVal . HashMap.fromList $ items
+    return . toGVal . Map.fromList $ items
 runExpression' (MemberLookupE _ baseExpr indexExpr) = do
     base <- runExpression baseExpr
     index <- runExpression indexExpr
@@ -584,7 +579,7 @@
 
 -- | Helper function to output a HTML value using whatever print function the
 -- context provides.
-echo :: (Monad m, Applicative m, Functor m, Monoid h)
+echo :: (Monad m, Monoid h)
      => GVal (Run p m h) -> Run p m h ()
 echo src = do
     e <- asks contextEncode
@@ -605,20 +600,20 @@
                     rsAtLineStart = endsWithNewline newlines l
                 }
 
-indented :: (Monad m, Applicative m, Functor m, Monoid h)
+indented :: (Monad m, Monoid h)
          => h
          -> Run p m h a
          -> Run p m h a
 indented i action = do
     pushIndent i *> action <* popIndent
 
-pushIndent :: (Monad m, Applicative m, Functor m, Monoid h)
+pushIndent :: (Monad m, Monoid h)
            => h
            -> Run p m h ()
 pushIndent i =
     modify $ \state ->
         state { rsIndentation = increaseIndent i (rsIndentation state) }
-popIndent :: (Monad m, Applicative m, Functor m, Monoid h)
+popIndent :: (Monad m, Monoid h)
            => Run p m h ()
 popIndent =
     modify $ \state ->
diff --git a/src/Text/Ginger/Run/Builtins.hs b/src/Text/Ginger/Run/Builtins.hs
--- a/src/Text/Ginger/Run/Builtins.hs
+++ b/src/Text/Ginger/Run/Builtins.hs
@@ -38,6 +38,7 @@
                , either
                )
 import qualified Prelude
+import Control.Monad.Error (runErrorT)
 import Data.Maybe (fromMaybe, isJust, isNothing)
 import qualified Data.List as List
 import Text.Ginger.AST
@@ -851,9 +852,14 @@
         go [r, h, Just def]
       [Just reG, Just haystackG, Just optsG] -> do
         opts <- parseCompOpts optsG
-        let re = RE.makeRegexOpts opts RE.defaultExecOpt (Text.unpack . asText $ reG)
+        let reM = runIdentity . runErrorT $
+                      RE.makeRegexOptsM opts RE.defaultExecOpt (Text.unpack . asText $ reG)
             haystack = Text.unpack . asText $ haystackG
-        return $ matchFunc re haystack
+        case reM of
+            Left err ->
+                throwHere $ ArgumentsError (Just "re.match") $ "invalid regex: " <> Text.pack err
+            Right re ->
+                return $ matchFunc re haystack
       _ -> barf
     barf = do
       throwHere $ ArgumentsError (Just "re.match") "expected: regex, haystack, [opts]"
diff --git a/src/Text/Ginger/Run/Type.hs b/src/Text/Ginger/Run/Type.hs
--- a/src/Text/Ginger/Run/Type.hs
+++ b/src/Text/Ginger/Run/Type.hs
@@ -193,7 +193,7 @@
 -- based on a lookup key, and a writer function (outputting HTML by whatever
 -- means the carrier monad provides, e.g. @putStr@ for @IO@, or @tell@ for
 -- @Writer@s).
-makeContextM' :: (Monad m, Functor m)
+makeContextM' :: Monad m
              => (VarName -> Run p m h (GVal (Run p m h)))
              -> (h -> m ())
              -> (GVal (Run p m h) -> h)
@@ -202,7 +202,7 @@
 makeContextM' lookupFn writeFn encodeFn newlines =
   makeContextExM' lookupFn writeFn (Prelude.const $ return ()) encodeFn newlines
 
-makeContextExM' :: (Monad m, Functor m)
+makeContextExM' :: Monad m
              => (VarName -> Run p m h (GVal (Run p m h)))
              -> (h -> m ())
              -> (RuntimeError p -> m ())
@@ -249,7 +249,7 @@
 makeContext = makeContextHtml
 
 {-#DEPRECATED makeContextM "Compatibility alias for makeContextHtmlM" #-}
-makeContextM :: (Monad m, Functor m)
+makeContextM :: Monad m
              => (VarName -> Run p m Html (GVal (Run p m Html)))
              -> (Html -> m ())
              -> GingerContext p m Html
@@ -259,13 +259,13 @@
                 -> GingerContext p (Writer Html) Html
 makeContextHtml l = makeContext' l toHtml (Just htmlNewlines)
 
-makeContextHtmlM :: (Monad m, Functor m)
+makeContextHtmlM :: Monad m
                  => (VarName -> Run p m Html (GVal (Run p m Html)))
                  -> (Html -> m ())
                  -> GingerContext p m Html
 makeContextHtmlM l w = makeContextM' l w toHtml (Just htmlNewlines)
 
-makeContextHtmlExM :: (Monad m, Functor m)
+makeContextHtmlExM :: Monad m
                  => (VarName -> Run p m Html (GVal (Run p m Html)))
                  -> (Html -> m ())
                  -> (RuntimeError p -> m ())
@@ -276,13 +276,13 @@
                 -> GingerContext p (Writer Text) Text
 makeContextText l = makeContext' l asText (Just textNewlines)
 
-makeContextTextM :: (Monad m, Functor m)
+makeContextTextM :: Monad m
                  => (VarName -> Run p m Text (GVal (Run p m Text)))
                  -> (Text -> m ())
                  -> GingerContext p m Text
 makeContextTextM l w = makeContextM' l w asText (Just textNewlines)
 
-makeContextTextExM :: (Monad m, Functor m)
+makeContextTextExM :: Monad m
                  => (VarName -> Run p m Text (GVal (Run p m Text)))
                  -> (Text -> m ())
                  -> (RuntimeError p -> m ())
@@ -521,13 +521,13 @@
 warnFromMaybe err d Nothing = warn err >> return d
 warnFromMaybe _ d (Just x) = return x
 
-setSourcePos :: (Monad m, Applicative m, Functor m)
+setSourcePos :: Monad m
              => p
              -> Run p m h ()
 setSourcePos pos =
   modify (\s -> s { rsCurrentSourcePos = pos })
 
-getSourcePos :: (Monad m, Applicative m, Functor m)
+getSourcePos :: Monad m
              => Run p m h p
 getSourcePos = gets rsCurrentSourcePos
 
@@ -539,7 +539,7 @@
 -- | @withSourcePos pos action@ runs @action@ in a context where the
 -- current source location is set to @pos@. The original source position is
 -- restored when @action@ finishes.
-withSourcePos :: (Monad m, Applicative m, Functor m)
+withSourcePos :: Monad m
               => p
               -> Run p m h a
               -> Run p m h a
