@@ -113,9 +113,31 @@ public function getSettings()
113113 *
114114 * @throws UnexpectedTokenException
115115 */
116- public function parseIdentifier ($ bIgnoreCase = true )
116+ public function parseIdentifier ($ bIgnoreCase = true , $ bNameStartCodePoint = true )
117117 {
118- $ sResult = $ this ->parseCharacter (true );
118+ $ sResult = null ;
119+ $ bCanParseCharacter = true ;
120+
121+ if ($ bNameStartCodePoint ) {
122+ // Check if 3 code points would start an identifier.
123+ // See <https://drafts.csswg.org/css-syntax-3/#would-start-an-identifier>.
124+ $ sNameStartCodePoint = '[a-zA-Z_]|[\x80-\xFF] ' ;
125+ $ sEscapeCode = '\\[^\r\n\f] ' ;
126+
127+ if (
128+ ! (
129+ preg_match ("/^-([- $ {sNameStartCodePoint}]| $ {sEscapeCode})/isSu " , $ this ->peek (3 )) ||
130+ preg_match ("/^ $ {sNameStartCodePoint}/isSu " , $ this ->peek ()) ||
131+ preg_match ("/^ $ {sEscapeCode}/isS " , $ this ->peek (2 ))
132+ )
133+ ) {
134+ $ bCanParseCharacter = false ;
135+ }
136+ }
137+
138+ if ($ bCanParseCharacter ) {
139+ $ sResult = $ this ->parseCharacter (true );
140+ }
119141 if ($ sResult === null ) {
120142 throw new UnexpectedTokenException ($ sResult , $ this ->peek (5 ), 'identifier ' , $ this ->iLineNo );
121143 }
@@ -179,14 +201,15 @@ public function parseCharacter($bIsForIdentifier)
179201 }
180202 if ($ bIsForIdentifier ) {
181203 $ peek = ord ($ this ->peek ());
182- // Ranges: a-z A-Z 0-9 - _
204+ $ peek = ord ($ this ->peek ());
205+ // Matches a name code point. See <https://drafts.csswg.org/css-syntax-3/#name-code-point>.
183206 if (
184- ($ peek >= 97 && $ peek <= 122 )
185- || ($ peek >= 65 && $ peek <= 90 )
186- || ($ peek >= 48 && $ peek <= 57 )
187- || ($ peek === 45 )
188- || ($ peek === 95 )
189- || ($ peek > 0xa1 )
207+ ($ peek >= 97 && $ peek <= 122 ) ||
208+ ($ peek >= 65 && $ peek <= 90 ) ||
209+ ($ peek >= 48 && $ peek <= 57 ) ||
210+ ($ peek === 45 ) ||
211+ ($ peek === 95 ) ||
212+ ($ peek > 0x81 )
190213 ) {
191214 return $ this ->consume (1 );
192215 }
0 commit comments