Skip to content

Commit 466b59c

Browse files
committed
ArrayObj: Handle more complex expressions in arrays.
1 parent 0a603aa commit 466b59c

File tree

4 files changed

+82
-50
lines changed

4 files changed

+82
-50
lines changed

src/Components/ArrayObj.php

Lines changed: 82 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,32 @@ public static function parse(Parser $parser, TokensList $list, array $options =
6363
$ret = empty($options['type']) ? new ArrayObj() : array();
6464

6565
/**
66-
* The state of the parser.
66+
* The last raw expression.
6767
*
68-
* Below are the states of the parser.
69-
*
70-
* 0 -----------------------[ ( ]------------------------> 1
68+
* @var string $lastRaw
69+
*/
70+
$lastRaw = '';
71+
72+
/**
73+
* The last value.
7174
*
72-
* 1 ------------------[ array element ]-----------------> 2
75+
* @var string $lastValue
76+
*/
77+
$lastValue = '';
78+
79+
/**
80+
* Counts brackets.
7381
*
74-
* 2 ------------------------[ , ]-----------------------> 1
75-
* 2 ------------------------[ ) ]-----------------------> (END)
82+
* @var int $brackets
83+
*/
84+
$brackets = 0;
85+
86+
/**
87+
* Last separator (bracket or comma).
7688
*
77-
* @var int $state
89+
* @var boolean $isCommaLast
7890
*/
79-
$state = 0;
91+
$isCommaLast = false;
8092

8193
for (; $list->idx < $list->count; ++$list->idx) {
8294
/**
@@ -92,49 +104,72 @@ public static function parse(Parser $parser, TokensList $list, array $options =
92104
}
93105

94106
// Skipping whitespaces and comments.
95-
if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
107+
if (($token->type === Token::TYPE_WHITESPACE)
108+
|| ($token->type === Token::TYPE_COMMENT)
109+
) {
110+
$lastRaw .= $token->token;
111+
$lastValue = trim($lastValue) .' ';
96112
continue;
97113
}
98114

99-
if ($state === 0) {
100-
if (($token->type !== Token::TYPE_OPERATOR) || ($token->value !== '(')) {
101-
$parser->error(
102-
__('An opening bracket was expected.'),
103-
$token
104-
);
105-
break;
106-
}
107-
$state = 1;
108-
} elseif ($state === 1) {
109-
if (($token->type === Token::TYPE_OPERATOR) && ($token->value === ')')) {
110-
// Empty array.
111-
break;
112-
}
113-
if (empty($options['type'])) {
114-
$ret->values[] = $token->value;
115-
$ret->raw[] = $token->token;
116-
} else {
117-
$ret[] = $options['type']::parse(
118-
$parser,
119-
$list,
120-
empty($options['typeOptions']) ? array() : $options['typeOptions']
121-
);
122-
}
123-
$state = 2;
124-
} elseif ($state === 2) {
125-
if (($token->type !== Token::TYPE_OPERATOR) || (($token->value !== ',') && ($token->value !== ')'))) {
126-
$parser->error(
127-
__('A comma or a closing bracket was expected'),
128-
$token
129-
);
130-
break;
131-
}
132-
if ($token->value === ',') {
133-
$state = 1;
134-
} else { // )
135-
break;
115+
if (($brackets === 0)
116+
&& (($token->type !== Token::TYPE_OPERATOR)
117+
|| ($token->value !== '('))
118+
) {
119+
$parser->error(__('An opening bracket was expected.'), $token);
120+
break;
121+
}
122+
123+
if ($token->type === Token::TYPE_OPERATOR) {
124+
if ($token->value === '(') {
125+
if (++$brackets === 1) { // 1 is the base level.
126+
continue;
127+
}
128+
} elseif ($token->value === ')') {
129+
if (--$brackets === 0) { // Array ended.
130+
break;
131+
}
132+
} elseif ($token->value === ',') {
133+
if ($brackets === 1) {
134+
$isCommaLast = true;
135+
if (empty($options['type'])) {
136+
$ret->raw[] = trim($lastRaw);
137+
$ret->values[] = trim($lastValue);
138+
$lastRaw = $lastValue = '';
139+
}
140+
}
141+
continue;
136142
}
137143
}
144+
145+
if (empty($options['type'])) {
146+
$lastRaw .= $token->token;
147+
$lastValue .= $token->value;
148+
} else {
149+
$ret[] = $options['type']::parse(
150+
$parser,
151+
$list,
152+
empty($options['typeOptions']) ? array() : $options['typeOptions']
153+
);
154+
}
155+
}
156+
157+
// Handling last element.
158+
//
159+
// This is treated differently to treat the following cases:
160+
//
161+
// => array()
162+
// (,) => array('', '')
163+
// () => array()
164+
// (a,) => array('a', '')
165+
// (a) => array('a')
166+
//
167+
$lastRaw = trim($lastRaw);
168+
if ((empty($options['type']))
169+
&& ((strlen($lastRaw) > 0) || ($isCommaLast))
170+
) {
171+
$ret->raw[] = $lastRaw;
172+
$ret->values[] = trim($lastValue);
138173
}
139174

140175
return $ret;

tests/Components/ArrayObjTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ public function testParseProvider()
5050
{
5151
return array(
5252
array('parser/parseArrayErr1'),
53-
array('parser/parseArrayErr2'),
5453
array('parser/parseArrayErr3'),
5554
);
5655
}

tests/data/parser/parseArrayErr2.in

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/data/parser/parseArrayErr2.out

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)