[Lldb-commits] [lldb] Draft: [LLDB] Add scalar literal node (PR #147064)
Ilia Kuklin via lldb-commits
lldb-commits at lists.llvm.org
Fri Jul 4 07:24:50 PDT 2025
https://github.com/kuilpd created https://github.com/llvm/llvm-project/pull/147064
A draft to discuss scalar literal node implementation
>From cf1f908360399ac51770d9fb7e1dac03eceab0e9 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Thu, 3 Jul 2025 19:34:17 +0500
Subject: [PATCH] [LLDB] *WIP* Add scalar literal node and binary addition
---
lldb/include/lldb/ValueObject/DILAST.h | 58 ++++
lldb/include/lldb/ValueObject/DILEval.h | 15 +
lldb/include/lldb/ValueObject/DILLexer.h | 1 +
lldb/include/lldb/ValueObject/DILParser.h | 3 +
lldb/source/ValueObject/DILAST.cpp | 21 ++
lldb/source/ValueObject/DILEval.cpp | 405 ++++++++++++++++++++++
lldb/source/ValueObject/DILLexer.cpp | 10 +-
lldb/source/ValueObject/DILParser.cpp | 74 +++-
8 files changed, 581 insertions(+), 6 deletions(-)
diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h
index 709f0639135f1..a9d244031d55f 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -9,6 +9,7 @@
#ifndef LLDB_VALUEOBJECT_DILAST_H
#define LLDB_VALUEOBJECT_DILAST_H
+#include "lldb/ValueObject/DILLexer.h"
#include "lldb/ValueObject/ValueObject.h"
#include "llvm/Support/Error.h"
#include <cstdint>
@@ -19,10 +20,12 @@ namespace lldb_private::dil {
/// The various types DIL AST nodes (used by the DIL parser).
enum class NodeKind {
eArraySubscriptNode,
+ eBinaryOpNode,
eBitExtractionNode,
eErrorNode,
eIdentifierNode,
eMemberOfNode,
+ eScalarLiteralNode,
eUnaryOpNode,
};
@@ -32,6 +35,14 @@ enum class UnaryOpKind {
Deref, // "*"
};
+enum class BinaryOpKind {
+ Add, // "+"
+ Sub, // "-"
+};
+
+/// Translates DIL tokens to BinaryOpKind.
+BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind);
+
/// Forward declaration, for use in DIL AST nodes. Definition is at the very
/// end of this file.
class Visitor;
@@ -178,6 +189,49 @@ class BitFieldExtractionNode : public ASTNode {
int64_t m_last_index;
};
+class ScalarLiteralNode : public ASTNode {
+public:
+ ScalarLiteralNode(uint32_t location, lldb::BasicType type, Scalar value)
+ : ASTNode(location, NodeKind::eScalarLiteralNode), m_type(type),
+ m_value(value) {}
+
+ llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
+
+ lldb::BasicType GetType() const { return m_type; }
+ Scalar GetValue() const & { return m_value; }
+
+ static bool classof(const ASTNode *node) {
+ return node->GetKind() == NodeKind::eScalarLiteralNode;
+ }
+
+private:
+ lldb::BasicType m_type;
+ Scalar m_value;
+};
+
+class BinaryOpNode : public ASTNode {
+public:
+ BinaryOpNode(uint32_t location, BinaryOpKind kind, ASTNodeUP lhs,
+ ASTNodeUP rhs)
+ : ASTNode(location, NodeKind::eBinaryOpNode), m_kind(kind),
+ m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {}
+
+ llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
+
+ BinaryOpKind GetKind() const { return m_kind; }
+ ASTNode *GetLHS() const { return m_lhs.get(); }
+ ASTNode *GetRHS() const { return m_rhs.get(); }
+
+ static bool classof(const ASTNode *node) {
+ return node->GetKind() == NodeKind::eBinaryOpNode;
+ }
+
+private:
+ BinaryOpKind m_kind;
+ ASTNodeUP m_lhs;
+ ASTNodeUP m_rhs;
+};
+
/// This class contains one Visit method for each specialized type of
/// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
/// the correct function in the DIL expression evaluator for evaluating that
@@ -195,6 +249,10 @@ class Visitor {
Visit(const ArraySubscriptNode *node) = 0;
virtual llvm::Expected<lldb::ValueObjectSP>
Visit(const BitFieldExtractionNode *node) = 0;
+ virtual llvm::Expected<lldb::ValueObjectSP>
+ Visit(const ScalarLiteralNode *node) = 0;
+ virtual llvm::Expected<lldb::ValueObjectSP>
+ Visit(const BinaryOpNode *node) = 0;
};
} // namespace lldb_private::dil
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index 45e29b3ddcd7b..9e9028f6122fd 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -54,6 +54,21 @@ class Interpreter : Visitor {
Visit(const ArraySubscriptNode *node) override;
llvm::Expected<lldb::ValueObjectSP>
Visit(const BitFieldExtractionNode *node) override;
+ llvm::Expected<lldb::ValueObjectSP>
+ Visit(const ScalarLiteralNode *node) override;
+ llvm::Expected<lldb::ValueObjectSP> Visit(const BinaryOpNode *node) override;
+
+ lldb::ValueObjectSP
+ ConvertValueObjectToTypeSystem(lldb::ValueObjectSP valobj,
+ lldb::TypeSystemSP type_system);
+
+ llvm::Error PrepareBinaryAddition(lldb::ValueObjectSP &lhs,
+ lldb::ValueObjectSP &rhs,
+ uint32_t location);
+
+ llvm::Expected<lldb::ValueObjectSP>
+ EvaluateBinaryAddition(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
+ uint32_t location);
// Used by the interpreter to create objects, perform casts, etc.
lldb::TargetSP m_target;
diff --git a/lldb/include/lldb/ValueObject/DILLexer.h b/lldb/include/lldb/ValueObject/DILLexer.h
index 9c1ba97680253..58059657bf3a5 100644
--- a/lldb/include/lldb/ValueObject/DILLexer.h
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -34,6 +34,7 @@ class Token {
minus,
numeric_constant,
period,
+ plus,
r_paren,
r_square,
star,
diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h
index 9eda7bac4a364..c57ef0cf28022 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -87,6 +87,7 @@ class DILParser {
ASTNodeUP Run();
ASTNodeUP ParseExpression();
+ ASTNodeUP ParseAdditiveExpression();
ASTNodeUP ParseUnaryExpression();
ASTNodeUP ParsePostfixExpression();
ASTNodeUP ParsePrimaryExpression();
@@ -96,6 +97,8 @@ class DILParser {
std::string ParseIdExpression();
std::string ParseUnqualifiedId();
std::optional<int64_t> ParseIntegerConstant();
+ ASTNodeUP ParseNumericLiteral();
+ ASTNodeUP ParseNumericConstant();
void BailOut(const std::string &error, uint32_t loc, uint16_t err_len);
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index b1cd824c2299e..7aee692f2b28a 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -11,6 +11,18 @@
namespace lldb_private::dil {
+BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind) {
+ switch (token_kind) {
+ case Token::minus:
+ return BinaryOpKind::Sub;
+ case Token::plus:
+ return BinaryOpKind::Add;
+ default:
+ break;
+ }
+ llvm_unreachable("Unknown binary operator kind.");
+}
+
llvm::Expected<lldb::ValueObjectSP> ErrorNode::Accept(Visitor *v) const {
llvm_unreachable("Attempting to Visit a DIL ErrorNode.");
}
@@ -37,4 +49,13 @@ BitFieldExtractionNode::Accept(Visitor *v) const {
return v->Visit(this);
}
+llvm::Expected<lldb::ValueObjectSP>
+ScalarLiteralNode::Accept(Visitor *v) const {
+ return v->Visit(this);
+}
+
+llvm::Expected<lldb::ValueObjectSP> BinaryOpNode::Accept(Visitor *v) const {
+ return v->Visit(this);
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 8ca9b4215985d..2e42b57e93042 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -7,7 +7,9 @@
//===----------------------------------------------------------------------===//
#include "lldb/ValueObject/DILEval.h"
+#include "lldb/Core/Module.h"
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/ValueObject/DILAST.h"
@@ -401,4 +403,407 @@ Interpreter::Visit(const BitFieldExtractionNode *node) {
return child_valobj_sp;
}
+static CompilerType GetBasicTypeFromCU(std::shared_ptr<StackFrame> ctx,
+ lldb::BasicType basic_type) {
+ SymbolContext symbol_context =
+ ctx->GetSymbolContext(lldb::eSymbolContextCompUnit);
+ auto language = symbol_context.comp_unit->GetLanguage();
+
+ symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule);
+ auto type_system =
+ symbol_context.module_sp->GetTypeSystemForLanguage(language);
+
+ if (type_system)
+ if (auto compiler_type = type_system.get()->GetBasicTypeFromAST(basic_type))
+ return compiler_type;
+
+ CompilerType empty_type;
+ return empty_type;
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const ScalarLiteralNode *node) {
+ CompilerType result_type =
+ GetBasicTypeFromCU(m_exe_ctx_scope, node->GetType());
+ Scalar value = node->GetValue();
+
+ // Scalar later could be float or bool
+ if (result_type.IsInteger() || result_type.IsNullPtrType() ||
+ result_type.IsPointerType()) {
+ llvm::APInt val = value.GetAPSInt();
+ return ValueObject::CreateValueObjectFromAPInt(m_target, val, result_type,
+ "result");
+ }
+
+ return lldb::ValueObjectSP();
+}
+
+static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
+ lldb::BasicType basic_type) {
+ if (type_system)
+ if (auto compiler_type = type_system.get()->GetBasicTypeFromAST(basic_type))
+ return compiler_type;
+
+ CompilerType empty_type;
+ return empty_type;
+}
+
+static CompilerType DoIntegralPromotion(CompilerType from,
+ std::shared_ptr<StackFrame> ctx) {
+ if (!from.IsInteger() && !from.IsUnscopedEnumerationType())
+ return from;
+
+ if (!from.IsPromotableIntegerType())
+ return from;
+
+ if (from.IsUnscopedEnumerationType())
+ return DoIntegralPromotion(from.GetEnumerationIntegerType(), ctx);
+ lldb::BasicType builtin_type =
+ from.GetCanonicalType().GetBasicTypeEnumeration();
+ lldb::TypeSystemSP type_system = from.GetTypeSystem().GetSharedPointer();
+
+ uint64_t from_size = 0;
+ if (builtin_type == lldb::eBasicTypeWChar ||
+ builtin_type == lldb::eBasicTypeSignedWChar ||
+ builtin_type == lldb::eBasicTypeUnsignedWChar ||
+ builtin_type == lldb::eBasicTypeChar16 ||
+ builtin_type == lldb::eBasicTypeChar32) {
+ // Find the type that can hold the entire range of values for our type.
+ bool is_signed = from.IsSigned();
+ if (auto temp = from.GetByteSize(ctx.get()))
+ from_size = *temp;
+
+ CompilerType promote_types[] = {
+ GetBasicType(type_system, lldb::eBasicTypeInt),
+ GetBasicType(type_system, lldb::eBasicTypeUnsignedInt),
+ GetBasicType(type_system, lldb::eBasicTypeLong),
+ GetBasicType(type_system, lldb::eBasicTypeUnsignedLong),
+ GetBasicType(type_system, lldb::eBasicTypeLongLong),
+ GetBasicType(type_system, lldb::eBasicTypeUnsignedLongLong),
+ };
+ for (auto &type : promote_types) {
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(ctx.get()))
+ byte_size = *temp;
+ if (from_size < byte_size ||
+ (from_size == byte_size &&
+ is_signed == (bool)(type.GetTypeInfo() & lldb::eTypeIsSigned))) {
+ return type;
+ }
+ }
+
+ llvm_unreachable("char type should fit into long long");
+ }
+
+ // Here we can promote only to "int" or "unsigned int".
+ CompilerType int_type = GetBasicType(type_system, lldb::eBasicTypeInt);
+ uint64_t int_byte_size = 0;
+ if (auto temp = int_type.GetByteSize(ctx.get()))
+ int_byte_size = *temp;
+
+ // Signed integer types can be safely promoted to "int".
+ if (from.IsSigned()) {
+ return int_type;
+ }
+ // Unsigned integer types are promoted to "unsigned int" if "int" cannot hold
+ // their entire value range.
+ return (from_size == int_byte_size)
+ ? GetBasicType(type_system, lldb::eBasicTypeUnsignedInt)
+ : int_type;
+}
+
+static lldb::ValueObjectSP UnaryConversion(lldb::ValueObjectSP valobj,
+ std::shared_ptr<StackFrame> ctx) {
+ // Perform usual conversions for unary operators.
+ CompilerType in_type = valobj->GetCompilerType();
+ CompilerType result_type;
+
+ if (valobj->GetCompilerType().IsInteger() ||
+ valobj->GetCompilerType().IsUnscopedEnumerationType()) {
+ CompilerType promoted_type =
+ DoIntegralPromotion(valobj->GetCompilerType(), ctx);
+ if (!promoted_type.CompareTypes(valobj->GetCompilerType()))
+ return valobj->CastToBasicType(promoted_type);
+ }
+
+ return valobj;
+}
+
+static size_t ConversionRank(CompilerType type) {
+ // Get integer conversion rank
+ // https://eel.is/c++draft/conv.rank
+ switch (type.GetCanonicalType().GetBasicTypeEnumeration()) {
+ case lldb::eBasicTypeBool:
+ return 1;
+ case lldb::eBasicTypeChar:
+ case lldb::eBasicTypeSignedChar:
+ case lldb::eBasicTypeUnsignedChar:
+ return 2;
+ case lldb::eBasicTypeShort:
+ case lldb::eBasicTypeUnsignedShort:
+ return 3;
+ case lldb::eBasicTypeInt:
+ case lldb::eBasicTypeUnsignedInt:
+ return 4;
+ case lldb::eBasicTypeLong:
+ case lldb::eBasicTypeUnsignedLong:
+ return 5;
+ case lldb::eBasicTypeLongLong:
+ case lldb::eBasicTypeUnsignedLongLong:
+ return 6;
+
+ // The ranks of char16_t, char32_t, and wchar_t are equal to the
+ // ranks of their underlying types.
+ case lldb::eBasicTypeWChar:
+ case lldb::eBasicTypeSignedWChar:
+ case lldb::eBasicTypeUnsignedWChar:
+ return 3;
+ case lldb::eBasicTypeChar16:
+ return 3;
+ case lldb::eBasicTypeChar32:
+ return 4;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static lldb::BasicType BasicTypeToUnsigned(lldb::BasicType basic_type) {
+ switch (basic_type) {
+ case lldb::eBasicTypeInt:
+ return lldb::eBasicTypeUnsignedInt;
+ case lldb::eBasicTypeLong:
+ return lldb::eBasicTypeUnsignedLong;
+ case lldb::eBasicTypeLongLong:
+ return lldb::eBasicTypeUnsignedLongLong;
+ default:
+ return basic_type;
+ }
+}
+
+static void PerformIntegerConversions(std::shared_ptr<StackFrame> ctx,
+ lldb::ValueObjectSP &lhs,
+ lldb::ValueObjectSP &rhs,
+ bool convert_lhs, bool convert_rhs) {
+ CompilerType l_type = lhs->GetCompilerType();
+ CompilerType r_type = rhs->GetCompilerType();
+ if (r_type.IsSigned() && !l_type.IsSigned()) {
+ uint64_t l_size = 0;
+ uint64_t r_size = 0;
+ if (auto temp = l_type.GetByteSize(ctx.get()))
+ l_size = *temp;
+ ;
+ if (auto temp = r_type.GetByteSize(ctx.get()))
+ r_size = *temp;
+ if (l_size <= r_size) {
+ if (r_size == l_size) {
+ lldb::TypeSystemSP type_system =
+ l_type.GetTypeSystem().GetSharedPointer();
+ auto r_type_unsigned = GetBasicType(
+ type_system,
+ BasicTypeToUnsigned(
+ r_type.GetCanonicalType().GetBasicTypeEnumeration()));
+ if (convert_rhs)
+ rhs = rhs->CastToBasicType(r_type_unsigned);
+ }
+ }
+ }
+ if (convert_lhs)
+ lhs = lhs->CastToBasicType(rhs->GetCompilerType());
+}
+
+static CompilerType ArithmeticConversions(lldb::ValueObjectSP &lhs,
+ lldb::ValueObjectSP &rhs,
+ std::shared_ptr<StackFrame> ctx) {
+ // Apply unary conversion (e.g. intergal promotion) for both operands.
+ lhs = UnaryConversion(lhs, ctx);
+ rhs = UnaryConversion(rhs, ctx);
+
+ CompilerType lhs_type = lhs->GetCompilerType();
+ CompilerType rhs_type = rhs->GetCompilerType();
+
+ if (lhs_type.CompareTypes(rhs_type))
+ return lhs_type;
+
+ // If either of the operands is not arithmetic (e.g. pointer), we're done.
+ if (!lhs_type.IsScalarType() || !rhs_type.IsScalarType()) {
+ CompilerType bad_type;
+ return bad_type;
+ }
+
+ // Removed floating point conversions
+ if (lhs_type.IsFloat() || rhs_type.IsFloat()) {
+ CompilerType bad_type;
+ return bad_type;
+ }
+
+ if (lhs_type.IsInteger() && rhs_type.IsInteger()) {
+ using Rank = std::tuple<size_t, bool>;
+ Rank l_rank = {ConversionRank(lhs_type), !lhs_type.IsSigned()};
+ Rank r_rank = {ConversionRank(rhs_type), !rhs_type.IsSigned()};
+
+ if (l_rank < r_rank) {
+ PerformIntegerConversions(ctx, lhs, rhs, true, true);
+ } else if (l_rank > r_rank) {
+ PerformIntegerConversions(ctx, rhs, lhs, true, true);
+ }
+ }
+
+ return rhs_type;
+}
+
+llvm::Error Interpreter::PrepareBinaryAddition(lldb::ValueObjectSP &lhs,
+ lldb::ValueObjectSP &rhs,
+ uint32_t location) {
+ // Operation '+' works for:
+ //
+ // {scalar,unscoped_enum} <-> {scalar,unscoped_enum}
+ // {integer,unscoped_enum} <-> pointer
+ // pointer <-> {integer,unscoped_enum}
+ auto orig_lhs_type = lhs->GetCompilerType();
+ auto orig_rhs_type = rhs->GetCompilerType();
+ auto result_type = ArithmeticConversions(lhs, rhs, m_exe_ctx_scope);
+
+ if (result_type.IsScalarType())
+ return llvm::Error::success();
+
+ // Removed pointer arithmetics
+ return llvm::make_error<DILDiagnosticError>(m_expr, "unimplemented",
+ location);
+}
+
+static lldb::ValueObjectSP EvaluateArithmeticOpInteger(lldb::TargetSP target,
+ BinaryOpKind kind,
+ lldb::ValueObjectSP lhs,
+ lldb::ValueObjectSP rhs,
+ CompilerType rtype) {
+ assert(lhs->GetCompilerType().IsInteger() &&
+ rhs->GetCompilerType().IsInteger() &&
+ "invalid ast: both operands must be integers");
+
+ auto wrap = [target, rtype](auto value) {
+ return ValueObject::CreateValueObjectFromAPInt(target, value, rtype,
+ "result");
+ };
+
+ llvm::Expected<llvm::APSInt> l_value = lhs->GetValueAsAPSInt();
+ llvm::Expected<llvm::APSInt> r_value = rhs->GetValueAsAPSInt();
+
+ if (l_value && r_value) {
+ llvm::APSInt l = *l_value;
+ llvm::APSInt r = *r_value;
+
+ switch (kind) {
+ case BinaryOpKind::Add:
+ return wrap(l + r);
+
+ default:
+ assert(false && "invalid ast: invalid arithmetic operation");
+ return lldb::ValueObjectSP();
+ }
+ } else {
+ return lldb::ValueObjectSP();
+ }
+}
+
+static lldb::ValueObjectSP EvaluateArithmeticOp(lldb::TargetSP target,
+ BinaryOpKind kind,
+ lldb::ValueObjectSP lhs,
+ lldb::ValueObjectSP rhs,
+ CompilerType rtype) {
+ assert((rtype.IsInteger() || rtype.IsFloat()) &&
+ "invalid ast: result type must either integer or floating point");
+
+ // Evaluate arithmetic operation for two integral values.
+ if (rtype.IsInteger()) {
+ return EvaluateArithmeticOpInteger(target, kind, lhs, rhs, rtype);
+ }
+
+ // Removed floating point arithmetics
+
+ return lldb::ValueObjectSP();
+}
+
+llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinaryAddition(
+ lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs, uint32_t location) {
+ // Addition of two arithmetic types.
+ if (lhs->GetCompilerType().IsScalarType() &&
+ rhs->GetCompilerType().IsScalarType()) {
+ return EvaluateArithmeticOp(m_target, BinaryOpKind::Add, lhs, rhs,
+ lhs->GetCompilerType().GetCanonicalType());
+ }
+
+ // Removed pointer arithmetics
+ return llvm::make_error<DILDiagnosticError>(m_expr, "unimplemented",
+ location);
+}
+
+lldb::ValueObjectSP
+Interpreter::ConvertValueObjectToTypeSystem(lldb::ValueObjectSP valobj,
+ lldb::TypeSystemSP type_system) {
+ auto apsint = valobj->GetValueAsAPSInt();
+ if (apsint) {
+ llvm::APInt value = *apsint;
+ if (type_system) {
+ lldb::BasicType basic_type = valobj->GetCompilerType()
+ .GetCanonicalType()
+ .GetBasicTypeEnumeration();
+ if (auto compiler_type =
+ type_system.get()->GetBasicTypeFromAST(basic_type)) {
+ valobj->GetValue().SetCompilerType(compiler_type);
+ return ValueObject::CreateValueObjectFromAPInt(m_target, value,
+ compiler_type, "result");
+ }
+ }
+ }
+
+ return lldb::ValueObjectSP();
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const BinaryOpNode *node) {
+ auto lhs_or_err = Evaluate(node->GetLHS());
+ if (!lhs_or_err)
+ return lhs_or_err;
+ lldb::ValueObjectSP lhs = *lhs_or_err;
+ auto rhs_or_err = Evaluate(node->GetRHS());
+ if (!rhs_or_err)
+ return rhs_or_err;
+ lldb::ValueObjectSP rhs = *rhs_or_err;
+
+ lldb::TypeSystemSP lhs_system =
+ lhs->GetCompilerType().GetTypeSystem().GetSharedPointer();
+ lldb::TypeSystemSP rhs_system =
+ rhs->GetCompilerType().GetTypeSystem().GetSharedPointer();
+
+ // Is this a correct way to check if type systems are the same?
+ if (lhs_system != rhs_system) {
+ // If one of the nodes is a scalar const, convert it to the
+ // type system of another one
+ if (node->GetLHS()->GetKind() == NodeKind::eScalarLiteralNode)
+ lhs = ConvertValueObjectToTypeSystem(lhs, rhs_system);
+ else if (node->GetRHS()->GetKind() == NodeKind::eScalarLiteralNode)
+ rhs = ConvertValueObjectToTypeSystem(rhs, lhs_system);
+ else
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "incompatible type systems", node->GetLocation());
+ }
+
+ switch (node->GetKind()) {
+ case BinaryOpKind::Add:
+ if (auto err = PrepareBinaryAddition(lhs, rhs, node->GetLocation()))
+ return err;
+ return EvaluateBinaryAddition(lhs, rhs, node->GetLocation());
+
+ // Other ops
+
+ default:
+ break;
+ }
+
+ return llvm::make_error<DILDiagnosticError>(m_expr, "unimplemented",
+ node->GetLocation());
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp
index eaefaf484bc18..2031bf677d6d7 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -40,6 +40,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "numeric_constant";
case Kind::period:
return "period";
+ case Kind::plus:
+ return "plus";
case Kind::r_paren:
return "r_paren";
case Kind::r_square:
@@ -114,10 +116,10 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
return Token(Token::identifier, maybe_word->str(), position);
constexpr std::pair<Token::Kind, const char *> operators[] = {
- {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
- {Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
- {Token::period, "."}, {Token::r_paren, ")"}, {Token::r_square, "]"},
- {Token::star, "*"},
+ {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
+ {Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
+ {Token::period, "."}, {Token::plus, "+"}, {Token::r_paren, ")"},
+ {Token::r_square, "]"}, {Token::star, "*"},
};
for (auto [kind, str] : operators) {
if (remainder.consume_front(str))
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index eac41fab90763..6de54eabc8ca1 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -80,9 +80,30 @@ ASTNodeUP DILParser::Run() {
// Parse an expression.
//
// expression:
-// unary_expression
+// additive_expression
//
-ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); }
+ASTNodeUP DILParser::ParseExpression() { return ParseAdditiveExpression(); }
+
+// Parse an additive_expression.
+//
+// additive_expression:
+// unary_expression {"+" unary_expression}
+// unary_expression {"-" unary_expression}
+//
+ASTNodeUP DILParser::ParseAdditiveExpression() {
+ auto lhs = ParseUnaryExpression();
+
+ while (CurToken().IsOneOf({Token::plus, Token::minus})) {
+ Token token = CurToken();
+ m_dil_lexer.Advance();
+ auto rhs = ParseUnaryExpression();
+ lhs = std::make_unique<BinaryOpNode>(
+ token.GetLocation(), GetBinaryOpKindFromToken(token.GetKind()),
+ std::move(lhs), std::move(rhs));
+ }
+
+ return lhs;
+}
// Parse an unary_expression.
//
@@ -183,6 +204,8 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
// "(" expression ")"
//
ASTNodeUP DILParser::ParsePrimaryExpression() {
+ if (CurToken().Is(Token::numeric_constant))
+ return ParseNumericLiteral();
if (CurToken().IsOneOf(
{Token::coloncolon, Token::identifier, Token::l_paren})) {
// Save the source location for the diagnostics message.
@@ -351,6 +374,7 @@ void DILParser::BailOut(const std::string &error, uint32_t loc,
// integer_literal:
// ? Integer constant ?
//
+// Haven't removed this yet in order to not rewrite the array subscription
std::optional<int64_t> DILParser::ParseIntegerConstant() {
std::string number_spelling;
if (CurToken().GetKind() == Token::minus) {
@@ -370,6 +394,52 @@ std::optional<int64_t> DILParser::ParseIntegerConstant() {
return std::nullopt;
}
+// Parse a numeric_literal.
+//
+// numeric_literal:
+// ? Token::numeric_constant ?
+//
+ASTNodeUP DILParser::ParseNumericLiteral() {
+ Expect(Token::numeric_constant);
+ ASTNodeUP numeric_constant = ParseNumericConstant();
+ if (numeric_constant->GetKind() == NodeKind::eErrorNode) {
+ BailOut(llvm::formatv("Failed to parse token as numeric-constant: {0}",
+ CurToken()),
+ CurToken().GetLocation(), CurToken().GetSpelling().length());
+ return std::make_unique<ErrorNode>();
+ }
+ m_dil_lexer.Advance();
+ return numeric_constant;
+}
+
+static constexpr std::pair<const char *, lldb::BasicType> type_suffixes[] = {
+ {"ull", lldb::eBasicTypeUnsignedLongLong},
+ {"ul", lldb::eBasicTypeUnsignedLong},
+ {"u", lldb::eBasicTypeUnsignedInt},
+ {"ll", lldb::eBasicTypeLongLong},
+ {"l", lldb::eBasicTypeLong},
+};
+
+ASTNodeUP DILParser::ParseNumericConstant() {
+ Token token = CurToken();
+ auto spelling = token.GetSpelling();
+ llvm::StringRef spelling_ref = spelling;
+ lldb::BasicType type = lldb::eBasicTypeInt;
+ for (auto [suffix, t] : type_suffixes) {
+ if (spelling_ref.consume_back_insensitive(suffix)) {
+ type = t;
+ break;
+ }
+ }
+ llvm::APInt raw_value;
+ if (!spelling_ref.getAsInteger(0, raw_value)) {
+ Scalar scalar_value(raw_value);
+ return std::make_unique<ScalarLiteralNode>(token.GetLocation(), type,
+ scalar_value);
+ }
+ return std::make_unique<ErrorNode>();
+}
+
void DILParser::Expect(Token::Kind kind) {
if (CurToken().IsNot(kind)) {
BailOut(llvm::formatv("expected {0}, got: {1}", kind, CurToken()),
More information about the lldb-commits
mailing list