Пример #1
0
            private List <MetricFilterExpressionToken> TokenizeFilterString(string filterString)
            {
                List <MetricFilterExpressionToken> tokenList = new List <MetricFilterExpressionToken>();
                int pos = 0;

                // preliminary tokenizing loop
                while (pos < filterString.Length)
                {
                    char c = filterString[pos];

                    // Whitespace Token
                    if (char.IsWhiteSpace(c))
                    {
                        StringBuilder sb = new StringBuilder();

                        for (sb.Append(c); ++pos < filterString.Length && char.IsWhiteSpace(c = filterString[pos]); sb.Append(c))
                        {
                        }

                        // The whitespace tokens will be removed later, but are required to separate other tokens for now
                        tokenList.Add(new MetricFilterExpressionToken(sb.ToString(), MetricFilterExpressionToken.TokenType.Whitespace));
                    }
                    else if (char.IsLetter(c) || c == '_')
                    {
                        // Identifier Token (keywords are handled later)
                        StringBuilder sb = new StringBuilder();

                        for (sb.Append(c); ++pos < filterString.Length && (char.IsLetterOrDigit(c = filterString[pos]) || c == '_' || c == '.'); sb.Append(c))
                        {
                        }

                        tokenList.Add(new MetricFilterExpressionToken(sb.ToString(), MetricFilterExpressionToken.TokenType.Identifier));
                    }
                    else if (char.IsDigit(c) || c == '-')
                    {
                        // only supported token starting with a number is DateTimeOffset
                        StringBuilder sb = new StringBuilder();

                        for (sb.Append(c);
                             ++pos < filterString.Length &&
                             (char.IsDigit(c = filterString[pos]) || "TZ:.-+".Contains(c));
                             sb.Append(c))
                        {
                        }

                        tokenList.Add(new MetricFilterExpressionToken(sb.ToString(), MetricFilterExpressionToken.TokenType.DateTimeOffsetValue));
                    }
                    else
                    {
                        switch (c)
                        {
                        case '\'':
                            StringBuilder sb = new StringBuilder();

                            // slight variation here to avoid capturing opening quote
                            for (pos++; pos < filterString.Length && (c = filterString[pos]) != '\''; pos++)
                            {
                                sb.Append(c);
                            }

                            // verify and step over closing quote
                            if (pos++ >= filterString.Length)
                            {
                                throw new FormatException("Unclosed StringValue token");
                            }

                            tokenList.Add(new MetricFilterExpressionToken(sb.ToString(), MetricFilterExpressionToken.TokenType.StringValue));

                            break;

                        case ')':
                        case '(':
                            tokenList.Add(new MetricFilterExpressionToken(
                                              filterString.Substring(pos++, 1),
                                              c == '(' ? MetricFilterExpressionToken.TokenType.OpenParen : MetricFilterExpressionToken.TokenType.CloseParen));
                            break;

                        default:
                            throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Unexpected character encountered '{0}'", c));
                        }
                    }
                }

                // Second pass identifies keywords (operators) and duration values
                for (int i = 0; i < tokenList.Count; i++)
                {
                    MetricFilterExpressionToken t = tokenList[i];

                    if (t.Type == MetricFilterExpressionToken.TokenType.Whitespace)
                    {
                        tokenList.RemoveAt(i--);
                        continue;
                    }

                    if (t.Type != MetricFilterExpressionToken.TokenType.Identifier)
                    {
                        continue;
                    }

                    // The OData spec appears to be case sensitive here.
                    switch (t.Value)
                    {
                    case "and":
                        t.Type = MetricFilterExpressionToken.TokenType.AndOperator;
                        continue;

                    case "or":
                        t.Type = MetricFilterExpressionToken.TokenType.OrOperator;
                        continue;

                    case "eq":
                        t.Type = MetricFilterExpressionToken.TokenType.EqOperator;
                        continue;

                    case "duration":
                        if (i + 1 < tokenList.Count && tokenList[i + 1].Type == MetricFilterExpressionToken.TokenType.StringValue)
                        {
                            t.Type  = MetricFilterExpressionToken.TokenType.DurationValue;
                            t.Value = tokenList[i + 1].Value;
                            tokenList.RemoveAt(i + 1);
                        }

                        continue;
                    }
                }

                return(tokenList);
            }
Пример #2
0
        // Parse filter clause (or parenthesized expression) corresponds to F -> ID EQ VALUE | (E)
        private static MetricFilterExpressionTree ParseFilterClause(MetricFilterExpressionTokenizer tokenizer)
        {
            if (tokenizer == null || tokenizer.IsEmpty)
            {
                throw GenerateFilterParseException(null, MetricFilterExpressionToken.TokenType.Identifier);
            }

            MetricFilterExpressionToken token = tokenizer.Current;

            switch (token.Type)
            {
            case MetricFilterExpressionToken.TokenType.Identifier:     // F -> ID EQ VALUE
                // validate and store the parameter name
                FilterParameter parameter = ParseParameter(token.Value);

                // Consume name
                tokenizer.Advance();

                // Verify and comsume EQ
                if (tokenizer.IsEmpty || tokenizer.Current.Type != MetricFilterExpressionToken.TokenType.EqOperator)
                {
                    throw GenerateFilterParseException(tokenizer.Current, MetricFilterExpressionToken.TokenType.EqOperator);
                }

                tokenizer.Advance();
                MetricFilterExpressionToken.TokenType expectedType = GetExpectedTokenTypeForParameter(parameter);

                // Verify, store, and consume value
                if (tokenizer.IsEmpty || tokenizer.Current.Type != expectedType)
                {
                    throw GenerateFilterParseException(tokenizer.Current, expectedType);
                }

                string value = tokenizer.Current.Value;
                tokenizer.Advance();

                return(new MetricFilterExpressionTree()
                {
                    Value = new KeyValuePair <FilterParameter, string>(ParseParameter(token.Value), value)
                });

            case MetricFilterExpressionToken.TokenType.OpenParen:     // F -> (E)
                // Consume (
                tokenizer.Advance();

                // Match Expression
                MetricFilterExpressionTree node = ParseFilterExpression(tokenizer);

                // Verify and consume )
                if (tokenizer.IsEmpty || tokenizer.Current.Type != MetricFilterExpressionToken.TokenType.CloseParen)
                {
                    throw GenerateFilterParseException(tokenizer.Current, MetricFilterExpressionToken.TokenType.CloseParen);
                }

                tokenizer.Advance();

                return(node);

            default:
                throw GenerateFilterParseException(token, MetricFilterExpressionToken.TokenType.Identifier);
            }
        }
Пример #3
0
 private static FormatException GenerateFilterParseException(MetricFilterExpressionToken encountered, MetricFilterExpressionToken.TokenType expected)
 {
     return(new FormatException(
                string.Format(CultureInfo.InvariantCulture, "Failed to parse expression. Expected {0} token (encountered {1}).", expected, encountered)));
 }
 private static FormatException GenerateFilterParseException(MetricFilterExpressionToken encountered, MetricFilterExpressionToken.TokenType expected)
 {
     return new FormatException(
         string.Format(CultureInfo.InvariantCulture, "Failed to parse expression. Expected {0} token (encountered {1}).", expected, encountered));
 }