diff --git a/src/Exception/FileNotFoundException.php b/src/Exception/FileNotFoundException.php new file mode 100644 index 0000000..c4c6b98 --- /dev/null +++ b/src/Exception/FileNotFoundException.php @@ -0,0 +1,17 @@ + + * @date 2021/1/26 13:52 + */ + + +namespace JerryYan\DSL\Exception; + + +use Exception; + +class FileNotFoundException extends Exception +{ + +} \ No newline at end of file diff --git a/src/Reader/FileReader.php b/src/Reader/FileReader.php index 09328d5..85bee76 100644 --- a/src/Reader/FileReader.php +++ b/src/Reader/FileReader.php @@ -9,10 +9,22 @@ namespace JerryYan\DSL\Reader; -class FileReader /** extends ReaderInterface */ +use JerryYan\DSL\Exception\FileNotFoundException; + +class FileReader extends StringReader { + /** + * FileReader constructor. + * @param string $fileName + * @throws FileNotFoundException + * @author Jerry Yan <792602257@qq.com> + * @date 2021/1/26 13:52 + */ public function __construct(string $fileName) { + if (!file_exists($fileName)) throw new FileNotFoundException; + $content = file_get_contents($fileName); + parent::__construct($content); } } \ No newline at end of file diff --git a/src/Reader/ReaderInterface.php b/src/Reader/ReaderInterface.php index f4d2c19..2dafcb5 100644 --- a/src/Reader/ReaderInterface.php +++ b/src/Reader/ReaderInterface.php @@ -133,6 +133,17 @@ abstract class ReaderInterface $this->currentPosition += $charLength; } + /** + * 移动Cursor至上一字符 + * @param int $charLength + * @author Jerry Yan <792602257@qq.com> + * @date 2020/12/19 15:05 + */ + protected function moveCursorToPrevChar(int $charLength = 1): void + { + $this->currentPosition -= $charLength; + } + /** * 移动Cursor至下一行 * @param int|null $newPos 下一行位置,不提供则手动检测 diff --git a/src/Reader/StringReader.php b/src/Reader/StringReader.php index dcdec40..cce31a8 100644 --- a/src/Reader/StringReader.php +++ b/src/Reader/StringReader.php @@ -79,18 +79,16 @@ class StringReader extends ReaderInterface // 否则就结束(已经匹配完成) break 2; case "\r": - if ($this->getNextChar($this->nextPosition) === "\n") { - // CRLF换行 - if (empty($curToken)) { - $this->moveCursorToNextChar(); - } - $this->nextPosition++; - } - // CR换行 if (empty($curToken)) { + // CRLF换行 + if ($this->getNextChar($this->nextPosition) === "\n") { + $this->nextPosition++; + } $this->moveCursorToNextLine(); continue 2; } else { + // 重置游标 + $this->nextPosition--; break 2; } case "\n": @@ -99,6 +97,7 @@ class StringReader extends ReaderInterface $this->moveCursorToNextLine(); continue 2; } else { + $this->nextPosition--; break 2; } default: diff --git a/src/Token/Factory/DefaultFactory.php b/src/Token/Factory/DefaultFactory.php index 63a4a4f..51a6764 100644 --- a/src/Token/Factory/DefaultFactory.php +++ b/src/Token/Factory/DefaultFactory.php @@ -16,6 +16,9 @@ use JerryYan\DSL\Token\TokenFake; use JerryYan\DSL\Token\TokenLogicAnd; use JerryYan\DSL\Token\TokenLogicEqual; use JerryYan\DSL\Token\TokenLogicFake; +use JerryYan\DSL\Token\TokenLogicGreater; +use JerryYan\DSL\Token\TokenLogicLess; +use JerryYan\DSL\Token\TokenLogicNot; use JerryYan\DSL\Token\TokenLogicNotEqual; use JerryYan\DSL\Token\TokenLogicOr; use JerryYan\DSL\Token\TokenNumber; @@ -29,8 +32,11 @@ class DefaultFactory extends FactoryInterface Token::CURRY => TokenCurry::class, Token::LOGIC_AND => TokenLogicAnd::class, Token::LOGIC_OR => TokenLogicOr::class, + Token::LOGIC_NOT => TokenLogicNot::class, Token::LOGIC_EQUAL => TokenLogicEqual::class, Token::LOGIC_NOT_EQUAL => TokenLogicNotEqual::class, + Token::LOGIC_GREATER => TokenLogicGreater::class, + Token::LOGIC_LESS => TokenLogicLess::class, Token::LOGIC_FAKE => TokenLogicFake::class, Token::VARIABLE => TokenVariable::class, Token::NUMBER => TokenNumber::class, diff --git a/src/Token/TokenComment.php b/src/Token/TokenComment.php new file mode 100644 index 0000000..916fa87 --- /dev/null +++ b/src/Token/TokenComment.php @@ -0,0 +1,17 @@ + + * @date 2021/1/26 13:43 + */ + + +namespace JerryYan\DSL\Token; + + +class TokenComment extends TokenInterface +{ + public static $alias = [ + '//' + ]; +} \ No newline at end of file diff --git a/src/Token/TokenCommentBlock.php b/src/Token/TokenCommentBlock.php new file mode 100644 index 0000000..82f6301 --- /dev/null +++ b/src/Token/TokenCommentBlock.php @@ -0,0 +1,17 @@ + + * @date 2021/1/26 13:44 + */ + + +namespace JerryYan\DSL\Token; + + +class TokenCommentBlock extends TokenInterface +{ + public static $alias = [ + '/*', '*/' + ]; +} \ No newline at end of file diff --git a/src/Token/TokenLogicGreater.php b/src/Token/TokenLogicGreater.php new file mode 100644 index 0000000..3ffad43 --- /dev/null +++ b/src/Token/TokenLogicGreater.php @@ -0,0 +1,15 @@ + + * @date 2021/1/26 13:48 + */ + + +namespace JerryYan\DSL\Token; + + +class TokenLogicGreater extends TokenInterface +{ + +} \ No newline at end of file diff --git a/src/Token/TokenLogicLess.php b/src/Token/TokenLogicLess.php new file mode 100644 index 0000000..99fb233 --- /dev/null +++ b/src/Token/TokenLogicLess.php @@ -0,0 +1,15 @@ + + * @date 2021/1/26 13:48 + */ + + +namespace JerryYan\DSL\Token; + + +class TokenLogicLess extends TokenInterface +{ + +} \ No newline at end of file diff --git a/src/Token/TokenLogicNot.php b/src/Token/TokenLogicNot.php new file mode 100644 index 0000000..760dc1d --- /dev/null +++ b/src/Token/TokenLogicNot.php @@ -0,0 +1,17 @@ + + * @date 2021/1/26 13:46 + */ + + +namespace JerryYan\DSL\Token; + + +class TokenLogicNot extends TokenInterface +{ + public static $alias = [ + '不成立' + ]; +} \ No newline at end of file diff --git a/tests/Reader/FileReaderTest.php b/tests/Reader/FileReaderTest.php new file mode 100644 index 0000000..9c95f0f --- /dev/null +++ b/tests/Reader/FileReaderTest.php @@ -0,0 +1,45 @@ + + * @date 2021/1/26 13:52 + */ + +namespace JerryYan\DSL\Test\Reader; + +use JerryYan\DSL\Exception\FileNotFoundException; +use JerryYan\DSL\Reader\FileReader; +use JerryYan\DSL\Reader\ReaderInterface; + +class FileReaderTest extends StringReaderTest +{ + protected $files = [ + __DIR__ . DIRECTORY_SEPARATOR . 'test.jdsl' + ]; + /** @var ReaderInterface[] */ + protected $readerArray = []; + protected $things = [ + [ + 'original' => "当 这个 等于 那个 的时候 则\r\n对 用户表 中的 该用户 更新 字段 状态 为 禁用", + 'tokens' => ["当", "这个", "等于", "那个", "的时候", "则", "对", "用户表", "中的", "该用户", "更新", "字段", "状态", "为", "禁用"], + 'nextTokens' => ["这个", "等于", "那个", "的时候", "则", "对", "用户表", "中的", "该用户", "更新", "字段", "状态", "为", "禁用", ""], + 'positions' => [0, 2, 5, 8, 11, 15, 18, 20, 24, 27, 31, 34, 37, 40, 42, 45, 47], + 'lines' => [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + 'linePositions' => [0, 2, 5, 8, 11, 15, 0, 2, 6, 9, 13, 16, 19, 22, 24, 27, 29], + 'moveToNextLines' => [6], + ], + ]; + + protected function setUp(): void + { + foreach ($this->files as $file) { + $this->readerArray[] = new FileReader($file); + } + } + + public function testFileNotFoundException() + { + $this->expectException(FileNotFoundException::class); + new FileReader('Not Exist File'); + } +} diff --git a/tests/Reader/StringReaderTest.php b/tests/Reader/StringReaderTest.php index 2cbc18a..00ec1a2 100644 --- a/tests/Reader/StringReaderTest.php +++ b/tests/Reader/StringReaderTest.php @@ -7,19 +7,16 @@ namespace JerryYan\DSL\Test\Reader; +use JerryYan\DSL\Reader\ReaderInterface; use JerryYan\DSL\Reader\StringReader; use PHPUnit\Framework\TestCase; class StringReaderTest extends TestCase { - protected $readerWithCrLf; - protected $reader; - protected $things; - protected $thingsWithCrLf; - - protected function setUp(): void - { - $this->things = [ + /** @var ReaderInterface[] */ + protected $readerArray = []; + protected $things = [ + [ 'original' => " Ahhh This Is 一个 新的 TOken", 'tokens' => ["Ahhh", "This", "Is", "一个", "新的", "TOken"], 'nextTokens' => ["This", "Is", "一个", "新的", "TOken", ""], @@ -27,8 +24,8 @@ class StringReaderTest extends TestCase 'lines' => [1, 1, 1, 1, 1, 1], 'linePositions' => [1, 7, 12, 15, 18, 21], 'moveToNextLines' => [], - ]; - $this->thingsWithCrLf = [ + ], + [ 'original' => " 中文 \r\n\r 这是 \r Is A \n\n 一个 新的 TOken", 'tokens' => ["中文", "这是", "Is", "A", "一个", "新的", "TOken"], 'nextTokens' => ["这是", "Is", "A", "一个", "新的", "TOken", ""], @@ -36,29 +33,34 @@ class StringReaderTest extends TestCase 'lines' => [1, 3, 4, 4, 6, 6, 6], 'linePositions' => [1, 1, 1, 4, 1, 4, 7], 'moveToNextLines' => [1, 2, 4], - ]; - $this->reader = new StringReader($this->things['original']); - $this->readerWithCrLf = new StringReader($this->thingsWithCrLf['original']); + ] + ]; + + protected function setUp(): void + { + foreach ($this->things as $thing) { + $this->readerArray[] = new StringReader($thing['original']); + } } public function testGetNextChar() { - $this->reader->reset(); - $this->assertEquals(mb_substr(trim($this->things['original']), 0, 1), $this->reader->getNextChar(), "不匹配"); - $this->assertEquals($this->things['positions'][0], $this->reader->getCurrentPosition(), "CurPos与预计不符"); - $this->readerWithCrLf->reset(); - $this->assertEquals(mb_substr(trim($this->thingsWithCrLf['original']), 0, 1), $this->readerWithCrLf->getNextChar(), "不匹配"); - $this->assertEquals($this->thingsWithCrLf['positions'][0], $this->readerWithCrLf->getCurrentPosition(), "CurPos与预计不符"); + foreach ($this->things as $index=>$thing) { + $reader = $this->readerArray[$index]; + $reader->reset(); + $this->assertEquals(mb_substr(trim($thing['original']), 0, 1), $reader->getNextChar(), "不匹配"); + $this->assertEquals($thing['positions'][0], $reader->getCurrentPosition(), "CurPos与预计不符"); + } } public function testGetCurrentToken() { - $this->reader->reset(); - $this->assertEquals($this->things['positions'][0], $this->reader->getCurrentPosition(), "CurPos与预计不符"); - $this->assertEquals($this->things['tokens'][0], $this->reader->getCurrentToken(), "不匹配"); - $this->readerWithCrLf->reset(); - $this->assertEquals($this->thingsWithCrLf['positions'][0], $this->readerWithCrLf->getCurrentPosition(), "CurPos与预计不符"); - $this->assertEquals($this->thingsWithCrLf['tokens'][0], $this->readerWithCrLf->getCurrentToken(), "不匹配"); + foreach ($this->things as $index=>$thing) { + $reader = $this->readerArray[$index]; + $reader->reset(); + $this->assertEquals($thing['positions'][0], $reader->getCurrentPosition(), "CurPos与预计不符"); + $this->assertEquals($thing['tokens'][0], $reader->getCurrentToken(), "不匹配"); + } } /** @@ -71,37 +73,23 @@ class StringReaderTest extends TestCase */ public function testMoveToNextToken() { - $this->reader->reset(); - foreach ($this->things['nextTokens'] as $key=> $nextToken){ - $oldCurToken = $this->reader->getCurrentToken(); - $oldNextPos = $this->reader->getNextPosition(); - $oldNextToken = $this->reader->getNextToken(); - $this->assertEquals($nextToken, $oldNextToken, "不匹配"); - $this->assertEquals($this->things['positions'][$key], $this->reader->getCurrentPosition(), "CurPos与预计不符"); - $this->assertEquals($this->things['lines'][$key], $this->reader->getCurrentLine(), "CurLine与预计不符"); - $this->assertEquals($this->things['linePositions'][$key], $this->reader->getCurrentLinePosition(), "CLPos与预计不符"); - $hasNext = $this->reader->moveToNextToken(); - if ($hasNext) { - $this->assertNotEquals($oldCurToken, $this->reader->getCurrentToken(), "CurToken与旧CurToken相同"); - $this->assertNotEquals($oldNextPos, $this->reader->getNextPosition(), "NextPos与旧NextPos相同"); - $this->assertNotEquals($this->reader->getNextPosition(), $this->reader->getCurrentPosition(), "CurPos与NextPos相同"); - } - } - // Cr/LF Support - $this->readerWithCrLf->reset(); - foreach ($this->thingsWithCrLf['nextTokens'] as $key=> $nextToken){ - $oldCurToken = $this->readerWithCrLf->getCurrentToken(); - $oldNextPos = $this->readerWithCrLf->getNextPosition(); - $oldNextToken = $this->readerWithCrLf->getNextToken(); - $this->assertEquals($nextToken, $oldNextToken, "不匹配"); - $this->assertEquals($this->thingsWithCrLf['positions'][$key], $this->readerWithCrLf->getCurrentPosition(), "CurPos与预计不符"); - $this->assertEquals($this->thingsWithCrLf['lines'][$key], $this->readerWithCrLf->getCurrentLine(), "CurLine与预计不符"); - $this->assertEquals($this->thingsWithCrLf['linePositions'][$key], $this->readerWithCrLf->getCurrentLinePosition(), "CLPos与预计不符"); - $hasNext = $this->readerWithCrLf->moveToNextToken(); - if ($hasNext) { - $this->assertNotEquals($oldCurToken, $this->readerWithCrLf->getCurrentToken(), "CurToken与旧CurToken相同"); - $this->assertNotEquals($oldNextPos, $this->readerWithCrLf->getNextPosition(), "NextPos与旧NextPos相同"); - $this->assertNotEquals($this->readerWithCrLf->getNextPosition(), $this->readerWithCrLf->getCurrentPosition(), "CurPos与NextPos相同"); + foreach ($this->things as $index=>$thing) { + $reader = $this->readerArray[$index]; + $reader->reset(); + foreach ($thing['nextTokens'] as $key=> $nextToken){ + $oldCurToken = $reader->getCurrentToken(); + $oldNextPos = $reader->getNextPosition(); + $oldNextToken = $reader->getNextToken(); + $this->assertEquals($nextToken, $oldNextToken, "不匹配"); + $this->assertEquals($thing['positions'][$key], $reader->getCurrentPosition(), "CurPos与预计不符"); + $this->assertEquals($thing['lines'][$key], $reader->getCurrentLine(), "CurLine与预计不符"); + $this->assertEquals($thing['linePositions'][$key], $reader->getCurrentLinePosition(), "CLPos与预计不符"); + $hasNext = $reader->moveToNextToken(); + if ($hasNext) { + $this->assertNotEquals($oldCurToken, $reader->getCurrentToken(), "CurToken与旧CurToken相同"); + $this->assertNotEquals($oldNextPos, $reader->getNextPosition(), "NextPos与旧NextPos相同"); + $this->assertNotEquals($reader->getNextPosition(), $reader->getCurrentPosition(), "CurPos与NextPos相同"); + } } } } @@ -113,38 +101,45 @@ class StringReaderTest extends TestCase */ public function testGetNextToken() { - $this->reader->reset(); - $nextPos = $this->reader->getNextPosition(); - $string = $this->reader->getNextToken(); - $this->assertEquals($string, $this->reader->getNextToken(), "不匹配"); - $this->assertEquals($this->reader->getNextToken(), $this->reader->getNextToken(), "不匹配"); - $this->assertEquals($nextPos, $this->reader->getNextPosition(), "NextPos不可以发生变化"); + foreach ($this->things as $index=>$thing) { + $reader = $this->readerArray[$index]; + $reader->reset(); + $nextPos = $reader->getNextPosition(); + $string = $reader->getNextToken(); + $this->assertEquals($string, $reader->getNextToken(), "不匹配"); + $this->assertEquals($reader->getNextToken(), $reader->getNextToken(), "不匹配"); + $this->assertEquals($nextPos, $reader->getNextPosition(), "NextPos不可以发生变化"); + } } public function testSkipCurrentLine() { - $this->readerWithCrLf->resetCursor(); - foreach ($this->thingsWithCrLf['moveToNextLines'] as $key){ - $this->readerWithCrLf->skipCurrentLine(); - $this->assertEquals($this->thingsWithCrLf['lines'][$key], $this->readerWithCrLf->getCurrentLine(), "行号不匹配"); - $this->assertEquals($this->thingsWithCrLf['linePositions'][$key], $this->readerWithCrLf->getCurrentLinePosition(), "CLPos不匹配"); - $this->assertEquals($this->thingsWithCrLf['tokens'][$key], $this->readerWithCrLf->getCurrentToken(), "Token不匹配"); - $this->assertEquals($this->thingsWithCrLf['positions'][$key], $this->readerWithCrLf->getCurrentPosition(), "CurPos不匹配"); - $this->assertEquals($this->thingsWithCrLf['nextTokens'][$key], $this->readerWithCrLf->getNextToken(), "NextToken不匹配"); + foreach ($this->things as $index=>$thing) { + $reader = $this->readerArray[$index]; + $reader->reset(); + foreach ($thing['moveToNextLines'] as $key){ + $reader->skipCurrentLine(); + $this->assertEquals($thing['lines'][$key], $reader->getCurrentLine(), "行号不匹配"); + $this->assertEquals($thing['linePositions'][$key], $reader->getCurrentLinePosition(), "CLPos不匹配"); + $this->assertEquals($thing['tokens'][$key], $reader->getCurrentToken(), "Token不匹配"); + $this->assertEquals($thing['positions'][$key], $reader->getCurrentPosition(), "CurPos不匹配"); + $this->assertEquals($thing['nextTokens'][$key], $reader->getNextToken(), "NextToken不匹配"); + } } } public function testResetCursor() { - $this->readerWithCrLf->moveToNextToken(); - $curPos = $this->readerWithCrLf->getCurrentPosition(); - $nextPos = $this->readerWithCrLf->getNextPosition(); - $curLine = $this->readerWithCrLf->getCurrentLine(); - $string = $this->readerWithCrLf->getCurrentToken(); - $this->readerWithCrLf->resetCursor(); - $this->assertNotEquals($curPos, $this->readerWithCrLf->getCurrentPosition(), "CurPos未发生变化"); - $this->assertNotEquals($nextPos, $this->readerWithCrLf->getNextPosition(), "NextPos未发生变化"); - $this->assertNotEquals($curLine, $this->readerWithCrLf->getCurrentLine(), "CurLine未发生变化"); - $this->assertNotEquals($string, $this->readerWithCrLf->getCurrentToken(), "CurToken未发生变化"); + foreach ($this->things as $index=>$thing) { + $reader = $this->readerArray[$index]; + $reader->moveToNextToken(); + $curPos = $reader->getCurrentPosition(); + $nextPos = $reader->getNextPosition(); + $string = $reader->getCurrentToken(); + $reader->resetCursor(); + $this->assertNotEquals($curPos, $reader->getCurrentPosition(), "CurPos未发生变化"); + $this->assertNotEquals($nextPos, $reader->getNextPosition(), "NextPos未发生变化"); + $this->assertNotEquals($string, $reader->getCurrentToken(), "CurToken未发生变化"); + } } } diff --git a/tests/Reader/test.jdsl b/tests/Reader/test.jdsl new file mode 100644 index 0000000..a615234 --- /dev/null +++ b/tests/Reader/test.jdsl @@ -0,0 +1,2 @@ +当 这个 等于 那个 的时候 则 +对 用户表 中的 该用户 更新 字段 状态 为 禁用 \ No newline at end of file