{-# LANGUAGE TemplateHaskell #-} module Text.Scanf.TH where import Data.Char (isSpace) import Language.Haskell.TH import Language.Haskell.TH.Syntax import Language.Haskell.TH.Quote import Text.Scanf.Internal formatString :: String -> Q Exp formatString "" = [|Empty|] formatString ('%' : s1) = case s1 of 'c' : s' -> [|char $(formatString s')|] 'd' : s' -> [|int $(formatString s')|] 'f' : s' -> [|double $(formatString s')|] 'l' : s' -> [|integer $(formatString s')|] 's' : s' -> [|string $(formatString s')|] '%' : s' -> [|constant "%" $(formatString s')|] _ -> error "Invalid format string" formatString s@(c : _) | isSpace c = let (s0, s') = span isSpace s in [|whitespace $(lift s0) $(formatString s')|] formatString s = let (s0, s') = break (\c -> isSpace c || c == '%') s in [|constant $(lift s0) $(formatString s')|] -- | Parse a typed 'Format' string. -- -- The following conversion strings are supported: -- -- - @%d@: signed integer ('Int') -- - @%l@: signed integer ('Integer', unbounded) -- - @%f@: floating point ('Double') -- - @%s@: string of non-space characters ('String') -- - @%c@: single character ('Char') -- - @%%@: parse/print a literal percent character -- -- N.B.: in 'scanf', spaces in the format string match any number of whitespace -- character until the next nonspace character. -- -- @ -- ['fmt'|%d lazy %s and %d strict %s|] -- :: 'Format' ('Int' ':+' 'String' ':+' 'Int' ':+' 'String' ':+' ()) -- @ fmt :: QuasiQuoter fmt = QuasiQuoter { quoteExp = formatString , quotePat = undefined , quoteType = undefined , quoteDec = undefined }