2121use Sabberworm \CSS \Value \CSSString ;
2222use Sabberworm \CSS \Rule \Rule ;
2323use Sabberworm \CSS \Parsing \UnexpectedTokenException ;
24+ use Sabberworm \CSS \Comment \Comment ;
2425
2526/**
2627 * Parser class parses CSS from text into a data structure.
@@ -83,12 +84,12 @@ public function parse() {
8384 }
8485
8586 private function parseDocument (Document $ oDocument ) {
86- $ this ->consumeWhiteSpace ();
8787 $ this ->parseList ($ oDocument , true );
8888 }
8989
9090 private function parseList (CSSList $ oList , $ bIsRoot = false ) {
9191 while (!$ this ->isEnd ()) {
92+ $ comments = $ this ->consumeWhiteSpace ();
9293 $ oListItem = null ;
9394 if ($ this ->oParserSettings ->bLenientParsing ) {
9495 try {
@@ -104,9 +105,9 @@ private function parseList(CSSList $oList, $bIsRoot = false) {
104105 return ;
105106 }
106107 if ($ oListItem ) {
108+ $ oListItem ->setComments ($ comments );
107109 $ oList ->append ($ oListItem );
108110 }
109- $ this ->consumeWhiteSpace ();
110111 }
111112 if (!$ bIsRoot ) {
112113 throw new SourceException ("Unexpected end of document " , $ this ->iLineNo );
@@ -161,7 +162,6 @@ private function parseAtRule() {
161162 $ oResult = new KeyFrame ($ iIdentifierLineNum );
162163 $ oResult ->setVendorKeyFrame ($ sIdentifier );
163164 $ oResult ->setAnimationName (trim ($ this ->consumeUntil ('{ ' , false , true )));
164- $ this ->consumeWhiteSpace ();
165165 $ this ->parseList ($ oResult );
166166 return $ oResult ;
167167 } else if ($ sIdentifier === 'namespace ' ) {
@@ -182,7 +182,6 @@ private function parseAtRule() {
182182 } else {
183183 //Unknown other at rule (font-face or such)
184184 $ sArgs = trim ($ this ->consumeUntil ('{ ' , false , true ));
185- $ this ->consumeWhiteSpace ();
186185 $ bUseRuleSet = true ;
187186 foreach ($ this ->blockRules as $ sBlockRuleName ) {
188187 if ($ this ->identifierIs ($ sIdentifier , $ sBlockRuleName )) {
@@ -303,17 +302,17 @@ private function parseCharacter($bIsForIdentifier) {
303302 }
304303
305304 private function parseSelector () {
305+ $ aComments = array ();
306306 $ oResult = new DeclarationBlock ($ this ->iLineNo );
307- $ oResult ->setSelector ($ this ->consumeUntil ('{ ' , false , true ));
308- $ this -> consumeWhiteSpace ( );
307+ $ oResult ->setSelector ($ this ->consumeUntil ('{ ' , false , true , $ aComments ));
308+ $ oResult -> setComments ( $ aComments );
309309 $ this ->parseRuleSet ($ oResult );
310310 return $ oResult ;
311311 }
312312
313313 private function parseRuleSet ($ oRuleSet ) {
314314 while ($ this ->comes ('; ' )) {
315315 $ this ->consume ('; ' );
316- $ this ->consumeWhiteSpace ();
317316 }
318317 while (!$ this ->comes ('} ' )) {
319318 $ oRule = null ;
@@ -327,7 +326,6 @@ private function parseRuleSet($oRuleSet) {
327326 if ($ this ->streql (substr ($ sConsume , -1 ), '} ' )) {
328327 --$ this ->iCurrentPosition ;
329328 } else {
330- $ this ->consumeWhiteSpace ();
331329 while ($ this ->comes ('; ' )) {
332330 $ this ->consume ('; ' );
333331 }
@@ -343,14 +341,15 @@ private function parseRuleSet($oRuleSet) {
343341 if ($ oRule ) {
344342 $ oRuleSet ->addRule ($ oRule );
345343 }
346- $ this ->consumeWhiteSpace ();
347344 }
348345 $ this ->consume ('} ' );
349346 }
350347
351348 private function parseRule () {
349+ $ aComments = $ this ->consumeWhiteSpace ();
352350 $ oRule = new Rule ($ this ->parseIdentifier (), $ this ->iLineNo );
353- $ this ->consumeWhiteSpace ();
351+ $ oRule ->setComments ($ aComments );
352+ $ oRule ->addComments ($ this ->consumeWhiteSpace ());
354353 $ this ->consume (': ' );
355354 $ oValue = $ this ->parseValue (self ::listDelimiterForRule ($ oRule ->getRule ()));
356355 $ oRule ->setValue ($ oValue );
@@ -369,7 +368,6 @@ private function parseRule() {
369368 }
370369 while ($ this ->comes ('; ' )) {
371370 $ this ->consume ('; ' );
372- $ this ->consumeWhiteSpace ();
373371 }
374372 return $ oRule ;
375373 }
@@ -568,48 +566,65 @@ private function consumeExpression($mExpression) {
568566 }
569567
570568 private function consumeWhiteSpace () {
569+ $ comments = array ();
571570 do {
572571 while (preg_match ('/ \\s/isSu ' , $ this ->peek ()) === 1 ) {
573572 $ this ->consume (1 );
574573 }
575574 if ($ this ->oParserSettings ->bLenientParsing ) {
576575 try {
577- $ bHasComment = $ this ->consumeComment ();
576+ $ oComment = $ this ->consumeComment ();
578577 } catch (UnexpectedTokenException $ e ) {
579578 // When we can’t find the end of a comment, we assume the document is finished.
580579 $ this ->iCurrentPosition = $ this ->iLength ;
581580 return ;
582581 }
583582 } else {
584- $ bHasComment = $ this ->consumeComment ();
583+ $ oComment = $ this ->consumeComment ();
585584 }
586- } while ($ bHasComment );
585+ if ($ oComment !== false ) {
586+ $ comments [] = $ oComment ;
587+ }
588+ } while ($ oComment !== false );
589+ return $ comments ;
587590 }
588591
592+ /**
593+ * @return false|Comment
594+ */
589595 private function consumeComment () {
596+ $ mComment = false ;
590597 if ($ this ->comes ('/* ' )) {
598+ $ iLineNo = $ this ->iLineNo ;
591599 $ this ->consume (1 );
592- while ($ this ->consume (1 ) !== '' ) {
600+ $ mComment = '' ;
601+ while (($ char = $ this ->consume (1 )) !== '' ) {
602+ $ mComment .= $ char ;
593603 if ($ this ->comes ('*/ ' )) {
594604 $ this ->consume (2 );
595- return true ;
605+ break ;
596606 }
597607 }
598608 }
599- return false ;
609+
610+ if ($ mComment !== false ) {
611+ // We skip the * which was included in the comment.
612+ return new Comment (substr ($ mComment , 1 ), $ iLineNo );
613+ }
614+
615+ return $ mComment ;
600616 }
601617
602618 private function isEnd () {
603619 return $ this ->iCurrentPosition >= $ this ->iLength ;
604620 }
605621
606- private function consumeUntil ($ aEnd , $ bIncludeEnd = false , $ consumeEnd = false ) {
622+ private function consumeUntil ($ aEnd , $ bIncludeEnd = false , $ consumeEnd = false , array & $ comments = array () ) {
607623 $ aEnd = is_array ($ aEnd ) ? $ aEnd : array ($ aEnd );
608624 $ out = '' ;
609625 $ start = $ this ->iCurrentPosition ;
610626
611627 while (($ char = $ this ->consume (1 )) !== '' ) {
612- $ this ->consumeComment ();
613628 if (in_array ($ char , $ aEnd )) {
614629 if ($ bIncludeEnd ) {
615630 $ out .= $ char ;
@@ -619,6 +634,9 @@ private function consumeUntil($aEnd, $bIncludeEnd = false, $consumeEnd = false)
619634 return $ out ;
620635 }
621636 $ out .= $ char ;
637+ if ($ comment = $ this ->consumeComment ()) {
638+ $ comments [] = $ comment ;
639+ }
622640 }
623641
624642 $ this ->iCurrentPosition = $ start ;
0 commit comments