Skip to content

Commit

Permalink
karm-io: Better test coverage of SScan.
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepy-monax committed Apr 10, 2024
1 parent 413a456 commit 59fab78
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 10 deletions.
7 changes: 1 addition & 6 deletions src/libs/karm-io/expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,14 @@

namespace Karm::Re {

template <typename T>
concept Expr = requires(T expr, Io::SScan &scan) {
{ expr(scan) } -> Meta::Same<bool>;
};

/// Match a string against an Expr
///
/// Returns
/// - Match::YES : If the Expr match the whole string
/// - 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 <StaticEncoding E>
Match match(Re::Expr auto expr, _Str<E> input) {
Match match(Expr auto expr, _Str<E> input) {
Io::_SScan<E> scan(input);
if (not expr(scan))
return Match::NO;
Expand Down
47 changes: 43 additions & 4 deletions src/libs/karm-io/sscan.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@
#include <karm-base/string.h>
#include <karm-meta/callable.h>

namespace Karm {

namespace Io {
template <StaticEncoding E>
struct _SScan;
} // namespace Io

namespace Re {
template <typename T>
concept Expr = requires(T expr, Io::_SScan<Utf8> &scan) {
{ expr(scan) } -> Meta::Same<bool>;
};

} // namespace Re

} // namespace Karm

namespace Karm::Io {

template <StaticEncoding E>
Expand Down Expand Up @@ -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<decltype(expr), decltype(*this)>
{
auto rollback = rollbackPoint();
Expand Down Expand Up @@ -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;
Expand All @@ -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 =
Expand All @@ -159,7 +198,7 @@ struct _SScan {
return Match::NO;
}

_Str<E> token(auto expr) {
_Str<E> token(Re::Expr auto expr) {
_begin = _cursor;
if (not skip(expr))
_cursor = _begin;
Expand Down
143 changes: 143 additions & 0 deletions src/libs/karm-io/tests/test-sscan.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#include <karm-io/sscan.h>
#include <karm-test/macros.h>

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

0 comments on commit 59fab78

Please sign in to comment.