module Package.C.Triple.Parse ( parseTriple
                              , parseTripleIO
                              ) where

import           CPkgPrelude
import           Package.C.Error
import           Package.C.Triple.Type
import           Text.Megaparsec
import           Text.Megaparsec.Char

type Parser = Parsec Void String

parseTripleIO :: MonadIO m => String -> m TargetTriple
parseTripleIO = parseIO parseTriple

parseIO :: MonadIO m => Parser a -> String -> m a
parseIO p str =
    case parse p "(none)" str of
        Right x  -> pure x
        Left err -> parseErr (errorBundlePretty err)

parseTriple :: Parser TargetTriple
parseTriple = TargetTriple
    <$> parseArch
    <*> optional (try (char '-' *> parseManufacturer))
    <*> (char '-' *> parseOS)
    <*> optional (char '-' *> parseABI)

tryString :: String -> Parser String
tryString = try . string

parseArch :: Parser Arch
parseArch =
        (tryString "x86_64" $> X64)
    <|> (tryString "armv7l" $> Arm)
    <|> (tryString "arm" $> Arm)
    <|> (tryString "aarch64" $> AArch)
    <|> (tryString "riscv64" $> RISCV64)
    <|> (tryString "powerpc64le" $> PowerPC64le)
    <|> (tryString "powerpc64" $> PowerPC64)
    <|> (tryString "powerpc" $> PowerPC)
    <|> (tryString "sparc64" $> Sparc64)
    <|> (tryString "s390x" $> S390x)
    <|> (tryString "alpha" $> Alpha)
    <|> (tryString "m68k" $> M68k)
    <|> (tryString "mipsisa32r6el" $> MipsIsa32r6El)
    <|> (tryString "mipsisa32r6" $> MipsIsa32r6)
    <|> (tryString "mipsisa64r6el" $> MipsIsa64r6El)
    <|> (tryString "mipsisa64r6" $> MipsIsa64r6)
    <|> (tryString "mips64el" $> Mips64El)
    <|> (tryString "mips64" $> Mips64)
    <|> (tryString "mipsel" $> MipsEl)
    <|> (tryString "mips" $> Mips)
    <|> (tryString "i686" $> X86)
    <|> (tryString "sh4" $> SH4)
    <|> (tryString "hppa64" $> HPPA64)
    <|> (tryString "hppa" $> HPPA)

parseManufacturer :: Parser Manufacturer
parseManufacturer =
        (tryString "unknown" $> Unknown)
    <|> (tryString "apple" $> Apple)
    <|> (tryString "ibm" $> IBM)
    <|> (tryString "pc" $> PC)

parseOS :: Parser OS
parseOS =
        (tryString "darwin" $> Darwin)
    <|> (tryString "dragonfly" $> Dragonfly)
    <|> (tryString "freebsd" $> FreeBSD)
    <|> (tryString "linux" $> Linux)
    <|> (tryString "openbsd" $> OpenBSD)
    <|> (tryString "netbsd" $> NetBSD)
    <|> (tryString "solaris" $> Solaris)
    <|> (tryString "w64" $> Windows)
    <|> (tryString "redox" $> Redox)
    <|> (tryString "haiku" $> Haiku)
    <|> (tryString "ios" $> IOS)
    <|> (tryString "aix" $> AIX)
    <|> (tryString "hurd" $> Hurd)
    <|> (tryString "android" $> Android)
    <|> (tryString "none" $> NoOs)

parseABI :: Parser ABI
parseABI =
        (tryString "gnueabihf" $> GNUeabihf)
    <|> (tryString "gnuabi64" $> GNUabi64)
    <|> (tryString "gnueabi" $> GNUeabi)
    <|> (tryString "gnuspe" $> GNUspe)
    <|> (tryString "gnu" $> GNU)
    <|> (tryString "mingw32" $> MinGw)