/// <summary> /// Evaluate as boolean /// </summary> internal override bool BoolEvaluate(ConditionEvaluationState state) { ProjectErrorUtilities.VerifyThrowInvalidProject (LeftChild.CanBoolEvaluate(state), state.conditionAttribute, "ExpressionDoesNotEvaluateToBoolean", LeftChild.GetUnexpandedValue(state), LeftChild.GetExpandedValue(state), state.parsedCondition); if (LeftChild.BoolEvaluate(state)) { // Short circuit return true; } else { ProjectErrorUtilities.VerifyThrowInvalidProject (RightChild.CanBoolEvaluate(state), state.conditionAttribute, "ExpressionDoesNotEvaluateToBoolean", RightChild.GetUnexpandedValue(state), RightChild.GetExpandedValue(state), state.parsedCondition); return RightChild.BoolEvaluate(state); } }
/// <summary> /// Value after any item and property expressions are expanded /// </summary> /// <returns></returns> internal override string GetExpandedValue(ConditionEvaluationState state) { if (cachedExpandedValue == null) { cachedExpandedValue = state.expanderToUse.ExpandAllIntoString(value, state.conditionAttribute); } return cachedExpandedValue; }
/// <summary> /// The main evaluate entry point for expression trees /// </summary> /// <param name="state"></param> /// <returns></returns> internal bool Evaluate(ConditionEvaluationState state) { ProjectErrorUtilities.VerifyThrowInvalidProject( CanBoolEvaluate(state), state.conditionAttribute, "ConditionNotBooleanDetail", state.parsedCondition, GetExpandedValue(state)); return BoolEvaluate(state); }
/// <summary> /// Evaluates as boolean and evaluates children as boolean, numeric, or string. /// Order in which comparisons are attempted is numeric, boolean, then string. /// Updates conditioned properties table. /// </summary> internal override bool BoolEvaluate(ConditionEvaluationState state) { ProjectErrorUtilities.VerifyThrowInvalidProject (LeftChild != null && RightChild != null, state.conditionAttribute, "IllFormedCondition", state.parsedCondition); if (LeftChild.CanNumericEvaluate(state) && RightChild.CanNumericEvaluate(state)) { return Compare(LeftChild.NumericEvaluate(state), RightChild.NumericEvaluate(state)); } else if (LeftChild.CanBoolEvaluate(state) && RightChild.CanBoolEvaluate(state)) { return Compare(LeftChild.BoolEvaluate(state), RightChild.BoolEvaluate(state)); } else // string comparison { string leftExpandedValue = LeftChild.GetExpandedValue(state); string rightExpandedValue = RightChild.GetExpandedValue(state); ProjectErrorUtilities.VerifyThrowInvalidProject (leftExpandedValue != null && rightExpandedValue != null, state.conditionAttribute, "IllFormedCondition", state.parsedCondition); if (!conditionedPropertiesUpdated) { string leftUnexpandedValue = LeftChild.GetUnexpandedValue(state); string rightUnexpandedValue = RightChild.GetUnexpandedValue(state); if (leftUnexpandedValue != null) { Utilities.UpdateConditionedPropertiesTable (state.conditionedPropertiesInProject, leftUnexpandedValue, rightExpandedValue); } if (rightUnexpandedValue != null) { Utilities.UpdateConditionedPropertiesTable (state.conditionedPropertiesInProject, rightUnexpandedValue, leftExpandedValue); } conditionedPropertiesUpdated = true; } return Compare(leftExpandedValue, rightExpandedValue); } }
/// <summary> /// Evaluate as boolean /// </summary> internal override bool BoolEvaluate(ConditionEvaluationState state) { ProjectErrorUtilities.VerifyThrowInvalidProject (LeftChild.CanNumericEvaluate(state) && RightChild.CanNumericEvaluate(state), state.conditionAttribute, "ComparisonOnNonNumericExpression", state.parsedCondition, /* helpfully display unexpanded token and expanded result in error message */ (LeftChild.CanNumericEvaluate(state) ? RightChild.GetUnexpandedValue(state) : LeftChild.GetUnexpandedValue(state)), (LeftChild.CanNumericEvaluate(state) ? RightChild.GetExpandedValue(state) : LeftChild.GetExpandedValue(state))); return Compare(LeftChild.NumericEvaluate(state), RightChild.NumericEvaluate(state)); }
public void SimpleEvaluationTests() { Parser p = new Parser(); Expander expander = new Expander(new BuildPropertyGroup()); Hashtable conditionedProperties = null; ConditionEvaluationState state = new ConditionEvaluationState(DummyAttribute, expander, conditionedProperties, string.Empty); AssertParseEvaluate(p, "true", state, true); AssertParseEvaluate(p, "on", state, true); AssertParseEvaluate(p, "yes", state, true); AssertParseEvaluate(p, "false", state, false); AssertParseEvaluate(p, "off", state, false); AssertParseEvaluate(p, "no", state, false); }
/// <summary> /// Whether it can be evaluated as a boolean: never allowed for numerics /// </summary> internal override bool CanBoolEvaluate(ConditionEvaluationState state) { // Numeric expressions are never allowed to be treated as booleans. return false; }
internal override string GetExpandedValue(ConditionEvaluationState state) { return value; }
internal override bool CanBoolEvaluate(ConditionEvaluationState state) { return(ConversionUtilities.CanConvertStringToBool(GetExpandedValue(state))); }
/// <summary> /// Value before any item and property expressions are expanded /// </summary> /// <returns></returns> internal override string GetUnexpandedValue(ConditionEvaluationState state) { return(value); }
/// <summary> /// Value before any item and property expressions are expanded /// </summary> /// <returns></returns> internal override string GetUnexpandedValue(ConditionEvaluationState state) { return null; }
/// <summary> /// Evaluate node as boolean /// </summary> internal override bool BoolEvaluate(ConditionEvaluationState state) { if (String.Equals(functionName, "exists", StringComparison.OrdinalIgnoreCase)) { // Check we only have one argument VerifyArgumentCount(1, state); // Expand properties and items, and verify the result is an appropriate scalar string expandedValue = ExpandArgumentForScalarParameter("exists", (GenericExpressionNode)arguments[0], state); if (Project.PerThreadProjectDirectory != null && !String.IsNullOrEmpty(expandedValue)) { try { expandedValue = Path.GetFullPath(Path.Combine(Project.PerThreadProjectDirectory, expandedValue)); } catch (Exception e) // Catching Exception, but rethrowing unless it's an IO related exception. { if (ExceptionHandling.NotExpectedException(e)) { throw; } // Ignore invalid characters or path related exceptions // We will ignore the PathTooLong exception caused by GetFullPath becasue in single proc this code // is not executed and the condition is just evaluated to false as File.Exists and Directory.Exists does not throw in this situation. // To be consistant with that we will return a false in this case also. // DevDiv Bugs: 46035 return(false); } } // Both Exists functions return false if the value is null or empty return(File.Exists(expandedValue) || Directory.Exists(expandedValue)); } else if (String.Equals(functionName, "HasTrailingSlash", StringComparison.OrdinalIgnoreCase)) { // Check we only have one argument VerifyArgumentCount(1, state); // Expand properties and items, and verify the result is an appropriate scalar string expandedValue = ExpandArgumentForScalarParameter("HasTrailingSlash", (GenericExpressionNode)arguments[0], state); // Is the last character a backslash? if (expandedValue.Length != 0) { char lastCharacter = expandedValue[expandedValue.Length - 1]; // Either back or forward slashes satisfy the function: this is useful for URL's return(lastCharacter == Path.DirectorySeparatorChar || lastCharacter == Path.AltDirectorySeparatorChar); } else { return(false); } } // We haven't implemented any other "functions" else { ProjectErrorUtilities.VerifyThrowInvalidProject( false, state.conditionAttribute, "UndefinedFunctionCall", state.parsedCondition, this.functionName); return(false); } }
/// <summary> /// Returns expanded value with '!' prepended. Useful for error messages. /// </summary> internal override string GetExpandedValue(ConditionEvaluationState state) { return "!" + LeftChild.GetExpandedValue(state); }
private void AssertParseEvaluateThrow(Parser p, string expression, ConditionEvaluationState state) { bool fExceptionCaught; try { fExceptionCaught = false; GenericExpressionNode tree = p.Parse(expression, DummyAttribute, ParserOptions.AllowAll); state.parsedCondition = expression; tree.Evaluate(state); } catch (InvalidProjectFileException e) { Console.WriteLine(e.BaseMessage); fExceptionCaught = true; } Assertion.Assert(fExceptionCaught); }
private bool EvaluateCondition(string conditionExpression, Expander expander) { Parser p = new Parser(); ConditionEvaluationState state = new ConditionEvaluationState(DummyAttribute, expander, null, conditionExpression); GenericExpressionNode node = p.Parse(conditionExpression, DummyAttribute, ParserOptions.AllowAll); bool result = node.Evaluate(state); return result; }
internal override bool CanBoolEvaluate(ConditionEvaluationState state) { return LeftChild.CanBoolEvaluate(state); }
/// <summary> /// Returns expanded value with '!' prepended. Useful for error messages. /// </summary> internal override string GetExpandedValue(ConditionEvaluationState state) { return("!" + LeftChild.GetExpandedValue(state)); }
internal override bool CanBoolEvaluate(ConditionEvaluationState state) { return(LeftChild.CanBoolEvaluate(state)); }
/// <summary> /// Evaluate node as boolean /// </summary> internal override bool BoolEvaluate(ConditionEvaluationState state) { if (String.Compare(functionName, "exists", StringComparison.OrdinalIgnoreCase) == 0) { // Check we only have one argument VerifyArgumentCount(1, state); // Expand properties and items, and verify the result is an appropriate scalar string expandedValue = ExpandArgumentForScalarParameter("exists", (GenericExpressionNode)arguments[0], state); if (Project.PerThreadProjectDirectory != null && !String.IsNullOrEmpty(expandedValue)) { try { expandedValue = Path.GetFullPath(Path.Combine(Project.PerThreadProjectDirectory, expandedValue)); } catch (Exception e) // Catching Exception, but rethrowing unless it's an IO related exception. { if (ExceptionHandling.NotExpectedException(e)) throw; // Ignore invalid characters or path related exceptions // We will ignore the PathTooLong exception caused by GetFullPath becasue in single proc this code // is not executed and the condition is just evaluated to false as File.Exists and Directory.Exists does not throw in this situation. // To be consistant with that we will return a false in this case also. // DevDiv Bugs: 46035 return false; } } // Both Exists functions return false if the value is null or empty return File.Exists(expandedValue) || Directory.Exists(expandedValue); } else if (String.Compare(functionName, "HasTrailingSlash", StringComparison.OrdinalIgnoreCase) == 0) { // Check we only have one argument VerifyArgumentCount(1, state); // Expand properties and items, and verify the result is an appropriate scalar string expandedValue = ExpandArgumentForScalarParameter("HasTrailingSlash", (GenericExpressionNode)arguments[0], state); // Is the last character a backslash? if (expandedValue.Length != 0) { char lastCharacter = expandedValue[expandedValue.Length - 1]; // Either back or forward slashes satisfy the function: this is useful for URL's return (lastCharacter == Path.DirectorySeparatorChar || lastCharacter == Path.AltDirectorySeparatorChar); } else { return false; } } // We haven't implemented any other "functions" else { ProjectErrorUtilities.VerifyThrowInvalidProject( false, state.conditionAttribute, "UndefinedFunctionCall", state.parsedCondition, this.functionName); return false; } }
internal abstract bool CanNumericEvaluate(ConditionEvaluationState state);
internal override bool CanBoolEvaluate(ConditionEvaluationState state) { return ConversionUtilities.CanConvertStringToBool(GetExpandedValue(state)); }
internal abstract bool BoolEvaluate(ConditionEvaluationState state);
/// <summary> /// Whether boolean evaluation is allowed: always allowed for operators /// </summary> internal override bool CanBoolEvaluate(ConditionEvaluationState state) { return true; }
internal abstract double NumericEvaluate(ConditionEvaluationState state);
/// <summary> /// Check that the number of function arguments is correct. /// </summary> /// <param name="expected"></param> private void VerifyArgumentCount(int expected, ConditionEvaluationState state) { ProjectErrorUtilities.VerifyThrowInvalidProject (arguments.Count == expected, state.conditionAttribute, "IncorrectNumberOfFunctionArguments", state.parsedCondition, arguments.Count, expected); }
/// <summary> /// Value before any item and property expressions are expanded /// </summary> /// <returns></returns> internal abstract string GetUnexpandedValue(ConditionEvaluationState state);
/// <summary> /// Evaluate as numeric /// </summary> internal override double NumericEvaluate(ConditionEvaluationState state) { return(ConversionUtilities.ConvertDecimalOrHexToDouble(GetExpandedValue(state))); }
public void NegativeTests() { Parser p = new Parser(); Expander expander = new Expander(new BuildPropertyGroup()); Hashtable conditionedProperties = null; ConditionEvaluationState state = new ConditionEvaluationState(DummyAttribute, expander, conditionedProperties, string.Empty); AssertParseEvaluateThrow(p, "foobar", state); AssertParseEvaluateThrow(p, "0", state); AssertParseEvaluateThrow(p, "$(platform) == xx > 1==2", state); AssertParseEvaluateThrow(p, "!0", state); AssertParseEvaluateThrow(p, ">", state); AssertParseEvaluateThrow(p, "true!=false==", state); AssertParseEvaluateThrow(p, "()", state); AssertParseEvaluateThrow(p, "!1", state); AssertParseEvaluateThrow(p, "true!=false==true", state); AssertParseEvaluateThrow(p, "'a'>'a'", state); AssertParseEvaluateThrow(p, "=='x'", state); AssertParseEvaluateThrow(p, "==", state); AssertParseEvaluateThrow(p, "1==(2", state); AssertParseEvaluateThrow(p, "'a'==('a'=='a')", state); AssertParseEvaluateThrow(p, "true == on and ''", state); AssertParseEvaluateThrow(p, "'' or 'true'", state); }
internal override bool CanNumericEvaluate(ConditionEvaluationState state) { return(ConversionUtilities.ValidDecimalOrHexNumber(GetExpandedValue(state))); }
/// <summary> /// Numeric evaluation is never allowed for operators /// </summary> internal override double NumericEvaluate(ConditionEvaluationState state) { // Should be unreachable: all calls check CanNumericEvaluate() first ErrorUtilities.VerifyThrow(false, "Cannot numeric evaluate an operator"); return(0.0D); }
/// <summary> /// Evaluate as boolean /// </summary> internal override bool BoolEvaluate(ConditionEvaluationState state) { // Should be unreachable: all calls check CanBoolEvaluate() first ErrorUtilities.VerifyThrow(false, "Can't evaluate a numeric expression as boolean."); return false; }
/// <summary> /// Whether boolean evaluation is allowed: always allowed for operators /// </summary> internal override bool CanBoolEvaluate(ConditionEvaluationState state) { return(true); }
internal override bool CanNumericEvaluate(ConditionEvaluationState state) { // It is not always possible to numerically evaluate even a numerical expression - // for example, it may overflow a double. So check here. return ConversionUtilities.ValidDecimalOrHexNumber(value); }
/// <summary> /// Whether the node can be evaluated as a numeric: by default, /// this is not allowed /// </summary> internal override bool CanNumericEvaluate(ConditionEvaluationState state) { return(false); }
internal abstract bool CanBoolEvaluate(ConditionEvaluationState state);
/// <summary> /// Value after any item and property expressions are expanded /// </summary> /// <returns></returns> internal override string GetExpandedValue(ConditionEvaluationState state) { return(null); }
/// <summary> /// Evaluate as numeric /// </summary> internal override double NumericEvaluate(ConditionEvaluationState state) { return ConversionUtilities.ConvertDecimalOrHexToDouble(GetExpandedValue(state)); }
public void NotTests() { Console.WriteLine("NegationParseTest()"); Parser p = new Parser(); Hashtable conditionedProperties = null; BuildPropertyGroup propertyBag = new BuildPropertyGroup(); propertyBag.SetProperty("foo", "4"); propertyBag.SetProperty("bar", "32"); Expander expander = new Expander(propertyBag); ConditionEvaluationState state = new ConditionEvaluationState(DummyAttribute, expander, conditionedProperties, string.Empty); AssertParseEvaluate(p, "!true", state, false); AssertParseEvaluate(p, "!(true)", state, false); AssertParseEvaluate(p, "!($(foo) <= 5)", state, false); AssertParseEvaluate(p, "!($(foo) <= 5 and $(bar) >= 15)", state, false); }
internal override bool CanNumericEvaluate(ConditionEvaluationState state) { return ConversionUtilities.ValidDecimalOrHexNumber(GetExpandedValue(state)); }
/// <summary> /// Whether it can be evaluated as a boolean: never allowed for numerics /// </summary> internal override bool CanBoolEvaluate(ConditionEvaluationState state) { // Numeric expressions are never allowed to be treated as booleans. return(false); }
/// <summary> /// Numeric evaluation is never allowed for operators /// </summary> internal override double NumericEvaluate(ConditionEvaluationState state) { // Should be unreachable: all calls check CanNumericEvaluate() first ErrorUtilities.VerifyThrow(false, "Cannot numeric evaluate an operator"); return 0.0D; }
internal override bool CanNumericEvaluate(ConditionEvaluationState state) { // It is not always possible to numerically evaluate even a numerical expression - // for example, it may overflow a double. So check here. return(ConversionUtilities.ValidDecimalOrHexNumber(value)); }
/// <summary> /// Whether the node can be evaluated as a numeric: by default, /// this is not allowed /// </summary> internal override bool CanNumericEvaluate(ConditionEvaluationState state) { return false; }
/// <summary> /// Expands properties and items in the argument, and verifies that the result is consistent /// with a scalar parameter type. /// </summary> /// <param name="function">Function name for errors</param> /// <param name="argumentNode">Argument to be expanded</param> /// <returns>Scalar result</returns> /// <owner>danmose</owner> private string ExpandArgumentForScalarParameter(string function, GenericExpressionNode argumentNode, ConditionEvaluationState state) { string argument = argumentNode.GetUnexpandedValue(state); List <TaskItem> items = state.expanderToUse.ExpandAllIntoTaskItems(argument, state.conditionAttribute); string expandedValue = String.Empty; if (items.Count == 0) { // Empty argument, that's fine. } else if (items.Count == 1) { expandedValue = items[0].ItemSpec; } else // too many items for the function { // We only allow a single item to be passed into a scalar parameter. ProjectErrorUtilities.VerifyThrowInvalidProject(false, state.conditionAttribute, "CannotPassMultipleItemsIntoScalarFunction", function, argument, state.expanderToUse.ExpandAllIntoString(argument, state.conditionAttribute)); } return(expandedValue); }
/// <summary> /// Evaluate as boolean /// </summary> internal override bool BoolEvaluate(ConditionEvaluationState state) { // Should be unreachable: all calls check CanBoolEvaluate() first ErrorUtilities.VerifyThrow(false, "Can't evaluate a numeric expression as boolean."); return(false); }
/// <summary> /// Expands properties and items in the argument, and verifies that the result is consistent /// with a scalar parameter type. /// </summary> /// <param name="function">Function name for errors</param> /// <param name="argumentNode">Argument to be expanded</param> /// <returns>Scalar result</returns> /// <owner>danmose</owner> private string ExpandArgumentForScalarParameter(string function, GenericExpressionNode argumentNode, ConditionEvaluationState state) { string argument = argumentNode.GetUnexpandedValue(state); List<TaskItem> items = state.expanderToUse.ExpandAllIntoTaskItems(argument, state.conditionAttribute); string expandedValue = String.Empty; if (items.Count == 0) { // Empty argument, that's fine. } else if (items.Count == 1) { expandedValue = items[0].ItemSpec; } else // too many items for the function { // We only allow a single item to be passed into a scalar parameter. ProjectErrorUtilities.VerifyThrowInvalidProject(false, state.conditionAttribute, "CannotPassMultipleItemsIntoScalarFunction", function, argument, state.expanderToUse.ExpandAllIntoString(argument, state.conditionAttribute)); } return expandedValue; }