diff options
| author | JMC47 <JMC4789@gmail.com> | 2025-01-27 21:16:29 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-27 21:16:29 -0500 |
| commit | e18a4d04b4fc1363b1ce48b2fc43589ef3a05962 (patch) | |
| tree | 442a0a31d039f9327e61dea14d9920cf5627f1b3 /Source/Core/InputCommon | |
| parent | 2b5cd96cb1287f45e44f72dece3b53d00020725f (diff) | |
| parent | 5078a63084121fa31d6d763dfa30ba5b0f99f040 (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.cpp | 62 | ||||
| -rw-r--r-- | Source/Core/InputCommon/ControlReference/ExpressionParser.h | 2 |
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, |
