module Radium.Formats.Condensed ( Molecule(..)
, readCondensed
, writeCondensed
) where
import Text.ParserCombinators.Parsec
data Molecule a = Ion (Molecule a) Int
| Molecule [Molecule a] Int
| Element a Int
deriving (Eq, Show)
type SymbolMolecule = Molecule String
instance Functor Molecule where
fmap f (Ion m n) = Ion (fmap f m) n
fmap f (Molecule ms n) = Molecule (map (fmap f) ms) n
fmap f (Element s n) = Element (f s) n
readCondensed :: String -> SymbolMolecule
readCondensed xs = case parse ion "" xs of
Left _ -> Molecule [] 0
Right val -> val
ion :: Parser SymbolMolecule
ion = do
c <- number
m <- formula
n <- optionMaybe ionNumber
return $ case n of
Just val -> Ion (Molecule m c) val
_ -> Molecule m c
formula :: Parser [SymbolMolecule]
formula = many (subformula <|> element)
subformula :: Parser SymbolMolecule
subformula = do
s <- between (char '(') (char ')') formula
n <- number
return (Molecule s n)
element :: Parser SymbolMolecule
element = do
s <- symbol
n <- number
return (Element s n)
symbol :: Parser String
symbol = do
s <- upper
ss <- many lower
return (s:ss)
number :: Parser Int
number = do
ds <- many digit
return $ if null ds then 1 else read ds :: Int
ionNumber :: Parser Int
ionNumber = do
s <- char '-' <|> char '+'
n <- number
return $ if s == '+' then n else (n)
writeCondensed :: SymbolMolecule -> String
writeCondensed (Ion x n) = writeCondensed x ++ writeIon n
writeCondensed (Molecule xs n) = writeNumber n ++ concatMap writeCondensed xs
writeCondensed (Element x n) = x ++ writeNumber n
writeIon :: Int -> String
writeIon 0 = ""
writeIon 1 = "+"
writeIon (1) = "-"
writeIon n = if n > 1 then "+" ++ show n else show n
writeNumber :: Int -> String
writeNumber 0 = ""
writeNumber 1 = ""
writeNumber (1) = "-"
writeNumber n = show n