1<?php
2
3declare(strict_types=1);
4
5namespace JMS\Serializer\Type;
6
7use Hoa\Compiler\Llk\TreeNode;
8use Hoa\Visitor\Element;
9use Hoa\Visitor\Visit;
10use JMS\Serializer\Type\Exception\InvalidNode;
11use function strpos;
12
13final class TypeVisitor implements Visit
14{
15    /**
16     * {@inheritdoc}
17     */
18    public function visit(Element $element, &$handle = null, $eldnah = null)
19    {
20        switch ($element->getId()) {
21            case '#simple_type':
22                return $this->visitSimpleType($element);
23            case '#compound_type':
24                return $this->visitCompoundType($element, $handle, $eldnah);
25        }
26
27        throw new InvalidNode();
28    }
29
30    /**
31     * @return string|mixed[]
32     */
33    private function visitSimpleType(TreeNode $element)
34    {
35        $tokenNode = $element->getChild(0);
36        $token = $tokenNode->getValueToken();
37        $value = $tokenNode->getValueValue();
38
39        if ('name' === $token) {
40            return ['name' => $value, 'params' => []];
41        }
42
43        if ('empty_string' === $token) {
44            return '';
45        }
46
47        if ('null' === $token) {
48            return null;
49        }
50
51        if ('number' === $token) {
52            return false === strpos($value, '.') ? intval($value) : floatval($value);
53        }
54
55        $escapeChar = 'quoted_string' === $token ? '"' : "'";
56
57        if (false === strpos($value, $escapeChar)) {
58            return $value;
59        }
60
61        return str_replace($escapeChar . $escapeChar, $escapeChar, $value);
62    }
63
64    private function visitCompoundType(TreeNode $element, ?int &$handle, ?int $eldnah): array
65    {
66        $nameToken = $element->getChild(0);
67        $parameters = array_slice($element->getChildren(), 1);
68
69        return [
70            'name' => $nameToken->getValueValue(),
71            'params' => array_map(
72                function (TreeNode $node) use ($handle, $eldnah) {
73                    return $node->accept($this, $handle, $eldnah);
74                },
75                $parameters
76            ),
77        ];
78    }
79}
80