module NumericQQ
(
  bin,
  oct,
  hex
)
where

import NumericQQ.Prelude
import Numeric
import Data.Char
import Language.Haskell.TH
import Language.Haskell.TH.Quote


type Base = Int

bin :: QuasiQuoter
bin = qq 2

oct :: QuasiQuoter
oct = qq 8

hex :: QuasiQuoter
hex = qq 16

qq :: Base -> QuasiQuoter
qq base = QuasiQuoter {quoteExp = exp} where
  exp s = 
    case parse base s of
      Nothing -> fail $ "A string \"" <> s <> 
                        "\" cannot be parsed as a base-" <> 
                        show base <> " number"
      Just i -> return $ LitE (IntegerL (fromIntegral i))

parse :: Base -> String -> Maybe Int
parse base string = 
  case readInt base ((< base) . digitToInt) digitToInt string of
    [] -> Nothing
    [(r, "")] -> Just r
    [(_, _)] -> Nothing
    r -> $bug $ "Unexpected parsing result: " <> show r