Passed
Push — master ( 6c3f09...c54108 )
by William
03:43
created

ExpressionArray   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Test Coverage

Coverage 95.74%

Importance

Changes 0
Metric Value
eloc 46
dl 0
loc 117
ccs 45
cts 47
cp 0.9574
rs 10
c 0
b 0
f 0
wmc 25

3 Methods

Rating   Name   Duplication   Size   Complexity  
D parse() 0 87 22
A build() 0 8 2
A __toString() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\SqlParser\Components;
6
7
use PhpMyAdmin\SqlParser\Component;
8
use PhpMyAdmin\SqlParser\Exceptions\ParserException;
9
use PhpMyAdmin\SqlParser\Parser;
10
use PhpMyAdmin\SqlParser\Token;
11
use PhpMyAdmin\SqlParser\TokensList;
12
13
use function count;
14
use function implode;
15
use function is_array;
16
use function preg_match;
17
use function strlen;
18
use function substr;
19
20
/**
21
 * Parses a list of expressions delimited by a comma.
22
 */
23
final class ExpressionArray implements Component
24
{
25
    /**
26
     * @param Parser               $parser  the parser that serves as context
27
     * @param TokensList           $list    the list of tokens that are being parsed
28
     * @param array<string, mixed> $options parameters for parsing
29
     *
30
     * @return Expression[]
31
     *
32
     * @throws ParserException
33
     */
34 494
    public static function parse(Parser $parser, TokensList $list, array $options = [])
35
    {
36 494
        $ret = [];
37
38
        /**
39
         * The state of the parser.
40
         *
41
         * Below are the states of the parser.
42
         *
43
         *      0 ----------------------[ array ]---------------------> 1
44
         *
45
         *      1 ------------------------[ , ]------------------------> 0
46
         *      1 -----------------------[ else ]----------------------> (END)
47
         *
48
         * @var int
49
         */
50 494
        $state = 0;
51
52 494
        for (; $list->idx < $list->count; ++$list->idx) {
53
            /**
54
             * Token parsed at this moment.
55
             */
56 494
            $token = $list->tokens[$list->idx];
57
58
            // End of statement.
59 494
            if ($token->type === Token::TYPE_DELIMITER) {
60 228
                break;
61
            }
62
63
            // Skipping whitespaces and comments.
64 488
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
65 380
                continue;
66
            }
67
68
            if (
69 488
                ($token->type === Token::TYPE_KEYWORD)
70 488
                && ($token->flags & Token::FLAG_KEYWORD_RESERVED)
71 488
                && ((~$token->flags & Token::FLAG_KEYWORD_FUNCTION))
72 488
                && ($token->value !== 'DUAL')
73 488
                && ($token->value !== 'NULL')
74 488
                && ($token->value !== 'CASE')
75 488
                && ($token->value !== 'NOT')
76
            ) {
77
                // No keyword is expected.
78 408
                break;
79
            }
80
81 478
            if ($state === 0) {
82 478
                if ($token->type === Token::TYPE_KEYWORD && $token->value === 'CASE') {
83 38
                    $expr = CaseExpression::parse($parser, $list, $options);
84
                } else {
85 476
                    $expr = Expression::parse($parser, $list, $options);
86
                }
87
88 478
                if ($expr === null) {
89 2
                    break;
90
                }
91
92 476
                $ret[] = $expr;
93 476
                $state = 1;
94 188
            } elseif ($state === 1) {
95 188
                if ($token->value !== ',') {
96 20
                    break;
97
                }
98
99 178
                $state = 0;
100
            }
101
        }
102
103 494
        if ($state === 0) {
0 ignored issues
show
introduced by
The condition $state === 0 is always true.
Loading history...
104 20
            $parser->error('An expression was expected.', $list->tokens[$list->idx]);
105
        }
106
107 494
        --$list->idx;
108
109 494
        if (is_array($ret)) {
0 ignored issues
show
introduced by
The condition is_array($ret) is always true.
Loading history...
110 494
            $retIndex = count($ret) - 1;
111 494
            if (isset($ret[$retIndex])) {
112 476
                $expr = $ret[$retIndex]->expr;
113 476
                if (preg_match('/\s*--\s.*$/', $expr, $matches)) {
114 4
                    $found = $matches[0];
115 4
                    $ret[$retIndex]->expr = substr($expr, 0, strlen($expr) - strlen($found));
116
                }
117
            }
118
        }
119
120 494
        return $ret;
121
    }
122
123
    /**
124
     * @param Expression[]         $component the component to be built
125
     * @param array<string, mixed> $options   parameters for building
126
     */
127 74
    public static function build($component, array $options = []): string
128
    {
129 74
        $ret = [];
130 74
        foreach ($component as $frag) {
131 74
            $ret[] = $frag::build($frag);
132
        }
133
134 74
        return implode(', ', $ret);
135
    }
136
137
    public function __toString(): string
138
    {
139
        return static::build($this);
0 ignored issues
show
Bug introduced by
$this of type PhpMyAdmin\SqlParser\Components\ExpressionArray is incompatible with the type PhpMyAdmin\SqlParser\Components\Expression[] expected by parameter $component of PhpMyAdmin\SqlParser\Com...xpressionArray::build(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

139
        return static::build(/** @scrutinizer ignore-type */ $this);
Loading history...
140
    }
141
}
142