private function compileNode(
        bool $isCompilingHostTrie,
        TrieNode $currTrieNode,
        AstNode $ast,
        Route $route,
        ?TrieNode $hostTrie
    ): void {
        $astChildren = $ast->children;
        $numAstChildren = \count($astChildren);
        $isEndpoint = false;
        $segmentContainsVariable = false;
        $segmentBuffer = [];

        foreach ($isCompilingHostTrie ? \array_reverse($astChildren) : $astChildren as $i => $childAstNode) {
            /**
             * This isn't an endpoint if we're compiling a path trie which has a host trie
             * This is an endpoint if it's the last node or the last non-optional node
             */
            $isEndpoint = $isEndpoint
                || (
                    ($isCompilingHostTrie || $hostTrie === null)
                    && (
                        $i === $numAstChildren - 1
                        || $childAstNode->type === AstNodeTypes::OPTIONAL_ROUTE_PART
                        || ($astChildren[$i + 1]->type === AstNodeTypes::OPTIONAL_ROUTE_PART)
                    )
                );

            switch ($childAstNode->type) {
                case AstNodeTypes::SEGMENT_DELIMITER:
                    // Checking if this is an endpoint handles the case of a route at the root path
                    if ($isEndpoint || \count($segmentBuffer) > 0) {
                        $newTrieNode = self::createTrieNode(
                            $segmentBuffer,
                            $segmentContainsVariable,
                            $isEndpoint,
                            $route,
                            $hostTrie
                        );
                        $currTrieNode->addChild($newTrieNode);
                        $currTrieNode = $newTrieNode;
                    }

                    break;
                case AstNodeTypes::OPTIONAL_ROUTE_PART:
                    // Handles flushing 'foo' in the case of 'foo[/bar]'
                    if (\count($segmentBuffer) > 0) {
                        $newTrieNode = self::createTrieNode(
                            $segmentBuffer,
                            $segmentContainsVariable,
                            $isEndpoint,
                            $route,
                            $hostTrie
                        );
                        $currTrieNode->addChild($newTrieNode);
                        $currTrieNode = $newTrieNode;
                    }

                    $this->compileNode($isCompilingHostTrie, $currTrieNode, $childAstNode, $route, $hostTrie);
                    break;
                case AstNodeTypes::TEXT:
                    $segmentBuffer[] = $childAstNode->value;
                    break;
                case AstNodeTypes::VARIABLE:
                    $segmentContainsVariable = true;
                    $segmentBuffer[] = $this->compileVariableNode($childAstNode);
                    break;
                default:
                    throw new InvalidArgumentException("Unexpected node type {$childAstNode->type}");
            }
        }

        // Check if we need to flush the buffer
        if (\count($segmentBuffer) > 0) {
            $currTrieNode->addChild(
                self::createTrieNode($segmentBuffer, $segmentContainsVariable, $isEndpoint, $route, $hostTrie)
            );
        }
    }
private function compileNode(
        bool $isCompilingHostTrie,
        TrieNode $currTrieNode,
        AstNode $ast,
        Route $route,
        ?TrieNode $hostTrie
    ): void {
        $astChildren = $ast->children;
        $numAstChildren = \count($astChildren);
        $isEndpoint = false;
        $segmentContainsVariable = false;
        $segmentBuffer = [];

        foreach ($isCompilingHostTrie ? \array_reverse($astChildren) : $astChildren as $i => $childAstNode) {
            /**
             * This isn't an endpoint if we're compiling a path trie which has a host trie
             * This is an endpoint if it's the last node or the last non-optional node
             */
            $isEndpoint = $isEndpoint
                || (
                    ($isCompilingHostTrie || $hostTrie === null)
                    && (
                        $i === $numAstChildren - 1
                        || $childAstNode->type === AstNodeTypes::OPTIONAL_ROUTE_PART
                        || ($astChildren[$i + 1]->type === AstNodeTypes::OPTIONAL_ROUTE_PART)
                    )
                );

            switch ($childAstNode->type) {
                case AstNodeTypes::SEGMENT_DELIMITER:
                    // Checking if this is an endpoint handles the case of a route at the root path
                    if ($isEndpoint || \count($segmentBuffer) > 0) {
                        $newTrieNode = self::createTrieNode(
                            $segmentBuffer,
                            $segmentContainsVariable,
                            $isEndpoint,
                            $route,
                            $hostTrie
                        );
                        $currTrieNode->addChild($newTrieNode);
                        $currTrieNode = $newTrieNode;
                    }

                    break;
                case AstNodeTypes::OPTIONAL_ROUTE_PART:
                    // Handles flushing 'foo' in the case of 'foo[/bar]'
                    if (\count($segmentBuffer) > 0) {
                        $newTrieNode = self::createTrieNode(
                            $segmentBuffer,
                            $segmentContainsVariable,
                            $isEndpoint,
                            $route,
                            $hostTrie
                        );
                        $currTrieNode->addChild($newTrieNode);
                        $currTrieNode = $newTrieNode;
                    }

                    $this->compileNode($isCompilingHostTrie, $currTrieNode, $childAstNode, $route, $hostTrie);
                    break;
                case AstNodeTypes::TEXT:
                    $segmentBuffer[] = $childAstNode->value;
                    break;
                case AstNodeTypes::VARIABLE:
                    $segmentContainsVariable = true;
                    $segmentBuffer[] = $this->compileVariableNode($childAstNode);
                    break;
                default:
                    throw new InvalidArgumentException("Unexpected node type {$childAstNode->type}");
            }
        }

        // Check if we need to flush the buffer
        if (\count($segmentBuffer) > 0) {
            $currTrieNode->addChild(
                self::createTrieNode($segmentBuffer, $segmentContainsVariable, $isEndpoint, $route, $hostTrie)
            );
        }
    }
private function compileNode ( bool $ isCompilingHostTrie , TrieNode $ currTrieNode , AstNode $ ast , Route $ route , ? TrieNode $ hostTrie ) : void { $ astChildren = $ ast -> children ; $ numAstChildren = \ count ( $ astChildren ) ; $ isEndpoint = false ; $ segmentContainsVariable = false ; $ segmentBuffer = [ ] ; foreach ( $ isCompilingHostTrie ? \ array_reverse ( $ astChildren ) : $ astChildren as $ i => $ childAstNode ) { /**
             * This isn't an endpoint if we're compiling a path trie which has a host trie
             * This is an endpoint if it's the last node or the last non-optional node
             */ $ isEndpoint = $ isEndpoint || ( ( $ isCompilingHostTrie || $ hostTrie === null ) && ( $ i === $ numAstChildren - 1 || $ childAstNode -> type === AstNodeTypes :: OPTIONAL_ROUTE_PART || ( $ astChildren [ $ i + 1 ] -> type === AstNodeTypes :: OPTIONAL_ROUTE_PART ) ) ) ; switch ( $ childAstNode -> type ) { case AstNodeTypes :: SEGMENT_DELIMITER : // Checking if this is an endpoint handles the case of a route at the root path if ( $ isEndpoint || \ count ( $ segmentBuffer ) > 0 ) { $ newTrieNode = self :: createTrieNode ( $ segmentBuffer , $ segmentContainsVariable , $ isEndpoint , $ route , $ hostTrie ) ; $ currTrieNode -> addChild ( $ newTrieNode ) ; $ currTrieNode = $ newTrieNode ; } break ; case AstNodeTypes :: OPTIONAL_ROUTE_PART : // Handles flushing 'foo' in the case of 'foo[/bar]' if ( \ count ( $ segmentBuffer ) > 0 ) { $ newTrieNode = self :: createTrieNode ( $ segmentBuffer , $ segmentContainsVariable , $ isEndpoint , $ route , $ hostTrie ) ; $ currTrieNode -> addChild ( $ newTrieNode ) ; $ currTrieNode = $ newTrieNode ; } $ this -> compileNode ( $ isCompilingHostTrie , $ currTrieNode , $ childAstNode , $ route , $ hostTrie ) ; break ; case AstNodeTypes :: TEXT : $ segmentBuffer [ ] = $ childAstNode -> value ; break ; case AstNodeTypes :: VARIABLE : $ segmentContainsVariable = true ; $ segmentBuffer [ ] = $ this -> compileVariableNode ( $ childAstNode ) ; break ; default : throw new InvalidArgumentException ( "Unexpected node type {$childAstNode->type}" ) ; } } // Check if we need to flush the buffer if ( \ count ( $ segmentBuffer ) > 0 ) { $ currTrieNode -> addChild ( self :: createTrieNode ( $ segmentBuffer , $ segmentContainsVariable , $ isEndpoint , $ route , $ hostTrie ) ) ; } }
Creates a new node

@param bool $isCompilingHostTrie Whether or not we're compiling a host trie
@param TrieNode $currTrieNode The current node
@param AstNode $ast The current AST node
@param Route $route The current route
@param TrieNode|null $hostTrie The host trie if one should be included, otherwise null
Creates a new node