//****************************************************************** /// <summary> /// For the given oReplacePatternNode, this method finds the /// corresponding find-pattern node and the parse-tree node it /// matched. (The parse-tree node must be in the branch indicated by /// oMorphologyParseRoot if this optional argument is not null.) A /// new node is created by copying features from the parse-tree node /// and merging features from the oReplacePatternNode. Then children /// are copied recursively either from the parse-tree node or from /// the oReplacePatternNode. Returns null if the oReplacePatternNode /// was optional and the parse-tree node was not found. Otherwise, /// returns the new node after adding it to the ReplacedNodes list. /// (Note that this method calls the CopyLeafAndChildren() method if /// it determines that the node is a leaf node.) /// </summary> SyntaxNode CopyNodeAndChildren(SyntaxNode oReplacePatternNode, SyntaxNode oMorphologyParseRoot) { Debug.Assert(oReplacePatternNode != null); //************************************************************** // For the given oReplacePatternNode, find the corresponding // find-pattern node and the parse-tree node it matched: // // Search the MatchingNodes list for a node pair where the // .FindPatternNode has the same label as the given // oReplacePatternNode. // // If oMorphologyParseRoot is not null, restrict this search to // node pairs where the .ParseTreeNode is contained in the // branch dominated by this oMorphologyParseRoot. // // If a matching node pair is found, set oParseTreeNode and // oFindPatternNode to the node-pair values. Otherwise, set // oParseTreeNode and oFindPatternNode both to null. SyntaxNode oParseTreeNode = null; SyntaxNode oFindPatternNode = null; SyntaxNodePair oNodePair = FindMatchingPairFromLabel( oReplacePatternNode.Label,oMorphologyParseRoot); if (oNodePair != null) { oParseTreeNode = oNodePair.ParseTreeNode; oFindPatternNode = oNodePair.FindPatternNode; } //************************************************************** // If a matching node pair was not found and oReplacePatternNode // is optional, nothing will be copied, so return null. if ((oNodePair == null) && (oReplacePatternNode.IsOptionalNode)) { return null; } //************************************************************** // If this is a leaf node, call CopyLeafAndChildren() instead. // // Each child of a syntax leaf is the root of a morphology // parse. (A syntax leaf may have one or more alternative // morphology parses.) CopyLeafAndChildren() is called because // a different algorithm is needed to copy these children. bool bIsSyntaxLeaf = false; if (oParseTreeNode != null) { if (oParseTreeNode.IsSyntaxLeaf) { bIsSyntaxLeaf = true; } } if (oReplacePatternNode.IsSyntaxLeaf) { bIsSyntaxLeaf = true; } if (bIsSyntaxLeaf) { return CopyLeafAndChildren(oReplacePatternNode); } //************************************************************** // Create a new parse-tree node by copying the features from the // matching oParseTreeNode (if found) and then merging the // features from oReplacePatternNode. if (VerboseDebugging) { string sParseString = "null"; if (oParseTreeNode != null) { sParseString = oParseTreeNode.ToString(); } string sReplaceString = "null"; if (oReplacePatternNode != null) { sReplaceString = oReplacePatternNode.ToString(); } Debug.WriteLine("Copying node: CopyFeatures(" + sParseString + "," + sReplaceString + ")."); } SyntaxNode oNewNode = CopyFeatures(oParseTreeNode,oReplacePatternNode); //************************************************************** // Check if any children are specified by oFindPatternNode or // oReplacePatternNode. bool bFindPatternHasChildren = false; if (oFindPatternNode != null) { if (oFindPatternNode.ChildNodes.Count > 0) { bFindPatternHasChildren = true; } } bool bReplacePatternHasChildren = false; if (oReplacePatternNode.ChildNodes.Count > 0) { bReplacePatternHasChildren = true; } //************************************************************** // Copy children either from the matching oParseTreeNode or from // the oReplacePatternNode: // // If oParseTreeNode is not null and no children are specified // by oFindPatternNode or oReplacePatternNode, copy the // oParseTreeNode children. // // Otherwise, copy the oReplacePatternNode children. if ((oParseTreeNode != null) && (! bFindPatternHasChildren) && (! bReplacePatternHasChildren)) { //********************************************************** // Copy the oParseTreeNode children. foreach (SyntaxNode oParseChild in oParseTreeNode.ChildNodes) { SyntaxNode oNewChild = oParseChild.CloneBranch(); oNewNode.ChildNodes.Add(oNewChild); } } else { //********************************************************** // Copy the oReplacePatternNode children. foreach (SyntaxNode oReplaceChild in oReplacePatternNode.ChildNodes) { SyntaxNode oNewChild = CopyNodeAndChildren( oReplaceChild,oMorphologyParseRoot); if (oNewChild != null) { oNewNode.ChildNodes.Add(oNewChild); } } } //************************************************************** // Return the new parse-tree node after adding it to the // ReplacedNodes list. SyntaxNodeTriple oNodeTriple = new SyntaxNodeTriple(); oNodeTriple.ParseTreeNode = oNewNode; oNodeTriple.FindPatternNode = oFindPatternNode; oNodeTriple.ReplacePatternNode = oReplacePatternNode; ReplacedNodes.Push(oNodeTriple); return oNewNode; }
//****************************************************************** /// <summary> /// Returns true if the indicated tree branch (dominated by oBranch) /// contains the given node (oNode). Returns false otherwise. /// </summary> private bool BranchContainsNode(SyntaxNode oBranch,SyntaxNode oNode) { Debug.Assert(oBranch != null); Debug.Assert(oNode != null); //************************************************************** // Search the branch recursively. if (oBranch == oNode) { return true; } foreach (SyntaxNode oChildBranch in oBranch.ChildNodes) { if (BranchContainsNode(oChildBranch,oNode)) { return true; } } return false; }
//****************************************************************** /// <summary> /// For the given oReplacePatternNode, this method finds the /// corresponding find-pattern node and the parse-tree node it /// matched. A new node is created by copying features from the /// parse-tree node and merging features from the /// oReplacePatternNode. Then children are copied recursively from /// the parse-tree node. Children are also copied recursively from /// the oReplacePatternNode if they do not correspond to children of /// the parse-tree node. Returns null if the oReplacePatternNode was /// optional and the parse-tree node was not found. Otherwise, /// returns the new node after adding it to the ReplacedNodes list. /// (Note that this method is only for copying leaf nodes.) /// </summary> SyntaxNode CopyLeafAndChildren(SyntaxNode oReplacePatternNode) { Debug.Assert(oReplacePatternNode != null); //************************************************************** // For the given oReplacePatternNode, find the corresponding // find-pattern node and the parse-tree node it matched: // // Search the MatchingNodes list for a node pair where the // .FindPatternNode has the same label as the given // oReplacePatternNode. // // If a matching node pair is found, set oParseTreeNode and // oFindPatternNode to the node-pair values. Otherwise, set // oParseTreeNode and oFindPatternNode both to null. SyntaxNode oParseTreeNode = null; SyntaxNode oFindPatternNode = null; SyntaxNodePair oNodePair = FindMatchingPairFromLabel(oReplacePatternNode.Label); if (oNodePair != null) { oParseTreeNode = oNodePair.ParseTreeNode; oFindPatternNode = oNodePair.FindPatternNode; } //************************************************************** // If a matching node pair was not found and oReplacePatternNode // is optional, nothing will be copied, so return null. if ((oNodePair == null) && (oReplacePatternNode.IsOptionalNode)) { return null; } //************************************************************** // This method should only be called for leaf nodes. if (oParseTreeNode != null) { Debug.Assert(oParseTreeNode.IsSyntaxLeaf || oReplacePatternNode.IsSyntaxLeaf); } else { Debug.Assert(oReplacePatternNode.IsSyntaxLeaf); } //************************************************************** // Create a new parse-tree node by copying the features from the // matching oParseTreeNode (if found) and then merging the // features from oReplacePatternNode. if (VerboseDebugging) { string sParseString = "null"; if (oParseTreeNode != null) { sParseString = oParseTreeNode.ToString(); } string sReplaceString = "null"; if (oReplacePatternNode != null) { sReplaceString = oReplacePatternNode.ToString(); } Debug.WriteLine("Copying leaf: CopyFeatures(" + sParseString + "," + sReplaceString + ")."); } SyntaxNode oNewNode = CopyFeatures(oParseTreeNode,oReplacePatternNode); //************************************************************** // Each child of a syntax leaf is the root of a morphology // parse. (A syntax leaf may have one or more alternative // morphology parses.) // // Each child will be copied recursively from oParseTreeNode. // Additional children will also be copied recursively from // oReplacePatternNode if they do not correspond to children of // oParseTreeNode. // // Create a list to keep track of the oReplacePatternNode // children as they are used. (A replace-pattern child is marked // as used if it has the same label as a find-pattern child // matching one of the oParseTreeNode children.) ArrayList oUsedReplaceChildren = new ArrayList(); //************************************************************** // Copy the oParseTreeNode children. if (oParseTreeNode != null) { foreach (SyntaxNode oParseChild in oParseTreeNode.ChildNodes) { //****************************************************** // Look for the find-pattern node that matched this // parse-tree child: // // Search the MatchingNodes list for a node pair where // the .ParseTreeNode is the same as oParseChild. // // If found, set oFindChild to the .FindPatternNode // value from the node pair. Otherwise, set oFindChild // to null. SyntaxNodePair oChildNodePair = FindMatchingPairFromNode(oParseChild); SyntaxNode oFindChild = null; if (oChildNodePair != null) { oFindChild = oChildNodePair.FindPatternNode; } //****************************************************** // If oFindChild is null (no find-pattern matched // this parse-tree child), copy oParseChild. // // Otherwise, copy each oReplacePatternNode child that // has the same label as oFindChild. if (oFindChild == null) { //************************************************** // Copy oParseChild. SyntaxNode oNewChild = oParseChild.CloneBranch(); oNewNode.ChildNodes.Add(oNewChild); } else { //************************************************** // Copy each oReplacePatternNode child that has the // same label as oFindChild. foreach (SyntaxNode oReplaceChild in oReplacePatternNode.ChildNodes) { if (oReplaceChild.Label == oFindChild.Label) { //****************************************** // Copy the oReplacePatternNode child. // // Since oParseTreeNode is a syntax leaf, // each of its children is the root of a // morphology parse. So oParseChild is used // as the oMorphologyParseRoot argument to // the CopyNodeAndChildren() method. SyntaxNode oNewChild = CopyNodeAndChildren( oReplaceChild,oParseChild); if (oNewChild != null) { oNewNode.ChildNodes.Add(oNewChild); } //****************************************** // Add this oReplaceChild to the list of // oUsedReplaceChildren (if not already // there). if (! oUsedReplaceChildren .Contains(oReplaceChild)) { oUsedReplaceChildren.Add(oReplaceChild); } } } } } } //************************************************************** // Copy any oReplacePatternNode children that have not yet been // used. foreach (SyntaxNode oReplaceChild in oReplacePatternNode.ChildNodes) { if (! oUsedReplaceChildren.Contains(oReplaceChild)) { SyntaxNode oNewChild = CopyNodeAndChildren(oReplaceChild); if (oNewChild != null) { oNewNode.ChildNodes.Add(oNewChild); } } } //************************************************************** // Return the new parse-tree node after adding it to the // ReplacedNodes list. SyntaxNodeTriple oNodeTriple = new SyntaxNodeTriple(); oNodeTriple.ParseTreeNode = oNewNode; oNodeTriple.FindPatternNode = oFindPatternNode; oNodeTriple.ReplacePatternNode = oReplacePatternNode; ReplacedNodes.Push(oNodeTriple); return oNewNode; }
//****************************************************************** /// <summary> /// Inserts the given node into the collection at the specified /// zero-based index, then sets the node's ParentNode property. /// </summary> public void Insert(int iIndex,SyntaxNode oNode) { //************************************************************** // Validate the parameters. Debug.Assert(iIndex >= 0); Debug.Assert(iIndex <= InnerList.Count); if (oNode == null) { string sMessage = "Invalid argument: " + "SyntaxNodeCollection cannot insert a null item."; throw new Exception(sMessage); } if (InnerList.Contains(oNode)) { string sMessage = "Invalid argument: " + "SyntaxNodeCollection already contains this item."; throw new Exception(sMessage); } //************************************************************** // Insert the node into the list. InnerList.Insert(iIndex,oNode); //************************************************************** // Set the node's ParentNode property. oNode.ParentNode = ParentNode; }
//****************************************************************** /// <summary> /// Initializes a new instance of the SyntaxNodeCollection class, /// using the indicated oParentNode to set the collection's private /// ParentNode property, which will be used to initialize the /// ParentNode property of each node that is added to this /// collection. /// </summary> public SyntaxNodeCollection(SyntaxNode oParentNode) { moParentNode = oParentNode; }
//****************************************************************** /// <summary> /// Displays the Features form so the user can view (but not edit) /// the features of the given SyntaxNode. The user can also modify /// the FavoriteListFeatures, FavoriteTreeFeatures and /// CopyFavoritesOnly settings. If the user clicks OK, changes are /// saved to the settings, and DialogResult.OK is returned. /// Otherwise, DialogResult.Cancel is returned and any changes are /// discarded. /// </summary> public static DialogResult OpenFeaturesReadOnly(SyntaxNode oNode) { //************************************************************** // Validate the parameters. if (oNode == null) { string sMessage = "Invalid argument: " + "FeaturesForm.OpenFeaturesReadOnly() requires " + "a SyntaxNode object that is not null."; throw new Exception(sMessage); } //************************************************************** // Create an instance of the FeaturesForm. FeaturesForm oForm = new FeaturesForm(); //************************************************************** // Set the form's ReadOnly property to true (the user is not // allowed to edit features). oForm.ReadOnly = true; //************************************************************** // Set the form's DisplayedNode property to a copy of the node // specified by the oNode parameter. oForm.DisplayedNode = oNode.CloneNode(); //************************************************************** // Show the form so the user can view (but not edit) the // features of the DisplayedNode. DialogResult iResult = oForm.ShowDialog(); //************************************************************** // Return the dialog result. return iResult; }
//****************************************************************** /// <summary> /// Returns true if the collection contains the given node. Returns /// false otherwise. /// </summary> public bool Contains(SyntaxNode oNode) { Debug.Assert(oNode != null); return InnerList.Contains(oNode); }
//****************************************************************** /// <summary> /// Associates the given oTreeNode with with the indicated /// oSyntaxNode (by setting oTreeNode.Tag to oSyntaxNode). The /// oSyntaxNode features are then used to determine the text that is /// displayed by the oTreeNode. (If this node is a leaf node and /// morphology nodes are not shown, the oSyntaxNode can have child /// nodes to represent morphology. Otherwise, the given oSyntaxNode /// cannot have child nodes.) /// </summary> private void PopulateNode(TreeViewerNode oTreeNode, SyntaxNode oSyntaxNode) { Debug.Assert(oTreeNode != null); Debug.Assert(oSyntaxNode != null); //************************************************************** // The oSyntaxNode can have child nodes (representing // morphology) only if this is a leaf node and morphology nodes // are not shown. if (! oSyntaxNode.IsSyntaxLeaf) { Debug.Assert(oSyntaxNode.ChildNodes.Count == 0); } if (ShowMorphology) { Debug.Assert(oSyntaxNode.ChildNodes.Count == 0); } //************************************************************** // Set the oTreeNode.Tag to associate the displayed node with // the indicated oSyntaxNode. oTreeNode.Tag = oSyntaxNode; //************************************************************** // If this is a leaf node, display the node's text in a bold // font style. Otherwise, use a regular font style. if (oSyntaxNode.IsSyntaxLeaf) { Font oFont = Font; if (oFont.FontFamily.IsStyleAvailable(FontStyle.Bold)) { oFont = new Font(oFont,FontStyle.Bold); } oTreeNode.Font = oFont; } else { Font oFont = Font; if (oFont.FontFamily.IsStyleAvailable(FontStyle.Regular)) { oFont = new Font(oFont,FontStyle.Regular); } oTreeNode.Font = oFont; } //************************************************************** // The displayed text always starts with the node's label. string sText = oSyntaxNode.Label; //************************************************************** // If the ShowFeatures property is true, add the name and value // text for each feature. if (ShowFeatures) { //********************************************************** // For find-pattern and replace-pattern nodes, show all // features. // // For parse-tree nodes, only show the features that are // named in the FavoriteTreeFeatures collection. SyntaxNode oFilteredSyntaxNode = oSyntaxNode.CloneNode(); if ((! DisplayFindPattern) && (! DisplayReplacePattern)) { FilterFeatures(oFilteredSyntaxNode, FavoriteTreeFeatures); } //********************************************************** // Append the name and value text for each feature (except // the node-label feature, since the text already starts // with the node's label). foreach (SyntaxFeature oFeature in oFilteredSyntaxNode.Features) { if (oFeature.Name != TreeTranEngineString.NodeLabel) { string sName = oFeature.Name; string sValue = oFeature.Value; sText = sText + Environment.NewLine + sName + "=" + sValue; } } } //************************************************************** // Set the text of the displayed node. oTreeNode.Text = sText; }
//****************************************************************** /// <summary> /// Displays the parse tree specified by the ParseTreeRoot property /// (or the FindPatternRoot or the DisplayPatternRoot) of the given /// TreeTransfer object. The TreeTransfer object also specifies the /// node to select (CurrentParseTreeNode property) and the nodes to /// highlight (in the MatchingNodes and ReplacedNodes collections). /// This method does not change the Modified property, raise the /// TreeChanged event or clear the undo information. /// </summary> private void PopulateRoot(TreeTransfer oTreeTransfer) { Debug.Assert(oTreeTransfer != null); //************************************************************** // Make a private copy of the FeaturesForm.FavoriteTreeFeatures // collection. This private copy will be used until the // PopulateRoot() method is called again, so this tree will // display a consistent set of features when parts of the tree // are edited (even if the FeaturesForm collection changes). FavoriteTreeFeatures.Clear(); foreach (string sName in FeaturesForm.FavoriteTreeFeatures) { FavoriteTreeFeatures.Add(sName); } //************************************************************** // Call BeginUpdate() to disable redrawing the tree, but not if // redrawing was already disabled by the calling code. bool bCallEndUpdate = false; if (! IsUpdating) { BeginUpdate(); bCallEndUpdate = true; } //************************************************************** // Get the root node that specifies the tree to display. // // Display the find-pattern tree if DisplayFindPattern is true. // Display the replace-pattern tree if DisplayReplacePattern is // true. Display the parse tree otherwise. SyntaxNode oSyntaxRoot = oTreeTransfer.ParseTreeRoot; if (DisplayFindPattern) { oSyntaxRoot = oTreeTransfer.FindPatternRoot; } if (DisplayReplacePattern) { oSyntaxRoot = oTreeTransfer.ReplacePatternRoot; } //************************************************************** // If the specified root node is null, display a blank node. if (oSyntaxRoot == null) { oSyntaxRoot = new SyntaxNode(); } //************************************************************** // Create the root TreeViewerNode and then call PopulateBranch() // to display the tree. TreeViewerNode oTreeRoot = new TreeViewerNode(); moTreeViewer.RootNode = oTreeRoot; PopulateBranch(oTreeRoot,oSyntaxRoot,oTreeTransfer); //************************************************************** // If no node is selected, select the root node. if (moTreeViewer.SelectedNode == null) { moTreeViewer.SelectedNode = moTreeViewer.RootNode; } //************************************************************** // Call EndUpdate() to redraw the tree, but not if redrawing was // already disabled by the calling code. if (bCallEndUpdate) { EndUpdate(); } }
//****************************************************************** /// <summary> /// Uses the given oTreeNode to display features of the indicated /// oSyntaxNode. Children are then recursively added to oTreeNode to /// represent the children of oSyntaxNode (unless it is a leaf node /// and morphology nodes are hidden). If the optional oTreeTransfer /// argument is given, its CurrentParseTreeNode indicates the node /// to select, and items in its MatchingNodes and ReplacedNodes /// collections indicate nodes to highlight. /// </summary> private void PopulateBranch(TreeViewerNode oTreeNode, SyntaxNode oSyntaxNode) { TreeTransfer oTreeTransfer = new TreeTransfer(); PopulateBranch(oTreeNode,oSyntaxNode,oTreeTransfer); }
//****************************************************************** /// <summary> /// Uses the given oTreeNode to display features of the indicated /// oSyntaxNode. Children are then recursively added to oTreeNode to /// represent the children of oSyntaxNode (unless it is a leaf node /// and morphology nodes are hidden). If the optional oTreeTransfer /// argument is given, its CurrentParseTreeNode indicates the node /// to select, and items in its MatchingNodes and ReplacedNodes /// collections indicate nodes to highlight. /// </summary> private void PopulateBranch(TreeViewerNode oTreeNode, SyntaxNode oSyntaxNode,TreeTransfer oTreeTransfer) { Debug.Assert(oTreeNode != null); Debug.Assert(oSyntaxNode != null); Debug.Assert(oTreeTransfer != null); //************************************************************** // The given oTreeNode should not already have children. Debug.Assert(oTreeNode.ChildNodes.Count == 0); //************************************************************** // Set the node's context menu. oTreeNode.ContextMenu = moMenu; //************************************************************** // Use the oTreeTransfer.CurrentParseTreeNode property to // determine if the node is selected. if (oSyntaxNode == oTreeTransfer.CurrentParseTreeNode) { moTreeViewer.SelectedNode = oTreeNode; } //************************************************************** // Use the oTreeTransfer.MatchingNodes and .ReplacedNodes // collections to determine the node's background color. Color oForeColor = SystemColors.WindowText; Color oBackColor = SystemColors.Window; foreach (SyntaxNodePair oNodePair in oTreeTransfer.MatchingNodes) { if (oSyntaxNode == oNodePair.ParseTreeNode) { oBackColor = FindPatternColor; } } foreach (SyntaxNodeTriple oNodeTriple in oTreeTransfer.ReplacedNodes) { if (oSyntaxNode == oNodeTriple.ParseTreeNode) { oBackColor = ReplacePatternColor; } } if (DisplayFindPattern) { oBackColor = FindPatternColor; } if (DisplayReplacePattern) { oBackColor = ReplacePatternColor; } oTreeNode.ForeColor = oForeColor; oTreeNode.BackColor = oBackColor; //************************************************************** // Determine if the node's children should be shown. // // A node's children are usually shown, but if the node is a // leaf node and ShowMorphology is false, the leaf node's // children (representing morphology) are not shown (unless the // leaf node's children are selected or highlighted). bool bShowChildNodes = true; if (oSyntaxNode.IsSyntaxLeaf) { if (! ShowMorphology) { bShowChildNodes = false; //****************************************************** // Even if ShowMorphology is false, a leaf node's // children are shown if any of the child branches // contains a selected or highlighted node. foreach (SyntaxNode oSyntaxChild in oSyntaxNode.ChildNodes) { if (BranchContainsSelectionOrHighlight( oSyntaxChild,oTreeTransfer)) { bShowChildNodes = true; } } } } //************************************************************** // Display the node (showing or hiding its children). if (bShowChildNodes) { //********************************************************** // Display the node and its children. // // Clone the oSyntaxNode (without including child nodes) and // call PopulateNode(). PopulateNode(oTreeNode,oSyntaxNode.CloneNode()); //********************************************************** // For each child node, add a new TreeViewerNode to the tree // and make a recursive call to PopulateBranch(). foreach (SyntaxNode oSyntaxChild in oSyntaxNode.ChildNodes) { TreeViewerNode oTreeChild = new TreeViewerNode(); oTreeNode.ChildNodes.Add(oTreeChild); PopulateBranch(oTreeChild,oSyntaxChild,oTreeTransfer); } } else { //********************************************************** // Display the node, but hide its children. // // Clone the entire oSyntaxNode branch (so the cloned branch // includes child nodes that represent morphology) and call // PopulateNode(). PopulateNode(oTreeNode,oSyntaxNode.CloneBranch()); } }
//****************************************************************** /// <summary> /// Recursively traverses the tree dominated by the indicated /// oSyntaxNode, removing all node features with names that do not /// appear in the given oFeatureNames collection. /// </summary> private void FilterFeatures(SyntaxNode oSyntaxNode, StringCollection oFeatureNames) { Debug.Assert(oSyntaxNode != null); Debug.Assert(oFeatureNames != null); //************************************************************** // Create a filtered-features collection. SyntaxFeatureCollection oFilteredFeatures = new SyntaxFeatureCollection(); //************************************************************** // Always copy the node's label feature to the filtered-features // collection. oFilteredFeatures[TreeTranEngineString.NodeLabel] = oSyntaxNode.Label; //************************************************************** // For each feature name in the oFeatureNames collection, copy // the named feature (if it exists) from the node to the // filtered-features collection. (The features are copied in the // same order that the names appear in oFeaturesNames.) foreach (string sName in oFeatureNames) { if (oSyntaxNode.Features.Contains(sName)) { string sValue = oSyntaxNode.Features[sName]; oFilteredFeatures[sName] = sValue; } } //************************************************************** // Clear the node's features, and then copy all the features // from the filtered-features collection back to the node. oSyntaxNode.Features.Clear(); foreach (SyntaxFeature oFeature in oFilteredFeatures) { string sName = oFeature.Name; string sValue = oFeature.Value; oSyntaxNode.Features[sName] = sValue; } //************************************************************** // Recursively traverse each child branch, filtering features. foreach (SyntaxNode oSyntaxChild in oSyntaxNode.ChildNodes) { FilterFeatures(oSyntaxChild,oFeatureNames); } }
//****************************************************************** #region [Constructor] //****************************************************************** /// <summary> /// Initializes a new instance of the SyntaxNodeCollection class, /// using the indicated oParentNode to set the collection's private /// ParentNode property, which will be used to initialize the /// ParentNode property of each node that is added to this /// collection. /// </summary> public SyntaxNodeCollection(SyntaxNode oParentNode) { moParentNode = oParentNode; }
//****************************************************************** /// <summary> /// Searches the collection for the given node. Returns the node's /// zero-based index if it was found. Returns -1 otherwise. /// </summary> public int IndexOf(SyntaxNode oNode) { Debug.Assert(oNode != null); return(InnerList.IndexOf(oNode)); }
//****************************************************************** /// <summary> /// Searches the MatchingNodes list for a node pair where the /// .ParseTreeNode is the same as the given oParseTreeNode. Returns /// the first matching node pair, if a match is found. Returns null /// otherwise. /// </summary> private SyntaxNodePair FindMatchingPairFromNode( SyntaxNode oParseTreeNode) { Debug.Assert(oParseTreeNode != null); //************************************************************** // Search the MatchingNodes list for a node pair where the // .ParseTreeNode is the same as the given oParseTreeNode. // Return the (first) matching node pair if found. foreach (SyntaxNodePair oPair in MatchingNodes) { Debug.Assert(oPair.ParseTreeNode != null); Debug.Assert(oPair.FindPatternNode != null); if (oPair.ParseTreeNode == oParseTreeNode) { return oPair; } } //************************************************************** // Return null if a match was not found. return null; }
//****************************************************************** /// <summary> /// Recursively traverses the tree dominated by the indicated /// oSyntaxNode, making sure each node has a label that is not /// already in the given oLabelsInUse collection. If necessary, node /// labels are renamed to make them unique. Each node label is added /// to the oLabelsInUse collection as nodes are traversed. /// </summary> private void RenameLabelsInUse(SyntaxNode oSyntaxNode, StringCollection oLabelsInUse) { Debug.Assert(oSyntaxNode != null); Debug.Assert(oLabelsInUse != null); //************************************************************** // Check if the node's label already exists in the oLabelsInUse // collection. If so, change the label to a new string // consisting of the node's category string followed by the "#" // character and a number (for example: "NP#2"). Keep // incrementing the number, until the node's label is not found // in the oLabelsInUse collection. int iNumber = 1; while (oLabelsInUse.Contains(oSyntaxNode.Label)) { ++iNumber; string sLabel = oSyntaxNode.Category + "#" + iNumber.ToString(); if (oSyntaxNode.IsOptionalNode) { //****************************************************** // If the node is optional, make sure its new label // indicates that it is optional by enclosing the new // label string in parenthesis (for example: "(NP#2)"). sLabel = TreeTranEngineString.LeftParenthesis + sLabel + TreeTranEngineString.RightParenthesis; } oSyntaxNode.Features[TreeTranEngineString.NodeLabel] = sLabel; } //************************************************************** // Add the node's label to the oLabelsInUse collection. oLabelsInUse.Add(oSyntaxNode.Label); //************************************************************** // Recursively traverse each child branch. foreach (SyntaxNode oSyntaxChild in oSyntaxNode.ChildNodes) { RenameLabelsInUse(oSyntaxChild,oLabelsInUse); } }
//****************************************************************** /// <summary> /// Returns true if the collection contains the given node. Returns /// false otherwise. /// </summary> public bool Contains(SyntaxNode oNode) { Debug.Assert(oNode != null); return(InnerList.Contains(oNode)); }
//****************************************************************** /// <summary> /// Copies the current selection to the clipboard. /// </summary> public void Copy() { //************************************************************** // Validate the current state. if (! CanCopy()) { string sMessage = "Invalid state: " + "A call to ParseTreeViewer.Copy() is not allowed " + "if ParseTreeViewer.CanCopy() returns false."; throw new Exception(sMessage); } //************************************************************** // Clone the selected branch. If no branch is selected, clone // the whole tree. (As a last result, use an empty node.) SyntaxNode oSyntaxBranchToCopy = null; if (moTreeViewer.SelectedNode != null) { oSyntaxBranchToCopy = CloneBranch(moTreeViewer.SelectedNode); } if (oSyntaxBranchToCopy == null) { oSyntaxBranchToCopy = CloneTree(); } if (oSyntaxBranchToCopy == null) { oSyntaxBranchToCopy = new SyntaxNode(); } //************************************************************** // If the CopyFavoritesOnly option is true and we are copying // from a parse tree (not a find pattern or replace pattern), // filter out any features that are not named in the // FavoriteListFeatures collection. if (FeaturesForm.CopyFavoritesOnly) { if ((! DisplayFindPattern) && (! DisplayReplacePattern)) { FilterFeatures(oSyntaxBranchToCopy, FeaturesForm.FavoriteListFeatures); } } //************************************************************** // Create a RuleWriter that writes to a string. StringBuilder oStringBuilder = new StringBuilder(); TextWriter oTextWriter = new StringWriter(oStringBuilder); RuleWriter oRuleWriter = new RuleWriter(oTextWriter); //************************************************************** // Make a rule that uses the indicated branch as its find // pattern (and has an empty replace pattern). oRuleWriter.RuleName = "(tree fragment on clipboard)"; oRuleWriter.FindPatternRoot = oSyntaxBranchToCopy; oRuleWriter.ReplacePatternRoot = null; //************************************************************** // Write the rule to the string. oRuleWriter.Write(); //************************************************************** // Close the RuleWriter. oRuleWriter.Close(); //************************************************************** // Copy the string to the clipboard. const bool bCopy = true; Clipboard.SetDataObject(oStringBuilder.ToString(),bCopy); }
//****************************************************************** /// <summary> /// Adds the given node to the end of the collection, then sets the /// node's ParentNode property. Returns the zero-based index of the /// added node. /// </summary> public int Add(SyntaxNode oNode) { Debug.Assert(oNode != null); Debug.Assert(! InnerList.Contains(oNode)); int iIndex = Count; Insert(iIndex,oNode); return iIndex; }
//****************************************************************** /// <summary> /// Deletes the current selection. /// </summary> public void Delete() { //************************************************************** // Validate the current state. if (! CanDelete()) { string sMessage = "Invalid state: " + "A call to ParseTreeViewer.Delete() is not allowed " + "if ParseTreeViewer.CanDelete() returns false."; throw new Exception(sMessage); } //************************************************************** // Prevent modification to a read-only tree. if (ReadOnly) { return; } //************************************************************** // Use the current contents of the tree (before the delete // operation) to set the undo information. TreeTransferForUndo = RecreateTreeTransfer(); //************************************************************** // Call BeginUpdate() to disable redrawing the tree, but not if // redrawing was already disabled by the calling code. bool bCallEndUpdate = false; if (! IsUpdating) { BeginUpdate(); bCallEndUpdate = true; } //************************************************************** // Delete the branch dominated by the selected node. if (moTreeViewer.SelectedNode != null) { if (moTreeViewer.SelectedNode == moTreeViewer.RootNode) { //****************************************************** // The selected node is the root node. // // Replace the root node with an empty node. Select the // new root node. moTreeViewer.RootNode = new TreeViewerNode(); SyntaxNode oSyntaxNode = new SyntaxNode(); PopulateBranch(moTreeViewer.RootNode,oSyntaxNode); moTreeViewer.SelectedNode = moTreeViewer.RootNode; } else { //****************************************************** // The selected node is not the root node. // // Remove the selected node. Select the parent of the // removed node. TreeViewerNode oTreeParent = moTreeViewer.SelectedNode.ParentNode; if (oTreeParent != null) { oTreeParent.ChildNodes .Remove(moTreeViewer.SelectedNode); moTreeViewer.SelectedNode = oTreeParent; } } } //************************************************************** // Call EndUpdate() to redraw the tree, but not if redrawing was // already disabled by the calling code. if (bCallEndUpdate) { EndUpdate(); } //************************************************************** // Set the Modified property to true and raise the TreeChanged // event. Modified = true; OnTreeChanged(new EventArgs()); }
//****************************************************************** /// <summary> /// Searches the collection for the given node. Returns the node's /// zero-based index if it was found. Returns -1 otherwise. /// </summary> public int IndexOf(SyntaxNode oNode) { Debug.Assert(oNode != null); return InnerList.IndexOf(oNode); }
//****************************************************************** /// <summary> /// Saves the displayed rules to the indicated rule file /// (sFileName). The Modified property is set to false after the /// file is saved. /// </summary> public void SaveRuleFile(string sFileName) { //************************************************************** // Validate the parameters. if ((sFileName == null) || (sFileName == "")) { string sMessage = "Invalid argument: " + "RuleListViewer.SaveRuleFile() requires " + "a file name that is not null or blank."; throw new Exception(sMessage); } //************************************************************** // Create a RuleWriter to write to the indicated rule file. StreamWriter oStreamWriter = new StreamWriter(sFileName); RuleWriter oRuleWriter = new RuleWriter(oStreamWriter); //************************************************************** // For each item in the ListView, write the rule to the file. foreach (ListViewItem oItem in moListView.Items) { //********************************************************** // Get the rule from the ListView item. Debug.Assert(oItem is RuleListViewerItem); RuleListViewerItem oRuleItem = (RuleListViewerItem) oItem; //********************************************************** // Make sure the find pattern is not null. SyntaxNode oFindPatternRoot = oRuleItem.FindPatternRoot; if (oFindPatternRoot == null) { oFindPatternRoot = new SyntaxNode(); } //********************************************************** // Make sure the replace pattern is not null. SyntaxNode oReplacePatternRoot = oRuleItem.ReplacePatternRoot; if (oReplacePatternRoot == null) { oReplacePatternRoot = new SyntaxNode(); } //********************************************************** // Write the rule to the file. oRuleWriter.RuleName = oRuleItem.Text; oRuleWriter.FindPatternRoot = oFindPatternRoot; oRuleWriter.ReplacePatternRoot = oReplacePatternRoot; oRuleWriter.Write(); } //************************************************************** // Close the RuleWriter. oRuleWriter.Close(); //************************************************************** // Set the Modified property to false. Modified = false; }
//****************************************************************** /// <summary> /// Removes the given node from the collection, after recursively /// clearing the children of the removed node. /// </summary> public void Remove(SyntaxNode oNode) { Debug.Assert(oNode != null); Debug.Assert(InnerList.Contains(oNode)); //************************************************************** // Recursively clear the children of the indicated node. oNode.ChildNodes.Clear(); //************************************************************** // Remove the indicated node. InnerList.Remove(oNode); //************************************************************** // Set the parent of the removed node to null. oNode.ParentNode = null; }
//****************************************************************** /// <summary> /// Copies the current selection to the clipboard. /// </summary> public void Copy() { //************************************************************** // Validate the current state. if (! CanCopy()) { string sMessage = "Invalid state: " + "A call to RuleListViewer.Copy() is not allowed " + "if RuleListViewer.CanCopy() returns false."; throw new Exception(sMessage); } //************************************************************** // Create a RuleWriter that writes to a string. StringBuilder oStringBuilder = new StringBuilder(); TextWriter oTextWriter = new StringWriter(oStringBuilder); RuleWriter oRuleWriter = new RuleWriter(oTextWriter); //************************************************************** // Write each selected rule to the string. foreach (ListViewItem oItem in moListView.Items) { //********************************************************** // Get the rule from the ListView item. Debug.Assert(oItem is RuleListViewerItem); RuleListViewerItem oRuleItem = (RuleListViewerItem) oItem; //********************************************************** // If the item is selected, write the rule to the string. if (oRuleItem.Selected) { //****************************************************** // Make sure the find pattern is not null. SyntaxNode oFindPatternRoot = oRuleItem.FindPatternRoot; if (oFindPatternRoot == null) { oFindPatternRoot = new SyntaxNode(); } //****************************************************** // Make sure the replace pattern is not null. SyntaxNode oReplacePatternRoot = oRuleItem.ReplacePatternRoot; if (oReplacePatternRoot == null) { oReplacePatternRoot = new SyntaxNode(); } //****************************************************** // Write the rule to the string. oRuleWriter.RuleName = oRuleItem.Text; oRuleWriter.FindPatternRoot = oFindPatternRoot; oRuleWriter.ReplacePatternRoot = oReplacePatternRoot; oRuleWriter.Write(); } } //************************************************************** // Close the RuleWriter. oRuleWriter.Close(); //************************************************************** // Copy the string to the clipboard. const bool bCopy = true; Clipboard.SetDataObject(oStringBuilder.ToString(),bCopy); }
//****************************************************************** /// <summary> /// Replaces the sub-tree dominated by the CurrentParseTreeNode, /// using the tree dominated by the ReplacePatternRoot as a pattern. /// Corresponding nodes (matched by a find-pattern node with the /// same label as the replace-pattern node) are copied from the /// MatchingNodes stack and their features are merged with features /// from the replace pattern. The replaced nodes in the new sub-tree /// are also stored in the ReplacedNodes stack. /// </summary> public void ReplaceCurrentMatchingBranch() { Debug.WriteLineIf(VerboseDebugging, "ReplaceAlgorithm.ReplaceCurrentMatchingBranch() called."); //************************************************************** // Validate the current state. if (ParseTreeRoot == null) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "ParseTreeRoot is null."; throw new Exception(sMessage); } if (MatchingNodes.Count < 1) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "MatchingNodes is empty."; throw new Exception(sMessage); } foreach (SyntaxNodePair oNodePair in MatchingNodes) { if (oNodePair.ParseTreeNode == null) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "MatchingNodes contains an item where " + ".ParseTreeNode is null."; throw new Exception(sMessage); } if (oNodePair.FindPatternNode == null) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "MatchingNodes contains an item where " + ".FindPatternNode is null."; throw new Exception(sMessage); } } if (ReplacedNodes.Count > 0) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "ReplacedNodes is not empty."; throw new Exception(sMessage); } if (CurrentParseTreeNode == null) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "CurrentParseTreeNode is null."; throw new Exception(sMessage); } //************************************************************** // Clear the ReplacedNodes list. ReplacedNodes.Clear(); //************************************************************** // If ReplacePatternRoot is null, use an empty SyntaxNode (one // with no features and no children) instead. SyntaxNode oReplacePatternRoot = ReplacePatternRoot; if (oReplacePatternRoot == null) { oReplacePatternRoot = new SyntaxNode(); } //************************************************************** // Use the oReplacePatternRoot and the MatchingNodes list to // create a new branch to replace the CurrentParseTreeNode. SyntaxNode oNewBranch = CopyNodeAndChildren(oReplacePatternRoot); //************************************************************** // BUGBUG: We may need to make another pass through the new // branch to: // // (1) copy features (or substrings) from another node using a // path <../DP/NP/featurename>. // // (2) recompute any feature values after other features have // changed (like changes to the word string because // morphology strings have changed). //************************************************************** // If the new branch is null, use an empty SyntaxNode (one with // no features and no children) instead, and add this to the // ReplacedNodes list. if (oNewBranch == null) { oNewBranch = new SyntaxNode(); SyntaxNodeTriple oNodeTriple = new SyntaxNodeTriple(); oNodeTriple.ParseTreeNode = oNewBranch; oNodeTriple.FindPatternNode = null; oNodeTriple.ReplacePatternNode = new SyntaxNode(); ReplacedNodes.Push(oNodeTriple); } Debug.Assert(ReplacedNodes.Count > 0); //************************************************************** // If the CurrentParseTreeNode has a parent node, find its // index in the parent's ChildNodes collection, and replace the // child at that index with the new branch. SyntaxNode oParent = CurrentParseTreeNode.ParentNode; if (oParent != null) { int iIndex = oParent.ChildNodes.IndexOf(CurrentParseTreeNode); oParent.ChildNodes.Insert(iIndex,oNewBranch); oParent.ChildNodes.Remove(CurrentParseTreeNode); } //************************************************************** // If the CurrentParseTreeNode is the same as the ParseTreeRoot, // replace the ParseTreeRoot with the new branch. if (CurrentParseTreeNode == ParseTreeRoot) { ParseTreeRoot = oNewBranch; } //************************************************************** // Set CurrentParseTreeNode to the new branch. CurrentParseTreeNode = oNewBranch; //************************************************************** // Dump the ReplacedNodes list for verbose debugging. if (VerboseDebugging) { foreach (SyntaxNodeTriple oNodeTriple in ReplacedNodes) { Debug.Assert(oNodeTriple.ParseTreeNode != null); Debug.Assert(oNodeTriple.ReplacePatternNode != null); } Debug.WriteLine("ReplacedNodes: " + ReplacedNodes.ToString() + "."); } Debug.WriteLineIf(VerboseDebugging, "ReplaceAlgorithm.ReplaceCurrentMatchingBranch() returns."); }
//****************************************************************** /// <summary> /// Copies the current selection to the clipboard. /// </summary> public void Copy() { //************************************************************** // Validate the current state. if (! CanCopy()) { string sMessage = "Invalid state: " + "A call to ParseListViewer.Copy() is not allowed " + "if ParseListViewer.CanCopy() returns false."; throw new Exception(sMessage); } //************************************************************** // Create a RuleWriter that writes to a string. StringBuilder oStringBuilder = new StringBuilder(); TextWriter oTextWriter = new StringWriter(oStringBuilder); RuleWriter oRuleWriter = new RuleWriter(oTextWriter); //************************************************************** // Write each selected parse to the string. foreach (ListViewItem oItem in moListView.Items) { //********************************************************** // Get the parse from the ListView item. Debug.Assert(oItem is ParseListViewerItem); ParseListViewerItem oParseItem = (ParseListViewerItem) oItem; //********************************************************** // If the item is selected, write the parse to the string. if (oParseItem.Selected) { //****************************************************** // Make sure the parse tree is not null. SyntaxNode oParseTreeRoot = oParseItem.ParseTreeRoot; if (oParseTreeRoot == null) { oParseTreeRoot = new SyntaxNode(); } //****************************************************** // Write the parse tree to the string. // // The parse tree is written in the format of a transfer // rule: the .RuleName is the item's displayed text, the // .FindPatternRoot is the parse tree, and the // .ReplacePatternRoot is null. oRuleWriter.RuleName = oParseItem.Text; oRuleWriter.FindPatternRoot = oParseTreeRoot; oRuleWriter.ReplacePatternRoot = null; oRuleWriter.Write(); } } //************************************************************** // Close the RuleWriter. oRuleWriter.Close(); //************************************************************** // Copy the string to the clipboard. const bool bCopy = true; Clipboard.SetDataObject(oStringBuilder.ToString(),bCopy); }
//****************************************************************** /// <summary> /// Creates a new parse-tree node. Features are copied from the /// given oParseTreeNode (if not null). Then features are merged /// from the given oReplacePatternNode (if not null). Returns the /// new parse-tree node. /// </summary> private SyntaxNode CopyFeatures(SyntaxNode oParseTreeNode, SyntaxNode oReplacePatternNode) { Debug.Assert((oParseTreeNode != null) || (oReplacePatternNode != null)); //************************************************************** // Create a new SyntaxNode. SyntaxNode oNewNode = new SyntaxNode(); //************************************************************** // Copy all the features from oParseTreeNode (if not null). if (oParseTreeNode != null) { foreach (SyntaxFeature oFeature in oParseTreeNode.Features) { oNewNode.Features[oFeature.Name] = oFeature.Value; } } //************************************************************** // Merge the features from oReplacePatternNode (if not null): // // Copy each feature from oReplacePatternNode, except for the // node-label feature. (Copied features will replace existing // features with the same name.) // // If a feature from oReplacePatternNode has the delete-feature // string for its value, delete the feature from the new node. if (oReplacePatternNode != null) { foreach (SyntaxFeature oFeature in oReplacePatternNode.Features) { if (oFeature.Name != TreeTranEngineString.NodeLabel) { oNewNode.Features[oFeature.Name] = oFeature.Value; } if (oFeature.Value == TreeTranEngineString.DeleteFeature) { oNewNode.Features.Remove(oFeature.Name); } } } //************************************************************** // Return the new SyntaxNode. return oNewNode; }
//****************************************************************** /// <summary> /// Saves the displayed parses to the indicated parse file /// (sFileName). The Modified property is set to false after the /// file is saved. /// </summary> public void SaveParseFile(string sFileName) { //************************************************************** // Validate the parameters. if ((sFileName == null) || (sFileName == "")) { string sMessage = "Invalid argument: " + "ParseListViewer.SaveParseFile() requires " + "a file name that is not null or blank."; throw new Exception(sMessage); } //************************************************************** // Create a ParseWriter to write to the indicated parse file. StreamWriter oStreamWriter = new StreamWriter(sFileName); ParseWriter oParseWriter = new ParseWriter(oStreamWriter); //************************************************************** // For each item in the ListView, write the parse to the file. foreach (ListViewItem oItem in moListView.Items) { //********************************************************** // Get the parse from the ListView item. Debug.Assert(oItem is ParseListViewerItem); ParseListViewerItem oParseItem = (ParseListViewerItem) oItem; //********************************************************** // Make sure the parse tree is not null. SyntaxNode oParseTreeRoot = oParseItem.ParseTreeRoot; if (oParseTreeRoot == null) { oParseTreeRoot = new SyntaxNode(); } //********************************************************** // Write the parse tree to the file. oParseWriter.ParseTreeRoot = oParseTreeRoot; oParseWriter.Write(); } //************************************************************** // Close the ParseWriter. oParseWriter.Close(); //************************************************************** // Set the Modified property to false. Modified = false; }
//****************************************************************** /// <summary> /// For the given oReplacePatternNode, this method finds the /// corresponding find-pattern node and the parse-tree node it /// matched. (The parse-tree node must be in the branch indicated by /// oMorphologyParseRoot if this optional argument is not null.) A /// new node is created by copying features from the parse-tree node /// and merging features from the oReplacePatternNode. Then children /// are copied recursively either from the parse-tree node or from /// the oReplacePatternNode. Returns null if the oReplacePatternNode /// was optional and the parse-tree node was not found. Otherwise, /// returns the new node after adding it to the ReplacedNodes list. /// (Note that this method calls the CopyLeafAndChildren() method if /// it determines that the node is a leaf node.) /// </summary> SyntaxNode CopyNodeAndChildren(SyntaxNode oReplacePatternNode) { return CopyNodeAndChildren(oReplacePatternNode,null); }
//****************************************************************** /// <summary> /// Copies the selected features from the ListView to the clipboard. /// </summary> private void CopySelectedFeatures() { //************************************************************** // Create a SyntaxNode and set its features by copying the // selected feature names and values from the ListView. // // (Do not copy blank features, which can appear when the // show-all-favorites option is checked.) SyntaxNode oNode = new SyntaxNode(); foreach (ListViewItem oItem in moListView.SelectedItems) { string sName = oItem.SubItems[moNameColumn.Index].Text; string sValue = oItem.SubItems[moValueColumn.Index].Text; if ((sName != "") && (sValue != "")) { oNode.Features[sName] = sValue; } } //************************************************************** // Create a RuleWriter that writes to a string. StringBuilder oStringBuilder = new StringBuilder(); TextWriter oTextWriter = new StringWriter(oStringBuilder); RuleWriter oRuleWriter = new RuleWriter(oTextWriter); //************************************************************** // Make a rule that uses the SyntaxNode with the selected // features as its find pattern (and has an empty replace // pattern). oRuleWriter.RuleName = "(tree fragment on clipboard)"; oRuleWriter.FindPatternRoot = oNode; oRuleWriter.ReplacePatternRoot = null; //************************************************************** // Write the rule to the string. oRuleWriter.Write(); //************************************************************** // Close the RuleWriter. oRuleWriter.Close(); //************************************************************** // Copy the string to the clipboard. const bool bCopy = true; Clipboard.SetDataObject(oStringBuilder.ToString(),bCopy); }
//****************************************************************** /// <summary> /// Searches the MatchingNodes list for a node pair where the /// .FindPatternNode label matches the given sLabel string. If the /// optional oMorphologyParseRoot argument is not null, the search /// is restricted to node pairs where the .ParseTreeNode is /// contained in the branch dominated by the oMorphologyParseRoot /// node. Returns the first matching node pair, if a match is found. /// Returns null otherwise. /// </summary> private SyntaxNodePair FindMatchingPairFromLabel(string sLabel, SyntaxNode oMorphologyParseRoot) { Debug.Assert(sLabel != null); //************************************************************** // Check if a oMorphologyParseRoot is specified. if (oMorphologyParseRoot != null) { //********************************************************** // If a oMorphologyParseRoot is specified, search the // MatchingNodes list for a node pair where the // .FindPatternNode label matches the sLabel string and the // .ParseTreeNode is contained in the parse-tree branch // dominated by oMorphologyParseRoot. Return the (first) // matching node pair if found. foreach (SyntaxNodePair oPair in MatchingNodes) { Debug.Assert(oPair.ParseTreeNode != null); Debug.Assert(oPair.FindPatternNode != null); if (oPair.FindPatternNode.Label == sLabel) { if (BranchContainsNode(oMorphologyParseRoot, oPair.ParseTreeNode)) { return oPair; } } } } else { //********************************************************** // Otherwise, search the MatchingNodes list for any node // pair where the .FindPatternNode label matches the sLabel // string. Return the (first) matching node pair if found. foreach (SyntaxNodePair oPair in MatchingNodes) { Debug.Assert(oPair.ParseTreeNode != null); Debug.Assert(oPair.FindPatternNode != null); if (oPair.FindPatternNode.Label == sLabel) { return oPair; } } } //************************************************************** // Return null if a match was not found. return null; }
//****************************************************************** /// <summary> /// Displays the Features form so the user can view and edit the /// features of the given SyntaxNode. The user can also modify the /// FavoriteListFeatures, FavoriteTreeFeatures and CopyFavoritesOnly /// settings. If the user clicks OK, the edits are saved to the /// SyntaxNode features, changes are saved to the settings, and /// DialogResult.OK is returned. Otherwise, DialogResult.Cancel is /// returned and any changes are discarded. /// </summary> public static DialogResult OpenFeatures(SyntaxNode oNode) { //************************************************************** // Validate the parameters. if (oNode == null) { string sMessage = "Invalid argument: " + "FeaturesForm.OpenFeatures() requires " + "a SyntaxNode object that is not null."; throw new Exception(sMessage); } //************************************************************** // Create an instance of the FeaturesForm. FeaturesForm oForm = new FeaturesForm(); //************************************************************** // Set the form's ReadOnly property to false. oForm.ReadOnly = false; //************************************************************** // Set the form's DisplayedNode property to a copy of the node // specified by the oNode parameter. oForm.DisplayedNode = oNode.CloneNode(); //************************************************************** // Show the form so the user can view and edit the features of // the DisplayedNode. DialogResult iResult = oForm.ShowDialog(); //************************************************************** // If the user clicked OK, save the changes that the user made // to the features: // // Update the specified oNode by clearing its features and then // copying all the features from the form's DisplayedNode to the // oNode.Features collection. if (iResult == DialogResult.OK) { oNode.Features.Clear(); foreach (SyntaxFeature oFeature in oForm.DisplayedNode.Features) { oNode.Features[oFeature.Name] = oFeature.Value; } } //************************************************************** // Return the dialog result. return iResult; }
//****************************************************************** /// <summary> /// Recursively traverses the indicated branch (dominiated by oNode) /// of the find-pattern tree or replace-pattern tree, writing the /// nodes and their features. /// </summary> private void WriteNode(SyntaxNode oNode) { //************************************************************** // Write the opening <Node> tag: // // <Node> Writer.WriteStartElement(RuleXml.NodeElement); //************************************************************** // Write the node features. foreach (SyntaxFeature oFeature in oNode.Features) { //************************************************************** // Write the <Feature> tag: // // <Feature name="..." value="..." /> // // The "name" attribute represents the feature Name. // // The "value" attribute represents the feature Value. Writer.WriteStartElement(RuleXml.FeatureElement); Writer.WriteAttributeString(RuleXml.NameAttribute, oFeature.Name); Writer.WriteAttributeString(RuleXml.ValueAttribute, oFeature.Value); Writer.WriteEndElement(); } //************************************************************** // Write the child nodes. foreach (SyntaxNode oChild in oNode.ChildNodes) { WriteNode(oChild); } //************************************************************** // Write the closing <Node> tag: // // </Node> Writer.WriteEndElement(); }
//****************************************************************** #region [FindNextMatchingBranch() Method] //****************************************************************** /// <summary> /// Moves the CurrentParseTreeNode forward in the parse tree, until /// the sub-tree dominated by this node matches the pattern /// dominated by FindPatternRoot. If CurrentParseTreeNode is null /// when this method is called, the search starts with the first /// node in the parse tree. Otherwise, the search continues with the /// next node in the tree. If a matching sub-tree is found, true is /// returned and the MatchingNodes stack contains the list of /// matching node pairs. If no match is found, CurrentParseTreeNode /// is set to null and false is returned. /// </summary> public bool FindNextMatchingBranch() { Debug.WriteLineIf(VerboseDebugging, "FindAlgorithm.FindNextMatchingBranch() called."); //************************************************************** // Validate the current state. if (CurrentParseTreeNode != null) { SyntaxNode oNode = CurrentParseTreeNode; while (oNode != ParseTreeRoot) { if (oNode.ParentNode == null) { string sMessage = "FindNextMatchingBranch() " + "called with an invalid state: " + "the ParseTreeRoot tree does not contain " + "the CurrentParseTreeNode."; throw new Exception(sMessage); } oNode = oNode.ParentNode; } } //************************************************************** // Clear the lists of MatchingNodes and ReplacedNodes. MatchingNodes.Clear(); ReplacedNodes.Clear(); //************************************************************** // Save the previous value of the CurrentParseTreeNode. SyntaxNode oPreviousParseTreeNode = CurrentParseTreeNode; //************************************************************** // Move the CurrentParseTreeNode to the next branch to compare: // // If CurrentParseTreeNode is null, start with the first // parse-tree node in post order. // // Otherwise, move to the next node in post order. // // Note: The parse tree is traversed in post-order (parent after // its children) to prevent infinite recursion that could occur // if an XP node was replaced by a node with XP children, and // then the rule was applied recursively to these children. if (CurrentParseTreeNode == null) { CurrentParseTreeNode = GetFirstNodeInPostOrder(ParseTreeRoot); } else { CurrentParseTreeNode = GetNextNodeInPostOrder(CurrentParseTreeNode); } //************************************************************** // Check if the previous branch should be deleted. // // When the ReplaceCurrentMatchingBranch() method needs to // delete the current parse-tree node, it sets it to an empty // node (one with no features and no children) instead. This is // so we can use the current parse-tree node to determine where // to find the next node to compare. // // If the previous branch is an empty node (with no features and // no children), delete it. if (oPreviousParseTreeNode != null) { if ((oPreviousParseTreeNode.Features.Count == 0) && (oPreviousParseTreeNode.ChildNodes.Count == 0)) { //****************************************************** // Remove the empty node from its parent's ChildNodes // collection. If the empty node is the same as the // ParseTreeRoot, set the ParseTreeRoot to null. SyntaxNode oParent = oPreviousParseTreeNode.ParentNode; if (oParent != null) { oParent.ChildNodes.Remove(oPreviousParseTreeNode); } if (oPreviousParseTreeNode == ParseTreeRoot) { ParseTreeRoot = null; } } } //************************************************************** // If FindPatternRoot is null, nothing can match this pattern. // In this case, set CurrentParseTreeNode to null so there will // be no comparisons and false will be returned. if (FindPatternRoot == null) { CurrentParseTreeNode = null; } //************************************************************** // Traverse the parse tree (in post order), looking for a match, // until there are no more nodes to traverse. Return true if a // match is found. while (CurrentParseTreeNode != null) { //********************************************************** // Return true if the current branch matches the pattern. if (CurrentBranchMatchesPattern()) { Debug.Assert(MatchingNodes.Count > 0); Debug.Assert(ReplacedNodes.Count == 0); Debug.Assert(CurrentParseTreeNode != null); Debug.WriteLineIf(VerboseDebugging, "FindAlgorithm.FindNextMatchingBranch() returns " + "true."); return(true); } //********************************************************** // Move to the next node in post order. CurrentParseTreeNode = GetNextNodeInPostOrder(CurrentParseTreeNode); } //************************************************************** // A matching branch was not found, so return false. Debug.Assert(MatchingNodes.Count == 0); Debug.Assert(ReplacedNodes.Count == 0); Debug.Assert(CurrentParseTreeNode == null); Debug.WriteLineIf(VerboseDebugging, "FindAlgorithm.FindNextMatchingBranch() returns false."); return(false); }