src/Leevel/View/Parser.php
protected function packNode(string &$compiled): void
    {
        if (true === $this->jsNode) {
            $nodeTag = $this->compiler->getJsTagHelp();
            $compiler = 'Js';
        } else {
            $nodeTag = $this->compiler->getNodeTagHelp();
            $compiler = 'Node';
        }

        // 尾标签栈
        $tailStack = new Stack(['array']);

        // 载入节点属性分析器 & 依次处理所有标签
        while (null !== ($tag = $this->nodeStack->out())) {
            // 尾标签，加入到尾标签中
            if ('tail' === $tag['type']) {
                $tailStack->in($tag);

                continue;
            }

            // 从尾标签栈取出一项
            $tailTag = $tailStack->out();

            // 单标签节点
            if (!$tailTag or !$this->findHeadTag($tag, $tailTag)) {
                if (true !== $nodeTag[$tag['name']]['single']) {
                    throw new InvalidArgumentException(
                        sprintf(
                            '%s type nodes must be used in pairs, and no corresponding tail tags are found.',
                            $tag['name']
                        ).
                        '<br />'.
                        $this->getLocation($tag['position'])
                    );
                }

                // 退回栈中
                if ($tailTag) {
                    $tailStack->in($tailTag);
                }

                $themeNode = [
                    'content'  => $tag['content'],
                    'compiler' => $tag['name'].$compiler, // 编译器
                    'source'   => $tag['source'],
                    'name'     => $tag['name'],
                ];

                $themeNode['position'] = $tag['position'];
                $themeNode = $this->normalizeThemeStruct($themeNode);
            }

            // 成对标签
            else {
                // 头尾标签中间为整个标签内容
                $start = $tag['position']['start'];
                $len = $tailTag['position']['end'] - $start + 1;
                $source = substr($compiled, $start, $len);

                $themeNode = [
                    'content'  => $source,
                    'compiler' => $tag['name'].$compiler, // 编译器
                    'source'   => $source,
                    'name'     => $tag['name'],
                ];

                $themeNode['position'] = $this->getPosition($compiled, $source, $start);
                $themeNode = $this->normalizeThemeStruct($themeNode);

                // 标签 body
                $start = $tag['position']['end'] + 1;
                $len = $tailTag['position']['start'] - $start;

                if ($len > 0) {
                    $body = substr($compiled, $start, $len);

                    $themeBody = [
                        'content'  => $body,
                        'compiler' => null, // 编译器
                        'source'   => $body,
                        'is_body'  => true,
                    ];

                    $themeBody['position'] = $this->getPosition($compiled, $body, $start);
                    $themeBody = $this->normalizeThemeStruct($themeBody);
                    $themeNode = $this->addThemeTree($themeNode, $themeBody);
                }
            }

            // 标签属性
            $themeAttr = [
                'content'        => $tag['content'],
                'compiler'       => 'attributeNode', // 编译器
                'source'         => $tag['source'],
                'attribute_list' => [],
                'is_attribute'   => true,
                'parent_name'    => $themeNode['name'],
                'is_js'          => $this->jsNode,
            ];

            $themeAttr['position'] = $this->getPosition($compiled, $tag['source'], 0);
            $themeAttr = $this->normalizeThemeStruct($themeAttr);
            $themeNode = $this->addThemeTree($themeNode, $themeAttr);

            // 将模板数据加入到树结构中
            $this->addTheme($themeNode);
        }
    }
protected function packNode(string &$compiled): void
    {
        if (true === $this->jsNode) {
            $nodeTag = $this->compiler->getJsTagHelp();
            $compiler = 'Js';
        } else {
            $nodeTag = $this->compiler->getNodeTagHelp();
            $compiler = 'Node';
        }

        // 尾标签栈
        $tailStack = new Stack(['array']);

        // 载入节点属性分析器 & 依次处理所有标签
        while (null !== ($tag = $this->nodeStack->out())) {
            // 尾标签，加入到尾标签中
            if ('tail' === $tag['type']) {
                $tailStack->in($tag);

                continue;
            }

            // 从尾标签栈取出一项
            $tailTag = $tailStack->out();

            // 单标签节点
            if (!$tailTag or !$this->findHeadTag($tag, $tailTag)) {
                if (true !== $nodeTag[$tag['name']]['single']) {
                    throw new InvalidArgumentException(
                        sprintf(
                            '%s type nodes must be used in pairs, and no corresponding tail tags are found.',
                            $tag['name']
                        ).
                        '<br />'.
                        $this->getLocation($tag['position'])
                    );
                }

                // 退回栈中
                if ($tailTag) {
                    $tailStack->in($tailTag);
                }

                $themeNode = [
                    'content'  => $tag['content'],
                    'compiler' => $tag['name'].$compiler, // 编译器
                    'source'   => $tag['source'],
                    'name'     => $tag['name'],
                ];

                $themeNode['position'] = $tag['position'];
                $themeNode = $this->normalizeThemeStruct($themeNode);
            }

            // 成对标签
            else {
                // 头尾标签中间为整个标签内容
                $start = $tag['position']['start'];
                $len = $tailTag['position']['end'] - $start + 1;
                $source = substr($compiled, $start, $len);

                $themeNode = [
                    'content'  => $source,
                    'compiler' => $tag['name'].$compiler, // 编译器
                    'source'   => $source,
                    'name'     => $tag['name'],
                ];

                $themeNode['position'] = $this->getPosition($compiled, $source, $start);
                $themeNode = $this->normalizeThemeStruct($themeNode);

                // 标签 body
                $start = $tag['position']['end'] + 1;
                $len = $tailTag['position']['start'] - $start;

                if ($len > 0) {
                    $body = substr($compiled, $start, $len);

                    $themeBody = [
                        'content'  => $body,
                        'compiler' => null, // 编译器
                        'source'   => $body,
                        'is_body'  => true,
                    ];

                    $themeBody['position'] = $this->getPosition($compiled, $body, $start);
                    $themeBody = $this->normalizeThemeStruct($themeBody);
                    $themeNode = $this->addThemeTree($themeNode, $themeBody);
                }
            }

            // 标签属性
            $themeAttr = [
                'content'        => $tag['content'],
                'compiler'       => 'attributeNode', // 编译器
                'source'         => $tag['source'],
                'attribute_list' => [],
                'is_attribute'   => true,
                'parent_name'    => $themeNode['name'],
                'is_js'          => $this->jsNode,
            ];

            $themeAttr['position'] = $this->getPosition($compiled, $tag['source'], 0);
            $themeAttr = $this->normalizeThemeStruct($themeAttr);
            $themeNode = $this->addThemeTree($themeNode, $themeAttr);

            // 将模板数据加入到树结构中
            $this->addTheme($themeNode);
        }
    }
装配节点.

@param string $compiled