private bool IsValueExpression(Expression expression) { if (expression is LiteralExpression) { CsTokenType tokenType = ((LiteralExpression)expression).Token.CsTokenType; return(tokenType == CsTokenType.Number || tokenType == CsTokenType.String || tokenType == CsTokenType.Null || tokenType == CsTokenType.True || tokenType == CsTokenType.False); } if (expression is ParenthesizedExpression) { return(this.IsValueExpression(((ParenthesizedExpression)expression).InnerExpression)); } if (expression is RelationalExpression) { RelationalExpression re = (RelationalExpression)expression; return(this.IsValueExpression(re.LeftHandSide) && this.IsValueExpression(re.RightHandSide)); } if (expression is ArithmeticExpression) { ArithmeticExpression ae = (ArithmeticExpression)expression; return(this.IsValueExpression(ae.LeftHandSide) && this.IsValueExpression(ae.RightHandSide)); } return(false); }
/// <summary> /// Checks whether parenthesis are needed within the arithmetic expressions. /// </summary> /// <param name="element"> /// The parent element. /// </param> /// <param name="expression"> /// The parent arithmetic expression. /// </param> /// <param name="childExpression"> /// The child arithmetic expression. /// </param> /// <returns> /// Returns true if there is no violation, or false if there is a violation. /// </returns> private bool CheckArithmeticParenthesisForExpressionAndChild(CsElement element, ArithmeticExpression expression, ArithmeticExpression childExpression) { Param.AssertNotNull(element, "element"); Param.AssertNotNull(expression, "expression"); Param.AssertNotNull(childExpression, "childExpression"); // Parenthesis are only required when the two expressions are not the same operator, // and when the two operators come from different families. if (expression.OperatorType != childExpression.OperatorType) { bool sameFamily = ((expression.OperatorType == ArithmeticExpression.Operator.Addition || expression.OperatorType == ArithmeticExpression.Operator.Subtraction) && (childExpression.OperatorType == ArithmeticExpression.Operator.Addition || childExpression.OperatorType == ArithmeticExpression.Operator.Subtraction)) || ((expression.OperatorType == ArithmeticExpression.Operator.Multiplication || expression.OperatorType == ArithmeticExpression.Operator.Division) && (childExpression.OperatorType == ArithmeticExpression.Operator.Multiplication || childExpression.OperatorType == ArithmeticExpression.Operator.Division)) || ((expression.OperatorType == ArithmeticExpression.Operator.LeftShift || expression.OperatorType == ArithmeticExpression.Operator.RightShift) && (childExpression.OperatorType == ArithmeticExpression.Operator.LeftShift || childExpression.OperatorType == ArithmeticExpression.Operator.RightShift)); if (!sameFamily) { this.AddViolation(element, expression.LineNumber, Rules.ArithmeticExpressionsMustDeclarePrecedence); return false; } } return true; }
/// <summary> /// Checks that parenthesis are used correctly within an arithmetic expression. /// </summary> /// <param name="element"> /// The parent element. /// </param> /// <param name="expression"> /// The expression to check. /// </param> private void CheckArithmeticExpressionParenthesis(CsElement element, ArithmeticExpression expression) { Param.AssertNotNull(element, "element"); Param.AssertNotNull(expression, "expression"); if (expression.LeftHandSide.ExpressionType == ExpressionType.Arithmetic) { if (!this.CheckArithmeticParenthesisForExpressionAndChild(element, expression, (ArithmeticExpression)expression.LeftHandSide)) { return; } } if (expression.RightHandSide.ExpressionType == ExpressionType.Arithmetic) { this.CheckArithmeticParenthesisForExpressionAndChild(element, expression, (ArithmeticExpression)expression.RightHandSide); } }
/// <summary> /// Reads an arithmetic expression. /// </summary> /// <param name="leftHandSide"> /// The expression on the left hand side of the operator. /// </param> /// <param name="previousPrecedence"> /// The precedence of the expression just before this one. /// </param> /// <param name="parentReference"> /// The parent code unit. /// </param> /// <param name="unsafeCode"> /// Indicates whether the code being parsed resides in an unsafe code block. /// </param> /// <returns> /// Returns the expression. /// </returns> private ArithmeticExpression GetArithmeticExpression( Expression leftHandSide, ExpressionPrecedence previousPrecedence, Reference<ICodePart> parentReference, bool unsafeCode) { Param.AssertNotNull(leftHandSide, "leftHandSide"); Param.Ignore(previousPrecedence); Param.AssertNotNull(parentReference, "parentReference"); Param.Ignore(unsafeCode); ArithmeticExpression expression = null; Reference<ICodePart> expressionReference = new Reference<ICodePart>(); // Read the details of the expression. OperatorSymbol operatorToken = this.PeekOperatorToken(parentReference, expressionReference); Debug.Assert( operatorToken.Category == OperatorCategory.Arithmetic || operatorToken.Category == OperatorCategory.Shift, "Expected an arithmetic or shift operator"); // Check the precedence of the operators to make sure we can gather this statement now. ExpressionPrecedence precedence = GetOperatorPrecedence(operatorToken.SymbolType); if (CheckPrecedence(previousPrecedence, precedence)) { // Add the operator token to the document and advance the symbol manager up to it. this.symbols.Advance(); this.tokens.Add(operatorToken); // Get the expression on the right-hand side of the operator. Expression rightHandSide = this.GetOperatorRightHandExpression(precedence, expressionReference, unsafeCode); // Create the partial token list for the expression. CsTokenList partialTokens = new CsTokenList(this.tokens, leftHandSide.Tokens.First, this.tokens.Last); // Get the expression operator type. ArithmeticExpression.Operator type; switch (operatorToken.SymbolType) { case OperatorType.Plus: type = ArithmeticExpression.Operator.Addition; break; case OperatorType.Minus: type = ArithmeticExpression.Operator.Subtraction; break; case OperatorType.Multiplication: type = ArithmeticExpression.Operator.Multiplication; break; case OperatorType.Division: type = ArithmeticExpression.Operator.Division; break; case OperatorType.Mod: type = ArithmeticExpression.Operator.Mod; break; case OperatorType.LeftShift: type = ArithmeticExpression.Operator.LeftShift; break; case OperatorType.RightShift: type = ArithmeticExpression.Operator.RightShift; break; default: Debug.Fail("Unexpected operator type"); throw new InvalidOperationException(); } // Create and return the expression. expression = new ArithmeticExpression(partialTokens, type, leftHandSide, rightHandSide); expressionReference.Target = expression; } return expression; }
/// <summary> /// The save. /// </summary> /// <param name="operator"> /// The operator. /// </param> private void Save(ArithmeticExpression.Operator @operator) { var operatorString = string.Empty; switch (@operator) { case ArithmeticExpression.Operator.Addition: operatorString = "+"; break; case ArithmeticExpression.Operator.Division: operatorString = "/"; break; case ArithmeticExpression.Operator.LeftShift: operatorString = "<<"; break; case ArithmeticExpression.Operator.Mod: operatorString = "%"; break; case ArithmeticExpression.Operator.Multiplication: operatorString = "*"; break; case ArithmeticExpression.Operator.RightShift: operatorString = ">>"; break; case ArithmeticExpression.Operator.Subtraction: operatorString = "-"; break; default: break; } this.cppWriter.Write(' '); this.cppWriter.Write(operatorString); this.cppWriter.Write(' '); }
/// <summary> /// The save. /// </summary> /// <param name="arithmeticExpression"> /// The arithmetic expression. /// </param> private void Save(ArithmeticExpression arithmeticExpression) { @switch(arithmeticExpression.LeftHandSide); this.Save(arithmeticExpression.OperatorType); @switch(arithmeticExpression.RightHandSide); }