Skip to content

Commit

Permalink
Merge pull request #73 from phug-php/feature/issue-69-interpolations-…
Browse files Browse the repository at this point in the history
…in-comments

Ignore interpolations in comments
  • Loading branch information
kylekatarnls authored May 16, 2020
2 parents 5ace1d7 + b53a717 commit 39195e9
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 47 deletions.
5 changes: 5 additions & 0 deletions src/Phug/Lexer/Lexer/AbstractToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,9 @@ public function markAsHandled()
{
$this->handled = true;
}

public function __toString()
{
return '['.get_class($this).']';
}
}
6 changes: 0 additions & 6 deletions src/Phug/Lexer/Lexer/Analyzer/LineAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,6 @@ public function getLines()
public function getFlatLines()
{
return array_map(function ($line) {
foreach ($line as $chunk) {
if ($chunk instanceof TokenInterface) {
$this->state->throwException('Unexpected '.get_class($chunk).' inside raw text.');
}
}

return implode('', $line);
}, $this->lines);
}
Expand Down
11 changes: 6 additions & 5 deletions src/Phug/Lexer/Lexer/Scanner/CommentScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,26 @@ public function scan(State $state)
}

yield $state->endToken($token);

$line = $reader->readUntilNewLine();
$lines = $line === '' ? [] : [[$line]];

/** @var TextToken $token */
$token = $state->createToken(TextToken::class);

$analyzer = new LineAnalyzer($state, $reader, $lines);
$analyzer->disallowInterpolation();
$analyzer->analyze(false);
$lines = $analyzer->getFlatLines();

if (end($lines) === '') {
array_pop($lines);
}
$token->setValue(implode("\n", $lines));

//TODO: As it seems, this is the only TextToken that will actually contain newlines, thus Stat->endToken will
// end up with a wrong line offset. This is why endToken is not applied at all here and only the start
// position will be kept
$token->getSourceLocation()->setOffsetLength(1); //Let it have at least 1 length for debugging
$lines = implode("\n", $lines);
$token->setValue($lines);
$token->getSourceLocation()->setOffsetLength(mb_strlen($lines));

yield $token;

if ($analyzer->hasNewLine()) {
Expand Down
46 changes: 32 additions & 14 deletions src/Phug/Lexer/Lexer/Scanner/InterpolationScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,35 @@

class InterpolationScanner implements ScannerInterface
{
protected $interpolationChars = [
'tagInterpolation' => ['[', ']'],
'interpolation' => ['{', '}'],
];

protected $regExp;

public function __construct()
{
$interpolations = [];
$backIndex = 2;

foreach ($this->interpolationChars as $name => list($start, $end)) {
$start = preg_quote($start, '/');
$end = preg_quote($end, '/');
$interpolations[] = $start.'(?<'.$name.'>'.
'(?>"(?:\\\\[\\S\\s]|[^"\\\\])*"|\'(?:\\\\[\\S\\s]|[^\'\\\\])*\'|[^'.
$start.$end.
'\'"]++|(?-'.$backIndex.'))*+'.
')'.$end;
$backIndex++;
}

$this->regExp = '(?<text>.*?)'.
'(?<!\\\\)'.
'(?<escape>#|!(?='.preg_quote($this->interpolationChars['interpolation'][0], '/').'))'.
'(?<wrap>'.implode('|', $interpolations).')';
}

protected function throwEndOfLineExceptionIf(State $state, $condition)
{
if ($condition) {
Expand Down Expand Up @@ -103,21 +132,9 @@ public function scan(State $state)
{
$reader = $state->getReader();

//TODO: $state->endToken
while ($reader->match(
'(?<text>.*?)'.
'(?<!\\\\)'.
'(?<escape>#|!(?=\{))(?<wrap>'.
'\\[(?<tagInterpolation>'.
'(?>"(?:\\\\[\\S\\s]|[^"\\\\])*"|\'(?:\\\\[\\S\\s]|[^\'\\\\])*\'|[^\\[\\]\'"]++|(?-2))*+'.
')\\]|'.
'\\{(?<interpolation>'.
'(?>"(?:\\\\[\\S\\s]|[^"\\\\])*"|\'(?:\\\\[\\S\\s]|[^\'\\\\])*\'|[^{}\'"]++|(?-3))*+'.
')\\}'.
')'
)) {
while ($reader->match($this->regExp)) {
$text = $reader->getMatch('text');
$text = preg_replace('/\\\\([#!]\\[|#\\{)/', '$1', $text);
$text = preg_replace('/\\\\([#!]\\[|#{)/', '$1', $text);

if (mb_strlen($text) > 0) {
/** @var TextToken $token */
Expand All @@ -142,6 +159,7 @@ public function scan(State $state)
/** @var TextToken $token */
$token = $state->createToken(TextToken::class);
$token->setValue("\n");

yield $token;
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/Phug/AbstractLexerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ protected function filterTokenClass($className)
}
}

protected function assertTokens($expression, array $classNames, Lexer $lexer = null)
protected function assertTokens($expression, array $classNames, Lexer $lexer = null, &$tokens = [])
{
$lexer = $lexer ?: $this->lexer;
$tokens = iterator_to_array($lexer->lex($expression));
Expand Down
32 changes: 32 additions & 0 deletions tests/Phug/Lexer/Scanner/CommentScannerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,38 @@ public function testCommentInIndent()
]);
}

/**
* @covers \Phug\Lexer\Analyzer\LineAnalyzer::getFlatLines
*/
public function testInterpolationInComment()
{
$comment = implode("\n", [
'',
' p.',
' go to #[a(href=\'\') page]',
]);

$this->assertTokens("//$comment", [
CommentToken::class,
TextToken::class,
], null, $tokens);

/** @var TextToken $text */
$text = $tokens[1];

$this->assertSame($comment, $text->getValue());

$this->assertTokens("//-$comment", [
CommentToken::class,
TextToken::class,
], null, $tokens);

/** @var TextToken $text */
$text = $tokens[1];

$this->assertSame($comment, $text->getValue());
}

/**
* @covers \Phug\Lexer\Scanner\CommentScanner
* @covers \Phug\Lexer\Scanner\CommentScanner::scan
Expand Down
22 changes: 1 addition & 21 deletions tests/Phug/Lexer/Scanner/InterpolationScannerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

namespace Phug\Test\Lexer\Scanner;

use Phug\Lexer\Analyzer\LineAnalyzer;
use Phug\Lexer\State;
use Phug\Lexer\Token\ExpressionToken;
use Phug\Lexer\Token\IndentToken;
use Phug\Lexer\Token\InterpolationEndToken;
Expand All @@ -13,9 +11,7 @@
use Phug\Lexer\Token\TagInterpolationStartToken;
use Phug\Lexer\Token\TagToken;
use Phug\Lexer\Token\TextToken;
use Phug\Reader;
use Phug\Test\AbstractLexerTest;
use Phug\Util\SourceLocation;

class InterpolationScannerTest extends AbstractLexerTest
{
Expand Down Expand Up @@ -166,22 +162,6 @@ public function testScan()
]);
}

/**
* @covers \Phug\Lexer\Analyzer\LineAnalyzer::<public>
* @expectedException \Phug\LexerException
* @expectedExceptionMessage Failed to lex: Unexpected Phug\Lexer\Token\InterpolationStartToken inside raw text.
*/
public function testTokenInLineAnalyzer()
{
$input = 'p #{42}';
$analyzer = new LineAnalyzer(new State($this->lexer, $input, []), new Reader($input), [
[
new InterpolationStartToken(new SourceLocation('foo.pug', 12, 43)),
],
]);
$analyzer->getFlatLines();
}

/**
* @covers \Phug\Lexer\Scanner\InterpolationScanner::scanTagInterpolation
* @covers \Phug\Lexer\Scanner\InterpolationScanner::throwEndOfLineExceptionIf
Expand All @@ -192,7 +172,7 @@ public function testNewLineInTagInterpolation()
$this->expectMessageToBeThrown('End of line was reached with no closing bracket for interpolation.');

$input = "p #[em\n]";
$tokens = iterator_to_array($this->lexer->lex($input));
iterator_to_array($this->lexer->lex($input));
}

/**
Expand Down
10 changes: 10 additions & 0 deletions tests/Phug/Lexer/Token/InterpolationStartTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,14 @@ public function testEnd()
$start->setEnd($end);
self::assertSame($end, $start->getEnd());
}

/**
* @covers ::__toString
*/
public function testStringification()
{
$start = new InterpolationStartToken();

self::assertSame('['.InterpolationStartToken::class.']', "$start");
}
}

0 comments on commit 39195e9

Please sign in to comment.