[Lldb-commits] [lldb] 598d9d1 - [lldb] Add composite assignments to existing operators in DIL (#208853)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Sep 4 05:35:18 PDT 2026
Author: Ilia Kuklin
Date: 2026-09-04T17:35:12+05:00
New Revision: 598d9d1369d385582d2a90d71335073d1b2e0950
URL: https://github.com/llvm/llvm-project/commit/598d9d1369d385582d2a90d71335073d1b2e0950
DIFF: https://github.com/llvm/llvm-project/commit/598d9d1369d385582d2a90d71335073d1b2e0950.diff
LOG: [lldb] Add composite assignments to existing operators in DIL (#208853)
Add operators `*=`, `/=`, `%=`, `<<=`, `>>=`, `&=`, `^=`, `|=` to DIL.
Added:
Modified:
lldb/docs/dil-expr-lang.ebnf
lldb/include/lldb/ValueObject/DILAST.h
lldb/include/lldb/ValueObject/DILLexer.h
lldb/source/ValueObject/DILAST.cpp
lldb/source/ValueObject/DILEval.cpp
lldb/source/ValueObject/DILLexer.cpp
lldb/source/ValueObject/DILParser.cpp
lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
lldb/test/API/commands/frame/var-dil/expr/Assignment/main.cpp
Removed:
################################################################################
diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 3dddcbd1ef609..60bc05bd830eb 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -10,7 +10,12 @@ assignment_expression = conditional_expression
assignment_operator = "="
| "+="
- | "-=" ;
+ | "-="
+ | "*="
+ | "/="
+ | "%="
+ | "<<="
+ | ">>=" ;
pure_expression = conditional_expression ;
diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h
index 00a50c97324a1..f8b89ab136f15 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -59,6 +59,14 @@ enum class BinaryOpKind {
Shr, ///< ">>"
AddAssign, ///< "+="
SubAssign, ///< "-="
+ MulAssign, ///< "*="
+ DivAssign, ///< "/="
+ RemAssign, ///< "%="
+ AndAssign, ///< "&="
+ XorAssign, ///< "^="
+ OrAssign, ///< "|="
+ ShlAssign, ///< "<<="
+ ShrAssign, ///< ">>="
LAnd, ///< "&&"
LOr, ///< "||"
LT, ///< "<"
diff --git a/lldb/include/lldb/ValueObject/DILLexer.h b/lldb/include/lldb/ValueObject/DILLexer.h
index 446891d5ca000..22cd96876f7e7 100644
--- a/lldb/include/lldb/ValueObject/DILLexer.h
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -27,8 +27,10 @@ class Token {
enum Kind {
amp,
ampamp,
+ ampequal,
arrow,
caret,
+ caretequal,
colon,
coloncolon,
eof,
@@ -40,6 +42,7 @@ class Token {
greater,
greaterequal,
greatergreater,
+ greatergreaterequal,
identifier,
integer_constant,
kw_false,
@@ -49,12 +52,15 @@ class Token {
less,
lessequal,
lessless,
+ lesslessequal,
minus,
minusequal,
minusminus,
percent,
+ percentequal,
period,
pipe,
+ pipeequal,
pipepipe,
plus,
plusequal,
@@ -63,7 +69,9 @@ class Token {
r_paren,
r_square,
slash,
+ slashequal,
star,
+ starequal,
tilde,
};
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index 7128233d227a9..d9ba85b0a7042 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -17,12 +17,8 @@ BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind) {
return BinaryOpKind::Assign;
case Token::minus:
return BinaryOpKind::Sub;
- case Token::minusequal:
- return BinaryOpKind::SubAssign;
case Token::plus:
return BinaryOpKind::Add;
- case Token::plusequal:
- return BinaryOpKind::AddAssign;
case Token::star:
return BinaryOpKind::Mul;
case Token::slash:
@@ -39,6 +35,26 @@ BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind) {
return BinaryOpKind::Shl;
case Token::greatergreater:
return BinaryOpKind::Shr;
+ case Token::minusequal:
+ return BinaryOpKind::SubAssign;
+ case Token::plusequal:
+ return BinaryOpKind::AddAssign;
+ case Token::starequal:
+ return BinaryOpKind::MulAssign;
+ case Token::slashequal:
+ return BinaryOpKind::DivAssign;
+ case Token::percentequal:
+ return BinaryOpKind::RemAssign;
+ case Token::ampequal:
+ return BinaryOpKind::AndAssign;
+ case Token::caretequal:
+ return BinaryOpKind::XorAssign;
+ case Token::pipeequal:
+ return BinaryOpKind::OrAssign;
+ case Token::lesslessequal:
+ return BinaryOpKind::ShlAssign;
+ case Token::greatergreaterequal:
+ return BinaryOpKind::ShrAssign;
case Token::ampamp:
return BinaryOpKind::LAnd;
case Token::pipepipe:
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index f60ce03f2c962..627d30cae9bec 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -1357,24 +1357,12 @@ Interpreter::Visit(const BinaryOpNode &node) {
}
switch (node.GetKind()) {
- case BinaryOpKind::Add:
- return EvaluateBinaryAddition(lhs, rhs, node.GetLocation());
- case BinaryOpKind::AddAssign: {
- auto ret_or_err = EvaluateBinaryAddition(lhs, rhs, node.GetLocation());
- if (!ret_or_err)
- return ret_or_err;
- return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
- }
case BinaryOpKind::Assign:
return EvaluateAssignment(lhs, rhs, node.GetLocation());
+ case BinaryOpKind::Add:
+ return EvaluateBinaryAddition(lhs, rhs, node.GetLocation());
case BinaryOpKind::Sub:
return EvaluateBinarySubtraction(lhs, rhs, node.GetLocation());
- case BinaryOpKind::SubAssign: {
- auto ret_or_err = EvaluateBinarySubtraction(lhs, rhs, node.GetLocation());
- if (!ret_or_err)
- return ret_or_err;
- return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
- }
case BinaryOpKind::Mul:
return EvaluateBinaryMultiplication(lhs, rhs, node.GetLocation());
case BinaryOpKind::Div:
@@ -1388,6 +1376,72 @@ Interpreter::Visit(const BinaryOpNode &node) {
case BinaryOpKind::Shl:
case BinaryOpKind::Shr:
return EvaluateBinaryShift(node.GetKind(), lhs, rhs, node.GetLocation());
+ case BinaryOpKind::AddAssign: {
+ auto ret_or_err = EvaluateBinaryAddition(lhs, rhs, node.GetLocation());
+ if (!ret_or_err)
+ return ret_or_err;
+ return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+ }
+ case BinaryOpKind::SubAssign: {
+ auto ret_or_err = EvaluateBinarySubtraction(lhs, rhs, node.GetLocation());
+ if (!ret_or_err)
+ return ret_or_err;
+ return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+ }
+ case BinaryOpKind::MulAssign: {
+ auto ret_or_err =
+ EvaluateBinaryMultiplication(lhs, rhs, node.GetLocation());
+ if (!ret_or_err)
+ return ret_or_err;
+ return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+ }
+ case BinaryOpKind::DivAssign: {
+ auto ret_or_err = EvaluateBinaryDivision(lhs, rhs, node.GetLocation());
+ if (!ret_or_err)
+ return ret_or_err;
+ return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+ }
+ case BinaryOpKind::RemAssign: {
+ auto ret_or_err = EvaluateBinaryRemainder(lhs, rhs, node.GetLocation());
+ if (!ret_or_err)
+ return ret_or_err;
+ return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+ }
+ case BinaryOpKind::AndAssign: {
+ auto ret_or_err =
+ EvaluateBinaryBitwise(BinaryOpKind::And, lhs, rhs, node.GetLocation());
+ if (!ret_or_err)
+ return ret_or_err;
+ return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+ }
+ case BinaryOpKind::XorAssign: {
+ auto ret_or_err =
+ EvaluateBinaryBitwise(BinaryOpKind::Xor, lhs, rhs, node.GetLocation());
+ if (!ret_or_err)
+ return ret_or_err;
+ return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+ }
+ case BinaryOpKind::OrAssign: {
+ auto ret_or_err =
+ EvaluateBinaryBitwise(BinaryOpKind::Or, lhs, rhs, node.GetLocation());
+ if (!ret_or_err)
+ return ret_or_err;
+ return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+ }
+ case BinaryOpKind::ShlAssign: {
+ auto ret_or_err =
+ EvaluateBinaryShift(BinaryOpKind::Shl, lhs, rhs, node.GetLocation());
+ if (!ret_or_err)
+ return ret_or_err;
+ return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+ }
+ case BinaryOpKind::ShrAssign: {
+ auto ret_or_err =
+ EvaluateBinaryShift(BinaryOpKind::Shr, lhs, rhs, node.GetLocation());
+ if (!ret_or_err)
+ return ret_or_err;
+ return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+ }
case BinaryOpKind::EQ:
case BinaryOpKind::NE:
case BinaryOpKind::LT:
diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp
index abc54f1fd2f46..2cb7e3042c6f3 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -24,10 +24,14 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "amp";
case Kind::ampamp:
return "ampamp";
+ case Kind::ampequal:
+ return "ampequal";
case Kind::arrow:
return "arrow";
case Kind::caret:
return "caret";
+ case Kind::caretequal:
+ return "caretequal";
case Kind::colon:
return "colon";
case Kind::coloncolon:
@@ -50,6 +54,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "greaterequal";
case Kind::greatergreater:
return "greatergreater";
+ case Kind::greatergreaterequal:
+ return "greatergreaterequal";
case Kind::identifier:
return "identifier";
case Kind::integer_constant:
@@ -68,6 +74,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "lessequal";
case Kind::lessless:
return "lessless";
+ case Kind::lesslessequal:
+ return "lesslessequal";
case Kind::minus:
return "minus";
case Kind::minusequal:
@@ -76,10 +84,14 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "minusminus";
case Token::percent:
return "percent";
+ case Token::percentequal:
+ return "percentequal";
case Kind::period:
return "period";
case Kind::pipe:
return "pipe";
+ case Kind::pipeequal:
+ return "pipeequal";
case Kind::pipepipe:
return "pipepipe";
case Kind::plus:
@@ -96,8 +108,12 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "r_square";
case Token::slash:
return "slash";
+ case Token::slashequal:
+ return "slashequal";
case Token::star:
return "star";
+ case Token::starequal:
+ return "starequal";
case Token::tilde:
return "tilde";
}
@@ -228,8 +244,12 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
// be ordered longest-to-shortest in the list below. E.g. '::' must come
// before ':', and '+=' must come before '+'.
constexpr std::pair<Token::Kind, const char *> operators[] = {
+ {Token::greatergreaterequal, ">>="},
+ {Token::lesslessequal, "<<="},
{Token::ampamp, "&&"},
+ {Token::ampequal, "&="},
{Token::arrow, "->"},
+ {Token::caretequal, "^="},
{Token::coloncolon, "::"},
{Token::equalequal, "=="},
{Token::exclaimequal, "!="},
@@ -239,9 +259,13 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
{Token::lessless, "<<"},
{Token::minusequal, "-="},
{Token::minusminus, "--"},
+ {Token::percentequal, "%="},
+ {Token::pipeequal, "|="},
{Token::pipepipe, "||"},
{Token::plusequal, "+="},
{Token::plusplus, "++"},
+ {Token::slashequal, "/="},
+ {Token::starequal, "*="},
{Token::amp, "&"},
{Token::caret, "^"},
{Token::colon, ":"},
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index cc69fa175e303..6a8af6127fe75 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -141,13 +141,22 @@ ASTNodeUP DILParser::ParseExpression() { return ParseAssignmentExpression(); }
// "="
// "+="
// "-="
+// "*="
+// "/="
+// "%="
+// "<<="
+// ">>="
//
ASTNodeUP DILParser::ParseAssignmentExpression() {
auto lhs = ParseLogicalOrExpression();
assert(lhs && "ASTNodeUP must not contain a nullptr");
// Check if it's an assignment expression.
- if (CurToken().IsOneOf({Token::equal, Token::plusequal, Token::minusequal})) {
+ if (CurToken().IsOneOf({Token::equal, Token::plusequal, Token::minusequal,
+ Token::starequal, Token::slashequal,
+ Token::percentequal, Token::ampequal,
+ Token::caretequal, Token::pipeequal,
+ Token::lesslessequal, Token::greatergreaterequal})) {
// That's an assignment!
Token token = CurToken();
m_dil_lexer.Advance();
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
index dd5cd68796e70..bfd6f68a3e793 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
+++ b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
@@ -82,6 +82,88 @@ def test_assignment(self):
)
self.expect("frame variable 'p -= 2'", substrs=["p = 0x0000000000000002"])
+ self.expect("frame variable 'i = 2'", substrs=["2"])
+ self.expect("frame variable 'i *= 2'", substrs=["4"])
+ self.expect("frame variable 'iref *= 2'", substrs=["8"])
+ self.expect("frame variable 'd = 2.25'", substrs=["2.25"])
+ self.expect("frame variable 'd *= 2.0'", substrs=["4.5"])
+ self.expect("frame variable 'd *= 2'", substrs=["9"])
+ self.expect(
+ "frame variable 'i *= 2.0'",
+ error=True,
+ substrs=[
+ "Incompatible types for assignment: Cannot assign 'double' to 'int'"
+ ],
+ )
+
+ self.expect("frame variable 'i = 7'", substrs=["7"])
+ self.expect("frame variable 'i /= 3'", substrs=["2"])
+ self.expect("frame variable 'iref /= 2'", substrs=["1"])
+ self.expect("frame variable 'f = 4.5f'", substrs=["4.5"])
+ self.expect("frame variable 'f /= 2.0f", substrs=["2.25"])
+ self.expect("frame variable 'f /= 2", substrs=["1.125"])
+ self.expect(
+ "frame variable 'i /= 1.0f'",
+ error=True,
+ substrs=[
+ "Incompatible types for assignment: Cannot assign 'float' to 'int'"
+ ],
+ )
+
+ self.expect("frame variable 'i = 7'", substrs=["7"])
+ self.expect("frame variable 'i %= 4'", substrs=["3"])
+ self.expect("frame variable 'iref %= 3'", substrs=["0"])
+ self.expect(
+ "frame variable 'i %= 1.0'",
+ error=True,
+ substrs=["invalid operands to binary expression ('int' and 'double')"],
+ )
+
+ self.expect("frame variable 'i = 0xF'", substrs=["15"])
+ self.expect("frame variable 'i &= 0b101'", substrs=["5"])
+ self.expect("frame variable 'iref &= 0b100'", substrs=["4"])
+ self.expect(
+ "frame variable 'i &= 1.0'",
+ error=True,
+ substrs=["invalid operands to binary expression ('int' and 'double')"],
+ )
+
+ self.expect("frame variable 'i = 0xF'", substrs=["15"])
+ self.expect("frame variable 'i ^= 0b1000'", substrs=["7"])
+ self.expect("frame variable 'iref ^= 0b11'", substrs=["4"])
+ self.expect(
+ "frame variable 'i ^= 1.0'",
+ error=True,
+ substrs=["invalid operands to binary expression ('int' and 'double')"],
+ )
+
+ self.expect("frame variable 'i = 1'", substrs=["1"])
+ self.expect("frame variable 'i |= 0b110'", substrs=["7"])
+ self.expect("frame variable 'iref |= 0b1001'", substrs=["15"])
+ self.expect(
+ "frame variable 'i |= 1.0'",
+ error=True,
+ substrs=["invalid operands to binary expression ('int' and 'double')"],
+ )
+
+ self.expect("frame variable 'i = 0xF'", substrs=["15"])
+ self.expect("frame variable 'i >>= 1'", substrs=["7"])
+ self.expect("frame variable 'iref >>= 2'", substrs=["1"])
+ self.expect(
+ "frame variable 'i >>= 1.0'",
+ error=True,
+ substrs=["invalid operands to binary expression ('int' and 'double')"],
+ )
+
+ self.expect("frame variable 'i = 1'", substrs=["1"])
+ self.expect("frame variable 'i <<= 1'", substrs=["2"])
+ self.expect("frame variable 'iref <<= 2'", substrs=["8"])
+ self.expect(
+ "frame variable 'i <<= 1.0'",
+ error=True,
+ substrs=["invalid operands to binary expression ('int' and 'double')"],
+ )
+
# Check that there can be only one assignment and only at top level
self.expect(
"frame variable 'i = i += 1'",
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Assignment/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/Assignment/main.cpp
index 6438ce08bfb48..f7e90c45d49f7 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/Assignment/main.cpp
+++ b/lldb/test/API/commands/frame/var-dil/expr/Assignment/main.cpp
@@ -12,6 +12,8 @@ int main(int argc, char **argv) {
float farr[2] = {1.0f, 2.0f};
int arr[2] = {1, 2};
+ int &iref = i;
+
enum Enum { ONE, TWO };
Enum eOne = ONE;
Enum eTwo = TWO;
More information about the lldb-commits
mailing list