@@ -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 ;
0 commit comments