module Text.LLVM.Parser where
import Text.LLVM.AST
import Data.Int (Int32)
import Text.Parsec
import Text.Parsec.String
pNameChar :: Parser Char
pNameChar = letter <|> digit <|> oneOf "-$._"
pIdent :: Parser Ident
pIdent = Ident <$> (char '%' >> many1 pNameChar)
pSymbol :: Parser Symbol
pSymbol = Symbol <$> (char '@' >> many1 pNameChar)
pInt32 :: Parser Int32
pInt32 = read <$> many1 digit
pPrimType :: Parser PrimType
pPrimType = choice
[ Integer <$> try (char 'i' >> pInt32)
, FloatType <$> try pFloatType
, try (string "label") >> return Label
, try (string "void") >> return Void
, try (string "x86mmx") >> return X86mmx
, try (string "metadata") >> return Metadata
]
pFloatType :: Parser FloatType
pFloatType = choice
[ try (string "half") >> return Half
, try (string "float") >> return Float
, try (string "double") >> return Double
, try (string "fp128") >> return Fp128
, try (string "x86_fp80") >> return X86_fp80
, try (string "ppc_fp128") >> return PPC_fp128
]
pType :: Parser Type
pType = pType0 >>= pFunPtr
where
pType0 :: Parser Type
pType0 =
choice
[ Alias <$> pIdent
, brackets (pNumType Array)
, braces (Struct <$> pTypeList)
, angles (braces (PackedStruct <$> pTypeList) <|> spaced (pNumType Vector))
, string "opaque" >> return Opaque
, PrimType <$> pPrimType
]
pTypeList :: Parser [Type]
pTypeList = sepBy (spaced pType) (char ',')
pNumType :: (Int32 -> Type -> Type) -> Parser Type
pNumType f =
do n <- pInt32
spaces >> char 'x' >> spaces
t <- pType
return (f n t)
pArgList :: Type -> Parser Type
pArgList t0 = spaces >> (p1 [] <|> return (FunTy t0 [] False))
where
p1 ts =
(string "..." >> spaces >> return (FunTy t0 (reverse ts) True))
<|> (pType >>= \t -> (spaces >> p2 (t : ts)))
p2 ts =
(char ',' >> spaces >> p1 ts)
<|> return (FunTy t0 (reverse ts) False)
pFunPtr :: Type -> Parser Type
pFunPtr t0 = pFun <|> pPtr <|> return t0
where
pFun = parens (pArgList t0) >>= pFunPtr
pPtr = char '*' >> pFunPtr (PtrTo t0)
parseType :: String -> Either ParseError Type
parseType = parse (pType <* eof) "<internal>"
angles :: Parser a -> Parser a
angles body = char '<' *> body <* char '>'
braces :: Parser a -> Parser a
braces body = char '{' *> body <* char '}'
brackets :: Parser a -> Parser a
brackets body = char '[' *> body <* char ']'
parens :: Parser a -> Parser a
parens body = char '(' *> body <* char ')'
spaced :: Parser a -> Parser a
spaced body = spaces *> body <* spaces