module Language.CSharp.Parser.Utility where



import Text.Parsec

import Text.Parsec.Pos

import Language.CSharp.Syntax

import Language.CSharp.Lexer



type P = Parsec [Positioned Token] ()



pEqualSign :: P ()

pEqualSign = pToken TOpAssign



pSemi :: P ()

pSemi = pToken TSemicolon



pPeriod :: P ()

pPeriod = pToken TPeriod



pComma :: P ()

pComma = pToken TComma



pColon :: P ()

pColon = pToken TColon



pLambda :: P ()

pLambda = pToken TLambda



betweenParens, betweenCurly, betweenSquare, betweenDiamond :: P a -> P a

betweenParens  = between pOParens pCParens

betweenCurly   = between pOCurly pCCurly

betweenSquare  = between pSOpen pSClose



betweenDiamond p = try (between (pToken TOpLessThan) (pToken TOpGreaterThan) p)

    <|> do pToken TOpLessThan

           r <- p

           i <- getInput

           case head i of

                (Positioned pos@(AlexPn a l c) TOpRightShift) 

                    -> setInput ( Positioned pos TOpGreaterThan 

                                : Positioned (AlexPn (a + 1) l (c + 1)) TOpGreaterThan : tail i)

                _   -> setInput i

           pToken TOpGreaterThan 

           return r



pOParens, pCParens :: P ()

pOParens = pToken TOParens

pCParens = pToken TCParens



pOCurly, pCCurly :: P ()

pOCurly = pToken TOCurly

pCCurly = pToken TCCurly



pSOpen, pSClose :: P ()

pSOpen  = pToken TOSquare

pSClose = pToken TCSquare



pName :: P Name

pName = do

    s  <- pIdentifier

    ss <- many (pToken TPeriod *> pIdentifier)

    return $ Name (s : ss)



pIdentifierKeyword :: String -> P ()

pIdentifierKeyword s = do

    name <- getSourceName

    token show (posFromToken name) matchToken

    where

        matchToken (Positioned _ t)

            | (TIdentifier s') <- t

            , s == s'   = Just ()

            | otherwise = Nothing



pIdentifier :: P Identifier

pIdentifier = do

    name <- getSourceName

    Identifier <$> token show (posFromToken name) matchToken

    where

        matchToken (Positioned _ (TIdentifier s)) = Just s

        matchToken _                              = Nothing



pToken :: Token -> P ()

pToken tok = do

    name <- getSourceName

    token show (posFromToken name) matchToken <?> show tok

    where

        matchToken (Positioned _ tok') = if tok == tok' then Just () else Nothing



eitherOrBoth :: P a -> P b -> P (Maybe a, Maybe b)

eitherOrBoth a b = do

    mA <- optionMaybe (try a)

    case mA of

        Nothing -> do

            b' <- try b

            mA <- optionMaybe a

            return (mA, Just b')

        Just a' -> do

            mB <- optionMaybe b

            return (Just a', mB)



chainlUnary1 :: P a -> P (a -> a) -> P a

chainlUnary1 p op = do

    fs <- many op

    x  <- p

    return $ foldr id x fs



chainPostfix :: P a -> P (a -> a) -> P a

chainPostfix p op = do x <- p; rest x

    where rest x = (do f <- op; rest $ f x) <|> return x



posFromToken :: SourceName -> Positioned a -> SourcePos

posFromToken source (Positioned (AlexPn _ l c) _) = newPos source l c 



getSourceName :: P SourceName

getSourceName = sourceName <$> getPosition