in Arriba/Arriba/Model/Query/QueryParser.cs [288:407]
private IExpression ParseTerm(bool includeHintTerms, bool hadExplicitBooleanOperator)
{
bool hadExplicitValueCompletion;
IExpression expression = null;
bool negate = false;
// Negate?
if (_scanner.Current.Type == TokenType.UnaryOperatorNot)
{
negate = true;
_scanner.Next();
// If the query ends with a !, create a term to hint
if (_scanner.Current.Type == TokenType.End)
{
if (includeHintTerms) return new TermExpression("") { Guidance = new IntelliSenseGuidance("", QueryTokenCategory.Term) };
}
}
if (_scanner.Current.Type == TokenType.LeftParen)
{
// Subquery := '(' Query ')'
// Consume the left paren
_scanner.Next();
// If there's nothing left, add a hint expression suggesting another term
if (_scanner.Current.Type == TokenType.End)
{
if (includeHintTerms) expression = new TermExpression("") { Guidance = new IntelliSenseGuidance("", QueryTokenCategory.Term) };
}
else
{
// Parse the subquery
expression = ParseQuery(includeHintTerms);
// Consume right paren, if provided (tolerate it missing)
if (_scanner.Current.Type == TokenType.RightParen)
{
_scanner.Next();
// *If* an explicit closing paren was found, tell IntelliSense the previous term was complete
// [Can't add a hint expression here without breaking valid expressions]
if (expression != null)
{
TermExpression lastTerm = expression.GetLastTerm();
if (lastTerm != null)
{
lastTerm.Guidance = new IntelliSenseGuidance("", QueryTokenCategory.BooleanOperator | QueryTokenCategory.Term);
}
}
}
}
}
else if (_scanner.Current.Type == TokenType.LeftBrace)
{
// ExplicitColumnName := '[' (NotEndBrace | ']]')+ ']'
bool hadExplicitNameCompletion;
string columnName = ParseUntilEndToken(TokenType.RightBrace, out hadExplicitNameCompletion);
if (!hadExplicitNameCompletion)
{
// "[PartialColumnNa" -> make it an equals empty term, indicate the column name needs completion
if (includeHintTerms) expression = new TermExpression(columnName, Operator.NotEquals, String.Empty) { Guidance = new IntelliSenseGuidance(columnName, QueryTokenCategory.ColumnName) };
}
else
{
expression = ParseOperatorAndValue(columnName, includeHintTerms, true);
}
}
else if (_scanner.Current.Type == TokenType.DoubleQuote)
{
// ExplicitValue := '"' (NotEndQuote || '""')+ '"'
string value = ParseUntilEndToken(TokenType.DoubleQuote, out hadExplicitValueCompletion);
if (!hadExplicitValueCompletion)
{
// "\"IncompleteQuotedValue" -> indicate value incomplete
expression = new TermExpression(value) { Guidance = new IntelliSenseGuidance(value, QueryTokenCategory.Value) };
}
else if (_scanner.Current.Type == TokenType.End && String.IsNullOrEmpty(_scanner.Current.Prefix))
{
// "\"QuotedValue\"", no trailing space -> don't suggest the next thing yet
expression = new TermExpression(value) { Guidance = new IntelliSenseGuidance(String.Empty, QueryTokenCategory.None) };
}
else
{
// "\"QuotedValue\" ", trailing space -> suggest the next operator or term
expression = new TermExpression(value) { Guidance = new IntelliSenseGuidance(String.Empty, QueryTokenCategory.BooleanOperator | QueryTokenCategory.Term) };
}
}
else
{
// NotSpaceParenOrCompareOperator, then look for compare operator and, if found, value
string firstValue = ParseNotSpaceParenOrCompareOperator(out hadExplicitValueCompletion);
// If there was no valid value left, it's the end of this term
if (String.IsNullOrEmpty(firstValue)) return null;
if (!hadExplicitValueCompletion)
{
// "BareValu" -> column or value completion on this term
QueryTokenCategory options = QueryTokenCategory.ColumnName | QueryTokenCategory.Value;
if (!hadExplicitBooleanOperator) options |= QueryTokenCategory.BooleanOperator;
expression = new TermExpression(firstValue) { Guidance = new IntelliSenseGuidance(firstValue, options) };
}
else
{
expression = ParseOperatorAndValue(firstValue, includeHintTerms, false);
}
}
// Negate the expression, if not was present
if (negate && expression != null)
{
expression = new NotExpression(expression);
}
return expression;
}