Skip to content

Commit 2875198

Browse files
authored
Merge pull request #176 from raxbg/improvement/better_eof_handling
Improve EOF handling + handle lonely import statements
2 parents 841f697 + 8ba1325 commit 2875198

File tree

5 files changed

+34
-10
lines changed

5 files changed

+34
-10
lines changed

lib/Sabberworm/CSS/CSSList/CSSList.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Sabberworm\CSS\Parsing\ParserState;
77
use Sabberworm\CSS\Parsing\SourceException;
88
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
9+
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
910
use Sabberworm\CSS\Property\AtRule;
1011
use Sabberworm\CSS\Property\Charset;
1112
use Sabberworm\CSS\Property\CSSNamespace;
@@ -111,14 +112,14 @@ private static function parseAtRule(ParserState $oParserState) {
111112
$oParserState->consumeWhiteSpace();
112113
$sMediaQuery = null;
113114
if (!$oParserState->comes(';')) {
114-
$sMediaQuery = $oParserState->consumeUntil(';');
115+
$sMediaQuery = trim($oParserState->consumeUntil(array(';', ParserState::EOF)));
115116
}
116-
$oParserState->consume(';');
117+
$oParserState->consumeUntil(array(';', ParserState::EOF), true, true);
117118
return new Import($oLocation, $sMediaQuery, $iIdentifierLineNum);
118119
} else if ($sIdentifier === 'charset') {
119120
$sCharset = CSSString::parse($oParserState);
120121
$oParserState->consumeWhiteSpace();
121-
$oParserState->consume(';');
122+
$oParserState->consumeUntil(array(';', ParserState::EOF), true, true);
122123
return new Charset($sCharset, $iIdentifierLineNum);
123124
} else if (self::identifierIs($sIdentifier, 'keyframes')) {
124125
$oResult = new KeyFrame($iIdentifierLineNum);
@@ -136,7 +137,7 @@ private static function parseAtRule(ParserState $oParserState) {
136137
$sPrefix = $mUrl;
137138
$mUrl = Value::parsePrimitiveValue($oParserState);
138139
}
139-
$oParserState->consume(';');
140+
$oParserState->consumeUntil(array(';', ParserState::EOF), true, true);
140141
if ($sPrefix !== null && !is_string($sPrefix)) {
141142
throw new UnexpectedTokenException('Wrong namespace prefix', $sPrefix, 'custom', $iIdentifierLineNum);
142143
}

lib/Sabberworm/CSS/Parsing/ParserState.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33

44
use Sabberworm\CSS\Comment\Comment;
55
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
6+
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
67
use Sabberworm\CSS\Settings;
78

89
class ParserState {
10+
const EOF = null;
11+
912
private $oParserSettings;
1013

1114
private $sText;
@@ -118,8 +121,7 @@ public function consumeWhiteSpace() {
118121
if($this->oParserSettings->bLenientParsing) {
119122
try {
120123
$oComment = $this->consumeComment();
121-
} catch(UnexpectedTokenException $e) {
122-
// When we can’t find the end of a comment, we assume the document is finished.
124+
} catch(UnexpectedEOFException $e) {
123125
$this->iCurrentPosition = $this->iLength;
124126
return;
125127
}
@@ -160,7 +162,7 @@ public function consume($mValue = 1) {
160162
return $mValue;
161163
} else {
162164
if ($this->iCurrentPosition + $mValue > $this->iLength) {
163-
throw new UnexpectedTokenException($mValue, $this->peek(5), 'count', $this->iLineNo);
165+
throw new UnexpectedEOFException($mValue, $this->peek(5), 'count', $this->iLineNo);
164166
}
165167
$sResult = $this->substr($this->iCurrentPosition, $mValue);
166168
$iLineCount = substr_count($sResult, "\n");
@@ -214,7 +216,8 @@ public function consumeUntil($aEnd, $bIncludeEnd = false, $consumeEnd = false, a
214216
$out = '';
215217
$start = $this->iCurrentPosition;
216218

217-
while (($char = $this->consume(1)) !== '') {
219+
while (!$this->isEnd()) {
220+
$char = $this->consume(1);
218221
if (in_array($char, $aEnd)) {
219222
if ($bIncludeEnd) {
220223
$out .= $char;
@@ -229,8 +232,12 @@ public function consumeUntil($aEnd, $bIncludeEnd = false, $consumeEnd = false, a
229232
}
230233
}
231234

235+
if (in_array(self::EOF, $aEnd)) {
236+
return $out;
237+
}
238+
232239
$this->iCurrentPosition = $start;
233-
throw new UnexpectedTokenException('One of ("'.implode('","', $aEnd).'")', $this->peek(5), 'search', $this->iLineNo);
240+
throw new UnexpectedEOFException('One of ("'.implode('","', $aEnd).'")', $this->peek(5), 'search', $this->iLineNo);
234241
}
235242

236243
private function inputLeft() {
@@ -309,4 +316,4 @@ private function strpos($sString, $sNeedle, $iOffset) {
309316
return strpos($sString, $sNeedle, $iOffset);
310317
}
311318
}
312-
}
319+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Sabberworm\CSS\Parsing;
4+
5+
/**
6+
* Thrown if the CSS parsers encounters end of file it did not expect
7+
* Extends UnexpectedTokenException in order to preserve backwards compatibility
8+
*/
9+
class UnexpectedEOFException extends UnexpectedTokenException {}

tests/Sabberworm/CSS/ParserTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,4 +760,10 @@ function testLargeSizeValuesInFile() {
760760
$sExpected = '.overlay {z-index: 10000000000000000000000;}';
761761
$this->assertSame($sExpected, $oDoc->render());
762762
}
763+
764+
function testLonelyImport() {
765+
$oDoc = $this->parsedStructureForFile('lonely-import');
766+
$sExpected = "@import url(\"example.css\") only screen and (max-width: 600px);";
767+
$this->assertSame($sExpected, $oDoc->render());
768+
}
763769
}

tests/files/lonely-import.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import "example.css" only screen and (max-width: 600px)

0 commit comments

Comments
 (0)