Make sure captures work with transforms

This commit is contained in:
Jan
2021-02-13 16:01:58 +01:00
parent 37232e3176
commit 32f815c378
5 changed files with 207 additions and 44 deletions

View File

@ -1,5 +1,7 @@
#include <catch2/catch.hpp>
#include <sstream>
#include "Utils/ClassUtils.h"
#include "Parsing/Header/Impl/HeaderParserValue.h"
#include "Parsing/Header/Matcher/HeaderMatcherFactory.h"
@ -812,9 +814,15 @@ namespace test::parsing::matcher
create.Char(':'),
create.Identifier()
}))
}).Transform([](std::vector<std::reference_wrapper<const HeaderParserValue>>& values)
}).Transform([](HeaderMatcherFactory::token_list_t& values)
{
return HeaderParserValue::TypeName(values[0].get().GetPos(), new std::string());
std::ostringstream str;
str << values[0].get().IdentifierValue();
for (auto i = 3u; i < values.size(); i += 3)
str << "::" << values[i].get().IdentifierValue();
return HeaderParserValue::TypeName(values[0].get().GetPos(), new std::string(str.str()));
})
}, LABEL_TYPENAME);
@ -845,4 +853,122 @@ namespace test::parsing::matcher
REQUIRE(test.PerformTest());
REQUIRE(test.GetConsumedTokenCount() == 6);
}
TEST_CASE("Matcher: Can capture within transform", "[parsing][matcher]")
{
static constexpr auto LABEL_TYPENAME = 1;
static constexpr auto CAPTURE_TYPENAME = 1;
static constexpr auto CAPTURE_FIRST_TYPENAME_IDENTIFIER = 2;
MatchersTestsHelper test;
const TokenPos pos;
const auto create = test.Factory();
test.Matchers(
{
create.Type(HeaderParserValueType::STRUCT),
create.Label(LABEL_TYPENAME).Capture(CAPTURE_TYPENAME),
create.Char('{')
});
test.LabeledMatchers(
{
create.And({
create.Identifier().Capture(CAPTURE_FIRST_TYPENAME_IDENTIFIER),
create.OptionalLoop(create.And({
create.Char(':'),
create.Char(':'),
create.Identifier()
}))
}).Transform([](HeaderMatcherFactory::token_list_t& values)
{
std::ostringstream str;
str << values[0].get().IdentifierValue();
for (auto i = 3u; i < values.size(); i += 3)
str << "::" << values[i].get().IdentifierValue();
return HeaderParserValue::TypeName(values[0].get().GetPos(), new std::string(str.str()));
})
}, LABEL_TYPENAME);
test.Tokens({
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
HeaderParserValue::Identifier(pos, new std::string("hello")),
HeaderParserValue::Character(pos, ':'),
HeaderParserValue::Character(pos, ':'),
HeaderParserValue::Identifier(pos, new std::string("world")),
HeaderParserValue::Character(pos, '{'),
HeaderParserValue::Invalid(pos)
});
test.MatchCallback([](sequence_result_t& result)
{
REQUIRE(result.NextTag() == matcher_t::NO_ID);
REQUIRE(result.HasNextCapture(CAPTURE_TYPENAME));
{
const auto& capture = result.NextCapture(CAPTURE_TYPENAME);
REQUIRE(capture.m_type == HeaderParserValueType::TYPE_NAME);
REQUIRE(capture.TypeNameValue() == "hello::world");
}
REQUIRE(!result.HasNextCapture(CAPTURE_TYPENAME));
REQUIRE(result.HasNextCapture(CAPTURE_FIRST_TYPENAME_IDENTIFIER));
{
const auto& capture = result.NextCapture(CAPTURE_FIRST_TYPENAME_IDENTIFIER);
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
REQUIRE(capture.IdentifierValue() == "hello");
}
REQUIRE(!result.HasNextCapture(CAPTURE_FIRST_TYPENAME_IDENTIFIER));
});
REQUIRE(test.PerformTest());
REQUIRE(test.GetConsumedTokenCount() == 6);
}
TEST_CASE("Matcher: Can transform and capture in the same matcher", "[parsing][matcher]")
{
static constexpr auto CAPTURE_NAME = 1;
MatchersTestsHelper test;
const TokenPos pos;
const auto create = test.Factory();
test.Matchers(
{
create.Type(HeaderParserValueType::STRUCT),
create.Identifier().Capture(CAPTURE_NAME).Transform([](HeaderMatcherFactory::token_list_t& tokens)
{
auto str = tokens[0].get().IdentifierValue();
std::transform(str.begin(), str.end(), str.begin(), toupper);
return HeaderParserValue::Identifier(tokens[0].get().GetPos(), new std::string(std::move(str)));
}),
create.Char('{')
});
test.Tokens({
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
HeaderParserValue::Identifier(pos, new std::string("hello_world")),
HeaderParserValue::Character(pos, '{'),
HeaderParserValue::Invalid(pos)
});
test.MatchCallback([](sequence_result_t& result)
{
REQUIRE(result.NextTag() == matcher_t::NO_ID);
REQUIRE(result.HasNextCapture(CAPTURE_NAME));
{
const auto& capture = result.NextCapture(CAPTURE_NAME);
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
REQUIRE(capture.IdentifierValue() == "HELLO_WORLD");
}
REQUIRE(!result.HasNextCapture(CAPTURE_NAME));
});
REQUIRE(test.PerformTest());
REQUIRE(test.GetConsumedTokenCount() == 3);
}
}