StringReader部分
This commit is contained in:
parent
9484b3c098
commit
9a0e925f6e
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,4 +2,4 @@
|
|||||||
composer.phar
|
composer.phar
|
||||||
vendor/
|
vendor/
|
||||||
composer.lock
|
composer.lock
|
||||||
|
.phpunit*
|
||||||
|
@ -13,9 +13,18 @@
|
|||||||
"php": ">=7.1",
|
"php": ">=7.1",
|
||||||
"ext-mbstring": "*"
|
"ext-mbstring": "*"
|
||||||
},
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.0",
|
||||||
|
"mockery/mockery": "^1.4"
|
||||||
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"JerryYan\\DSL\\": "src"
|
"JerryYan\\DSL\\": "src"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"JerryYan\\DSL\\Test\\": "tests"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,7 +9,10 @@
|
|||||||
namespace JerryYan\DSL\Reader;
|
namespace JerryYan\DSL\Reader;
|
||||||
|
|
||||||
|
|
||||||
class FileReader extends ReaderInterface
|
class FileReader /** extends ReaderInterface */
|
||||||
{
|
{
|
||||||
|
public function __construct(string $fileName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -17,13 +17,42 @@ namespace JerryYan\DSL\Reader;
|
|||||||
*/
|
*/
|
||||||
abstract class ReaderInterface
|
abstract class ReaderInterface
|
||||||
{
|
{
|
||||||
protected $currentLine = 0;
|
protected $currentLine = 1;
|
||||||
protected $currentPosition = 0;
|
protected $currentPosition = 0;
|
||||||
protected $currentLinePosition = 0;
|
protected $currentLinePosition = 0;
|
||||||
#abstract public function getNextChar(): ?string;
|
protected $nextPosition = 0;
|
||||||
#abstract public function getCurrentToken(): ?string;
|
|
||||||
#abstract public function getNextToken(): ?string;
|
/**
|
||||||
#abstract public function moveToNextToken(): ?string;
|
* 获取下一个字符
|
||||||
|
* @return string
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/18 12:06
|
||||||
|
*/
|
||||||
|
abstract public function getNextChar(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前识别符
|
||||||
|
* @return string
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/18 12:06
|
||||||
|
*/
|
||||||
|
abstract public function getCurrentToken(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下一个识别符
|
||||||
|
* @return string
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/18 12:06
|
||||||
|
*/
|
||||||
|
abstract public function getNextToken(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动至下一个识别符
|
||||||
|
* @return bool
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/18 12:06
|
||||||
|
*/
|
||||||
|
abstract public function moveToNextToken(): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跳过当前行
|
* 跳过当前行
|
||||||
@ -31,7 +60,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 skipCurrentLine(): bool;
|
abstract public function skipCurrentLine(): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从当前位置跳到结束位置
|
* 从当前位置跳到结束位置
|
||||||
@ -40,5 +69,28 @@ 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置读取器
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/18 12:01
|
||||||
|
*/
|
||||||
|
public function reset(): void
|
||||||
|
{
|
||||||
|
$this->currentLine = 1;
|
||||||
|
$this->currentPosition = 0;
|
||||||
|
$this->nextPosition = 0;
|
||||||
|
$this->moveToNextToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置读取器
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/18 12:01
|
||||||
|
*/
|
||||||
|
public function resetCursor(): void
|
||||||
|
{
|
||||||
|
$this->reset();
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @filename StreamReader.php
|
|
||||||
* @author Jerry Yan <792602257@qq.com>
|
|
||||||
* @date 2020/12/17 14:58
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
namespace JerryYan\DSL\Reader;
|
|
||||||
|
|
||||||
|
|
||||||
class StreamReader extends ReaderInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
124
src/Reader/StringReader.php
Normal file
124
src/Reader/StringReader.php
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @filename StringReader.php
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/17 14:58
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace JerryYan\DSL\Reader;
|
||||||
|
|
||||||
|
|
||||||
|
class StringReader extends ReaderInterface
|
||||||
|
{
|
||||||
|
protected $string;
|
||||||
|
protected $currentToken;
|
||||||
|
|
||||||
|
public function __construct(string $string)
|
||||||
|
{
|
||||||
|
$this->string = $string;
|
||||||
|
$this->moveToNextToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getNextChar(int $startAt = null): string
|
||||||
|
{
|
||||||
|
if ($startAt === null) $startAt = $this->currentPosition;
|
||||||
|
return mb_substr($this->string, $startAt, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getCurrentToken(): string
|
||||||
|
{
|
||||||
|
return $this->currentToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getNextToken(): string
|
||||||
|
{
|
||||||
|
$curToken = "";
|
||||||
|
$curPos = $this->nextPosition;
|
||||||
|
while ($curChar = $this->getNextChar($curPos)) {
|
||||||
|
switch ($curChar) {
|
||||||
|
case " ":
|
||||||
|
// 如果开始的时候就有空白,跳过它
|
||||||
|
if (empty($curToken)) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
// 否则就结束(已经匹配完成)
|
||||||
|
break 2;
|
||||||
|
case "\r":
|
||||||
|
case "\n":
|
||||||
|
break 2;
|
||||||
|
default:
|
||||||
|
$curToken .= $curChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $curToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function moveToNextToken(): bool
|
||||||
|
{
|
||||||
|
$curToken = "";
|
||||||
|
$this->currentPosition = $this->nextPosition;
|
||||||
|
while ($curChar = $this->getNextChar($this->nextPosition)) {
|
||||||
|
$this->nextPosition++;
|
||||||
|
$this->currentLinePosition++;
|
||||||
|
switch ($curChar) {
|
||||||
|
case " ":
|
||||||
|
// 如果开始的时候就有空白,跳过它
|
||||||
|
if (empty($curToken)) {
|
||||||
|
$this->currentPosition++;
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
// 否则就结束(已经匹配完成)
|
||||||
|
break 2;
|
||||||
|
case "\r":
|
||||||
|
if ($this->getNextChar($this->nextPosition+1) === "\n") {
|
||||||
|
// CRLF换行
|
||||||
|
$this->nextPosition+=2;
|
||||||
|
}
|
||||||
|
// CR换行
|
||||||
|
$this->currentLine++;
|
||||||
|
$this->currentLinePosition=0;
|
||||||
|
break 2;
|
||||||
|
case "\n":
|
||||||
|
// LF换行
|
||||||
|
$this->currentLine++;
|
||||||
|
$this->currentLinePosition=0;
|
||||||
|
break 2;
|
||||||
|
default:
|
||||||
|
$curToken .= $curChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->currentToken = $curToken;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function skipCurrentLine(): bool
|
||||||
|
{
|
||||||
|
// TODO: Implement skipCurrentLine() method.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function skipUntil(string $end = "*/"): bool
|
||||||
|
{
|
||||||
|
// TODO: Implement skipUntil() method.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@
|
|||||||
namespace JerryYan\DSL\Token;
|
namespace JerryYan\DSL\Token;
|
||||||
|
|
||||||
|
|
||||||
class TokenAnd
|
class TokenAnd extends TokenInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
@ -12,8 +12,24 @@ namespace JerryYan\DSL\Token;
|
|||||||
class TokenFactory
|
class TokenFactory
|
||||||
{
|
{
|
||||||
/** @var array<string, string> Token类型及映射类 */
|
/** @var array<string, string> Token类型及映射类 */
|
||||||
#private $tokenMap = [
|
private $tokenMap = [
|
||||||
# Token::AND => TokenAnd::class,
|
Token::AND => TokenAnd::class,
|
||||||
#];
|
Token::OR => TokenOr::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $tokenNameMap = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
public function getTokenByName(string $name): TokenInterface
|
||||||
|
{
|
||||||
|
if (!isset($this->tokenNameMap[$name])) {
|
||||||
|
return new TokenUndefined();
|
||||||
|
}
|
||||||
|
$tokenType = $this->tokenNameMap[$name];
|
||||||
|
if (!isset($this->tokenMap[$tokenType])) {
|
||||||
|
return new TokenUndefined();
|
||||||
|
}
|
||||||
|
return new $this->tokenMap[$tokenType];
|
||||||
|
}
|
||||||
}
|
}
|
15
src/Token/TokenOr.php
Normal file
15
src/Token/TokenOr.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @filename TokenAnd.php
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/17 15:20
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace JerryYan\DSL\Token;
|
||||||
|
|
||||||
|
|
||||||
|
class TokenOr extends TokenInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
15
src/Token/TokenUndefined.php
Normal file
15
src/Token/TokenUndefined.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @filename TokenUndefined.php
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/18 12:15
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace JerryYan\DSL\Token;
|
||||||
|
|
||||||
|
|
||||||
|
class TokenUndefined extends TokenInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -9,7 +9,31 @@
|
|||||||
namespace JerryYan\DSL\Tokenizer;
|
namespace JerryYan\DSL\Tokenizer;
|
||||||
|
|
||||||
|
|
||||||
|
use ArrayIterator;
|
||||||
|
use JerryYan\DSL\Reader\ReaderInterface;
|
||||||
|
use JerryYan\DSL\Token\TokenFactory;
|
||||||
|
|
||||||
class Tokenizer extends TokenizerInterface
|
class Tokenizer extends TokenizerInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public function __construct(TokenFactory $tokenFactory)
|
||||||
|
{
|
||||||
|
$this->tokenFactory = $tokenFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
function tokenize(ReaderInterface $reader): ArrayIterator
|
||||||
|
{
|
||||||
|
$reader->resetCursor();
|
||||||
|
$tokens = [];
|
||||||
|
while($reader->moveToNextToken())
|
||||||
|
{
|
||||||
|
$currentTokenName = $reader->getCurrentToken();
|
||||||
|
$currentToken = $this->tokenFactory->getTokenByName($currentTokenName);
|
||||||
|
$tokens[] = $currentToken;
|
||||||
|
}
|
||||||
|
return new ArrayIterator($tokens);
|
||||||
|
}
|
||||||
}
|
}
|
@ -9,7 +9,20 @@
|
|||||||
namespace JerryYan\DSL\Tokenizer;
|
namespace JerryYan\DSL\Tokenizer;
|
||||||
|
|
||||||
|
|
||||||
|
use ArrayIterator;
|
||||||
|
use JerryYan\DSL\Reader\ReaderInterface;
|
||||||
|
use JerryYan\DSL\Token\TokenInterface;
|
||||||
|
|
||||||
abstract class TokenizerInterface
|
abstract class TokenizerInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
|
protected $tokenFactory;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param ReaderInterface $reader
|
||||||
|
* @return ArrayIterator<TokenInterface>
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/18 11:43
|
||||||
|
*/
|
||||||
|
abstract function tokenize(ReaderInterface $reader): ArrayIterator;
|
||||||
}
|
}
|
54
tests/Reader/StringReaderTest.php
Normal file
54
tests/Reader/StringReaderTest.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @filename StringReaderTest.php
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/18 12:19
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace JerryYan\DSL\Test\Reader;
|
||||||
|
|
||||||
|
use JerryYan\DSL\Reader\StringReader;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class StringReaderTest extends TestCase
|
||||||
|
{
|
||||||
|
protected $readerWithCn;
|
||||||
|
protected $reader;
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->reader = new StringReader(" Ahhh This Is 一个 新的 TOken");
|
||||||
|
$this->readerWithCn = new StringReader(" 中文 这是 Is 一个 新的 TOken");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetNextChar()
|
||||||
|
{
|
||||||
|
$this->reader->reset();
|
||||||
|
$this->assertEquals('A', $this->reader->getNextChar(), "不匹配");
|
||||||
|
$this->readerWithCn->reset();
|
||||||
|
$this->assertEquals('中', $this->readerWithCn->getNextChar(), "不匹配");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetCurrentToken()
|
||||||
|
{
|
||||||
|
$this->reader->reset();
|
||||||
|
$this->assertEquals('Ahhh', $this->reader->getCurrentToken(), "不匹配");
|
||||||
|
$this->readerWithCn->reset();
|
||||||
|
$this->assertEquals('中文', $this->readerWithCn->getCurrentToken(), "不匹配");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jerry Yan <792602257@qq.com>
|
||||||
|
* @date 2020/12/18 14:16
|
||||||
|
* @depends testGetNextChar
|
||||||
|
* @depends testGetCurrentToken
|
||||||
|
*/
|
||||||
|
public function testMoveToNextToken()
|
||||||
|
{
|
||||||
|
$this->reader->reset();
|
||||||
|
$this->reader->moveToNextToken();
|
||||||
|
$this->assertEquals('This', $this->reader->getCurrentToken(), "不匹配");
|
||||||
|
$this->readerWithCn->reset();
|
||||||
|
$this->readerWithCn->moveToNextToken();
|
||||||
|
$this->assertEquals('这是', $this->readerWithCn->getCurrentToken(), "不匹配");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user