优化光标移动逻辑

This commit is contained in:
Jerry Yan 2020-12-19 11:41:57 +08:00
parent 93348cffdc
commit f995b932e4
3 changed files with 84 additions and 12 deletions

View File

@ -62,7 +62,7 @@ abstract class ReaderInterface
* @author Jerry Yan <792602257@qq.com> * @author Jerry Yan <792602257@qq.com>
* @date 2020/12/17 15:43 * @date 2020/12/17 15:43
*/ */
abstract public function skipUntil(string $end="*/"): bool; abstract public function skipUntil(string $end = "*/"): bool;
/** /**
* 重置读取器 * 重置读取器
@ -91,12 +91,37 @@ abstract class ReaderInterface
{ {
return $this->currentPosition; return $this->currentPosition;
} }
public function getNextPosition(): int public function getNextPosition(): int
{ {
return $this->nextPosition; return $this->nextPosition;
} }
public function getCurrentLine(): int
{
return $this->currentLine;
}
public function getCurrentLinePosition(): int
{
return $this->currentLinePosition;
}
public function getCurrentToken(): string public function getCurrentToken(): string
{ {
return $this->currentToken; return $this->currentToken;
} }
protected function moveCursorToNextChar(): void
{
$this->currentPosition++;
$this->currentLinePosition++;
}
protected function moveCursorToNextLine(int $chars = 1): void
{
$this->currentPosition += $chars;
$this->currentLinePosition = 0;
$this->currentLine++;
}
} }

View File

@ -47,6 +47,9 @@ class StringReader extends ReaderInterface
break 2; break 2;
case "\r": case "\r":
case "\n": case "\n":
if (empty($curToken)) {
continue 2;
}
break 2; break 2;
default: default:
$curToken .= $curChar; $curToken .= $curChar;
@ -64,13 +67,12 @@ class StringReader extends ReaderInterface
$this->currentPosition = $this->nextPosition; $this->currentPosition = $this->nextPosition;
while ($curChar = $this->getNextChar($this->nextPosition)) { while ($curChar = $this->getNextChar($this->nextPosition)) {
$this->nextPosition++; $this->nextPosition++;
$this->currentLinePosition++;
switch ($curChar) { switch ($curChar) {
// TODO: 注释跳过 // TODO: 注释跳过
case " ": case " ":
// 如果开始的时候就有空白,跳过它 // 如果开始的时候就有空白,跳过它
if (empty($curToken)) { if (empty($curToken)) {
$this->currentPosition++; $this->moveCursorToNextChar();
continue 2; continue 2;
} }
// 否则就结束(已经匹配完成) // 否则就结束(已经匹配完成)
@ -78,17 +80,24 @@ class StringReader extends ReaderInterface
case "\r": case "\r":
if ($this->getNextChar($this->nextPosition + 1) === "\n") { if ($this->getNextChar($this->nextPosition + 1) === "\n") {
// CRLF换行 // CRLF换行
$this->moveCursorToNextChar();
$this->nextPosition++; $this->nextPosition++;
} }
// CR换行 // CR换行
$this->currentLine++; $this->moveCursorToNextLine();
$this->currentLinePosition = 0; if (empty($curToken)) {
break 2; continue 2;
} else {
break 2;
}
case "\n": case "\n":
// LF换行 // LF换行
$this->currentLine++; $this->moveCursorToNextLine();
$this->currentLinePosition = 0; if (empty($curToken)) {
break 2; continue 2;
} else {
break 2;
}
default: default:
$curToken .= $curChar; $curToken .= $curChar;
} }
@ -116,7 +125,7 @@ class StringReader extends ReaderInterface
break 2; break 2;
} }
} }
$this->nextPosition = $curPos + 1; $this->nextPosition = $curPos;
$this->currentLine++; $this->currentLine++;
$this->currentLinePosition = 0; $this->currentLinePosition = 0;
return $this->moveToNextToken(); return $this->moveToNextToken();

View File

@ -12,12 +12,14 @@ use PHPUnit\Framework\TestCase;
class StringReaderTest extends TestCase class StringReaderTest extends TestCase
{ {
protected $readerWithCrLf;
protected $readerWithCn; protected $readerWithCn;
protected $reader; protected $reader;
protected function setUp(): void protected function setUp(): void
{ {
$this->reader = new StringReader(" Ahhh This Is 一个 新的 TOken"); $this->reader = new StringReader(" Ahhh This Is 一个 新的 TOken");
$this->readerWithCn = new StringReader(" 中文 这是 Is 一个 新的 TOken"); $this->readerWithCn = new StringReader(" 中文 这是 Is 一个 新的 TOken");
$this->readerWithCrLf = new StringReader(" 中文 \r\n\r 这是 \r Is \n 一个 新的 TOken");
} }
public function testGetNextChar() public function testGetNextChar()
@ -46,26 +48,29 @@ class StringReaderTest extends TestCase
* @date 2020/12/18 14:16 * @date 2020/12/18 14:16
* @depends testGetNextChar * @depends testGetNextChar
* @depends testGetCurrentToken * @depends testGetCurrentToken
* @depends testGetNextToken
*/ */
public function testMoveToNextToken() public function testMoveToNextToken()
{ {
$this->reader->reset(); $this->reader->reset();
$oldCurToken = $this->reader->getCurrentToken(); $oldCurToken = $this->reader->getCurrentToken();
$oldNextPos = $this->reader->getNextPosition(); $oldNextPos = $this->reader->getNextPosition();
$oldNextToken = $this->reader->getNextToken();
$this->reader->moveToNextToken(); $this->reader->moveToNextToken();
$this->assertNotEquals($oldCurToken, $this->reader->getCurrentPosition(), "CurToken与旧CurToken相同"); $this->assertNotEquals($oldCurToken, $this->reader->getCurrentPosition(), "CurToken与旧CurToken相同");
$this->assertNotEquals($oldNextPos, $this->reader->getNextPosition(), "NextPos与旧NextPos相同"); $this->assertNotEquals($oldNextPos, $this->reader->getNextPosition(), "NextPos与旧NextPos相同");
$this->assertEquals('This', $this->reader->getCurrentToken(), "不匹配"); $this->assertEquals($oldNextToken, $this->reader->getCurrentToken(), "不匹配");
$this->assertEquals(7, $this->reader->getCurrentPosition(), "CurPos与预计不符"); $this->assertEquals(7, $this->reader->getCurrentPosition(), "CurPos与预计不符");
$this->assertNotEquals($this->reader->getNextPosition(), $this->reader->getCurrentPosition(), "CurPos与NextPos相同"); $this->assertNotEquals($this->reader->getNextPosition(), $this->reader->getCurrentPosition(), "CurPos与NextPos相同");
// CJK Support // CJK Support
$this->readerWithCn->reset(); $this->readerWithCn->reset();
$oldCurTokenCn = $this->readerWithCn->getCurrentToken(); $oldCurTokenCn = $this->readerWithCn->getCurrentToken();
$oldNextPosCn = $this->readerWithCn->getNextPosition(); $oldNextPosCn = $this->readerWithCn->getNextPosition();
$oldNextTokenCn = $this->readerWithCn->getNextToken();
$this->readerWithCn->moveToNextToken(); $this->readerWithCn->moveToNextToken();
$this->assertNotEquals($oldCurTokenCn, $this->readerWithCn->getCurrentPosition(), "CurToken与旧CurToken相同"); $this->assertNotEquals($oldCurTokenCn, $this->readerWithCn->getCurrentPosition(), "CurToken与旧CurToken相同");
$this->assertNotEquals($oldNextPosCn, $this->readerWithCn->getNextPosition(), "NextPos与旧NextPos相同"); $this->assertNotEquals($oldNextPosCn, $this->readerWithCn->getNextPosition(), "NextPos与旧NextPos相同");
$this->assertEquals('这是', $this->readerWithCn->getCurrentToken(), "不匹配"); $this->assertEquals($oldNextTokenCn, $this->readerWithCn->getCurrentToken(), "不匹配");
$this->assertEquals(5, $this->readerWithCn->getCurrentPosition(), "CurPos与预计不符"); $this->assertEquals(5, $this->readerWithCn->getCurrentPosition(), "CurPos与预计不符");
} }
@ -85,4 +90,37 @@ class StringReaderTest extends TestCase
$this->assertEquals($curPos, $this->reader->getCurrentPosition(), "CurPos不可以发生变化"); $this->assertEquals($curPos, $this->reader->getCurrentPosition(), "CurPos不可以发生变化");
$this->assertEquals($nextPos, $this->reader->getNextPosition(), "NextPos不可以发生变化"); $this->assertEquals($nextPos, $this->reader->getNextPosition(), "NextPos不可以发生变化");
} }
public function testSkipCurrentLine()
{
$this->readerWithCrLf->resetCursor();
$this->readerWithCrLf->skipCurrentLine();
// moveToNextToken又移动了
$this->assertEquals(3, $this->readerWithCrLf->getCurrentLine(), "行号不匹配");
$this->assertEquals(1, $this->readerWithCrLf->getCurrentLinePosition(), "CLPos不匹配");
$this->assertEquals("这是", $this->readerWithCrLf->getCurrentToken(), "Token不匹配");
$this->assertEquals(8, $this->readerWithCrLf->getCurrentPosition(), "CurPos不匹配");
$this->readerWithCrLf->skipCurrentLine();
$this->assertEquals(4, $this->readerWithCrLf->getCurrentLine(), "行号不匹配");
$this->assertEquals(1, $this->readerWithCrLf->getCurrentLinePosition(), "CLPos不匹配");
$this->assertEquals("Is", $this->readerWithCrLf->getCurrentToken(), "Token不匹配");
$this->assertEquals(13, $this->readerWithCrLf->getCurrentPosition(), "CurPos不匹配");
$this->readerWithCrLf->skipCurrentLine();
$this->assertEquals(5, $this->readerWithCrLf->getCurrentLine(), "行号不匹配");
$this->assertEquals(1, $this->readerWithCrLf->getCurrentLinePosition(), "CLPos不匹配");
$this->assertEquals("一个", $this->readerWithCrLf->getCurrentToken(), "Token不匹配");
$this->assertEquals(18, $this->readerWithCrLf->getCurrentPosition(), "CurPos不匹配");
}
public function testResetCursor()
{
$this->reader->moveToNextToken();
$curPos = $this->reader->getCurrentPosition();
$nextPos = $this->reader->getNextPosition();
$string = $this->reader->getCurrentToken();
$this->reader->resetCursor();
$this->assertNotEquals($curPos, $this->reader->getCurrentPosition(), "CurPos未发生变化");
$this->assertNotEquals($nextPos, $this->reader->getNextPosition(), "NextPos未发生变化");
$this->assertNotEquals($string, $this->reader->getCurrentToken(), "CurToken未发生变化");
}
} }