summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon
diff options
context:
space:
mode:
authorJordan Woyak <jordan.woyak@gmail.com>2025-01-28 01:33:39 -0600
committerJordan Woyak <jordan.woyak@gmail.com>2025-02-02 14:37:11 -0600
commitcdabd651aa6a429c9b96811cabdca3bdda925f6f (patch)
treedb8b98de668057012f684dbf52063ff81bf14f80 /Source/Core/InputCommon
parent84d28a4272f53df30550b43aaafafde1a520aeb0 (diff)
InputCommon/ExpressionParser: Add compound assignment operators.
Diffstat (limited to 'Source/Core/InputCommon')
-rw-r--r--Source/Core/InputCommon/ControlReference/ExpressionParser.cpp136
-rw-r--r--Source/Core/InputCommon/ControlReference/ExpressionParser.h6
2 files changed, 102 insertions, 40 deletions
diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
index 6c5fe6a57a..5fccc2feef 100644
--- a/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
+++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.cpp
@@ -25,6 +25,45 @@ using namespace ciface::Core;
class ControlExpression;
+// Check if operator is usable with assignment, e.g. += -= *=
+bool IsCompoundAssignmentUsableBinaryOperator(TokenType type)
+{
+ return type >= TOK_COMPOUND_ASSIGN_OPS_BEGIN && type < TOK_COMPOUND_ASSIGN_OPS_END;
+}
+
+TokenType GetBinaryOperatorTokenTypeFromChar(char c)
+{
+ switch (c)
+ {
+ case '+':
+ return TOK_ADD;
+ case '-':
+ return TOK_SUB;
+ case '*':
+ return TOK_MUL;
+ case '/':
+ return TOK_DIV;
+ case '%':
+ return TOK_MOD;
+ case '=':
+ return TOK_ASSIGN;
+ case '<':
+ return TOK_LTHAN;
+ case '>':
+ return TOK_GTHAN;
+ case ',':
+ return TOK_COMMA;
+ case '^':
+ return TOK_XOR;
+ case '&':
+ return TOK_AND;
+ case '|':
+ return TOK_OR;
+ default:
+ return TOK_INVALID;
+ }
+}
+
class HotkeySuppressions
{
public:
@@ -156,7 +195,32 @@ Token Lexer::NextToken()
if (it == expr.end())
return Token(TOK_EOF);
- char c = *it++;
+ const char c = *it++;
+
+ // Handle /* */ style comments.
+ if (c == '/' && it != expr.end() && *it == '*')
+ {
+ ++it;
+ const auto end_of_comment = expr.find("*/", it - expr.begin());
+ if (end_of_comment == std::string::npos)
+ return Token(TOK_INVALID);
+ it = expr.begin() + end_of_comment + 2;
+ return Token(TOK_COMMENT);
+ }
+
+ const auto tok_type = GetBinaryOperatorTokenTypeFromChar(c);
+ if (tok_type != TOK_INVALID)
+ {
+ // Check for compound assignment op, e.g. + immediately followed by =.
+ if (IsCompoundAssignmentUsableBinaryOperator(tok_type) && it != expr.end() && *it == '=')
+ {
+ ++it;
+ return Token(TOK_ASSIGN, std::string{c});
+ }
+
+ return Token(tok_type);
+ }
+
switch (c)
{
case ' ':
@@ -174,44 +238,8 @@ Token Lexer::NextToken()
return Token(TOK_QUESTION);
case ':':
return Token(TOK_COLON);
- case '&':
- return Token(TOK_AND);
- case '|':
- return Token(TOK_OR);
case '!':
return Token(TOK_NOT);
- case '+':
- return Token(TOK_ADD);
- case '-':
- return Token(TOK_SUB);
- case '*':
- return Token(TOK_MUL);
- case '/':
- {
- // Handle /* */ style comments.
- if (it != expr.end() && *it == '*')
- {
- ++it;
- const auto end_of_comment = expr.find("*/", it - expr.begin());
- if (end_of_comment == std::string::npos)
- return Token(TOK_INVALID);
- it = expr.begin() + end_of_comment + 2;
- return Token(TOK_COMMENT);
- }
- return Token(TOK_DIV);
- }
- case '%':
- return Token(TOK_MOD);
- case '=':
- return Token(TOK_ASSIGN);
- case '<':
- return Token(TOK_LTHAN);
- case '>':
- return Token(TOK_GTHAN);
- case ',':
- return Token(TOK_COMMA);
- case '^':
- return Token(TOK_XOR);
case '\'':
return GetDelimitedLiteral();
case '$':
@@ -363,6 +391,11 @@ public:
const ControlState lhs_value = lhs->GetValue();
const ControlState rhs_value = rhs->GetValue();
+ return CalculateValue(op, lhs_value, rhs_value);
+ }
+
+ static ControlState CalculateValue(TokenType op, ControlState lhs_value, ControlState rhs_value)
+ {
switch (op)
{
case TOK_AND:
@@ -436,6 +469,23 @@ public:
}
};
+class CompoundAssignmentExpression : public BinaryExpression
+{
+public:
+ using BinaryExpression::BinaryExpression;
+
+ ControlState GetValue() override { return GetLValue()->GetValue(); }
+
+ Expression* GetLValue() override
+ {
+ Expression* const lvalue = lhs->GetLValue();
+ const ControlState lhs_value = lvalue->GetValue();
+ const ControlState rhs_value = rhs->GetValue();
+ lvalue->SetValue(CalculateValue(op, lhs_value, rhs_value));
+ return lvalue;
+ }
+};
+
class LiteralExpression : public Expression
{
public:
@@ -934,7 +984,17 @@ private:
if (rhs.status == ParseStatus::SyntaxError)
return rhs;
- expr = std::make_unique<BinaryExpression>(op.type, std::move(expr), std::move(rhs.expr));
+ // Compound assignment token has operator in the data string.
+ if (op.type == TOK_ASSIGN && !op.data.empty())
+ {
+ const TokenType op_type = GetBinaryOperatorTokenTypeFromChar(op.data[0]);
+ expr = std::make_unique<CompoundAssignmentExpression>(op_type, std::move(expr),
+ std::move(rhs.expr));
+ }
+ else
+ {
+ expr = std::make_unique<BinaryExpression>(op.type, std::move(expr), std::move(rhs.expr));
+ }
}
else if (op.type == TOK_QUESTION && OperatorPrecedence(TOK_QUESTION) <= precedence)
{
diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.h b/Source/Core/InputCommon/ControlReference/ExpressionParser.h
index c4b8a0c006..2bb9709063 100644
--- a/Source/Core/InputCommon/ControlReference/ExpressionParser.h
+++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.h
@@ -30,18 +30,20 @@ enum TokenType
TOK_COLON,
// Binary Ops:
TOK_BINARY_OPS_BEGIN,
+ TOK_COMPOUND_ASSIGN_OPS_BEGIN = TOK_BINARY_OPS_BEGIN,
TOK_AND = TOK_BINARY_OPS_BEGIN,
TOK_OR,
+ TOK_XOR,
TOK_ADD,
TOK_SUB,
TOK_MUL,
TOK_DIV,
TOK_MOD,
- TOK_ASSIGN,
+ TOK_COMPOUND_ASSIGN_OPS_END,
+ TOK_ASSIGN = TOK_COMPOUND_ASSIGN_OPS_END,
TOK_LTHAN,
TOK_GTHAN,
TOK_COMMA,
- TOK_XOR,
TOK_BINARY_OPS_END,
};