{-# Language NoMonomorphismRestriction #-}

module Text.Printf.TH.Parser where

import Control.Applicative
import Data.CharSet (fromList)
import Text.Trifecta
import qualified Data.Set as S

import Text.Printf.TH.Types

flagSet = fromList "-+ #0"

specSet = fromList "diuoxXfFeEaAgGpcs?"

parseFmtStr = do
    atoms <-
        many $
        choice [Str "%" <$ string "%%", Arg <$> fmtArg, Str . return <$> noneOf "%"]
    return $ go atoms
  where
    go (Str s:Str s1:as) = go (Str (s ++ s1) : as)
    go (a:as) = a : go as
    go [] = []

fmtArg = do
    char '%'
    flags <-
        do fs <-
               many $ do
                   c <- oneOfSet flagSet <?> "flag"
                   pure $
                       case c of
                           '-' -> FlagLJust
                           '+' -> FlagSigned
                           ' ' -> FlagSpaced
                           '#' -> FlagPrefixed
                           '0' -> FlagZeroPadded
                           _ -> error "???"
           let flagSet = S.fromList fs
           if S.size flagSet < length fs
               then fail "Duplicate flags specified"
               else pure $ toFlagSet flagSet
    width <- optional $ choice [Given <$> natural, Need <$ char '*'] <?> "width"
    precision <-
        optional $
        (do char '.'
            choice [Given <$> natural, Need <$ char '*']) <?>
        "precision"
    spec <- oneOfSet specSet <?> "valid specifier"
    pure $ FormatArg flags width precision spec