private static AstExpression ParseExpression(Dictionary<string, Pivots.Pivot> pivotVsPivotValues,
GetChoiceDelegate get_choice_fn, string expression)
{
AstExpression result = null;
var rxResult = Pivots.ExpressionRx.Match(expression);
if (rxResult.Success) {
var state = ExpressionState.None;
AstExpression current = null;
bool invert = false;
foreach (var item in rxResult.Groups[1].Captures.Cast<Capture>().Select(each => each.Value.Trim()).Where(each => !string.IsNullOrEmpty(each))) {
switch (item[0]) {
case '!':
if (result != null && state == ExpressionState.None) {
throw new ClrPlusException("Invalid expression. (not expression must be separated from previous expression with an operator)");
}
if (item.Length % 2 != 0)
invert = !invert;
continue;
case '&':
case ',':
case '\\':
case '/':
if (state != ExpressionState.None) {
throw new ClrPlusException("Invalid expression. (May not state two operators in a row)");
}
if (result == null) {
throw new ClrPlusException("Invalid expression. (may not start with an operator)");
}
state = ExpressionState.HasAnd;
continue;
case '|':
case '+':
if (state != ExpressionState.None) {
throw new ClrPlusException("Invalid expression. (May not state two operators in a row)");
}
if (result == null) {
throw new ClrPlusException("Invalid expression. (may not start with an operator)");
}
state = ExpressionState.HasOr;
continue;
case '(':
if (result != null && state == ExpressionState.None) {
throw new ClrPlusException("Invalid expression. (nested expression must be separated from previous expression with an operator)");
}
if (item.EndsWith(")")) {
// parse nested expression.
current = ParseExpression(pivotVsPivotValues, get_choice_fn, item.Substring(1, item.Length - 2));
break;
}
throw new ClrPlusException("Mismatched '(' in expression");
default:
if (!Pivots.WordRx.IsMatch(item)) {
throw new ClrPlusException("Invalid characters in expression");
}
if (result != null && state == ExpressionState.None) {
throw new ClrPlusException("Invalid expression. (expression must be separated from previous expression with an operator)");
}
// otherwise, it's the word we're looking for.
//
string choice;
string pivot;
if (get_choice_fn(item, out choice, out pivot)) {
current = new PivotExpression(pivot, choice, false);
break;
}
else if (item.ToLowerInvariant() == "true") {
current = TrueExpression.instance;
break;
}
else if (item.ToLowerInvariant() == "false") {
current = FalseExpression.instance;
break;
}
throw new ClrPlusException(string.Format("Unmatched configuration choice '{0}", item));
}
if (invert)
current = current.Invert();
switch (state) {
case ExpressionState.None:
result = current;
continue;
case ExpressionState.HasAnd:
result = new AndExpression(result, current);
break;
case ExpressionState.HasOr:
result = new OrExpression(result, current);
break;
}
current = null;
state = ExpressionState.None;
}
}
if (result == null)
result = TrueExpression.instance;
return result;
}