private TItemState ComputeClosure(TItemState itemState)
            {
                List <TransRule> rules     = parent.rules;
                HashSet <TItem>  closure   = new HashSet <TItem>(itemState.stateItems);
                Queue <TItem>    closeless = new Queue <TItem>(itemState.stateItems);

                while (closeless.Count != 0)
                {
                    TItem item = closeless.Dequeue();
                    if (rules[item.ruleNum].body.Count == item.dotPos)
                    {
                        continue;
                    }

                    TransToken nextToken = rules[item.ruleNum].body[item.dotPos];
                    for (int i = 0; i < rules.Count; ++i)
                    {
                        if (nextToken.token != rules[i].head.token)
                        {
                            continue;
                        }
                        TItem newItem = new TItem(i, 0);

                        if (closure.Add(newItem))
                        {
                            closeless.Enqueue(newItem);
                        }
                    }
                }

                return(new TItemState(closure));
            }
            private HashSet <TItemState> FindAllStates()
            {
                var allTokens = new HashSet <TransToken> {
                };

                allTokens.UnionWith(parent.nonterms);
                allTokens.UnionWith(parent.terms);

                var foundStates         = new HashSet <TItemState> {
                };
                var transitionlessItems = new Queue <TItemState> {
                };
                int stateIdCounter      = 0;

                // Didn't want to create a variable for one time use
                // So, created a variable with reuseable name
                // These three lines add initial state kernel [S' -> .S]
                // anNtYWNoaW5lcy5zb3VyY2Vmb3JnZS5uZXQ=
                TItemState kernelState = new TItemState(new TItem(0, 0));

                kernelState.stateId = stateIdCounter++;
                foundStates.Add(kernelState);
                transitionlessItems.Enqueue(kernelState);

                while (transitionlessItems.Count != 0)
                {
                    kernelState = transitionlessItems.Dequeue();
                    TItemState kernelClosure = ComputeClosure(kernelState);

                    foreach (TransToken token in allTokens)
                    {
                        TItemState newState = Goto(kernelClosure, token);
                        if (newState.stateItems.Count == 0)
                        {
                            continue;
                        }
                        kernelState.transitions[token] = newState;

                        bool f**k = foundStates.Contains(newState);
                        int  ass  = newState.GetHashCode();
                        if (foundStates.TryGetValue(newState, out var oldState))
                        {
                            kernelState.transitions[token] = oldState;
                        }
                        else
                        {
                            newState.stateId = stateIdCounter++;
                            foundStates.Add(newState);
                            transitionlessItems.Enqueue(newState);
                        }
                    }
                }

                return(foundStates);
            }
                public override bool Equals(object obj)
                {
                    if (!(obj is TItemState))
                    {
                        return(false);
                    }

                    TItemState other = (TItemState)obj;

                    if (this.stateItems.SetEquals(other.stateItems))
                    {
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
            private TItemState Goto(TItemState itemState, TransToken nextTerm)
            {
                HashSet <TItem> resultingSet = new HashSet <TItem> {
                };

                foreach (TItem item in itemState.stateItems)
                {
                    TransRule rule = parent.rules[item.ruleNum];
                    if (rule.body.Count == item.dotPos)
                    {
                        continue;
                    }

                    if (rule.body[item.dotPos].token == nextTerm.token)
                    {
                        resultingSet.Add(new TItem(item.ruleNum, item.dotPos + 1));
                    }
                }

                return(new TItemState(resultingSet));
            }