private static IExpression ParseExpression(ref StringSlice text) { ConsumeWhitespace(ref text); if (text.Length == 0) { return(new AllExpression()); } List <IExpression> terms = new List <IExpression>(); terms.Add(ParseAndExpression(ref text)); while (true) { Literal <ExpressionToken> t = StartingToken(ref text); if (t?.Value == ExpressionToken.Or) { text = text.Substring(t.Text.Length); terms.Add(ParseAndExpression(ref text)); } else { break; } } return(terms.Count == 1 ? terms[0] : new OrExpression(terms)); }
private static IExpression ParseTerm(ref StringSlice text) { Literal <ExpressionToken> t = StartingToken(ref text); // All? if (t?.Value == ExpressionToken.All) { text = text.Substring(t.Text.Length); return(new AllExpression()); } // Parenthesized subexpression? if (t?.Value == ExpressionToken.LeftParen) { text = text.Substring(t.Text.Length); IExpression subexpression = ParseExpression(ref text); t = StartingToken(ref text); if (t?.Value != ExpressionToken.RightParen) { throw new QueryParseException("nested expression end paren", text); } text = text.Substring(t.Text.Length); return(subexpression); } // Not? if (t?.Value == ExpressionToken.Not) { text = text.Substring(t.Text.Length); return(new NotExpression(ParseTerm(ref text))); } // PropertyName CompareOperator Value StringSlice propertyName = ParseString(ref text); CompareOperator op = ParseCompareOperator(ref text); StringSlice value = ParseString(ref text); return(new TermExpression(propertyName.ToString(), op, value.ToString())); }
private static void ConsumeWhitespace(ref StringSlice text) { int whitespaceCount = 0; for (; whitespaceCount < text.Length; ++whitespaceCount) { if (!IsWhitespace(text[whitespaceCount])) { break; } } text = text.Substring(whitespaceCount); }
private static CompareOperator ParseCompareOperator(ref StringSlice text) { ConsumeWhitespace(ref text); foreach (Literal <CompareOperator> op in CompareOperators) { if (text.StartsWith(op.Text, StringComparison.OrdinalIgnoreCase)) { text = text.Substring(op.Text.Length); return(op.Value); } } throw new QueryParseException("compare operator", text); }
private static IExpression ParseAndExpression(ref StringSlice text) { List <IExpression> terms = new List <IExpression>(); terms.Add(ParseTerm(ref text)); while (true) { Literal <ExpressionToken> t = StartingToken(ref text); if (t?.Value == ExpressionToken.And) { text = text.Substring(t.Text.Length); terms.Add(ParseTerm(ref text)); } else { break; } } return(terms.Count == 1 ? terms[0] : new AndExpression(terms)); }
private static StringSlice ParseString(ref StringSlice text) { ConsumeWhitespace(ref text); if (text.Length == 0) { throw new QueryParseException("string", text); } char start = text[0]; if (start == '\'' || start == '"') { char terminator = start; // Keep a StringBuilder for unescaping (only if needed) and track what we've copied to it already StringBuilder unescapedForm = null; int nextCopyFrom = 1; int terminatorIndex = 1; for (; terminatorIndex < text.Length - 1; ++terminatorIndex) { if (text[terminatorIndex] == terminator) { // If this wasn't a doubled quote, the string is done if (text[terminatorIndex + 1] != terminator) { break; } // Copy to the StringBuilder without either quote if (unescapedForm == null) { unescapedForm = new StringBuilder(); } text.Substring(nextCopyFrom, terminatorIndex - nextCopyFrom).AppendTo(unescapedForm); // Include the second quote next time nextCopyFrom = terminatorIndex + 1; // Skip to look after the second quote next iteration terminatorIndex += 1; } } // Ensure the string is terminated if (terminatorIndex == text.Length || text[terminatorIndex] != terminator) { throw new QueryParseException("string terminator", text); } if (unescapedForm != null) { if (nextCopyFrom < terminatorIndex) { text.Substring(nextCopyFrom, terminatorIndex - nextCopyFrom).AppendTo(unescapedForm); } text = text.Substring(terminatorIndex + 1); return(unescapedForm.ToString()); } else { StringSlice resultSlice = text.Substring(1, terminatorIndex - 1); text = text.Substring(terminatorIndex + 1); return(resultSlice); } } else { // Read until whitespace or ')' (so closing a subexpression doesn't require a space) int terminatorIndex = 0; for (; terminatorIndex < text.Length; ++terminatorIndex) { char c = text[terminatorIndex]; if (c == ')' || IsWhitespace(c)) { break; } } // Consume and return the string StringSlice result = text.Substring(0, terminatorIndex); text = text.Substring(terminatorIndex); return(result); } }