private IExpression ParseExpression(PrecedenceLevel precedence) { _tracer.Trace("ParseExpression"); PrefixParseFn prefix; var ok = _prefixParseFns.TryGetValue(_curToken.Type, out prefix); if (!ok) { NoPrefixParseFnError(_curToken.Type); return(null); } var leftExpr = prefix(); // The precedence is what the original Pratt paper refers to as // right-binding power and PeekPrecedence() is what it refers to as // left-binding power. For as long as left-binding power > // right-binding power, we're going to add another level to the // Abstract Syntax Three, signifying operations which need to be // carried out first when the expression is evaluated. while (!PeekTokenIs(TokenType.Semicolon) && precedence < PeekPrecedence()) { InfixParseFn infix; ok = _infixParseFns.TryGetValue(_peekToken.Type, out infix); if (!ok) { return(leftExpr); } NextToken(); leftExpr = infix(leftExpr); } _tracer.Untrace("ParseExpression"); return(leftExpr); }
/// <summary> /// Parenthesizes the expression if it does not have the minimum required precedence. /// </summary> static void ParenthesizeIfRequired(Expression expr, PrecedenceLevel minimumPrecedence) { if (GetPrecedence(expr) < minimumPrecedence) { Parenthesize(expr); } }
// Binary Operators public override void VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression) { PrecedenceLevel precedence = GetPrecedence(binaryOperatorExpression); if (binaryOperatorExpression.Operator == BinaryOperatorType.NullCoalescing) { if (InsertParenthesesForReadability) { ParenthesizeIfRequired(binaryOperatorExpression.Left, PrecedenceLevel.NullableRewrap); if (GetBinaryOperatorType(binaryOperatorExpression.Right) == BinaryOperatorType.NullCoalescing) { ParenthesizeIfRequired(binaryOperatorExpression.Right, precedence); } else { ParenthesizeIfRequired(binaryOperatorExpression.Right, PrecedenceLevel.NullableRewrap); } } else { // ?? is right-associative ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence + 1); ParenthesizeIfRequired(binaryOperatorExpression.Right, precedence); } } else { if (InsertParenthesesForReadability && precedence < PrecedenceLevel.Equality) { // In readable mode, boost the priority of the left-hand side if the operator // there isn't the same as the operator on this expression. PrecedenceLevel boostTo = IsBitwise(binaryOperatorExpression.Operator) ? PrecedenceLevel.Unary : PrecedenceLevel.Equality; if (GetBinaryOperatorType(binaryOperatorExpression.Left) == binaryOperatorExpression.Operator) { ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence); } else { ParenthesizeIfRequired(binaryOperatorExpression.Left, boostTo); } ParenthesizeIfRequired(binaryOperatorExpression.Right, boostTo); } else { // all other binary operators are left-associative ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence); ParenthesizeIfRequired(binaryOperatorExpression.Right, precedence + 1); } } base.VisitBinaryOperatorExpression(binaryOperatorExpression); }
/// <summary> /// Computes whether matching two media types produced a better match than the previously selected one. /// </summary> /// <param name="selectedTypeIsAcceptable">Whether the currently selected type is acceptable to the client.</param> /// <param name="matchingTypeNameParts">The number of matched type name parts during type matching.</param> /// <param name="selectedMatchingTypeNameParts">The number of matched type name parts for the currently selected type.</param> /// <param name="matchingParameters">The number of matched parameters during type matching.</param> /// <param name="selectedMatchingParameters">The number of matched parameters for the currently selected type.</param> /// <returns> /// The <see cref="PrecedenceLevel"/> indicating whether the most recent match has higher precedence, /// the same precedence or lower precedence than the currently selected one. /// </returns> private static PrecedenceLevel ComputePrecedence( bool selectedTypeIsAcceptable, int matchingTypeNameParts, int selectedMatchingTypeNameParts, int matchingParameters, int selectedMatchingParameters) { PrecedenceLevel precedence = PrecedenceLevel.Lower; if (!selectedTypeIsAcceptable) { // the currently selected type is not acceptable to the client; this one matches the type // and thus is considered having higher precedence (although we might determine below that this type is // also not acceptable to the client due to a 0 quality value). precedence = PrecedenceLevel.Higher; } else if (matchingTypeNameParts > selectedMatchingTypeNameParts) { // the current type matches more type name parts: choose it. precedence = PrecedenceLevel.Higher; } else if (matchingTypeNameParts == selectedMatchingTypeNameParts) { // for exact type/subtype matches we check whether both types have no parameters; // if that is the case this match is more specific than a previous one (where the // supported type might have had parameters). // NOTE: only do so for exact type/subtype matches; if the media type specifies a // range ('*') we assume all parameters are supported. if (matchingTypeNameParts > 1 && matchingParameters == -1) { // the current type perfectly matches the parameters of the // acceptable type (both have no parameters) precedence = PrecedenceLevel.Higher; } // Now check the parameters and see whether we find a more specific match. if (matchingParameters > selectedMatchingParameters) { precedence = PrecedenceLevel.Higher; } else if (matchingParameters == selectedMatchingParameters) { precedence = PrecedenceLevel.Same; } } return(precedence); }
private IValueNode <TwisterPrimitive> Evaluate(PrecedenceLevel precedence = PrecedenceLevel.LogOr) { var nextPrecedence = (PrecedenceLevel)((int)precedence - 1); var left = EvaluateNext(precedence, nextPrecedence); var nextOperator = (_matcher.Peek as IValueToken <Operator>)?.Value; while (nextOperator.HasValue && IsOperatorInPrecedence(nextOperator.Value, precedence)) { var op = _matcher.MatchAndGet <IValueToken <Operator> >().Value; var right = precedence <= PrecedenceLevel.Multiplicative ? EvaluateUnary() : Evaluate(nextPrecedence); left = new BinaryExpressionNode(left, right, op); nextOperator = (_matcher.Peek as IValueToken <Operator>)?.Value; } return(left); }
private bool IsOperatorInPrecedence(Operator op, PrecedenceLevel precedence) { var isPrecedenceOperator = false; switch (precedence) { case PrecedenceLevel.Unary: isPrecedenceOperator |= op.IsUnaryArithmeticOperator(); break; case PrecedenceLevel.Multiplicative: switch (op) { case Operator.Multiplication: case Operator.ForwardSlash: case Operator.Modulo: isPrecedenceOperator = true; break; } break; case PrecedenceLevel.Addition: switch (op) { case Operator.Plus: case Operator.Minus: isPrecedenceOperator = true; break; } break; case PrecedenceLevel.Shift: switch (op) { case Operator.LeftShift: case Operator.RightShift: isPrecedenceOperator = true; break; } break; case PrecedenceLevel.Relational: switch (op) { case Operator.LogGreater: case Operator.LogGreaterEqual: case Operator.LogLess: case Operator.LogLessEqual: isPrecedenceOperator = true; break; } break; case PrecedenceLevel.Equality: switch (op) { case Operator.LogEqual: case Operator.LogNotEqual: isPrecedenceOperator = true; break; } break; case PrecedenceLevel.BitAnd: switch (op) { case Operator.BitAnd: isPrecedenceOperator = true; break; } break; case PrecedenceLevel.BitExor: switch (op) { case Operator.BitExOr: isPrecedenceOperator = true; break; } break; case PrecedenceLevel.BitOr: switch (op) { case Operator.BitOr: isPrecedenceOperator = true; break; } break; case PrecedenceLevel.LogAnd: switch (op) { case Operator.LogAnd: isPrecedenceOperator = true; break; } break; case PrecedenceLevel.LogOr: switch (op) { case Operator.LogOr: isPrecedenceOperator = true; break; } break; default: throw new UnexpectedTokenException("Unexpected arithmetic operator") { UnexpectedToken = _matcher.Current }; } return(isPrecedenceOperator); }
private IValueNode <TwisterPrimitive> EvaluateNext(PrecedenceLevel precedence, PrecedenceLevel nextPrecedence) => precedence <= PrecedenceLevel.Multiplicative ? EvaluateUnary() : Evaluate(nextPrecedence);
/// <summary> /// Matches the supported media types against the list of acceptable media types specified in the Accept header of the request. Matching follows the /// rules for media type matching as described in RFC 2616. /// </summary> /// <param name="acceptableTypes">The set of acceptable media types specified in the Accept header of the request.</param> /// <param name="supportedMediaTypes">The set of supported media types (sorted in descending precedence order).</param> /// <param name="format">The <see cref="ODataFormat"/> for the selected media type.</param> /// <returns>The media type that best matches the acceptable media types.</returns> private static MediaType MatchMediaTypes(IList <MediaType> acceptableTypes, MediaTypeWithFormat[] supportedMediaTypes, out ODataFormat format) { Debug.Assert(supportedMediaTypes != null, "supportedMediaTypes != null"); MediaTypeWithFormat selectedContentType = null; int selectedMatchingTypeNameParts = -1; int selectedMatchingParameters = -2;// -2 is an invalid value; GetMatchingParameters returns values >= -1 int selectedQualityValue = 0; int selectedPreferenceIndex = Int32.MaxValue; bool selectedAcceptable = false; if (acceptableTypes != null) { foreach (MediaType acceptableType in acceptableTypes) { for (int i = 0; i < supportedMediaTypes.Length; i++) { MediaTypeWithFormat supportedType = supportedMediaTypes[i]; // match the type name parts and parameters of the media type int matchingParameters, matchingQualityValue, acceptableTypeParameterCount; int matchingTypeNameParts = acceptableType.GetMatchingParts(supportedType.MediaType, out matchingParameters, out matchingQualityValue, out acceptableTypeParameterCount); if (!IsValidCandidate(matchingTypeNameParts, matchingParameters, acceptableTypeParameterCount)) { continue; } // only continue processing the type if it is acceptable or we don't have // an acceptable type yet. bool matchingAcceptable = matchingQualityValue != 0; if (!matchingAcceptable && selectedAcceptable) { continue; } PrecedenceLevel precedence = ComputePrecedence(selectedAcceptable, matchingTypeNameParts, selectedMatchingTypeNameParts, matchingParameters, selectedMatchingParameters); switch (precedence) { case PrecedenceLevel.Higher: { // A more specific type wins. selectedContentType = supportedType; selectedMatchingTypeNameParts = matchingTypeNameParts; selectedMatchingParameters = matchingParameters; selectedQualityValue = matchingQualityValue; selectedPreferenceIndex = i; selectedAcceptable = matchingAcceptable; } break; case PrecedenceLevel.Same: { // A type with a higher q-value wins. if (matchingQualityValue > selectedQualityValue) { selectedContentType = supportedType; selectedQualityValue = matchingQualityValue; selectedPreferenceIndex = i; selectedAcceptable = selectedQualityValue != 0; } else if (matchingQualityValue == selectedQualityValue) { // A type that is earlier in the supportedMediaTypes array wins. if (i < selectedPreferenceIndex) { selectedContentType = supportedType; selectedPreferenceIndex = i; } } } break; case PrecedenceLevel.Lower: continue; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.ODataUtils_MatchMediaTypes_UnreachableCodePath)); } } } } if (acceptableTypes == null || acceptableTypes.Count == 0) { // if not acceptable types are specified it means that all types are supported; // take the first supported type (as they are oredered by priority/precedence) selectedContentType = supportedMediaTypes[0]; } else if (!selectedAcceptable) { format = ODataFormat.Default; return(null); } format = selectedContentType.Format; return(selectedContentType.MediaType); }