<?php

declare (strict_types=1);
namespace OCA\Talk\Vendor\CuyZ\Valinor\Type\Parser\Lexer\Token;

use OCA\Talk\Vendor\CuyZ\Valinor\Type\Parser\Exception\Iterable\ListClosingBracketMissing;
use OCA\Talk\Vendor\CuyZ\Valinor\Type\Parser\Exception\Iterable\ListMissingSubType;
use OCA\Talk\Vendor\CuyZ\Valinor\Type\Parser\Lexer\TokenStream;
use OCA\Talk\Vendor\CuyZ\Valinor\Type\Type;
use OCA\Talk\Vendor\CuyZ\Valinor\Type\Types\ListType;
use OCA\Talk\Vendor\CuyZ\Valinor\Type\Types\NonEmptyListType;
/** @internal */
final class ListToken implements TraversingToken
{
    private static self $list;
    private static self $nonEmptyList;
    private function __construct(
        /** @var class-string<ListType|NonEmptyListType> */
        private string $listType,
        private string $symbol
    )
    {
    }
    public static function list(): self
    {
        return self::$list ??= new self(ListType::class, 'list');
    }
    public static function nonEmptyList(): self
    {
        return self::$nonEmptyList ??= new self(NonEmptyListType::class, 'non-empty-list');
    }
    public function traverse(TokenStream $stream): Type
    {
        if (!$stream->done() && $stream->next() instanceof OpeningBracketToken) {
            $stream->forward();
            if ($stream->done()) {
                throw new ListMissingSubType($this->symbol);
            }
            $subType = $stream->read();
            $listType = new $this->listType($subType);
            if ($stream->done() || !$stream->forward() instanceof ClosingBracketToken) {
                throw new ListClosingBracketMissing($listType);
            }
            return $listType;
        }
        return $this->listType::native();
    }
    public function symbol(): string
    {
        return $this->symbol;
    }
}