public static function createFromItems(array $items, Grammar $grammar): self
    {
        $final_items = [];
        $new_items = $items;
        /** @var Symbol $known_next_symbols */
        $known_next_symbols = [];
        while ($new_items) {
            /** @var Symbol $next_symbols */
            $next_symbols = [];
            foreach ($new_items as $new_item) {
                foreach ($final_items as $item) {
                    if (0 === Item::compare($item, $new_item)) {
                        goto NEXT_NEW_ITEM;
                    }
                }
                $final_items[] = $new_item;

                $next_symbol = $new_item->getExpected();
                if (!$next_symbol || $next_symbol->isTerminal()) {
                    continue;
                }
                $name = $next_symbol->getName();
                if (isset($known_next_symbols[$name])) {
                    continue;
                }
                $next_symbols[$name] = $next_symbol;

                NEXT_NEW_ITEM:
            }

            $known_next_symbols += $next_symbols;

            $new_items = [];

            foreach ($next_symbols as $next_symbol) {
                $rules = $grammar->getRulesFor($next_symbol);
                foreach ($rules as $rule) {
                    $new_items[] = Item::createFromRule($rule);
                }
            }
        }

        return new static($final_items, $items, $grammar);
    }