1<?php
2/**
3 * Handlebars parser (based on mustache)
4 *
5 * This class is responsible for turning raw template source into a set of
6 * Handlebars tokens.
7 *
8 * @category  Xamin
9 * @package   Handlebars
10 * @author    fzerorubigd <fzerorubigd@gmail.com>
11 * @author    Behrooz Shabani <everplays@gmail.com>
12 * @author    Mardix <https://github.com/mardix>
13 * @copyright 2012 (c) ParsPooyesh Co
14 * @copyright 2013 (c) Behrooz Shabani
15 * @copyright 2013 (c) Mardix
16 * @license   MIT
17 * @link      http://voodoophp.org/docs/handlebars
18 */
19
20namespace Handlebars;
21use ArrayIterator;
22use LogicException;
23
24class Parser
25{
26    /**
27     * Process array of tokens and convert them into parse tree
28     *
29     * @param array $tokens Set of
30     *
31     * @return array Token parse tree
32     */
33    public function parse(Array $tokens = [])
34    {
35        return $this->buildTree(new ArrayIterator($tokens));
36    }
37
38    /**
39     * Helper method for recursively building a parse tree.
40     *
41     * @param \ArrayIterator $tokens Stream of tokens
42     *
43     * @throws \LogicException when nesting errors or mismatched section tags
44     * are encountered.
45     * @return array Token parse tree
46     *
47     */
48    private function buildTree(ArrayIterator $tokens)
49    {
50        $stack = [];
51
52        do {
53            $token = $tokens->current();
54            $tokens->next();
55
56            if ($token === null) {
57                continue;
58            } else {
59                switch ($token[Tokenizer::TYPE]) {
60                case Tokenizer::T_END_SECTION:
61                    $newNodes = [];
62                    do {
63                        $result = array_pop($stack);
64                        if ($result === null) {
65                            throw new LogicException(
66                                'Unexpected closing tag: /' . $token[Tokenizer::NAME]
67                            );
68                        }
69
70                        if (!array_key_exists(Tokenizer::NODES, $result)
71                            && isset($result[Tokenizer::NAME])
72                            && $result[Tokenizer::NAME] == $token[Tokenizer::NAME]
73                        ) {
74                            $result[Tokenizer::NODES] = $newNodes;
75                            $result[Tokenizer::END] = $token[Tokenizer::INDEX];
76                            array_push($stack, $result);
77                            break 2;
78                        } else {
79                            array_unshift($newNodes, $result);
80                        }
81                    } while (true);
82                    break;
83                default:
84                    array_push($stack, $token);
85                }
86            }
87
88        } while ($tokens->valid());
89
90        return $stack;
91
92    }
93
94}
95