diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,20 @@
 # Revision history for PyF
 
+## 0.8.0.0 -- 2019-08-06
+
+- `f` (and `fWithDelimiters`) were renamed `fmt` (`fmtWithDelimiters`). `f` was causing too much shadowing in any codebase.
+- PyF now exposes the typeclass `PyFToString` and `PyFClassify` which can be extended to support any type as input for the formatters.
+- PyF now uses `Data.String.IsString t` as its output type if `OverloadedString` is enabled. It means that it behaves as a real haskell string literal.
+- A caveat of the previous change is that PyF does not have instances for `IO` anymore.
+
+### bugfixes and general improvements
+
+- An important amount of bugfixs
+- Error reporting for generic formatting (i.e. formatting without a specified type) is now more robust
+- Template haskell splices are simpler. This leads to more efficient / small generated code and in the event of this code appears in a GHC error message, it is more readable.
+- PyF now longer emit unnecessary default typing.
+
+
 ## 0.7.3.0 -- 2019-02-28
 
 - Tests: fix non reproducible tests
diff --git a/PyF.cabal b/PyF.cabal
--- a/PyF.cabal
+++ b/PyF.cabal
@@ -1,5 +1,5 @@
 name:                PyF
-version:             0.7.3.0
+version:             0.8.0.0
 synopsis: Quasiquotations for a python like interpolated string formater
 description: Quasiquotations for a python like interpolated string formater.
 license:             BSD3
@@ -14,6 +14,7 @@
 library
   exposed-modules:
                   PyF
+                  PyF.Class
                   PyF.Internal.PythonSyntax
                   PyF.Internal.QQ
                   PyF.Internal.Extensions
@@ -42,6 +43,14 @@
   other-modules: SpecUtils SpecCustomDelimiters
   build-tools:  python3
   build-depends:       base, PyF, hspec, text, template-haskell, process
+  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+test-suite pyf-overloaded
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             SpecOverloaded.hs
+  build-depends:       base, PyF, hspec, text, bytestring
   ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N
   default-language:    Haskell2010
 
diff --git a/Readme.md b/Readme.md
--- a/Readme.md
+++ b/Readme.md
@@ -14,7 +14,7 @@
 >>> name = "Dave"
 >>> age = 54
 
->>> [f|Person's name is {name}, age is {age:x}|]
+>>> [fmt|Person's name is {name}, age is {age:x}|]
 "Person's name is Dave, age is 36"
 ```
 
@@ -39,25 +39,25 @@
 
 ```haskell
 >>> name = "Guillaume"
->>> [f|{name:<11}|]
+>>> [fmt|{name:<11}|]
 "Guillaume  "
->>> [f|{name:>11}|]
+>>> [fmt|{name:>11}|]
 "  Guillaume"
->>> [f|{name:|^13}|]
+>>> [fmt|{name:|^13}|]
 "||Guillaume||"
 ```
 
 Padding inside `=` the sign:
 
 ```haskell
->>> [f|{-pi:=10.3}|]
+>>> [fmt|{-pi:=10.3}|]
 "-    3.142"
 ```
 
 ## Float rounding
 
 ```haskell
->>> [f|{pi:.2}|]
+>>> [fmt|{pi:.2}|]
 "3.14"
 ```
 
@@ -65,11 +65,11 @@
 
 ```haskell
 >>> v = 31
->>> [f|Binary: {v:#b}|]
+>>> [fmt|Binary: {v:#b}|]
 "Binary: 0b11111"
->>> [f|Octal (no prefix): {age:o}|]
+>>> [fmt|Octal (no prefix): {age:o}|]
 "Octal (no prefix): 37"
->>> [f|Hexa (caps and prefix): {age:#X}|]
+>>> [fmt|Hexa (caps and prefix): {age:#X}|]
 "Hexa (caps and prefix): 0x1F"
 ```
 
@@ -78,9 +78,9 @@
 Using `,` or `_`.
 
 ```haskell
->>> [f|{10 ^ 9 - 1:,}|]
+>>> [fmt|{10 ^ 9 - 1:,}|]
 "999,999,999"
->>> [f|{2 ^ 32  -1:_b}|]
+>>> [fmt|{2 ^ 32  -1:_b}|]
 "1111_1111_1111_1111_1111_1111_1111_1111"
 ```
 
@@ -89,9 +89,9 @@
 Using `+` to display the positive sign (if any) or ` ` to display a space instead:
 
 ```haskell
->>> [f|{pi:+.3}|]
+>>> [fmt|{pi:+.3}|]
 "+3.142"
->>> [f|{pi: .3}|]
+>>> [fmt|{pi: .3}|]
 " 3.142"
 ```
 
@@ -109,9 +109,9 @@
 First argument inside the curly braces can be a valid Haskell expression, for example:
 
 ```haskell
->>> [f|2pi = {2* pi:.2}|]
+>>> [fmt|2pi = {2* pi:.2}|]
 6.28
->>> [f|tail "hello" = {tail "hello":->6}|]
+>>> [fmt|tail "hello" = {tail "hello":->6}|]
 "tail \"hello\" = --ello"
 ```
 
@@ -122,7 +122,7 @@
 Most options can be combined. This generally leads to totally unreadable format string ;)
 
 ```haskell
->>> [f|{pi:~>5.2}|]
+>>> [fmt|{pi:~>5.2}|]
 "~~3.14"
 ```
 
@@ -131,7 +131,7 @@
 You can ignore a line break with `\` if needed. For example:
 
 ```haskell
-[f|\
+[fmt|\
 - a
 - b\
 |]
@@ -141,18 +141,25 @@
 
 # Output type
 
-*PyF* main entry point `f` is polymorphic and can represents `Text`, lazy `Text`, `String`, lazy text `Builder` or `IO` operations. Most of the time, type inference will do the right thing for you, but you may need to add type annotations.
-
-For example:
+*PyF* aims at extending the string literal syntax. As such, it default to `String` type. However, if the `OverloadedString` is enabled, PyF will happilly generate `IsString t => t` instead. This means that you can use PyF to generate `String`, but also `Text` and why not `ByteString`, with all the caveats known to this extension.
 
 ```haskell
->>> [f|hello {pi.2}|] :: String
+>>> [fmt|hello {pi.2}|] :: String
 "hello 3.14"
 ```
 
-Note: it works in ghci without any type annotation if the extensions
-`OverloadedStrings` and `ExtendedDefaultRules` are enabled.
+# Custom types
 
+PyF can format three categories of input types:
+
+- Floating. Using the `f`, `g`, `e`, ... type specifiers. Any type instance of `RealFloat` can be formated as such.
+- Integral. Using the `d`, `b`, `x`, `o`, ... type specifiers. Any type instance of `Integral` can be formated as such.
+- String. Using the `s` type specifier. Any type instance of `PyFToString` can be formated as such.
+
+See `PyF.Class` if you want to create new instances for the `PyFToString` class.
+
+By default, if you do not provide any type specifier, PyF uses the `PyFClassify` type class to decide if your type must be formated as a Floating, Integral or String.
+
 # Caveats
 
 ## Type inference
@@ -161,7 +168,7 @@
 
 ```haskell
 >>> v = 10 :: Double
->>> [f|A float: {v}|]
+>>> [fmt|A float: {v}|]
 A float: 10
 ```
 
@@ -176,7 +183,7 @@
 - Any parsing error on the mini language results in a clear indication of the error, for example:
 
 ```haskell
->>> [f|{age:.3d}|]
+>>> [fmt|{age:.3d}|]
 
 <interactive>:77:4: error:
     • <interactive>:1:8:
@@ -189,7 +196,7 @@
 - Error in variable name are also readable:
 
 ```haskell
->>> [f|{toto}|]
+>>> [fmt|{toto}|]
 <interactive>:78:4: error: Variable not in scope: toto
 ```
 
@@ -197,7 +204,7 @@
   too polymorphic), you will get an awful error:
 
 ```haskell
->>*> [f|{True:d}|]
+>>*> [fmt|{True:d}|]
 
 <interactive>:80:10: error:
     • No instance for (Integral Bool)
@@ -205,24 +212,10 @@
 ...
 ```
 
-- There is also one class of error related to alignement which can be triggered, when using alignement inside sign (i.e. `=`) with string. This can fail in two flavors:
-
-```haskell
->>> [f|{"hello":=10s}|]
-
-<interactive>:88:1: error:
-    • Exception when trying to run compile-time code:
-        String Cannot be aligned with the inside `=` mode
-CallStack (from HasCallStack):
-  error, called at src/PyF/Internal/QQ.hs:143:18 in PyF-0.4.0.0-inplace:PyF.Internal.QQ
-      Code: quoteExp f "{\"hello\":=10s}"
-    • In the quasi-quotation: [f|{"hello":=10s}|]
-```
-
-And
+- There is also one class of error related to alignement which can be triggered, when using alignement inside sign (i.e. `=`) with string:
 
 ```haskell
-*PyF PyF.Internal.QQ> [f|{"hello":=10}|]
+*PyF PyF.Internal.QQ> [fmt|{"hello":=10}|]
 
 <interactive>:89:10: error:
     • String Cannot be aligned with the inside `=` mode
@@ -232,7 +225,7 @@
 - Finally, if you make any type error inside the expression field, you are on your own:
 
 ```haskell
->>> [f|{3 + pi + "hello":10}|]
+>>> [fmt|{3 + pi + "hello":10}|]
 
 <interactive>:99:10: error:
     • No instance for (Floating [Char]) arising from a use of ‘pi’
@@ -253,7 +246,7 @@
 import PyF
 
 myCustomFormatter :: QuasiQuoter
-myCustomFormatter = fWithDelimiters ('@','!')
+myCustomFormatter = fmtWithDelimiters ('@','!')
 ```
 
 Later, in another module:
@@ -276,8 +269,8 @@
 
 - Number `n` formatter is not supported. In python this formatter can format a number and use current locale information for decimal part and thousand separator. There is no plan to support that because of the impure interface needed to read the locale.
 - Python support sub variables in the formatting options, such as `{varname:.{precision}}`, we should too. However should we accept `String` parameter (such as `<`), with a possible runtime error, or should we use the `ADT` such as `AlignRight`?
-- Python literal integers accepts binary/octal/hexa/decimal literals, PyF only accept decimal ones, hdece in to plan to support that, if you really need to format a float with a number of digit provided as a binary constant, open an issue.
-- Python support adding custom formatters for new types, such as date. This may be really cool, for example `[f|{today:%Y-%M-%D}`. I don't know how to support that now.
+- Python literal integers accepts binary/octal/hexa/decimal literals, PyF only accept decimal ones, I don't have a plan to support that, if you really need to format a float with a number of digit provided as a binary constant, open an issue.
+- Python support adding custom formatters for new types, such as date. This may be really cool, for example `[fmt|{today:%Y-%M-%D}`. I don't know how to support that now.
 
 ### Difference
 
@@ -295,15 +288,6 @@
 cabal new-test
 ```
 
-# TODO
-
-- Improve the error reporting with more Parsec annotation
-- Improve the parser for sub-expression (handle the `:` and `}` cases if possible).
-- Allow extension to others type / custom formatters (for date for example)
-- Improve code quality. This code is really ugly, but there is a really strong test suite so, well.
-- Work on performance, do we really care? For now, everything is internally done with `String`.
-- Directly expose the formatter to be used as a template haskell splice
-
 # Library note
 
 `PyF.Formatters` exposes two functions to format numbers. They are type-safe (as much as possible) and comes with a combination of formatting options not seen in other formatting libraries:
@@ -316,4 +300,3 @@
 # Conclusion
 
 Don't hesitate to make any suggestion, I'll be more than happy to work on it.
-
diff --git a/src/PyF.hs b/src/PyF.hs
--- a/src/PyF.hs
+++ b/src/PyF.hs
@@ -4,25 +4,20 @@
 {- | A lot of quasiquoters to format and interpolate string expression
 -}
 module PyF
-  ( f
+  ( fmt
    -- * With custom delimiters
-  , fWithDelimiters
+  , fmtWithDelimiters
+  , module PyF.Class
   )
 where
 
 import           Language.Haskell.TH.Quote (QuasiQuoter(..))
-import qualified PyF.Internal.QQ as QQ
-
-import           Language.Haskell.TH
-
-import qualified Data.Text.Lazy as LText
-import qualified Data.Text.Lazy.IO as LText
-import qualified Data.Text as SText
-import qualified Data.Text.Lazy.Builder as Builder
+import PyF.Internal.QQ (toExp)
+import PyF.Class
 
 templateF :: (Char, Char) -> String -> QuasiQuoter
 templateF delimiters fName = QuasiQuoter {
-    quoteExp = \s -> (AppE (VarE 'magicFormat)) <$> (QQ.toExp delimiters s)
+    quoteExp = \s -> (toExp delimiters s)
   , quotePat = err "pattern"
   , quoteType = err "type"
   , quoteDec = err "declaration"
@@ -30,30 +25,13 @@
   where
     err name = error (fName ++ ": This QuasiQuoter can not be used as a " ++ name ++ "!")
 
--- | Generic formatter, can format an expression to (lazy) Text, String, Builder and IO () depending on type inference
-f :: QuasiQuoter
-f = templateF pythonDelimiters "f"
-
-fWithDelimiters :: (Char, Char) -> QuasiQuoter
-fWithDelimiters delimiters = templateF delimiters "fWithDelimiters"
-
-class MagicFormat t where
-  magicFormat :: Builder.Builder -> t
-
-instance MagicFormat (IO ()) where
-  magicFormat = LText.putStrLn . Builder.toLazyText
-
-instance MagicFormat [Char] where
-  magicFormat = LText.unpack . Builder.toLazyText
-
-instance MagicFormat SText.Text where
-  magicFormat = LText.toStrict . Builder.toLazyText
-
-instance MagicFormat LText.Text where
-  magicFormat = Builder.toLazyText
+-- | Generic formatter, can format an expression to any @t@ as long as
+--   @t@ is an instance of 'IsString'.
+fmt :: QuasiQuoter
+fmt = templateF pythonDelimiters "fmt"
 
-instance MagicFormat Builder.Builder where
-  magicFormat = id
+fmtWithDelimiters :: (Char, Char) -> QuasiQuoter
+fmtWithDelimiters delimiters = templateF delimiters "fmtWithDelimiters"
 
 pythonDelimiters :: (Char, Char)
 pythonDelimiters = ('{', '}')
diff --git a/src/PyF/Class.hs b/src/PyF/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/PyF/Class.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DefaultSignatures #-}
+module PyF.Class where
+
+import Data.Int
+import Data.Word
+import Numeric.Natural
+
+import qualified Data.Text.Lazy as LText
+import qualified Data.Text as SText
+
+-- | The three categories of formatting in 'PyF'
+data PyFCategory
+  = PyFIntegral
+  -- ^ Format as an integral, no fractional part, precise value
+  | PyFFractional
+  -- ^ Format as a fractional, approximate value with a fractional part
+  | PyFString
+  -- ^ Format as a string
+
+-- | Classify a type to a 'PyFCategory'
+--   This classification will be used to decide which formatting to
+--   use when no type specifier in provided.
+type family PyFClassify t :: PyFCategory
+
+type instance PyFClassify Integer = 'PyFIntegral
+type instance PyFClassify Int = 'PyFIntegral
+type instance PyFClassify Int8 = 'PyFIntegral
+type instance PyFClassify Int16 = 'PyFIntegral
+type instance PyFClassify Int32 = 'PyFIntegral
+type instance PyFClassify Int64 = 'PyFIntegral
+type instance PyFClassify Natural = 'PyFIntegral
+type instance PyFClassify Word = 'PyFIntegral
+type instance PyFClassify Word8 = 'PyFIntegral
+type instance PyFClassify Word16 = 'PyFIntegral
+type instance PyFClassify Word32 = 'PyFIntegral
+type instance PyFClassify Word64 = 'PyFIntegral
+
+type instance PyFClassify Float = 'PyFFractional
+type instance PyFClassify Double = 'PyFFractional
+
+type instance PyFClassify String = 'PyFString
+type instance PyFClassify LText.Text = 'PyFString
+type instance PyFClassify SText.Text = 'PyFString
+
+-- | Convert a type to string
+--   The default implementation uses `Show`
+class PyFToString t where
+  pyfToString :: t -> String
+  default pyfToString :: Show t => t -> String
+  pyfToString = show
+
+instance PyFToString String where pyfToString = id
+instance PyFToString LText.Text where pyfToString = LText.unpack
+instance PyFToString SText.Text where pyfToString = SText.unpack
diff --git a/src/PyF/Internal/PythonSyntax.hs b/src/PyF/Internal/PythonSyntax.hs
--- a/src/PyF/Internal/PythonSyntax.hs
+++ b/src/PyF/Internal/PythonSyntax.hs
@@ -18,6 +18,7 @@
   , TypeFormat(..)
   , AlternateForm(..)
   , pattern DefaultFormatMode
+  , Parser
   )
 where
 
@@ -85,24 +86,37 @@
 parsePythonFormatString exts = parseGenericFormatString exts ('{', '}')
 
 parseGenericFormatString :: [ParseExtension.Extension] -> (Char, Char) -> Parser [Item]
-parseGenericFormatString exts delimiters = many ((Raw "\\" <$ "\\\\") <|> (Raw "" <$ "\\\n") <|> rawString delimiters <|> escapedParenthesis delimiters <|> replacementField exts delimiters) <* eof
+parseGenericFormatString exts delimiters = many (rawString delimiters <|> escapedParenthesis delimiters <|> replacementField exts delimiters) <* eof
 
 rawString :: (Char, Char) -> Parser Item
-rawString (openingChar,closingChar) = Raw . escapeChars <$> some (noneOf ([openingChar, closingChar]))
+rawString (openingChar,closingChar) = do
+  chars <- some (noneOf ([openingChar, closingChar]))
+  case escapeChars chars of
+    Left remaining -> do
+      offset <- getOffset
+      setOffset (offset - length remaining)
+      fancyFailure (Set.singleton (ErrorFail "lexical error in literal section"))
+    Right escaped -> return (Raw escaped)
 
 escapedParenthesis :: (Char, Char) -> Parser Item
 escapedParenthesis (openingChar, closingChar) = Raw <$> (parseRaw openingChar <|> parseRaw closingChar)
   where parseRaw c = c:[] <$ string (replicate 2 c)
 
-{- | Replace escape chars with their value
+{- | Replace escape chars with their value. Results in a Left with the
+remainder of the string on encountering a lexical error (such as a bad escape
+sequence).
 >>> escapeChars "hello \\n"
-"hello \n"
+Right "hello \n"
+>>> escapeChars "hello \\x"
+Left "\\x"
 -}
-escapeChars :: String -> String
-escapeChars "" = ""
+escapeChars :: String -> Either String String
+escapeChars "" = Right ""
+escapeChars ('\\':'\n':xs) = escapeChars xs
+escapeChars ('\\':'\\':xs) = ('\\' :) <$> escapeChars xs
 escapeChars s = case Data.Char.readLitChar s of
-                  [] -> ""
-                  ((c, xs):_) -> c : escapeChars xs
+                  ((c, xs):_) -> (c :) <$> escapeChars xs
+                  _ -> Left s
 
 replacementField :: [ParseExtension.Extension] -> (Char, Char) -> Parser Item
 replacementField exts (charOpening, charClosing) = do
@@ -156,11 +170,11 @@
   | CharacterF -- ^ Character, will convert an integer to its character representation
   | DecimalF SignMode -- ^ Decimal, base 10 integer formatting
   | ExponentialF Precision AlternateForm SignMode -- ^ Exponential notation for floatting points
-  | ExponentialCapsF Precision AlternateForm SignMode -- ^ Exponential notation with capitalised 'e'
+  | ExponentialCapsF Precision AlternateForm SignMode -- ^ Exponential notation with capitalised @e@
   | FixedF Precision AlternateForm SignMode -- ^ Fixed number of digits floating point
   | FixedCapsF Precision AlternateForm SignMode -- ^ Capitalized version of the previous
   | GeneralF Precision AlternateForm SignMode -- ^ General formatting: `FixedF` or `ExponentialF` depending on the number magnitude
-  | GeneralCapsF Precision AlternateForm SignMode -- ^ Same as `GeneralF` but with upper case 'E' and infinite / NaN
+  | GeneralCapsF Precision AlternateForm SignMode -- ^ Same as `GeneralF` but with upper case @E@ and infinite / NaN
   | OctalF AlternateForm SignMode -- ^ Octal, such as 00245
   | StringF Precision -- ^ Simple string
   | HexF AlternateForm SignMode -- ^ Hexadecimal, such as 0xaf3e
@@ -226,32 +240,39 @@
 
   case t of
     Nothing -> pure (FormatMode padding (DefaultF prec (fromMaybe Minus s)) grouping)
-    Just flag -> case evalFlag flag prec alternateForm s of
+    Just flag -> case evalFlag flag padding grouping prec alternateForm s of
       Right fmt -> pure (FormatMode padding fmt grouping)
       Left typeError -> do
         lastCharFailed typeError
 
-evalFlag :: TypeFlag -> Precision -> AlternateForm -> Maybe SignMode -> Either String TypeFormat
-evalFlag Flagb prec alt s = failIfPrec prec (BinaryF alt (defSign s))
-evalFlag Flagc prec alt s = failIfS s =<< failIfPrec prec =<< failIfAlt alt CharacterF
-evalFlag Flagd prec alt s = failIfPrec prec =<< failIfAlt alt (DecimalF (defSign s))
-evalFlag Flage prec alt s = pure $ExponentialF prec alt (defSign s)
-evalFlag FlagE prec alt s = pure $ ExponentialCapsF prec alt (defSign s)
-evalFlag Flagf prec alt s = pure $ FixedF prec alt (defSign s)
-evalFlag FlagF prec alt s = pure $ FixedCapsF prec alt (defSign s)
-evalFlag Flagg prec alt s = pure $ GeneralF prec alt (defSign s)
-evalFlag FlagG prec alt s = pure $ GeneralCapsF prec alt (defSign s)
-evalFlag Flagn _prec _alt _s = Left ("Type 'n' not handled (yet). " ++ errgGn)
-evalFlag Flago prec alt s = failIfPrec prec $ OctalF alt (defSign s)
-evalFlag Flags prec alt s = failIfS s =<< (failIfAlt alt $ StringF prec)
-evalFlag Flagx prec alt s = failIfPrec prec $ HexF alt (defSign s)
-evalFlag FlagX prec alt s = failIfPrec prec $ HexCapsF alt (defSign s)
-evalFlag FlagPercent prec alt s = pure $ PercentF prec alt (defSign s)
+evalFlag :: TypeFlag -> Padding -> Maybe Char -> Precision -> AlternateForm -> Maybe SignMode -> Either String TypeFormat
+evalFlag Flagb _pad _grouping prec alt s = failIfPrec prec (BinaryF alt (defSign s))
+evalFlag Flagc _pad _grouping prec alt s = failIfS s =<< failIfPrec prec =<< failIfAlt alt CharacterF
+evalFlag Flagd _pad _grouping prec alt s = failIfPrec prec =<< failIfAlt alt (DecimalF (defSign s))
+evalFlag Flage _pad _grouping prec alt s = pure $ExponentialF prec alt (defSign s)
+evalFlag FlagE _pad _grouping prec alt s = pure $ ExponentialCapsF prec alt (defSign s)
+evalFlag Flagf _pad _grouping prec alt s = pure $ FixedF prec alt (defSign s)
+evalFlag FlagF _pad _grouping prec alt s = pure $ FixedCapsF prec alt (defSign s)
+evalFlag Flagg _pad _grouping prec alt s = pure $ GeneralF prec alt (defSign s)
+evalFlag FlagG _pad _grouping prec alt s = pure $ GeneralCapsF prec alt (defSign s)
+evalFlag Flagn _pad _grouping _prec _alt _s = Left ("Type 'n' not handled (yet). " ++ errgGn)
+evalFlag Flago _pad _grouping prec alt s = failIfPrec prec $ OctalF alt (defSign s)
+evalFlag Flags pad grouping prec alt s = failIfGrouping grouping =<< failIfInsidePadding pad =<< failIfS s =<< (failIfAlt alt $ StringF prec)
+evalFlag Flagx _pad _grouping prec alt s = failIfPrec prec $ HexF alt (defSign s)
+evalFlag FlagX _pad _grouping prec alt s = failIfPrec prec $ HexCapsF alt (defSign s)
+evalFlag FlagPercent _pad _grouping prec alt s = pure $ PercentF prec alt (defSign s)
 
 defSign :: Maybe SignMode -> SignMode
 defSign Nothing = Minus
 defSign (Just s) = s
 
+failIfGrouping :: Maybe Char -> TypeFormat -> Either String TypeFormat
+failIfGrouping (Just _) _t = Left "String type is incompatible with grouping (_ or ,)."
+failIfGrouping Nothing t = Right t
+
+failIfInsidePadding :: Padding -> TypeFormat -> Either String TypeFormat
+failIfInsidePadding (Padding _ (Just (_, AnyAlign AlignInside))) _t = Left "String type is incompatible with inside padding (=)."
+failIfInsidePadding _ t = Right t
 
 errgGn :: String
 errgGn = "Use one of {'b', 'c', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 's', 'x', 'X', '%'}."
diff --git a/src/PyF/Internal/QQ.hs b/src/PyF/Internal/QQ.hs
--- a/src/PyF/Internal/QQ.hs
+++ b/src/PyF/Internal/QQ.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
@@ -9,10 +10,11 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE TypeApplications #-}
 
 {- | This module uses the python mini language detailed in
 'PyF.Internal.PythonSyntax' to build an template haskell expression
-representing a formatted string ('String', 'Text' or 'Builder').
+representing a formatted string.
 
 -}
 module PyF.Internal.QQ (
@@ -26,14 +28,6 @@
 
 import Data.Maybe (fromMaybe)
 
-import qualified Data.Text.Lazy.Builder as Builder
-
-import qualified Data.Text.Lazy as LText
-import qualified Data.Text as SText
-
-import qualified Data.Word as Word
-import qualified Data.Int as Int
-import Numeric.Natural
 import qualified Data.Maybe
 
 import PyF.Internal.PythonSyntax
@@ -43,6 +37,8 @@
 import PyF.Formatters (AnyAlign(..))
 import Data.Proxy
 import GHC.TypeLits
+import PyF.Class
+import Data.String (fromString)
 
 -- Be Careful: empty format string
 -- | Parse a string and return a formatter for it
@@ -50,13 +46,19 @@
 toExp delimiters s = do
   filename <- loc_filename <$> location
 
-  exts <- Data.Maybe.mapMaybe thExtToMetaExt <$> extsEnabled
+  thExts <- extsEnabled
+  let exts = Data.Maybe.mapMaybe thExtToMetaExt thExts
 
+  let
+    wrapFromString e = if OverloadedStrings `elem` thExts
+                       then [| fromString $(e) |]
+                       else e
+
   case parse (parseGenericFormatString exts delimiters) filename s of
     Left err -> do
       err' <- overrideErrorForFile filename err
       fail (errorBundlePretty err')
-    Right items -> goFormat items
+    Right items -> wrapFromString (goFormat items)
 
 -- Megaparsec displays error relative to what they parsed
 -- However the formatting string is part of a more complex file and we
@@ -74,8 +76,8 @@
   let
     -- drop the first lines of the file up to the line containing the quasiquote
     -- then, split in what is before the QQ and what is after.
-    -- e.g.  blablabla [f|hello|] will split to
-    -- "blablabla [f|" and "hello|]"
+    -- e.g.  blablabla [fmt|hello|] will split to
+    -- "blablabla [fmt|" and "hello|]"
     (prefix, postfix) = splitAt (col - 1) $ unlines $ drop (line - 1) (lines fileContent)
 
 
@@ -90,7 +92,14 @@
 toExpPython :: String -> Q Exp
 toExpPython = toExp ('{', '}')
 
+{-
+Note: Empty String Lifting
+
+Empty string are lifter as [] instead of "", so I'm using LitE (String L) instead
+-}
+
 goFormat :: [Item] -> Q Exp
+goFormat [] = pure $ LitE (StringL "") -- see [Empty String Lifting]
 goFormat items = foldl1 fofo <$> (mapM toFormat items)
 
 fofo :: Exp -> Exp -> Exp
@@ -99,92 +108,78 @@
 -- Real formatting is here
 
 toFormat :: Item -> Q Exp
-toFormat (Raw x) = [| Builder.fromString x |]
+toFormat (Raw x) = pure $ LitE (StringL x) -- see [Empty String Lifting]
 toFormat (Replacement expr y) = do
   formatExpr <- padAndFormat (fromMaybe DefaultFormatMode y)
-  pure (VarE 'Builder.fromString `AppE` (formatExpr `AppE` expr))
+  pure (formatExpr `AppE` expr)
 
-changePrec :: Precision -> Maybe Int
-changePrec PrecisionDefault = Just 6
-changePrec (Precision n) = Just (fromIntegral n)
+changePrec :: Precision -> Q Exp
+changePrec PrecisionDefault = [| Just 6 |]
+changePrec (Precision n) = [| Just n |]
 
-changePrec' :: Precision -> Maybe Int
-changePrec' PrecisionDefault = Nothing
-changePrec' (Precision n) = Just (fromIntegral n)
+changePrec' :: Precision ->  Q Exp
+changePrec' PrecisionDefault = [| Nothing |]
+changePrec' (Precision n) = [| Just n |]
 
-toGrp :: Maybe b -> a -> Maybe (a, b)
-toGrp mb a = (a,) <$> mb
+toGrp :: Maybe Char -> Int -> Q Exp
+toGrp mb a = [| grp |]
+  where grp = (a,) <$> mb
 
 withAlt :: AlternateForm -> Formatters.Format t t' t'' -> Q Exp
 withAlt NormalForm e = [| e |]
 withAlt AlternateForm e = [| Formatters.Alternate e |]
 
--- Todo: Alternates for floating
 padAndFormat :: FormatMode -> Q Exp
 padAndFormat (FormatMode padding tf grouping) = case tf of
   -- Integrals
-  BinaryF alt s -> [| formatAnyIntegral $(withAlt alt Formatters.Binary) s (newPadding padding) (toGrp grouping 4) |]
-  CharacterF -> [| formatAnyIntegral Formatters.Character Formatters.Minus (newPadding padding) Nothing |]
-  DecimalF s -> [| formatAnyIntegral Formatters.Decimal s (newPadding padding) (toGrp grouping 3) |]
-  HexF alt s -> [| formatAnyIntegral $(withAlt alt Formatters.Hexa) s (newPadding padding) (toGrp grouping 4) |]
-  OctalF alt s -> [| formatAnyIntegral $(withAlt alt Formatters.Octal) s (newPadding padding) (toGrp grouping 4) |]
-  HexCapsF alt s -> [| formatAnyIntegral (Formatters.Upper $(withAlt alt Formatters.Hexa)) s (newPadding padding) (toGrp grouping 4) |]
+  BinaryF alt s -> [| formatAnyIntegral $(withAlt alt Formatters.Binary) s $(newPaddingQ padding) $(toGrp grouping 4) |]
+  CharacterF -> [| formatAnyIntegral Formatters.Character Formatters.Minus $(newPaddingQ padding) Nothing |]
+  DecimalF s -> [| formatAnyIntegral Formatters.Decimal s $(newPaddingQ padding) $(toGrp grouping 3) |]
+  HexF alt s -> [| formatAnyIntegral $(withAlt alt Formatters.Hexa) s $(newPaddingQ padding) $(toGrp grouping 4) |]
+  OctalF alt s -> [| formatAnyIntegral $(withAlt alt Formatters.Octal) s $(newPaddingQ padding) $(toGrp grouping 4) |]
+  HexCapsF alt s -> [| formatAnyIntegral (Formatters.Upper $(withAlt alt Formatters.Hexa)) s $(newPaddingQ padding) $(toGrp grouping 4) |]
 
   -- Floating
-  ExponentialF prec alt s -> [| formatAnyFractional $(withAlt alt Formatters.Exponent) s (newPadding padding) (toGrp grouping 3) (changePrec prec) |]
-  ExponentialCapsF prec alt s -> [| formatAnyFractional (Formatters.Upper $(withAlt alt Formatters.Exponent)) s (newPadding padding) (toGrp grouping 3) (changePrec prec) |]
-  GeneralF prec alt s -> [| formatAnyFractional $(withAlt alt Formatters.Generic) s (newPadding padding) (toGrp grouping 3) (changePrec prec) |]
-  GeneralCapsF prec alt s -> [| formatAnyFractional (Formatters.Upper $(withAlt alt Formatters.Generic)) s (newPadding padding) (toGrp grouping 3) (changePrec prec) |]
-  FixedF prec alt s -> [| formatAnyFractional $(withAlt alt Formatters.Fixed) s (newPadding padding) (toGrp grouping 3) (changePrec prec) |]
-  FixedCapsF prec alt s -> [| formatAnyFractional (Formatters.Upper $(withAlt alt Formatters.Fixed)) s (newPadding padding) (toGrp grouping 3) (changePrec prec) |]
-  PercentF prec alt s -> [| formatAnyFractional $(withAlt alt Formatters.Percent) s (newPadding padding) (toGrp grouping 3) (changePrec prec) |]
+  ExponentialF prec alt s -> [| formatAnyFractional $(withAlt alt Formatters.Exponent) s $(newPaddingQ padding) $(toGrp grouping 3) $(changePrec prec) |]
+  ExponentialCapsF prec alt s -> [| formatAnyFractional (Formatters.Upper $(withAlt alt Formatters.Exponent)) s $(newPaddingQ padding) $(toGrp grouping 3) $(changePrec prec) |]
+  GeneralF prec alt s -> [| formatAnyFractional $(withAlt alt Formatters.Generic) s $(newPaddingQ padding) $(toGrp grouping 3) $(changePrec prec) |]
+  GeneralCapsF prec alt s -> [| formatAnyFractional (Formatters.Upper $(withAlt alt Formatters.Generic)) s $(newPaddingQ padding) $(toGrp grouping 3) $(changePrec prec) |]
+  FixedF prec alt s -> [| formatAnyFractional $(withAlt alt Formatters.Fixed) s $(newPaddingQ padding) $(toGrp grouping 3) $(changePrec prec) |]
+  FixedCapsF prec alt s -> [| formatAnyFractional (Formatters.Upper $(withAlt alt Formatters.Fixed)) s $(newPaddingQ padding) $(toGrp grouping 3) $(changePrec prec) |]
+  PercentF prec alt s -> [| formatAnyFractional $(withAlt alt Formatters.Percent) s $(newPaddingQ padding) $(toGrp grouping 3) $(changePrec prec) |]
 
   -- Default / String
-
-  -- Note: v / i / f uses pat and var to ensure stable name in error message
-  DefaultF prec s -> [| \($(pat "v")) ->
-      case categorise (Proxy :: Proxy $(typeAllowed)) $(var "v") of
-        Integral $(pat "i") -> formatAnyIntegral Formatters.Decimal s (newPadding padding) (toGrp grouping 3) $(var "i")
-        Fractional $(pat "f") -> formatAnyFractional Formatters.Generic s (newPadding padding) (toGrp grouping 3) (changePrec' prec) $(var "f")
-        StringType $(pat "f") -> Formatters.formatString (newPaddingForString padding) (changePrec' prec) $(var "f")
-                         |]
-   where
-     typeAllowed :: Q Type
-     typeAllowed = case padding of
-       PaddingDefault -> [t| EnableForString |]
-       Padding _ Nothing -> [t| EnableForString |]
-       Padding _ (Just (_, AnyAlign a)) -> case Formatters.getAlignForString a of
-         Nothing -> [t| DisableForString |]
-         Just _ -> [t| EnableForString |]
-
-  StringF prec -> [| Formatters.formatString pad (changePrec' prec) |]
-    where pad = newPaddingForString padding
-
--- Generate stable name in TH slices
--- The name are postfixed by _PyF to limit the risk of shadowing
-
-pat :: String -> Q Pat
-pat name = pure (VarP (mkName (name ++ "_PyF")))
-
-var :: String -> Q Exp
-var name = pure (VarE (mkName (name ++ "_PyF")))
+  DefaultF prec s -> [| formatAny s $(paddingToPaddingK padding) $(toGrp grouping 3) $(changePrec' prec) |]
+  StringF prec -> [| Formatters.formatString (newPaddingKForString $(paddingToPaddingK padding)) $(changePrec' prec) . pyfToString |]
 
-newPaddingForString :: Padding -> Maybe (Int, Formatters.AlignMode 'Formatters.AlignAll, Char)
-newPaddingForString padding = case padding of
-    PaddingDefault -> Nothing
-    Padding i Nothing -> Just (fromIntegral i, Formatters.AlignLeft, ' ') -- default align left and fill with space for string
-    Padding i (Just (mc, AnyAlign a)) -> case Formatters.getAlignForString a of
-      Nothing -> error alignErrorMsg
-      Just al -> pure (fromIntegral i, al, fromMaybe ' ' mc)
+newPaddingQ :: Padding -> Q Exp
+newPaddingQ pad = [| pad' |]
+  where pad' = newPaddingUnQ pad
 
-newPadding :: Padding -> Maybe (Integer, AnyAlign, Char)
-newPadding padding = case padding of
+newPaddingUnQ :: Padding -> Maybe (Integer, AnyAlign, Char)
+newPaddingUnQ padding = case padding of
     PaddingDefault -> Nothing
     (Padding i al) -> case al of
       Nothing -> Just (i, AnyAlign Formatters.AlignRight, ' ') -- Right align and space is default for any object, except string
       Just (Nothing, a) -> Just (i, a, ' ')
       Just (Just c, a) -> Just (i, a, c)
 
+data PaddingK k where
+  PaddingDefaultK :: PaddingK 'Formatters.AlignAll
+  PaddingK :: Integer -> (Maybe (Maybe Char, Formatters.AlignMode k)) -> PaddingK k
+
+paddingToPaddingK :: Padding -> Q Exp
+paddingToPaddingK p = case p of
+  PaddingDefault -> [| PaddingDefaultK |]
+  Padding i Nothing -> [| PaddingK i Nothing :: PaddingK 'Formatters.AlignAll |]
+  Padding i (Just (c, AnyAlign a)) -> [| PaddingK i (Just (c, a)) |]
+
+paddingKToPadding :: PaddingK k -> Padding
+paddingKToPadding p = case p of
+  PaddingDefaultK -> PaddingDefault
+  PaddingK i Nothing -> Padding i Nothing
+  PaddingK i (Just (c, a)) -> Padding i (Just (c, AnyAlign a))
+
 formatAnyIntegral :: (Show i, Integral i) => Formatters.Format t t' 'Formatters.Integral -> Formatters.SignMode -> Maybe (Integer, AnyAlign, Char) -> Maybe (Int, Char) -> i -> String
 formatAnyIntegral f s Nothing grouping i = Formatters.formatIntegral f s Nothing grouping i
 formatAnyIntegral f s (Just (padSize, AnyAlign alignMode, c)) grouping i = Formatters.formatIntegral f s (Just (fromIntegral padSize, alignMode, c)) grouping i
@@ -193,44 +188,35 @@
 formatAnyFractional f s Nothing grouping p i = Formatters.formatFractional f s Nothing grouping p i
 formatAnyFractional f s (Just (padSize, AnyAlign alignMode, c)) grouping p i = Formatters.formatFractional f s (Just (fromIntegral padSize, alignMode, c)) grouping p i
 
-data FormattingType where
-  StringType :: String -> FormattingType
-  Fractional :: RealFloat t => t -> FormattingType
-  Integral :: (Show t, Integral t) => t -> FormattingType
+class FormatAny i k where
+  formatAny :: Formatters.SignMode -> PaddingK k -> Maybe (Int, Char) -> Maybe Int -> i -> String
 
-class Categorise k t where
-  categorise :: Proxy k -> t -> FormattingType
+instance (FormatAny2 (PyFClassify t) t k) => FormatAny t k where
+  formatAny = formatAny2 (Proxy :: Proxy (PyFClassify t))
 
-instance Categorise k Integer where categorise _  i = Integral i
-instance Categorise k Int where categorise _  i = Integral i
-instance Categorise k Int.Int8 where categorise _  i = Integral i
-instance Categorise k Int.Int16 where categorise _  i = Integral i
-instance Categorise k Int.Int32 where categorise _  i = Integral i
-instance Categorise k Int.Int64 where categorise _  i = Integral i
+class FormatAny2 (c :: PyFCategory) (i :: *) (k :: Formatters.AlignForString) where
+  formatAny2 :: Proxy c -> Formatters.SignMode -> PaddingK k -> Maybe (Int, Char) -> Maybe Int -> i -> String
 
-instance Categorise k Natural where categorise _  i = Integral i
-instance Categorise k Word where categorise _  i = Integral i
-instance Categorise k Word.Word8 where categorise _  i = Integral i
-instance Categorise k Word.Word16 where categorise _  i = Integral i
-instance Categorise k Word.Word32 where categorise _  i = Integral i
-instance Categorise k Word.Word64 where categorise _  i = Integral i
+instance (Show t, Integral t) => FormatAny2 'PyFIntegral t k where
+  formatAny2 _ s a p _precision i = formatAnyIntegral Formatters.Decimal s (newPaddingUnQ (paddingKToPadding a)) p i
 
-instance Categorise k Float where categorise _  f = Fractional f
-instance Categorise k Double where categorise _  f = Fractional f
+instance (RealFloat t) => FormatAny2 'PyFFractional t k where
+  formatAny2 _ s a p precision t = formatAnyFractional Formatters.Generic s (newPaddingUnQ (paddingKToPadding a)) p precision t
 
--- This may use DataKinds extension, however the need for the
--- extension will leak inside the code calling the template haskell
--- quasi quotes.
-data EnableForString
-data DisableForString
+newPaddingKForString :: PaddingK 'Formatters.AlignAll -> Maybe (Int, Formatters.AlignMode 'Formatters.AlignAll, Char)
+newPaddingKForString padding = case padding of
+    PaddingDefaultK -> Nothing
+    PaddingK i Nothing -> Just (fromIntegral i, Formatters.AlignLeft, ' ') -- default align left and fill with space for string
+    PaddingK i (Just (mc, a)) -> Just (fromIntegral i, a, fromMaybe ' ' mc)
 
-instance Categorise EnableForString LText.Text where categorise _  t = StringType (LText.unpack t)
-instance Categorise EnableForString SText.Text where categorise _  t = StringType (SText.unpack t)
-instance Categorise EnableForString String where categorise _  t = StringType t
 
-alignErrorMsg :: String
-alignErrorMsg = "String Cannot be aligned with the inside `=` mode"
+-- TODO: _s(ign) and _grouping should trigger errors
+instance (PyFToString t) => FormatAny2 'PyFString t 'Formatters.AlignAll where
+  formatAny2 _ _s a _grouping precision t = Formatters.formatString (newPaddingKForString a) precision (pyfToString t)
 
-instance TypeError ('Text "String Cannot be aligned with the inside `=` mode") => Categorise DisableForString LText.Text where categorise _ _ = error "unreachable"
-instance TypeError ('Text "String Cannot be aligned with the inside `=` mode") => Categorise DisableForString SText.Text where categorise _ _ = error "unreachable"
-instance TypeError ('Text "String Cannot be aligned with the inside `=` mode") => Categorise DisableForString String where categorise _ _ = error "unreachable"
+instance TypeError ('Text "String type is incompatible with inside padding (=).") => FormatAny2 'PyFString t 'Formatters.AlignNumber where
+  formatAny2 = error "Unreachable"
+
+type family ToFmt t where
+  ToFmt 'PyFIntegral = 'Formatters.Integral
+  ToFmt 'PyFFractional = 'Formatters.Fractional
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,19 +1,21 @@
-{-# OPTIONS -Wno-type-defaults #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE ExtendedDefaultRules #-}
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE TypeApplications #-}
 {-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DeriveAnyClass, GeneralizedNewtypeDeriving, DerivingStrategies #-}
 
 import Test.Hspec
 
 import PyF
 import SpecUtils
 import SpecCustomDelimiters
+import Data.Text
 
 {-
-   - Normal tests are done using the recommanded API: [f|.....|]
+   - Normal tests are done using the recommanded API: [fmt|.....|]
    - Test with $(checkExample formatString result) are checked against the python reference implementation. Result is provided as documentation.
    - Test with $(checkExampleDiff formatString result) are not checked against the python reference implementation. This is known (and documented) differences.
    - Test with $(check formatString) are only tested against the python reference implementation.
@@ -22,6 +24,27 @@
 main :: IO ()
 main = hspec spec
 
+newtype FooFloating = FooFloating Float
+  deriving newtype (Show, RealFloat, RealFrac, Floating, Fractional, Real, Enum, Num, Ord, Eq)
+
+newtype FooIntegral = FooIntegral Integer
+  deriving newtype (Show, Integral, Real, Enum, Num, Ord, Eq)
+
+data Foo = Foo
+
+data FooDefault = FooDefault
+  deriving (Show)
+
+instance PyFToString FooDefault
+
+instance PyFToString Foo where
+  pyfToString Foo = "I'm a Foo"
+
+type instance PyFClassify Foo = 'PyFString
+type instance PyFClassify FooFloating = 'PyFFractional
+type instance PyFClassify FooIntegral = 'PyFIntegral
+type instance PyFClassify FooDefault = 'PyFString
+
 spec :: Spec
 spec = do
   describe "simple with external variable" $ do
@@ -29,9 +52,9 @@
       anInt = 123
       aFloat = 0.234
       aString = "hello"
-    it "int" $ [f|{anInt}|] `shouldBe` "123"
-    it "float" $ [f|{aFloat}|] `shouldBe` "0.234"
-    it "string" $ [f|{aString}|] `shouldBe` "hello"
+    it "int" $ [fmt|{anInt}|] `shouldBe` "123"
+    it "float" $ [fmt|{aFloat}|] `shouldBe` "0.234"
+    it "string" $ [fmt|{aString}|] `shouldBe` "hello"
   describe "only expression" $ do
     describe "default" $ do
       it "int" $(checkExample "{123}" "123")
@@ -178,7 +201,7 @@
         age = 31
         euroToFrancs = 6.55957
       in
-        [f|hello {name} you are {age} years old and the conversion rate of euro is {euroToFrancs:.2}|] `shouldBe` ("hello Guillaume you are 31 years old and the conversion rate of euro is 6.56")
+        [fmt|hello {name} you are {age} years old and the conversion rate of euro is {euroToFrancs:.2}|] `shouldBe` ("hello Guillaume you are 31 years old and the conversion rate of euro is 6.56")
 
 
   describe "error reporting" $ do
@@ -186,14 +209,14 @@
 
   describe "sub expressions" $ do
     it "works" $ do
-      [f|2pi = {2 * pi:.2}|] `shouldBe` "2pi = 6.28"
+      [fmt|2pi = {2 * pi:.2}|] `shouldBe` "2pi = 6.28"
 
   describe "escape strings" $ do
     it "works" $ do
-      [f|hello \n\b|] `shouldBe` "hello \n\b"
+      [fmt|hello \n\b|] `shouldBe` "hello \n\b"
 
   it "escape chars" $ do
-     [f|}}{{}}{{|] `shouldBe` "}{}{"
+     [fmt|}}{{}}{{|] `shouldBe` "}{}{"
 
   describe "custom delimiters" $ do
     it "works" $ do
@@ -201,24 +224,60 @@
     it "escape chars" $ do
        [myCustomFormatter|@@!!@@!!|] `shouldBe` "@!@!"
 
+  describe "empty line" $ do
+    it "works" $ do
+      [fmt||] `shouldBe` ""
 
   describe "multi line escape" $ do
     it "works" $ do
-      [f|\
+      [fmt|\
 - a
 - b
 \
 |] `shouldBe` "- a\n- b\n"
 
+    it "escapes in middle of line" $ do
+      [fmt|Example goes \
+here!|] `shouldBe` "Example goes here!"
+
+    it "escapes a lot of things" $ do
+      [fmt|\
+I'm a line with \n and \\ and a correct line
+ending, but that one is escaped\
+And I'm escaping before and after: \\{pi:.3f}\\
+yeah\
+|] `shouldBe` "I'm a line with \n and \\ and a correct line\nending, but that one is escapedAnd I'm escaping before and after: \\3.142\\\nyeah"
+
     it "escapes" $ do
-      [f|\\
+      [fmt|\\
 - a
 - b
 \
 |] `shouldBe` "\\\n- a\n- b\n"
 
+  describe "empty trailing value" $ do
+    it "String" $ do
+      ([fmt|\
+{pi:.0}
+|] :: String) `shouldBe` "3\n"
+
   describe "language extensions" $ do
      it "parses @Int" $ do
-       [f|hello {show @Int 10}|] `shouldBe` "hello 10"
+       [fmt|hello {show @Int 10}|] `shouldBe` "hello 10"
      it "parses BinaryLiterals" $ do
-       [f|hello {0b1111}|] `shouldBe` "hello 15"
+       [fmt|hello {0b1111}|] `shouldBe` "hello 15"
+
+
+  describe "custom types" $ do
+      it "works with integral" $ do
+        [fmt|{FooIntegral 10:d}|] `shouldBe` "10"
+      it "works with floating" $ do
+        [fmt|{FooFloating 25.123:f}|] `shouldBe` "25.123000"
+      it "works with string" $ do
+        [fmt|{Foo:s}|] `shouldBe` "I'm a Foo"
+        [fmt|{FooDefault:s}|] `shouldBe` "FooDefault"
+      it "works with classify" $ do
+        [fmt|{Foo}|] `shouldBe` "I'm a Foo"
+        [fmt|{FooIntegral 100}|] `shouldBe` "100"
+        [fmt|{FooFloating 100.123}|] `shouldBe` "100.123"
+        [fmt|{FooDefault}|] `shouldBe` "FooDefault"
diff --git a/test/SpecCustomDelimiters.hs b/test/SpecCustomDelimiters.hs
--- a/test/SpecCustomDelimiters.hs
+++ b/test/SpecCustomDelimiters.hs
@@ -5,4 +5,4 @@
 import PyF
 
 myCustomFormatter :: QuasiQuoter
-myCustomFormatter = fWithDelimiters ('@','!')
+myCustomFormatter = fmtWithDelimiters ('@','!')
diff --git a/test/SpecFail.hs b/test/SpecFail.hs
--- a/test/SpecFail.hs
+++ b/test/SpecFail.hs
@@ -29,14 +29,17 @@
   | Ok String
   deriving (Show, Eq)
 
+makeTemplate :: String -> String
+makeTemplate s = "{-# LANGUAGE QuasiQuotes, ExtendedDefaultRules, TypeApplications #-}\nimport PyF\ntruncate' = truncate @Float @Int\nhello = \"hello\"\nnumber = 3.14 :: Float\nmain :: IO ()\nmain = putStrLn [fmt|" ++ s ++ "|]\n"
+
 {- | Compile a formatting string
 
->>> checkCompile "pi:x"
+>>> checkCompile fileContent
 CompileError "Bla bla bla, Floating cannot be formatted as hexa (`x`)
 -}
-checkCompile :: String -> IO CompilationStatus
-checkCompile s = withSystemTempFile "PyFTest.hs" $ \path fd -> do
-  IO.hPutStr fd $ "{-# LANGUAGE QuasiQuotes, ExtendedDefaultRules, TypeApplications #-}\nimport PyF\ntruncate' = truncate @Float @Int\nhello = \"hello\"\nnumber = 3.14 :: Float\nmain :: IO ()\nmain = [f|" ++ s ++ "|]\n"
+checkCompile :: HasCallStack => String -> IO CompilationStatus
+checkCompile content = withSystemTempFile "PyFTest.hs" $ \path fd -> do
+  IO.hPutStr fd content
   IO.hFlush fd
 
   (ecode, _stdout, stderr) <- readProcessWithExitCode "ghc" [path,
@@ -104,12 +107,22 @@
 
 -- if the compilation fails, runs a golden test on compilation output
 -- else, fails the test
+fileFailCompile :: HasCallStack => FilePath -> Spec
+fileFailCompile path = do
+  fileContent <- runIO $ readFile path
+
+  -- I'm using the hash of the path, considering that the file content can evolve
+  failCompileContent (hash path) path fileContent
+
 failCompile :: HasCallStack => String -> Spec
-failCompile s = do
-  before (checkCompile s) $ it (s ++ " " ++ show (hash s)) $ \res -> case res of
-   CompileError output -> golden (show $ hash s) output
-   _ -> assertFailure (show res)
+failCompile s = failCompileContent (hash s) s (makeTemplate s)
 
+failCompileContent :: HasCallStack => Int -> String -> String -> Spec
+failCompileContent h caption fileContent = do
+  before (checkCompile fileContent) $ it (show caption) $ \res -> case res of
+   CompileError output -> golden (show h) output
+   _ -> assertFailure (show $ ".golden/" <> show h  <> "\n" <>show res)
+
 main :: IO ()
 main = hspec spec
 
@@ -134,8 +147,7 @@
         failCompile "{hello:=100s}"
         failCompile "{hello:=100}"
 
-      -- XXX: this are not failing for now, it should be fixed
-      xdescribe "grouping" $ do
+      describe "grouping" $ do
         failCompile "{hello:_s}"
         failCompile "{hello:,s}"
 
@@ -171,6 +183,11 @@
     xdescribe "not specified" $ do
       failCompile "{truncate number:.3}"
       failCompile "{hello:#}"
+      failCompile "{hello:+}"
+      failCompile "{hello: }"
+      failCompile "{hello:-}"
+      failCompile "{hello:_}"
+      failCompile "{hello:,}"
 
     describe "multiples lines" $ do
       failCompile "hello\n\n\n{pi:l}"
@@ -187,3 +204,17 @@
 
     describe "fail is not enabled extension" $ do
       failCompile "{0b0001}"
+
+    describe "lexical errors" $ do
+      failCompile "foo\\Pbar"
+
+    describe "fileFailures" $ do
+      mapM_ fileFailCompile [
+        "test/failureCases/bug18.hs"
+        ]
+
+    describe "Wrong type" $ do
+      failCompile "{True:s}"
+      failCompile "{True}"
+      failCompile "{True:f}"
+      failCompile "{True:d}"
diff --git a/test/SpecOverloaded.hs b/test/SpecOverloaded.hs
new file mode 100644
--- /dev/null
+++ b/test/SpecOverloaded.hs
@@ -0,0 +1,22 @@
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+import Test.Hspec
+
+import PyF
+import Data.Text
+import Data.ByteString
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec = do
+  describe "Test formatting with different types" $ do
+    it "String" $ do
+      [fmt|hello {10:d}|] `shouldBe` ("hello 10" :: String)
+    it "Text" $ do
+      [fmt|hello {10:d}|] `shouldBe` ("hello 10" :: Text)
+    it "ByteString" $ do
+      [fmt|hello {10:d}|] `shouldBe` ("hello 10" :: ByteString)
