module Language.CSharp.Parser.Expression where
import Text.Parsec hiding (Empty, sourceName)
import Language.CSharp.Lexer
import Language.CSharp.Syntax
import Language.CSharp.Parser.Utility
import {-# SOURCE #-} Language.CSharp.Parser.Statement
import Language.CSharp.Parser.Type
pMaybeExpression :: P (Maybe Expression)
pMaybeExpression = optionMaybe pExpression
pExpression :: P Expression
pExpression = pExpressionP1
pExpressionP1 :: P Expression
pExpressionP1 = pExpressionP2 `chainr1` pAssignment
where
pAssignment = do
operator <- pAssignmentOperator
return (\ target value -> Assign target operator value)
pAssignmentOperator :: P AssignmentOperator
pAssignmentOperator = choice
[ OpAssign <$ pToken TOpAssign
, OpAssignPlus <$ pToken TOpAssignPlus
, OpAssignMinus <$ pToken TOpAssignMinus
, OpAssignMultiply <$ pToken TOpAssignMultiply
, OpAssignDivide <$ pToken TOpAssignDivide
, OpAssignModulo <$ pToken TOpAssignModulo
, OpAssignBitwiseAnd <$ pToken TOpAssignBitwiseAnd
, OpAssignBitwiseOr <$ pToken TOpAssignBitwiseOr
, OpAssignBitwiseXor <$ pToken TOpAssignBitwiseXor
, OpAssignBitwiseLeftShift <$ pToken TOpAssignBitwiseLeftShift
, OpAssignBitwiseRightShift <$ pToken TOpAssignBitwiseRightShift
]
pExpressionP2 :: P Expression
pExpressionP2 = try pLambdaExpression <|> try pDelegateExpression <|> pExpressionP3
pLambdaExpression :: P Expression
pLambdaExpression = do
sig <- pAnonymousFunctionSignature
pLambda
body <- pAnonymousFunctionBody
return $ Lambda sig body
pDelegateExpression :: P Expression
pDelegateExpression = do
pToken TKWdelegate
sig <- optionMaybe pExplicitFunctionSignature
body <- betweenCurly pStatements
return $ Delegate sig body
pAnonymousFunctionSignature :: P AnonymousFunctionSignature
pAnonymousFunctionSignature = choice
[ try pExplicitFunctionSignature
, betweenParens $ ImplicitAnonymousFunctionSignature <$> sepBy pIdentifier pComma
, ImplicitAnonymousFunctionSignature . (:[]) <$> pIdentifier ]
pExplicitFunctionSignature :: P AnonymousFunctionSignature
pExplicitFunctionSignature = betweenParens $
ExplicitAnonymousFunctionSignature <$> sepBy pAnonymousFunctionParameter pComma
pAnonymousFunctionParameter :: P AnonymousFunctionParameter
pAnonymousFunctionParameter = do
modifier <- optionMaybe (RefParam <$ pToken TKWref <|> OutParam <$ pToken TKWout)
ty <- pType
name <- pIdentifier
return $ ExplicitAnonymousFunctionParameter modifier ty name
pAnonymousFunctionBody :: P AnonymousFunctionBody
pAnonymousFunctionBody = choice
[ AnonymousFunctionExpressionBody <$> pExpressionP1
, AnonymousFunctionStatementBody <$> betweenCurly pStatements ]
pExpressionP3 :: P Expression
pExpressionP3 = try pConditional <|> pExpressionP4
pConditional :: P Expression
pConditional = do
guard <- pExpressionP4
pToken TQuestion
exp1 <- pExpressionP4
pColon
exp2 <- pExpressionP3
return $ Conditional guard exp1 exp2
pExpressionP4 :: P Expression
pExpressionP4 = pExpressionP5
pExpressionP5 :: P Expression
pExpressionP5 = pExpressionP6 `chainr1` pNullCoalescing
where
pNullCoalescing = BinaryOperator BinaryNullCoalescing <$ pToken TOpNullCoalescing
pExpressionP6 :: P Expression
pExpressionP6 = pExpressionP7 `chainl1` pBooleanOr
where
pBooleanOr = BinaryOperator BinaryOr <$ pToken TOpOr
pExpressionP7 :: P Expression
pExpressionP7 = pExpressionP8 `chainl1` pBooleanAnd
where
pBooleanAnd = BinaryOperator BinaryAnd <$ pToken TOpAnd
pExpressionP8 :: P Expression
pExpressionP8 = pExpressionP9 `chainl1` pBitwiseOr
where
pBitwiseOr = BinaryOperator BinaryBitwiseOr <$ pToken TOpBitwiseOr
pExpressionP9 :: P Expression
pExpressionP9 = pExpressionP10 `chainl1` pBitwiseXor
where
pBitwiseXor = BinaryOperator BinaryBitwiseXor <$ pToken TOpBitwiseXor
pExpressionP10 :: P Expression
pExpressionP10 = pExpressionP11 `chainl1` pBitwiseAnd
where
pBitwiseAnd = BinaryOperator BinaryBitwiseAnd <$ pToken TOpBitwiseAnd
pExpressionP11 :: P Expression
pExpressionP11 = pExpressionP12 `chainl1` pOperators
where
pOperators = choice
[ BinaryOperator BinaryEquals <$ pToken TOpEqual
, BinaryOperator BinaryNotEquals <$ pToken TOpNotEqual ]
pExpressionP12 :: P Expression
pExpressionP12 = pExpressionP13 `chainl1` pOperators
where
pOperators = choice
[ BinaryOperator BinaryLessThan <$ pToken TOpLessThan
, BinaryOperator BinaryGreaterThan <$ pToken TOpGreaterThan
, BinaryOperator BinaryLessThanEqual <$ pToken TOpLessThanEqual
, BinaryOperator BinaryGreaterThanEqual <$ pToken TOpGreaterThanEqual
, BinaryOperator BinaryIs <$ pToken TKWis
, BinaryOperator BinaryAs <$ pToken TKWas ]
pExpressionP13 :: P Expression
pExpressionP13 = pExpressionP14 `chainl1` pOperators
where
pOperators = choice
[ BinaryOperator BinaryShiftLeft <$ pToken TOpLeftShift
, BinaryOperator BinaryShiftRight <$ pToken TOpRightShift ]
pExpressionP14 :: P Expression
pExpressionP14 = pExpressionP15 `chainl1` pOperators
where
pOperators = choice
[ BinaryOperator BinaryPlus <$ pToken TOpPlus
, BinaryOperator BinaryMinus <$ pToken TOpMinus ]
pExpressionP15 :: P Expression
pExpressionP15 = pExpressionP16 `chainl1` pOperators
where
pOperators = choice
[ BinaryOperator BinaryMultiply <$ pToken TOpMultiply
, BinaryOperator BinaryDivide <$ pToken TOpDivide
, BinaryOperator BinaryModulo <$ pToken TOpModulo ]
pExpressionP16 :: P Expression
pExpressionP16 = choice
[ UnaryAwait <$ pToken TOpAwait <*> pExpressionP16
, pExpressionP17 `chainlUnary1` pOperators
]
where
pOperators = choice
[ UnaryPlus <$ pToken TOpPlus
, UnaryMinus <$ pToken TOpMinus
, UnaryNot <$ pToken TOpNot
, UnaryBitwiseNot <$ pToken TOpBitwiseNot
, UnaryPreIncrement <$ pToken TOpPlusPlus
, UnaryPreDecrement <$ pToken TOpMinusMinus
, try (UnaryCast <$> betweenParens pType) ]
pExpressionP17 :: P Expression
pExpressionP17 = pTerm `chainPostfix` pPostfixOperator
pPostfixOperator :: P (Expression -> Expression)
pPostfixOperator = choice
[ UnaryPostIncrement <$ pToken TOpPlusPlus
, UnaryPostDecrement <$ pToken TOpMinusMinus
, flip ElementAccess <$> betweenSquare (sepBy1 pExpression pComma)
, try pPrimaryMemberAccess
, flip Invocation <$> pArguments ]
where
pPrimaryMemberAccess = do
pPeriod
name <- pIdentifier
typeArguments <- option [] pTypeArguments
return (\ e -> MemberAccess (PrimaryMemberAccess e name typeArguments))
pTerm :: P Expression
pTerm = choice
[ This <$ pToken TKWthis
, Base <$ pToken TKWbase
, Typeof <$ pToken TKWtypeof <*> betweenParens pTypeOfExpression
, Sizeof <$ pToken TKWsizeof <*> betweenParens pType
, Checked <$ pToken TKWchecked <*> betweenParens pExpression
, Unchecked <$ pToken TKWunchecked <*> betweenParens pExpression
, Nameof <$ pIdentifierKeyword "nameof" <*> betweenParens pNameofEntity
, try (Default <$ pToken TKWdefault <*> betweenParens pType)
, MemberAccess <$> try pMemberAccess
, SimpleName <$> pIdentifier <*> option [] pTypeArguments
, pNewExpression
, pParenthesizedExpression
, pLiteralExpression ]
pNameofEntity :: P NameofEntity
pNameofEntity = choice
[ NameofThis <$ pToken TKWthis <* pPeriod <*> pIdentifier
, NameofBase <$ pToken TKWbase <* pPeriod <*> pIdentifier
, NameofPredefinedType <$> pSimpleType <* pPeriod <*> pIdentifier
, NameofIdentifier <$> pIdentifier ]
pTypeOfExpression :: P TypeOfExpression
pTypeOfExpression = TypeofType <$> pTypeWithVoid <?> "a type"
pMemberAccess :: P MemberAccess
pMemberAccess = choice
[ PredefinedMemberAccess <$> pSimpleType
<* pPeriod
<*> pIdentifier
<*> option [] pTypeArguments
, QualifiedMemberAccess <$> pIdentifier
<* pToken TDoubleColon
<*> pIdentifier
<* pPeriod
<*> pIdentifier ]
pNewExpression :: P Expression
pNewExpression = pToken TKWnew *> choice
[ try $ ObjectCreationExpression <$> pType
<*> pArguments
<*> optionMaybe pObjectCreationInitializer
, try $ ObjectCreationTypeInitializer <$> pType <*> pObjectCreationInitializer
, try $ ArrayCreationExpression <$> pNonArrayType
<*> betweenSquare (sepBy1 pExpression pComma)
<*> many pRankSpecifier
<*> optionMaybe pArrayCreationInitializer
, try $ ArrayCreationTypeInitializer <$> pType <*> pArrayCreationInitializer
, ArrayCreationRankInitializer <$> pRankSpecifier <*> pArrayCreationInitializer ]
pObjectCreationInitializer :: P ObjectCreationInitializer
pObjectCreationInitializer = choice
[ try $ ObjectInitializer <$> betweenCurly (sepBy pMemberInitializer pComma)
, try $ CollectionInitializer <$> pArrayCreationInitializer ]
pMemberInitializer :: P MemberInitializer
pMemberInitializer =
MemberInitializer <$> pInitializerTarget <* pEqualSign <*> pInitializerValue
pArrayCreationInitializer :: P ArrayCreationInitializer
pArrayCreationInitializer = betweenCurly $ choice
[ ArrayCreationInitializerExpression <$> sepBy1 pExpression pComma
, ArrayCreationInitializerInitializers <$> sepBy1 pArrayCreationInitializer pComma ]
pInitializerTarget :: P InitializerTarget
pInitializerTarget = choice
[ InitializerTargetIdentifier <$> pIdentifier
, InitializerTargetList <$> betweenSquare (sepBy pArgument pComma) ]
pInitializerValue :: P InitializerValue
pInitializerValue = choice
[ InitializerValueExpression <$> pExpression
, InitializerValueInitializer <$> pObjectCreationInitializer ]
pLiteralExpression :: P Expression
pLiteralExpression = choice
[ Literal <$> pBooleanLiteral
, Literal <$> pIntLiteral
, Literal <$> pRealLiteral
, Literal <$> pCharLiteral
, Literal <$> pStringLiteral
, Literal NullLit <$ pToken TKWnull ]
pBooleanLiteral :: P Literal
pBooleanLiteral =
(BooleanLit True <$ pToken TKWtrue <|>
BooleanLit False <$ pToken TKWfalse) <?> "a boolean literal"
pIntLiteral :: P Literal
pIntLiteral = do
sourceName <- getSourceName
token show (posFromToken sourceName) matchToken <?> "an integral literal"
where
matchToken (Positioned _ (TIntLiteral x)) = Just (IntLit x)
matchToken (Positioned _ (TUIntLiteral x)) = Just (UIntLit x)
matchToken (Positioned _ (TLongLiteral x)) = Just (LongLit x)
matchToken (Positioned _ (TULongLiteral x)) = Just (ULongLit x)
matchToken _ = Nothing
pRealLiteral :: P Literal
pRealLiteral = do
sourceName <- getSourceName
token show (posFromToken sourceName) matchToken <?> "a floating point literal"
where
matchToken (Positioned _ (TFloatLiteral x)) = Just (FloatLit x)
matchToken (Positioned _ (TDoubleLiteral x)) = Just (DoubleLit x)
matchToken (Positioned _ (TDecimalLiteral x)) = Just (DecimalLit x)
matchToken _ = Nothing
pCharLiteral :: P Literal
pCharLiteral = do
sourceName <- getSourceName
token show (posFromToken sourceName) matchToken <?> "a char literal"
where
matchToken (Positioned _ (TCharLiteral x)) = Just (CharLit x)
matchToken _ = Nothing
pStringLiteral :: P Literal
pStringLiteral = do
sourceName <- getSourceName
token show (posFromToken sourceName) matchToken <?> "a string literal"
where
matchToken (Positioned _ tok)
= case tok of
TStringLiteral x -> Just (StringLit x)
TVerbatimStringLiteral x -> Just (VerbatimStringLit x)
_ -> Nothing
pParenthesizedExpression :: P Expression
pParenthesizedExpression = Parenthesized <$> betweenParens pExpression
pArguments :: P [Argument]
pArguments = betweenParens (sepBy pArgument pComma)
pArgument :: P Argument
pArgument = do
name <- optionMaybe (try (pIdentifier <* pColon))
choice [argument name, refArgument name, outArgument name]
where
argument name' = Argument name' <$> pExpression
refArgument name' = RefArgument name' <$ pToken TKWref <*> pExpression
outArgument name' = OutArgument name' <$ pToken TKWout <*> pExpression