Skip to content

Improve EOF handling + handle lonely import statements #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Nov 12, 2019
Merged
9 changes: 5 additions & 4 deletions lib/Sabberworm/CSS/CSSList/CSSList.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Sabberworm\CSS\Parsing\ParserState;
use Sabberworm\CSS\Parsing\SourceException;
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
use Sabberworm\CSS\Property\AtRule;
use Sabberworm\CSS\Property\Charset;
use Sabberworm\CSS\Property\CSSNamespace;
Expand Down Expand Up @@ -111,14 +112,14 @@ private static function parseAtRule(ParserState $oParserState) {
$oParserState->consumeWhiteSpace();
$sMediaQuery = null;
if (!$oParserState->comes(';')) {
$sMediaQuery = $oParserState->consumeUntil(';');
$sMediaQuery = trim($oParserState->consumeUntil(array(';', ParserState::EOF)));
}
$oParserState->consume(';');
$oParserState->consumeUntil(array(';', ParserState::EOF), true, true);
return new Import($oLocation, $sMediaQuery, $iIdentifierLineNum);
} else if ($sIdentifier === 'charset') {
$sCharset = CSSString::parse($oParserState);
$oParserState->consumeWhiteSpace();
$oParserState->consume(';');
$oParserState->consumeUntil(array(';', ParserState::EOF), true, true);
return new Charset($sCharset, $iIdentifierLineNum);
} else if (self::identifierIs($sIdentifier, 'keyframes')) {
$oResult = new KeyFrame($iIdentifierLineNum);
Expand All @@ -136,7 +137,7 @@ private static function parseAtRule(ParserState $oParserState) {
$sPrefix = $mUrl;
$mUrl = Value::parsePrimitiveValue($oParserState);
}
$oParserState->consume(';');
$oParserState->consumeUntil(array(';', ParserState::EOF), true, true);
if ($sPrefix !== null && !is_string($sPrefix)) {
throw new UnexpectedTokenException('Wrong namespace prefix', $sPrefix, 'custom', $iIdentifierLineNum);
}
Expand Down
19 changes: 13 additions & 6 deletions lib/Sabberworm/CSS/Parsing/ParserState.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@

use Sabberworm\CSS\Comment\Comment;
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
use Sabberworm\CSS\Settings;

class ParserState {
const EOF = null;

private $oParserSettings;

private $sText;
Expand Down Expand Up @@ -118,8 +121,7 @@ public function consumeWhiteSpace() {
if($this->oParserSettings->bLenientParsing) {
try {
$oComment = $this->consumeComment();
} catch(UnexpectedTokenException $e) {
// When we can’t find the end of a comment, we assume the document is finished.
} catch(UnexpectedEOFException $e) {
$this->iCurrentPosition = $this->iLength;
return;
}
Expand Down Expand Up @@ -160,7 +162,7 @@ public function consume($mValue = 1) {
return $mValue;
} else {
if ($this->iCurrentPosition + $mValue > $this->iLength) {
throw new UnexpectedTokenException($mValue, $this->peek(5), 'count', $this->iLineNo);
throw new UnexpectedEOFException($mValue, $this->peek(5), 'count', $this->iLineNo);
}
$sResult = $this->substr($this->iCurrentPosition, $mValue);
$iLineCount = substr_count($sResult, "\n");
Expand Down Expand Up @@ -214,7 +216,8 @@ public function consumeUntil($aEnd, $bIncludeEnd = false, $consumeEnd = false, a
$out = '';
$start = $this->iCurrentPosition;

while (($char = $this->consume(1)) !== '') {
while (!$this->isEnd()) {
$char = $this->consume(1);
if (in_array($char, $aEnd)) {
if ($bIncludeEnd) {
$out .= $char;
Expand All @@ -229,8 +232,12 @@ public function consumeUntil($aEnd, $bIncludeEnd = false, $consumeEnd = false, a
}
}

if (in_array(self::EOF, $aEnd)) {
return $out;
}

$this->iCurrentPosition = $start;
throw new UnexpectedTokenException('One of ("'.implode('","', $aEnd).'")', $this->peek(5), 'search', $this->iLineNo);
throw new UnexpectedEOFException('One of ("'.implode('","', $aEnd).'")', $this->peek(5), 'search', $this->iLineNo);
}

private function inputLeft() {
Expand Down Expand Up @@ -309,4 +316,4 @@ private function strpos($sString, $sNeedle, $iOffset) {
return strpos($sString, $sNeedle, $iOffset);
}
}
}
}
9 changes: 9 additions & 0 deletions lib/Sabberworm/CSS/Parsing/UnexpectedEOFException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Sabberworm\CSS\Parsing;

/**
* Thrown if the CSS parsers encounters end of file it did not expect
* Extends UnexpectedTokenException in order to preserve backwards compatibility
*/
class UnexpectedEOFException extends UnexpectedTokenException {}
6 changes: 6 additions & 0 deletions tests/Sabberworm/CSS/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -760,4 +760,10 @@ function testLargeSizeValuesInFile() {
$sExpected = '.overlay {z-index: 10000000000000000000000;}';
$this->assertSame($sExpected, $oDoc->render());
}

function testLonelyImport() {
$oDoc = $this->parsedStructureForFile('lonely-import');
$sExpected = "@import url(\"example.css\") only screen and (max-width: 600px);";
$this->assertSame($sExpected, $oDoc->render());
}
}
1 change: 1 addition & 0 deletions tests/files/lonely-import.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import "example.css" only screen and (max-width: 600px)