private void ComputeLr0ItemSetKernelsAndGotoLookup(out LrItemSetCollection itemSets, out Dictionary <int, Dictionary <SymbolId, int> > gotos, out int acceptIndex)
        {
            itemSets = new LrItemSetCollection();
            gotos    = new Dictionary <int, Dictionary <SymbolId, int> >();
            var itemSetByKernels = new Dictionary <IEnumerable <LrItem>, LrItemSet>(SetEqualityComparer <LrItem> .Default);
            var queue            = new Queue <LrItemSet>();
            var startItem        = new LrItemSet(new LrItem(this.ProductionRulesBySymbol[this.Init].Single(), 0, true));

            this.Lr0ComputeClosureNonterminals(startItem);
            itemSets.StartState = startItem;
            acceptIndex         = this.ProductionRulesBySymbol[this.Init].Single().Index;
            startItem.Index     = itemSets.Count;
            itemSets.Add(startItem);
            itemSetByKernels.Add(startItem.Kernels.ToArray(), startItem);
            queue.Enqueue(startItem);
            while (queue.Count > 0)
            {
                var itemSet       = queue.Dequeue();
                var gotoLookup    = this.Lr0GotoKernels(itemSet);
                var gotosForState = new Dictionary <SymbolId, int>();
                gotos.Add(itemSet.Index, gotosForState);
                foreach (var symbol in gotoLookup.Keys)
                {
                    if (!itemSetByKernels.TryGetValue(gotoLookup[symbol].Kernels, out var gotoState))
                    {
                        gotoState = gotoLookup[symbol];
                        this.Lr0ComputeClosureNonterminals(gotoState);
                        gotoState.Index = itemSets.Count;
                        itemSets.Add(gotoState);
                        itemSetByKernels.Add(gotoState.Kernels.ToArray(), gotoState);
                        queue.Enqueue(gotoState);
                    }
                    gotosForState.Add(symbol, gotoState.Index);
                }
            }
        }
        private Dictionary <StateKey <SymbolId>, int> ComputeGotoLookup(SymbolMetaDictionary symbolMeta, LrItemSetCollection itemSets)
        {
            var gotos            = new Dictionary <StateKey <SymbolId>, int>();
            var itemSetByKernels = itemSets.ToDictionary(s => s.Kernels.ToArray(), s => s, SetEqualityComparer <LrItem> .Default);

            foreach (var itemSet in itemSets)
            {
                foreach (var sym in symbolMeta.Keys)
                {
                    // Compute dynamic GOTO
                    var gotoClosure = this.Lr1Closure(symbolMeta, new LrItemSet(itemSet
                                                                                .Where(item => (item.Marker < item.Length) && item.Rule.RuleSymbolIds[item.Marker].Equals(sym))
                                                                                .Select(item => new LrItem(item.Rule, item.Marker + 1, true))));
                    if (!gotoClosure.Any())
                    {
                        continue;
                    }
                    var key = new StateKey <SymbolId>(itemSet.Index, sym);
                    if (gotos.ContainsKey(key))
                    {
                        continue;
                    }
                    // Match the dynamic GOTO to an actual state
                    if (itemSetByKernels.TryGetValue(gotoClosure.Kernels, out var existingGoto))
                    {
                        gotos.Add(key, existingGoto.Index);
                    }
                }
            }
            return(gotos);
        }