Skip to content

Commit

Permalink
[Core] Fix wrong col pos in StringLexer exception
Browse files Browse the repository at this point in the history
  • Loading branch information
sstok committed Sep 2, 2024
1 parent 633f529 commit 4a57601
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 8 deletions.
31 changes: 24 additions & 7 deletions lib/Core/Input/StringLexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ final class StringLexer
private $cursor;
private $char;
private $lineno;
private $col;
private $end;

private $linenoSnapshot;
private $colSnapshot;
private $cursorSnapshot;
private $charSnapshot;

Expand All @@ -48,10 +49,17 @@ public function parse(string $data, array $fieldLexers = []): void
$this->data = str_replace(["\r\n", "\r"], "\n", $data);
$this->valueLexers = $fieldLexers;
$this->end = mb_strlen($this->data, '8bit');

$this->lineno = 1;
$this->col = 0;
$this->cursor = 0;
$this->char = 0;

$this->linenoSnapshot = null;
$this->colSnapshot = null;
$this->cursorSnapshot = null;
$this->charSnapshot = null;

$this->skipEmptyLines();
}

Expand All @@ -61,8 +69,7 @@ public function parse(string $data, array $fieldLexers = []): void
public function skipWhitespace(): void
{
if (preg_match('/\h+/A', $this->data, $match, 0, $this->cursor)) {
$this->char += mb_strlen($match[0]);
$this->cursor += mb_strlen($match[0], '8bit');
$this->moveCursor($match[0]);
}
}

Expand All @@ -81,6 +88,13 @@ public function moveCursor(string $text): void
$this->lineno += mb_substr_count($text, "\n");
$this->char += mb_strlen($text);
$this->cursor += mb_strlen($text, '8bit');

if (str_contains($text, "\n")) {
// Find the last newline, start counting the characters from there as our new position.
$this->col = mb_strlen(mb_substr($text, mb_strrpos($text, "\n")));
} else {
$this->col += mb_strlen($text);
}
}

public function snapshot($force = false): void
Expand All @@ -90,6 +104,7 @@ public function snapshot($force = false): void
}

$this->linenoSnapshot = $this->lineno;
$this->colSnapshot = $this->col;
$this->cursorSnapshot = $this->cursor;
$this->charSnapshot = $this->char;
}
Expand All @@ -101,10 +116,12 @@ public function restoreCursor(): void
}

$this->lineno = $this->linenoSnapshot;
$this->col = $this->colSnapshot;
$this->cursor = $this->cursorSnapshot;
$this->char = $this->charSnapshot;

$this->linenoSnapshot = null;
$this->colSnapshot = null;
$this->cursorSnapshot = null;
$this->charSnapshot = null;
}
Expand Down Expand Up @@ -175,7 +192,7 @@ public function createSyntaxException($expected): StringLexerException

if ($this->isEnd()) {
return StringLexerException::syntaxErrorUnexpectedEnd(
$this->cursor,
$this->col,
$this->lineno,
$expected,
'end of string'
Expand All @@ -184,15 +201,15 @@ public function createSyntaxException($expected): StringLexerException

if ($this->data[$this->cursor] === "\n") {
return StringLexerException::syntaxErrorUnexpectedEnd(
$this->cursor,
$this->col,
$this->lineno,
$expected,
'line end'
);
}

return StringLexerException::syntaxError(
$this->cursor,
$this->col,
$this->lineno,
$expected,
mb_substr($this->data, $this->cursor, min(10, $this->end))
Expand All @@ -202,7 +219,7 @@ public function createSyntaxException($expected): StringLexerException
public function createFormatException($string): StringLexerException
{
return StringLexerException::formatError(
$this->cursor,
$this->col,
$this->lineno,
$string
);
Expand Down
38 changes: 38 additions & 0 deletions lib/Core/Tests/Input/StringLexerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace Rollerworks\Component\Search\Tests\Input;

use PHPUnit\Framework\TestCase;
use Rollerworks\Component\Search\Exception\StringLexerException;
use Rollerworks\Component\Search\Input\StringLexer;

/**
Expand Down Expand Up @@ -48,4 +49,41 @@ public function skips_whitespace_with_exception_of_new_lines(): void

self::assertTrue($this->lexer->isGlimpse("/\n/A"));
}

/** @test */
public function it_reports_the_correct_col(): void
{
$this->lexer->parse("he:");
$this->lexer->fieldIdentification();

$this->expectExceptionObject(StringLexerException::syntaxErrorUnexpectedEnd(3, 1, 'StringValue', 'end of string'));

$this->lexer->stringValue();
}

/** @test */
public function it_reports_the_correct_col_with_multiline(): void
{
$this->lexer->parse("he:\nid:");
$this->lexer->fieldIdentification();
$this->lexer->skipEmptyLines();

$this->lexer->fieldIdentification();

$this->expectExceptionObject(StringLexerException::syntaxErrorUnexpectedEnd(4, 2, 'StringValue', 'end of string'));

$this->lexer->stringValue();
}

/** @test */
public function it_reports_the_correct_col_when_start_at_newline(): void
{
$this->lexer->parse("he:\n");
$this->lexer->fieldIdentification();
$this->lexer->skipEmptyLines();

$this->expectExceptionObject(StringLexerException::syntaxErrorUnexpectedEnd(1, 2, 'StringValue', 'end of string'));

$this->lexer->stringValue();
}
}
2 changes: 1 addition & 1 deletion lib/Core/Tests/Input/StringQueryInputTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public static function provideQueryExceptionTests(): iterable
],
[
"(field1: value, value2, value3, value4, value5; ); \n&",
StringLexerException::formatError(52, 2, 'A group logical operator can only be used at the start of the input or before a group opening'),
StringLexerException::formatError(1, 2, 'A group logical operator can only be used at the start of the input or before a group opening'),
],
[
'field1: value value2)',
Expand Down

0 comments on commit 4a57601

Please sign in to comment.