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.3.2.0
+version:             0.3.5.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.
@@ -26,10 +26,10 @@
                  , Text.Ginger.Parse
                  , Text.Ginger.Run
                  , Text.PrintfA
+                 , Text.Ginger.Run.VM
+                 , Text.Ginger.Run.FuncUtils
   other-modules: Text.Ginger.Run.Type
-               , Text.Ginger.Run.FuncUtils
                , Text.Ginger.Run.Builtins
-               , Text.Ginger.Run.VM
   -- other-extensions:
   build-depends: base >=4.5 && <5
                , aeson
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
@@ -20,6 +20,7 @@
                , (++), (+), (-), (*), (/), div
                , (=<<), (>>=), return
                , undefined, otherwise, id, const
+               , fmap
                , Maybe (..)
                , Bool (..)
                , Either (..)
@@ -105,6 +106,26 @@
         , length :: Maybe Int -- ^ Get length of value, if it is a collection (list/dict)
         , isNull :: Bool -- ^ Check if the value is null
         , asJSON :: Maybe JSON.Value -- ^ Provide a custom JSON representation of the value
+        }
+
+-- | Marshal a GVal between carrier monads.
+-- This will lose 'asFunction' information, because functions cannot be
+-- transferred to other carrier monads, but it will keep all other data
+-- structures intact.
+marshalGVal :: GVal m -> GVal n
+marshalGVal g =
+    GVal
+        { asList = fmap marshalGVal <$> asList g
+        , asDictItems = fmap (\items -> [(k, marshalGVal v) | (k, v) <- items]) (asDictItems g)
+        , asLookup = fmap (fmap marshalGVal .) (asLookup g)
+        , asHtml = asHtml g
+        , asText = asText g
+        , asBoolean = asBoolean g
+        , asNumber = asNumber g
+        , asFunction = Nothing
+        , isNull = isNull g
+        , length = length g
+        , asJSON = asJSON g
         }
 
 -- | Convenience wrapper around 'asDictItems' to represent a 'GVal' as a
diff --git a/src/Text/Ginger/Parse.hs b/src/Text/Ginger/Parse.hs
--- a/src/Text/Ginger/Parse.hs
+++ b/src/Text/Ginger/Parse.hs
@@ -1,6 +1,7 @@
 {-#LANGUAGE TupleSections #-}
 {-#LANGUAGE OverloadedStrings #-}
 {-#LANGUAGE ScopedTypeVariables #-}
+{-#LANGUAGE DeriveGeneric #-}
 -- | Ginger parser.
 module Text.Ginger.Parse
 ( parseGinger
@@ -39,6 +40,8 @@
                             )
 import Control.Monad.Trans.Class ( lift )
 import Control.Applicative
+import Control.Exception (Exception)
+import GHC.Generics
 import Safe ( readMay )
 
 import Data.Text (Text)
@@ -73,7 +76,9 @@
         , peSourceLine :: Maybe Int -- ^ Line number, if available
         , peSourceColumn :: Maybe Int -- ^ Column number, if available
         }
-        deriving (Show)
+        deriving (Show, Generic)
+
+instance Exception ParserError where
 
 -- | Helper function to create a Ginger parser error from a Parsec error.
 fromParsecError :: ParseError -> ParserError
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
@@ -104,6 +104,7 @@
     , ("date", fromFunction gfnDateFormat)
     , ("dateformat", fromFunction gfnDateFormat)
     , ("default", fromFunction gfnDefault)
+    , ("dictsort", fromFunction gfnDictsort)
     , ("difference", fromFunction . variadicNumericFunc 0 $ difference)
     , ("e", fromFunction gfnEscape)
     , ("equals", fromFunction gfnEquals)
@@ -111,6 +112,7 @@
     , ("filesizeformat", fromFunction gfnFileSizeFormat)
     , ("filter", fromFunction gfnFilter)
     , ("floor", fromFunction . unaryNumericFunc 0 $ Prelude.fromIntegral . Prelude.floor)
+    , ("format", fromFunction gfnPrintf)
     , ("greater", fromFunction gfnGreater)
     , ("greaterEquals", fromFunction gfnGreaterEquals)
     , ("int", fromFunction . unaryFunc $ toGVal . fmap (Prelude.truncate :: Scientific -> Int) . asNumber)
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
@@ -528,3 +528,27 @@
 printfG :: String -> [GVal m] -> String
 printfG fmt args = printfa fmt (fmap P args)
 
+
+gfnDictsort :: Monad m => Function (Run m h)
+gfnDictsort args =
+    let extracted =
+            extractArgsDefL
+                [ ("dict", def)
+                , ("case_sensitive", def)
+                , ("by", "key")
+                ]
+                args
+    in case extracted of
+        Right [gDict, gCaseSensitive, gSortBy] -> do
+            let caseSensitive = asBoolean gCaseSensitive
+            sortByKey <- case asText gSortBy of
+                "key" -> return True
+                "value" -> return False
+                "val" -> return False
+                x -> fail $ "Invalid value for 'dictsort()' argument 'by': " ++ show x
+            let items = fromMaybe [] $ asDictItems gDict
+            let projection =
+                    (if caseSensitive then id else Text.toUpper) .
+                    (if sortByKey then fst else (asText . snd))
+            return . orderedDict . List.sortOn projection $ items
+        _ -> fail "Invalid arguments to 'dictsort'"
