module Data.Urn.QQ.ParseExp (
parseUrnList, parseUrn,
wordExp, weightExp, sizeExp,
btreeExp, wtreeExp,
urnExp
) where
import Data.Traversable
import Language.Haskell.TH
import Language.Haskell.Meta.Parse
import Data.Urn.Internal
import Data.Urn.Common (fromList)
parseUrnList :: String -> Either String [(Word, Exp)]
parseUrnList str =
case parseExp $ "[" ++ str ++ "]" of
Left _ ->
Left "Parse error in urn"
Right (ListE tups) ->
for tups $ \case
TupE [LitE (IntegerL w), e] | toInteger (minBound :: Word) <= w
, w <= toInteger (maxBound :: Word) ->
Right (fromInteger w :: Word, e)
TupE [_, _] ->
Left $ "A weighted pair in this urn lacked a valid literal weight"
_ ->
Left $ "This urn contained a non-pair element"
Right _ ->
Left "This urn does not contain a list of pairs"
parseUrn :: String -> Either String (Urn Exp)
parseUrn str = (fromList <$> parseUrnList str) >>= \case
Just urn -> Right urn
Nothing -> Left "Empty urn"
wordExp :: Word -> Exp
wordExp = LitE . IntegerL . toInteger
weightExp :: Weight -> Exp
weightExp = wordExp
sizeExp :: Size -> Exp
sizeExp (Size s) = ConE 'Size `AppE` wordExp s
btreeExp :: BTree Exp -> Exp
btreeExp (BLeaf a) = ConE 'BLeaf `AppE` a
btreeExp (BNode l r) = ConE 'BNode `AppE` wtreeExp l `AppE` wtreeExp r
wtreeExp :: WTree Exp -> Exp
wtreeExp wt = RecConE 'WTree [ ('weight, weightExp $ weight wt)
, ('btree, btreeExp $ btree wt) ]
urnExp :: Urn Exp -> Exp
urnExp u = RecConE 'Urn [ ('size, sizeExp $ size u)
, ('wtree, wtreeExp $ wtree u) ]