Support static expressions for menu simple string properties

This commit is contained in:
Jan 2023-12-25 22:59:56 +01:00
parent 1b5d6f7439
commit 7820390dd8
No known key found for this signature in database
GPG Key ID: 44B581F78FF5C57C
5 changed files with 92 additions and 8 deletions

View File

@ -58,6 +58,20 @@ MatcherFactoryWrapper<SimpleParserValue> MenuMatcherFactory::Numeric() const
})); }));
} }
MatcherFactoryWrapper<SimpleParserValue> MenuMatcherFactory::TextExpression() const
{
return MatcherFactoryWrapper(Or({
StringChain().Tag(TAG_STRING_CHAIN).Capture(CAPTURE_STRING_CHAIN),
Identifier().Tag(TAG_IDENTIFIER).Capture(CAPTURE_IDENTIFIER),
And({
Char('(').Capture(CAPTURE_FIRST_TOKEN),
Label(MenuExpressionMatchers::LABEL_EXPRESSION),
Char(')'),
})
.Tag(TAG_EXPRESSION),
}));
}
MatcherFactoryWrapper<SimpleParserValue> MenuMatcherFactory::IntExpression() const MatcherFactoryWrapper<SimpleParserValue> MenuMatcherFactory::IntExpression() const
{ {
return MatcherFactoryWrapper(Or({ return MatcherFactoryWrapper(Or({
@ -144,6 +158,42 @@ int MenuMatcherFactory::TokenIntExpressionValue(MenuFileParserState* state, Sequ
throw ParsingException(TokenPos(), "TokenIntExpressionValue must be expression or int"); throw ParsingException(TokenPos(), "TokenIntExpressionValue must be expression or int");
} }
std::string MenuMatcherFactory::TokenTextExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result)
{
const auto nextTag = result.PeekTag();
assert(nextTag == TAG_STRING_CHAIN || nextTag == TAG_IDENTIFIER || nextTag == TAG_EXPRESSION);
if (nextTag == TAG_STRING_CHAIN)
{
result.NextTag();
return result.NextCapture(CAPTURE_STRING_CHAIN).StringValue();
}
if (nextTag == TAG_IDENTIFIER)
{
result.NextTag();
return result.NextCapture(CAPTURE_IDENTIFIER).IdentifierValue();
}
if (nextTag == TAG_EXPRESSION)
{
result.NextTag();
const auto expression = MenuExpressionMatchers(state).ProcessExpression(result);
if (!expression || !expression->IsStatic())
throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Not a valid static expression");
const auto value = expression->EvaluateStatic();
if (value.m_type != SimpleExpressionValue::Type::STRING)
throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Expression MUST be string type");
return std::move(*value.m_string_value);
}
throw ParsingException(TokenPos(), "TokenIntExpressionValue must be expression or int");
}
double MenuMatcherFactory::TokenNumericExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) double MenuMatcherFactory::TokenNumericExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result)
{ {
const auto nextTag = result.PeekTag(); const auto nextTag = result.PeekTag();

View File

@ -8,13 +8,17 @@ namespace menu
{ {
class MenuMatcherFactory : public SimpleMatcherFactory class MenuMatcherFactory : public SimpleMatcherFactory
{ {
static constexpr auto TAG_INT = 1420; static constexpr auto TAG_STRING_CHAIN = 1420;
static constexpr auto TAG_NUMERIC = 1421; static constexpr auto TAG_IDENTIFIER = 1421;
static constexpr auto TAG_EXPRESSION = 1422; static constexpr auto TAG_INT = 1422;
static constexpr auto TAG_NUMERIC = 1423;
static constexpr auto TAG_EXPRESSION = 1424;
static constexpr auto CAPTURE_FIRST_TOKEN = 1420; static constexpr auto CAPTURE_FIRST_TOKEN = 1420;
static constexpr auto CAPTURE_INT = 1421; static constexpr auto CAPTURE_STRING_CHAIN = 1421;
static constexpr auto CAPTURE_NUMERIC = 1422; static constexpr auto CAPTURE_IDENTIFIER = 1422;
static constexpr auto CAPTURE_INT = 1423;
static constexpr auto CAPTURE_NUMERIC = 1424;
public: public:
explicit MenuMatcherFactory(const IMatcherForLabelSupplier<SimpleParserValue>* labelSupplier); explicit MenuMatcherFactory(const IMatcherForLabelSupplier<SimpleParserValue>* labelSupplier);
@ -24,6 +28,7 @@ namespace menu
_NODISCARD MatcherFactoryWrapper<SimpleParserValue> TextNoChain() const; _NODISCARD MatcherFactoryWrapper<SimpleParserValue> TextNoChain() const;
_NODISCARD MatcherFactoryWrapper<SimpleParserValue> Numeric() const; _NODISCARD MatcherFactoryWrapper<SimpleParserValue> Numeric() const;
_NODISCARD MatcherFactoryWrapper<SimpleParserValue> TextExpression() const;
_NODISCARD MatcherFactoryWrapper<SimpleParserValue> IntExpression() const; _NODISCARD MatcherFactoryWrapper<SimpleParserValue> IntExpression() const;
_NODISCARD MatcherFactoryWrapper<SimpleParserValue> NumericExpression() const; _NODISCARD MatcherFactoryWrapper<SimpleParserValue> NumericExpression() const;
@ -31,6 +36,7 @@ namespace menu
_NODISCARD static double TokenNumericFloatingPointValue(const SimpleParserValue& value); _NODISCARD static double TokenNumericFloatingPointValue(const SimpleParserValue& value);
_NODISCARD static std::string& TokenTextValue(const SimpleParserValue& value); _NODISCARD static std::string& TokenTextValue(const SimpleParserValue& value);
_NODISCARD static std::string TokenTextExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result);
_NODISCARD static int TokenIntExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result); _NODISCARD static int TokenIntExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result);
_NODISCARD static double TokenNumericExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result); _NODISCARD static double TokenNumericExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result);
}; };

View File

@ -1,5 +1,6 @@
#include "GenericStringPropertySequence.h" #include "GenericStringPropertySequence.h"
#include "Parsing/Menu/Matcher/MenuExpressionMatchers.h"
#include "Parsing/Menu/Matcher/MenuMatcherFactory.h" #include "Parsing/Menu/Matcher/MenuMatcherFactory.h"
#include <utility> #include <utility>
@ -10,10 +11,11 @@ GenericStringPropertySequence::GenericStringPropertySequence(std::string keyword
: m_set_callback(std::move(setCallback)) : m_set_callback(std::move(setCallback))
{ {
const MenuMatcherFactory create(this); const MenuMatcherFactory create(this);
AddLabeledMatchers(MenuExpressionMatchers().Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION);
AddMatchers({ AddMatchers({
create.KeywordIgnoreCase(std::move(keywordName)).Capture(CAPTURE_FIRST_TOKEN), create.KeywordIgnoreCase(std::move(keywordName)).Capture(CAPTURE_FIRST_TOKEN),
create.Text().Capture(CAPTURE_VALUE), create.TextExpression(),
}); });
} }
@ -21,7 +23,7 @@ void GenericStringPropertySequence::ProcessMatch(MenuFileParserState* state, Seq
{ {
if (m_set_callback) if (m_set_callback)
{ {
const auto& value = MenuMatcherFactory::TokenTextValue(result.NextCapture(CAPTURE_VALUE)); const auto value = MenuMatcherFactory::TokenTextExpressionValue(state, result);
m_set_callback(state, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), value); m_set_callback(state, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), value);
} }
} }

View File

@ -14,7 +14,6 @@ namespace menu
private: private:
static constexpr auto CAPTURE_FIRST_TOKEN = 1; static constexpr auto CAPTURE_FIRST_TOKEN = 1;
static constexpr auto CAPTURE_VALUE = 2;
const callback_t m_set_callback; const callback_t m_set_callback;

View File

@ -64,6 +64,33 @@ namespace test::parsing::menu::sequence::item
} }
}; };
TEST_CASE("ItemScopeSequences: Can use static expressions for simple text properties", "[parsing][sequence][menu]")
{
ItemSequenceTestsHelper helper(FeatureLevel::IW4, false);
const TokenPos pos;
helper.Tokens({
SimpleParserValue::Identifier(pos, new std::string("name")),
SimpleParserValue::Character(pos, '('),
SimpleParserValue::String(pos, new std::string("Hello")),
SimpleParserValue::Character(pos, '+'),
SimpleParserValue::String(pos, new std::string(" ")),
SimpleParserValue::Character(pos, '+'),
SimpleParserValue::String(pos, new std::string("World")),
SimpleParserValue::Character(pos, ')'),
SimpleParserValue::EndOfFile(pos),
});
const auto result = helper.PerformTest();
REQUIRE(result);
REQUIRE(helper.m_consumed_token_count == 8);
const auto* item = helper.m_state->m_current_item;
REQUIRE(item);
REQUIRE(item->m_name == "Hello World");
}
TEST_CASE("ItemScopeSequences: Rect works with only x,y,w,h as ints", "[parsing][sequence][menu]") TEST_CASE("ItemScopeSequences: Rect works with only x,y,w,h as ints", "[parsing][sequence][menu]")
{ {
ItemSequenceTestsHelper helper(FeatureLevel::IW4, false); ItemSequenceTestsHelper helper(FeatureLevel::IW4, false);