diff options
| author | Jordan Woyak <jordan.woyak@gmail.com> | 2024-11-06 19:13:33 -0600 |
|---|---|---|
| committer | Jordan Woyak <jordan.woyak@gmail.com> | 2024-11-07 08:31:25 -0600 |
| commit | 5078a63084121fa31d6d763dfa30ba5b0f99f040 (patch) | |
| tree | 5c16040323bd993ecacfdf6ebc389c3d6fbd0280 /Source/Core/InputCommon/ControlReference/ExpressionParser.cpp | |
| parent | 7e1074b140809b0da7aa7d02b6303a68cc351be2 (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.cpp | 62 |
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) |
