/// <summary> /// Creates a node representing the concatenation of the languages described by a given pair of nodes. /// </summary> /// <param name="node1">The first node.</param> /// <param name="node2">The second node.</param> /// <returns>The created node.</returns> public static RegexpTreeNode <TElement, TElementSet> Concat(RegexpTreeNode <TElement, TElementSet> node1, RegexpTreeNode <TElement, TElementSet> node2) { Argument.CheckIfNotNull(node1, "node1"); Argument.CheckIfNotNull(node2, "node2"); if (node1.Type == RegexpTreeNodeType.Nothing || node2.Type == RegexpTreeNodeType.Nothing) { // Concatenation with an empty language results in an empty language return(Nothing()); } if (node1.Type == RegexpTreeNodeType.Empty) { // Concatenation with an empty string is an identity return(node2); } if (node2.Type == RegexpTreeNodeType.Empty) { // Concatenation with an empty string is an identity return(node1); } var result = new RegexpTreeNode <TElement, TElementSet> { Type = RegexpTreeNodeType.Concat }; result.children.Capacity = 2; result.children.Add(node1); result.children.Add(node2); return(result); }
/// <summary> /// Creates a node representing the union of the languages described by a given pair of nodes. /// </summary> /// <param name="node1">The first node.</param> /// <param name="node2">The second node.</param> /// <returns>The created node.</returns> public static RegexpTreeNode <TElement, TElementSet> Or(RegexpTreeNode <TElement, TElementSet> node1, RegexpTreeNode <TElement, TElementSet> node2) { Argument.CheckIfNotNull(node1, "node1"); Argument.CheckIfNotNull(node2, "node2"); if (node1.Type == RegexpTreeNodeType.Empty && node2.Type == RegexpTreeNodeType.Empty) { // Identical children return(node1); } if (node1.Type == RegexpTreeNodeType.Nothing) { // Union with an empty language is an identity return(node2); } if (node2.Type == RegexpTreeNodeType.Nothing) { // Union with an empty language is an identity return(node1); } var result = new RegexpTreeNode <TElement, TElementSet> { Type = RegexpTreeNodeType.Union }; result.children.Capacity = 2; result.children.Add(node1); result.children.Add(node2); return(result); }
/// <summary> /// Copies the state of this node from another node. /// </summary> /// <param name="other">The node to copy the state from.</param> private void SetTo(RegexpTreeNode <TElement, TElementSet> other) { Debug.Assert(other != null, "A valid node must be provided."); this.Type = other.Type; this.elementSet = other.elementSet; this.children.Clear(); this.children.AddRange(other.children); this.simplified = other.simplified; this.toStringVerboseCached = other.toStringVerboseCached; }
/// <summary> /// Simplifies a node representing Kleene star. /// </summary> private void SimplifyStar() { Debug.Assert(this.Type == RegexpTreeNodeType.Star, "Must be run for Kleene star nodes only."); Debug.Assert(this.children.Count == 1, "A Kleene star node must have a single child."); //// The simplification can affect the node itself, but not its children //// since children are shared by multiple parents. RegexpTreeNode <TElement, TElementSet> child = this.children[0]; switch (child.Type) { case RegexpTreeNodeType.Empty: case RegexpTreeNodeType.Nothing: case RegexpTreeNodeType.Star: Debug.Fail("Should have been optimized away."); break; case RegexpTreeNodeType.Union: // 'Star' accepts the empty string anyway, no need to provide it as an alternative if (child.children.Any(c => c.Type == RegexpTreeNodeType.Empty)) { List <RegexpTreeNode <TElement, TElementSet> > nonEmptyUnionChildren = child.children.Where(c => c.Type != RegexpTreeNodeType.Empty).ToList(); if (nonEmptyUnionChildren.Count == 0) { // Empty only this.SetTo(RegexpTreeNode <TElement, TElementSet> .Empty()); } else if (nonEmptyUnionChildren.Count == 1) { this.children.Clear(); this.children.AddRange(nonEmptyUnionChildren); Debug.Assert(this.children.Count == 1, "There must be only one such node."); } else { // Can't modify child's children, so create a new node this.children.Clear(); var newUnionNode = new RegexpTreeNode <TElement, TElementSet> { Type = RegexpTreeNodeType.Union, children = nonEmptyUnionChildren, simplified = true }; this.children.Add(newUnionNode); } } break; } }
/// <summary> /// Creates a node representing the Kleene star of the language described by a given node. /// </summary> /// <param name="node">The node.</param> /// <returns>The created node.</returns> public static RegexpTreeNode <TElement, TElementSet> Star(RegexpTreeNode <TElement, TElementSet> node) { Argument.CheckIfNotNull(node, "node"); if (node.Type == RegexpTreeNodeType.Nothing || node.Type == RegexpTreeNodeType.Empty || node.Type == RegexpTreeNodeType.Star) { // In all these cases star doesn't affect its argument return(node); } var result = new RegexpTreeNode <TElement, TElementSet> { Type = RegexpTreeNodeType.Star }; result.children.Capacity = 1; result.children.Add(node); return(result); }