summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2025-01-27 21:16:29 -0500
committerGitHub <noreply@github.com>2025-01-27 21:16:29 -0500
commite18a4d04b4fc1363b1ce48b2fc43589ef3a05962 (patch)
tree442a0a31d039f9327e61dea14d9920cf5627f1b3 /Source/Core/InputCommon
parent2b5cd96cb1287f45e44f72dece3b53d00020725f (diff)
parent5078a63084121fa31d6d763dfa30ba5b0f99f040 (diff)
Merge pull request #13178 from jordan-woyak/input-expressions-conditional-op
InputCommon: Add ternary conditional operator to input expressions.
Diffstat (limited to 'Source/Core/InputCommon')
-rw-r--r--Source/Core/InputCommon/ControlReference/ExpressionParser.cpp62
-rw-r--r--Source/Core/InputCommon/ControlReference/ExpressionParser.h2
2 files changed, 50 insertions, 14 deletions
diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
index 0004393909..0db51cfe2a 100644
--- a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
+++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
@@ -171,6 +171,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 '|':
@@ -747,7 +751,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;
@@ -846,7 +850,7 @@ private:
}
}
- static int BinaryOperatorPrecedence(TokenType type)
+ static constexpr int OperatorPrecedence(TokenType type = TOK_EOF)
{
switch (type)
{
@@ -867,16 +871,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());
@@ -886,18 +890,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));
}
@@ -950,7 +984,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)
diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.h b/Source/Core/InputCommon/ControlReference/ExpressionParser.h
index 3172e77f48..af24900d52 100644
--- a/Source/Core/InputCommon/ControlReference/ExpressionParser.h
+++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.h
@@ -26,6 +26,8 @@ enum TokenType
TOK_BAREWORD,
TOK_COMMENT,
TOK_HOTKEY,
+ TOK_QUESTION,
+ TOK_COLON,
// Binary Ops:
TOK_BINARY_OPS_BEGIN,
TOK_AND = TOK_BINARY_OPS_BEGIN,