summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
diff options
context:
space:
mode:
authorJordan Woyak <jordan.woyak@gmail.com>2024-11-06 19:13:33 -0600
committerJordan Woyak <jordan.woyak@gmail.com>2024-11-07 08:31:25 -0600
commit5078a63084121fa31d6d763dfa30ba5b0f99f040 (patch)
tree5c16040323bd993ecacfdf6ebc389c3d6fbd0280 /Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
parent7e1074b140809b0da7aa7d02b6303a68cc351be2 (diff)
InputCommon: Add ternary conditional operator to input expressions.
Diffstat (limited to 'Source/Core/InputCommon/ControlReference/ExpressionParser.cpp')
-rw-r--r--Source/Core/InputCommon/ControlReference/ExpressionParser.cpp62
1 files changed, 48 insertions, 14 deletions
diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
index b558d6b78f..e256eeeff5 100644
--- a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
+++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
@@ -168,6 +168,10 @@ Token Lexer::NextToken()
return Token(TOK_RPAREN);
case '@':
return Token(TOK_HOTKEY);
+ case '?':
+ return Token(TOK_QUESTION);
+ case ':':
+ return Token(TOK_COLON);
case '&':
return Token(TOK_AND);
case '|':
@@ -745,7 +749,7 @@ private:
{
// Read one argument.
// Grab an expression, but stop at comma.
- auto arg = ParseBinary(BinaryOperatorPrecedence(TOK_COMMA));
+ auto arg = ParseInfixOperations(OperatorPrecedence(TOK_COMMA));
if (ParseStatus::Successful != arg.status)
return arg;
@@ -844,7 +848,7 @@ private:
}
}
- static int BinaryOperatorPrecedence(TokenType type)
+ static constexpr int OperatorPrecedence(TokenType type = TOK_EOF)
{
switch (type)
{
@@ -865,16 +869,16 @@ private:
case TOK_OR:
return 6;
case TOK_ASSIGN:
+ case TOK_QUESTION:
return 7;
case TOK_COMMA:
return 8;
default:
- ASSERT(false);
- return 0;
+ return 999;
}
}
- ParseResult ParseBinary(int precedence = 999)
+ ParseResult ParseInfixOperations(int precedence = OperatorPrecedence())
{
ParseResult lhs = ParseAtom(Chew());
@@ -884,18 +888,48 @@ private:
std::unique_ptr<Expression> expr = std::move(lhs.expr);
// TODO: handle LTR/RTL associativity?
- while (Peek().IsBinaryOperator() && BinaryOperatorPrecedence(Peek().type) < precedence)
+ while (true)
{
- const Token tok = Chew();
- ParseResult rhs = ParseBinary(BinaryOperatorPrecedence(tok.type));
- if (rhs.status == ParseStatus::SyntaxError)
+ const Token op = Peek();
+ if (op.IsBinaryOperator() && OperatorPrecedence(op.type) < precedence)
{
- return rhs;
- }
+ Chew();
+ ParseResult rhs = ParseInfixOperations(OperatorPrecedence(op.type));
+ if (rhs.status == ParseStatus::SyntaxError)
+ return rhs;
- expr = std::make_unique<BinaryExpression>(tok.type, std::move(expr), std::move(rhs.expr));
+ expr = std::make_unique<BinaryExpression>(op.type, std::move(expr), std::move(rhs.expr));
+ }
+ else if (op.type == TOK_QUESTION && OperatorPrecedence(TOK_QUESTION) <= precedence)
+ {
+ // Handle conditional operator: (a ? b : c)
+ Chew();
+ auto true_result = ParseInfixOperations(OperatorPrecedence(op.type));
+ if (true_result.status != ParseStatus::Successful)
+ return true_result;
+
+ const Token should_be_colon = Chew();
+ if (should_be_colon.type != TOK_COLON)
+ return ParseResult::MakeErrorResult(should_be_colon,
+ Common::GetStringT("Expected colon."));
+
+ auto false_result = ParseInfixOperations(OperatorPrecedence(op.type));
+ if (false_result.status != ParseStatus::Successful)
+ return false_result;
+
+ auto conditional = MakeFunctionExpression("if");
+ std::vector<std::unique_ptr<Expression>> args;
+ args.emplace_back(std::move(expr));
+ args.emplace_back(std::move(true_result.expr));
+ args.emplace_back(std::move(false_result.expr));
+ conditional->SetArguments(std::move(args));
+ expr = std::move(conditional);
+ }
+ else
+ {
+ break;
+ }
}
-
return ParseResult::MakeSuccessfulResult(std::move(expr));
}
@@ -948,7 +982,7 @@ private:
return ParseResult::MakeSuccessfulResult(std::make_unique<HotkeyExpression>(std::move(inputs)));
}
- ParseResult ParseToplevel() { return ParseBinary(); }
+ ParseResult ParseToplevel() { return ParseInfixOperations(); }
}; // namespace ExpressionParser
ParseResult ParseTokens(const std::vector<Token>& tokens)