public void ToStringInvalidOperatorTest() { ElementAttributeExpression attributeExpression = new ElementAttributeExpression(ElementAttributeType.Name); StringExpression stringExpression = new StringExpression("Test"); BinaryOperatorExpression operatorExpression = new BinaryOperatorExpression( (BinaryExpressionOperator) int.MinValue, attributeExpression, stringExpression); Assert.AreEqual(string.Format("($(Element.Name) {0} 'Test')", int.MinValue), operatorExpression.ToString()); }
public void ToStringTest() { ElementAttributeExpression attributeExpression = new ElementAttributeExpression( ElementAttributeType.Name); StringExpression stringExpression = new StringExpression("Test"); BinaryOperatorExpression operatorExpression = new BinaryOperatorExpression( BinaryExpressionOperator.Equal, attributeExpression, stringExpression); Assert.AreEqual("($(Element.Name) == 'Test')", operatorExpression.ToString()); }
/// <summary> /// Parses and expression to an expression tree. /// </summary> /// <param name="expression">Condition expression text.</param> /// <returns>A condition expression instance.</returns> public IConditionExpression Parse(string expression) { const int DefaultExpressionLength = 128; IConditionExpression conditionExpression = null; if (expression == null) { throw new ArgumentNullException("expression"); } else if (expression.Trim().Length == 0) { throw new ArgumentException("expression"); } List<IConditionExpression> nodes = new List<IConditionExpression>(); StringReader reader = new StringReader(expression); StringBuilder expressionBuilder = new StringBuilder(DefaultExpressionLength); bool inString = false; bool inAttribute = false; int depth = 0; int data = reader.Read(); while (data > 0) { char ch = (char)data; char nextCh = (char)reader.Peek(); if (inString && ch != '\'') { expressionBuilder.Append(ch); } else { switch (ch) { case ' ': case '\t': case '\r': case '\n': // Eat whitespace break; case ExpressionPrefix: CheckForInvalidOperator(expression, expressionBuilder); if (nextCh == ExpressionStart) { inAttribute = true; reader.Read(); } break; case '=': if (nextCh == '=') { nodes.Add(new OperatorExpressionPlaceholder(BinaryExpressionOperator.Equal)); reader.Read(); } else if (nextCh == '~') { nodes.Add(new OperatorExpressionPlaceholder(BinaryExpressionOperator.Matches)); reader.Read(); } break; case '!': if (nextCh == '=') { nodes.Add(new OperatorExpressionPlaceholder(BinaryExpressionOperator.NotEqual)); reader.Read(); } else { expressionBuilder.Append(ch); } break; case ':': nodes.Add(new OperatorExpressionPlaceholder(BinaryExpressionOperator.Contains)); reader.Read(); break; case 'O': if (nextCh == 'r' && !inAttribute && !inString) { nodes.Add(new OperatorExpressionPlaceholder(BinaryExpressionOperator.Or)); reader.Read(); } else { expressionBuilder.Append(ch); } break; case 'A': if (nextCh == 'n' && !inAttribute && !inString) { reader.Read(); nextCh = (char)reader.Peek(); if (nextCh == 'd') { nodes.Add(new OperatorExpressionPlaceholder(BinaryExpressionOperator.And)); reader.Read(); } } else { expressionBuilder.Append(ch); } break; case ExpressionEnd: if (inAttribute) { string attribute = expressionBuilder.ToString(); expressionBuilder = new StringBuilder(DefaultExpressionLength); ElementAttributeScope elementScope = ElementAttributeScope.Element; bool isFileExpression = false; int separatorIndex = attribute.LastIndexOf(ScopeSeparator); if (separatorIndex > 0) { try { string attributeScope = attribute.Substring(0, separatorIndex); attribute = attribute.Substring(separatorIndex + 1); if (attributeScope == FileAttributeScope) { isFileExpression = true; } else { elementScope = (ElementAttributeScope) Enum.Parse(typeof(ElementAttributeScope), attributeScope); } } catch (ArgumentException ex) { OnInvalidExpression(expression, "Unknown attribute scope: {0}", ex.Message); } } if (isFileExpression) { FileAttributeType fileAttribute = FileAttributeType.None; try { fileAttribute = (FileAttributeType) Enum.Parse(typeof(FileAttributeType), attribute); } catch (ArgumentException ex) { OnInvalidExpression(expression, "Unknown attribute: {0}", ex.Message); } FileAttributeExpression attributeExpresion = new FileAttributeExpression( fileAttribute); nodes.Add(attributeExpresion); } else { ElementAttributeType elementAttribute = ElementAttributeType.None; try { elementAttribute = (ElementAttributeType) Enum.Parse(typeof(ElementAttributeType), attribute); } catch (ArgumentException ex) { OnInvalidExpression(expression, "Unknown attribute: {0}", ex.Message); } ElementAttributeExpression attributeExpresion = new ElementAttributeExpression( elementAttribute, elementScope); nodes.Add(attributeExpresion); } inAttribute = false; } else if (expressionBuilder.Length > 0 && nodes.Count > 0) { IConditionExpression innerExpression = nodes[nodes.Count - 1]; nodes.RemoveAt(nodes.Count - 1); string unaryOperatorString = expressionBuilder.ToString().Trim(); expressionBuilder = new StringBuilder(DefaultExpressionLength); UnaryExpressionOperator? unaryOperator = null; if (unaryOperatorString == "!") { unaryOperator = UnaryExpressionOperator.Negate; } else { OnInvalidExpression(expression, "Invalid operator {0}", unaryOperatorString); } UnaryOperatorExpression unaryOperatorExpression = new UnaryOperatorExpression( unaryOperator.Value, innerExpression); nodes.Add(unaryOperatorExpression); depth--; } else { depth--; } break; case ExpressionStart: IConditionExpression nestedExpression = null; StringBuilder childExpressionBuilder = new StringBuilder(DefaultExpressionLength); data = reader.Read(); ch = (char)data; nextCh = (char)reader.Peek(); depth++; while (data > 0) { if (ch == ExpressionPrefix && nextCh == ExpressionStart) { inAttribute = true; childExpressionBuilder.Append(ExpressionPrefix); data = reader.Read(); childExpressionBuilder.Append(ExpressionStart); } else if (ch == ExpressionStart && !inAttribute) { depth++; childExpressionBuilder.Append(ExpressionStart); } else if (nextCh == ExpressionEnd) { childExpressionBuilder.Append(ch); if (inAttribute || depth > 1) { if (inAttribute) { inAttribute = false; } else if (depth > 1) { depth--; } } else { break; } } else { childExpressionBuilder.Append(ch); } data = reader.Read(); ch = (char)data; nextCh = (char)reader.Peek(); } try { nestedExpression = Parse(childExpressionBuilder.ToString()); } catch (ArgumentException) { OnInvalidExpression(expression); } nodes.Add(nestedExpression); break; case '\'': if (inString) { if (nextCh == '\'') { expressionBuilder.Append(ch); reader.Read(); } else { string str = expressionBuilder.ToString(); expressionBuilder = new StringBuilder(DefaultExpressionLength); StringExpression stringExpression = new StringExpression(str); nodes.Add(stringExpression); inString = false; } } else { CheckForInvalidOperator(expression, expressionBuilder); inString = true; } break; default: expressionBuilder.Append(ch); break; } } data = reader.Read(); } if (inString) { OnInvalidExpression(expression, "Expected '"); } else if (inAttribute || depth > 0) { OnInvalidExpression(expression, "Expected )"); } else if (depth < 0) { OnInvalidExpression(expression, "Unmatched )"); } // // Assembly the flat list of expressions and expression placeholders into an // expression tree. // conditionExpression = AssembleExpressionTree(nodes.AsReadOnly(), expression); return conditionExpression; }