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; }
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); }