From 59fab7808be2f6c079c586c10e0640b8ba37e519 Mon Sep 17 00:00:00 2001 From: VAN BOSSUYT Nicolas Date: Wed, 10 Apr 2024 17:53:56 +0200 Subject: [PATCH] karm-io: Better test coverage of SScan. --- src/libs/karm-io/expr.h | 7 +- src/libs/karm-io/sscan.h | 47 ++++++++- src/libs/karm-io/tests/test-sscan.cpp | 143 ++++++++++++++++++++++++++ 3 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 src/libs/karm-io/tests/test-sscan.cpp diff --git a/src/libs/karm-io/expr.h b/src/libs/karm-io/expr.h index ba8951aa75..faf4c6f33b 100644 --- a/src/libs/karm-io/expr.h +++ b/src/libs/karm-io/expr.h @@ -8,11 +8,6 @@ namespace Karm::Re { -template -concept Expr = requires(T expr, Io::SScan &scan) { - { expr(scan) } -> Meta::Same; -}; - /// Match a string against an Expr /// /// Returns @@ -20,7 +15,7 @@ concept Expr = requires(T expr, Io::SScan &scan) { /// - Match::NO : If the Expr doesn't match the string /// - Match::PARTIAL : If the Expr matches but the end of string is not reached template -Match match(Re::Expr auto expr, _Str input) { +Match match(Expr auto expr, _Str input) { Io::_SScan scan(input); if (not expr(scan)) return Match::NO; diff --git a/src/libs/karm-io/sscan.h b/src/libs/karm-io/sscan.h index 0f4def7029..8aaa345986 100644 --- a/src/libs/karm-io/sscan.h +++ b/src/libs/karm-io/sscan.h @@ -7,6 +7,23 @@ #include #include +namespace Karm { + +namespace Io { +template +struct _SScan; +} // namespace Io + +namespace Re { +template +concept Expr = requires(T expr, Io::_SScan &scan) { + { expr(scan) } -> Meta::Same; +}; + +} // namespace Re + +} // namespace Karm + namespace Karm::Io { template @@ -102,7 +119,7 @@ struct _SScan { } /// If the expression matches, advance the cursor. - bool skip(auto expr) + bool skip(Re::Expr auto expr) requires Meta::Callable { auto rollback = rollbackPoint(); @@ -135,7 +152,7 @@ struct _SScan { } /// Keep advancing the cursor while the expression matches. - bool eat(auto expr) { + bool eat(Re::Expr auto expr) { bool result = false; if (skip(expr)) { result = true; @@ -145,9 +162,31 @@ struct _SScan { return result; } + /// Check if a rune is ahead or not. + bool ahead(Rune c) { + return peek() == c; + } + + /// Check if a string is ahead or not. + bool ahead(Str str) { + auto rollback = rollbackPoint(); + for (auto r : iterRunes(str)) + if (next() != r) + return false; + return true; + } + + /// Check if the expression is ahead or not. + bool ahead(Re::Expr auto expr) { + auto rollback = rollbackPoint(); + if (not expr(*this)) + return false; + return true; + } + /// Check if the expression matches or not. /// The cursor is restored to the original position. - Match match(auto expr) { + Match match(Re::Expr auto expr) { auto rollback = rollbackPoint(); if (expr(*this)) { Match result = @@ -159,7 +198,7 @@ struct _SScan { return Match::NO; } - _Str token(auto expr) { + _Str token(Re::Expr auto expr) { _begin = _cursor; if (not skip(expr)) _cursor = _begin; diff --git a/src/libs/karm-io/tests/test-sscan.cpp b/src/libs/karm-io/tests/test-sscan.cpp new file mode 100644 index 0000000000..862425183a --- /dev/null +++ b/src/libs/karm-io/tests/test-sscan.cpp @@ -0,0 +1,143 @@ +#include +#include + +namespace Karm::Io::Tests { + +test$(sscanEnded) { + SScan s{""s}; + expect$(s.ended()); + + s = SScan{"a"s}; + expect$(not s.ended()); + + return Ok(); +} + +test$(sscanRem) { + SScan s{"abc"}; + expect$(s.rem() == 3); + + s = SScan{"abc"}; + s.next(); + expect$(s.rem() == 2); + + s = SScan{"abc"}; + s.next(3); + expect$(s.rem() == 0); + + return Ok(); +} + +test$(sscanRemStr) { + SScan s{"abc"}; + expect$(s.remStr() == "abc"); + + s = SScan{"abc"}; + s.next(); + expect$(s.remStr() == "bc"); + + s = SScan{"abc"}; + s.next(3); + expect$(s.remStr() == ""); + + return Ok(); +} + +test$(sscanCurr) { + SScan s{"abc"}; + expect$(s.curr() == 'a'); + + s = SScan{"abc"}; + s.next(); + expect$(s.curr() == 'b'); + + s = SScan{"abc"}; + s.next(3); + expect$(s.curr() == '\0'); + + return Ok(); +} + +test$(sscanPeek) { + SScan s{"abc"}; + + expect$(s.peek() == 'a'); + expect$(s.peek(1) == 'b'); + expect$(s.peek(2) == 'c'); + expect$(s.peek(3) == '\0'); + expect$(s.peek(4) == '\0'); + + return Ok(); +} + +test$(sscanNext) { + SScan s{"abc"}; + + expect$(s.next() == 'a'); + expect$(s.next() == 'b'); + expect$(s.next() == 'c'); + expect$(s.next() == '\0'); + expect$(s.next() == '\0'); + + return Ok(); +} + +test$(sscanSkip) { + SScan s{"abc"}; + + expect$(s.skip('a')); + expect$(s.rem() == 2); + expect$(s.skip('b')); + expect$(s.rem() == 1); + expect$(s.skip('c')); + expect$(s.rem() == 0); + + expect$(not s.skip('d')); + expect$(s.rem() == 0); + + s = SScan{"abc"}; + expect$(s.skip("ab")); + expect$(s.rem() == 1); + expect$(s.skip("c")); + expect$(s.rem() == 0); + expect$(not s.skip("d")); + expect$(s.rem() == 0); + + return Ok(); +} + +test$(sscanEat) { + SScan s{"abc"}; + + expect$(s.eat('a')); + expect$(s.eat('b')); + expect$(s.eat('c')); + expect$(not s.eat('d')); + + s = SScan{"abc"}; + expect$(s.eat("ab")); + expect$(s.eat("c")); + expect$(not s.eat("d")); + + s = SScan{"aaaaaa"}; + expect$(s.eat('a')); + expect$(s.ended()); + + return Ok(); +} + +test$(sscanAhead) { + SScan s{"abc"}; + + expect$(s.ahead('a')); + expectNot$(s.ahead('b')); + expect$(s.rem() == 3); + + expect$(s.ahead("ab")); + expectNot$(s.ahead("bc")); + expect$(s.rem() == 3); + + return Ok(); +} + +} // namespace Karm::Io::Tests