/// <summary> /// Constructor for the Choose object. Parses the contents of the Choose /// and sets up list of When blocks /// </summary> /// <remarks> /// </remarks> /// <owner>DavidLe</owner> /// <param name="parentProject"></param> /// <param name="parentGroupingCollection"></param> /// <param name="chooseElement"></param> /// <param name="importedFromAnotherProject"></param> /// <param name="nestingDepth">stack overflow guard</param> internal Choose ( Project parentProject, GroupingCollection parentGroupingCollection, XmlElement chooseElement, bool importedFromAnotherProject, int nestingDepth ) { whenClauseList = new ArrayList(); error.VerifyThrow(chooseElement != null, "Need valid <Choose> element."); // Make sure this really is the <Choose> node. ProjectXmlUtilities.VerifyThrowElementName(chooseElement, XMakeElements.choose); // Stack overflow guard. The only way in the MSBuild file format that MSBuild elements can be // legitimately nested without limit is the <Choose> construct. So, enforce a nesting limit // to avoid blowing our stack. nestingDepth++; ProjectErrorUtilities.VerifyThrowInvalidProject(nestingDepth <= maximumChooseNesting, chooseElement, "ChooseOverflow", maximumChooseNesting); this.importedFromAnotherProject = importedFromAnotherProject; // This <Choose> is coming from an existing XML element, so // walk through all the attributes and child elements, creating the // necessary When objects. // No attributes on the <Choose> element, so don't allow any. ProjectXmlUtilities.VerifyThrowProjectNoAttributes(chooseElement); bool foundOtherwise = false; // Loop through the child nodes of the <Choose> element. foreach (XmlNode chooseChildNode in chooseElement) { switch (chooseChildNode.NodeType) { // Handle XML comments under the <PropertyGroup> node (just ignore them). case XmlNodeType.Comment: // fall through case XmlNodeType.Whitespace: // ignore whitespace break; case XmlNodeType.Element: // The only two types of child nodes that a <Choose> element can contain // is are <When> elements and zero or one <Otherwise> elements. ProjectXmlUtilities.VerifyThrowProjectValidNamespace((XmlElement)chooseChildNode); if (chooseChildNode.Name == XMakeElements.when) { // don't allow <When> to follow <Otherwise> ProjectErrorUtilities.VerifyThrowInvalidProject(!foundOtherwise, chooseChildNode, "WhenNotAllowedAfterOtherwise"); When newWhen = new When(parentProject, parentGroupingCollection, (XmlElement)chooseChildNode, importedFromAnotherProject, When.Options.ProcessWhen, nestingDepth); this.whenClauseList.Add(newWhen); } else if (chooseChildNode.Name == XMakeElements.otherwise) { ProjectErrorUtilities.VerifyThrowInvalidProject(!foundOtherwise, chooseChildNode, "MultipleOtherwise"); When newWhen = new When(parentProject, parentGroupingCollection, (XmlElement)chooseChildNode, importedFromAnotherProject, When.Options.ProcessOtherwise, nestingDepth); otherwiseClause = newWhen; foundOtherwise = true; } else { ProjectXmlUtilities.ThrowProjectInvalidChildElement(chooseChildNode); } break; default: // Unrecognized child element. ProjectXmlUtilities.ThrowProjectInvalidChildElement(chooseChildNode); break; } } ProjectErrorUtilities.VerifyThrowInvalidProject(this.whenClauseList.Count != 0, chooseElement, "ChooseMustContainWhen"); }
/// <summary> /// Evaluates the Choose clause by stepping through each when and evaluating. /// </summary> /// <remarks> /// </remarks> /// <owner>DavidLe</owner> /// <param name="parentPropertyBag"></param> /// <param name="ignoreCondition"></param> /// <param name="honorCondition"></param> /// <param name="conditionedPropertiesTable"></param> /// <param name="pass"></param> internal void Evaluate ( BuildPropertyGroup parentPropertyBag, bool ignoreCondition, bool honorCondition, Hashtable conditionedPropertiesTable, ProcessingPass pass ) { if (pass == ProcessingPass.Pass1) { whenLastTaken = null; bool whenTaken = false; foreach (When currentWhen in this.whenClauseList) { if (currentWhen.EvaluateCondition(parentPropertyBag, conditionedPropertiesTable)) { whenTaken = true; currentWhen.Evaluate(parentPropertyBag, ignoreCondition, honorCondition, conditionedPropertiesTable, pass); whenLastTaken = currentWhen; break; } } if (!whenTaken && otherwiseClause != null) { // Process otherwise whenLastTaken = otherwiseClause; otherwiseClause.Evaluate(parentPropertyBag, ignoreCondition, honorCondition, conditionedPropertiesTable, pass); } } else { ErrorUtilities.VerifyThrow(pass == ProcessingPass.Pass2, "ProcessingPass must be Pass1 or Pass2."); if (whenLastTaken != null) { whenLastTaken.Evaluate(parentPropertyBag, ignoreCondition, honorCondition, conditionedPropertiesTable, pass); } } }