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; _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
