Skip to content

Commit bae1772

Browse files
authored
Reapply "[LLDB] Add ScalarLiteralNode and literal parsing in DIL" (#155610)
This patch introduces `ScalarLiteralNode` without any uses by other nodes yet. It also includes lexing and parsing for integer and floating point numbers. Reapplies #152308 with a fix.
1 parent 9dd38b0 commit bae1772

File tree

15 files changed

+429
-31
lines changed

15 files changed

+429
-31
lines changed

lldb/docs/dil-expr-lang.ebnf

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ postfix_expression = primary_expression
1515
| postfix_expression "." id_expression
1616
| postfix_expression "->" id_expression ;
1717
18-
primary_expression = id_expression
18+
primary_expression = numeric_literal
19+
| id_expression
1920
| "(" expression ")" ;
2021
2122
id_expression = unqualified_id
@@ -31,6 +32,9 @@ identifier = ? C99 Identifier ? ;
3132
3233
integer_literal = ? Integer constant: hexademical, decimal, octal, binary ? ;
3334
35+
numeric_literal = ? Integer constant: hexademical, decimal, octal, binary ?
36+
| ? Floating constant ? ;
37+
3438
register = "$" ? Register name ? ;
3539
3640
nested_name_specifier = type_name "::"

lldb/include/lldb/ValueObject/DILAST.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ enum class NodeKind {
2121
eArraySubscriptNode,
2222
eBitExtractionNode,
2323
eErrorNode,
24+
eFloatLiteralNode,
2425
eIdentifierNode,
26+
eIntegerLiteralNode,
2527
eMemberOfNode,
2628
eUnaryOpNode,
2729
};
@@ -178,6 +180,52 @@ class BitFieldExtractionNode : public ASTNode {
178180
int64_t m_last_index;
179181
};
180182

183+
enum class IntegerTypeSuffix { None, Long, LongLong };
184+
185+
class IntegerLiteralNode : public ASTNode {
186+
public:
187+
IntegerLiteralNode(uint32_t location, llvm::APInt value, uint32_t radix,
188+
bool is_unsigned, IntegerTypeSuffix type)
189+
: ASTNode(location, NodeKind::eIntegerLiteralNode),
190+
m_value(std::move(value)), m_radix(radix), m_is_unsigned(is_unsigned),
191+
m_type(type) {}
192+
193+
llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
194+
195+
const llvm::APInt &GetValue() const { return m_value; }
196+
uint32_t GetRadix() const { return m_radix; }
197+
bool IsUnsigned() const { return m_is_unsigned; }
198+
IntegerTypeSuffix GetTypeSuffix() const { return m_type; }
199+
200+
static bool classof(const ASTNode *node) {
201+
return node->GetKind() == NodeKind::eIntegerLiteralNode;
202+
}
203+
204+
private:
205+
llvm::APInt m_value;
206+
uint32_t m_radix;
207+
bool m_is_unsigned;
208+
IntegerTypeSuffix m_type;
209+
};
210+
211+
class FloatLiteralNode : public ASTNode {
212+
public:
213+
FloatLiteralNode(uint32_t location, llvm::APFloat value)
214+
: ASTNode(location, NodeKind::eFloatLiteralNode),
215+
m_value(std::move(value)) {}
216+
217+
llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
218+
219+
const llvm::APFloat &GetValue() const { return m_value; }
220+
221+
static bool classof(const ASTNode *node) {
222+
return node->GetKind() == NodeKind::eFloatLiteralNode;
223+
}
224+
225+
private:
226+
llvm::APFloat m_value;
227+
};
228+
181229
/// This class contains one Visit method for each specialized type of
182230
/// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
183231
/// the correct function in the DIL expression evaluator for evaluating that
@@ -195,6 +243,10 @@ class Visitor {
195243
Visit(const ArraySubscriptNode *node) = 0;
196244
virtual llvm::Expected<lldb::ValueObjectSP>
197245
Visit(const BitFieldExtractionNode *node) = 0;
246+
virtual llvm::Expected<lldb::ValueObjectSP>
247+
Visit(const IntegerLiteralNode *node) = 0;
248+
virtual llvm::Expected<lldb::ValueObjectSP>
249+
Visit(const FloatLiteralNode *node) = 0;
198250
};
199251

200252
} // namespace lldb_private::dil

lldb/include/lldb/ValueObject/DILEval.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ class Interpreter : Visitor {
5454
Visit(const ArraySubscriptNode *node) override;
5555
llvm::Expected<lldb::ValueObjectSP>
5656
Visit(const BitFieldExtractionNode *node) override;
57+
llvm::Expected<lldb::ValueObjectSP>
58+
Visit(const IntegerLiteralNode *node) override;
59+
llvm::Expected<lldb::ValueObjectSP>
60+
Visit(const FloatLiteralNode *node) override;
61+
62+
llvm::Expected<CompilerType>
63+
PickIntegerType(lldb::TypeSystemSP type_system,
64+
std::shared_ptr<ExecutionContextScope> ctx,
65+
const IntegerLiteralNode *literal);
5766

5867
// Used by the interpreter to create objects, perform casts, etc.
5968
lldb::TargetSP m_target;

lldb/include/lldb/ValueObject/DILLexer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ class Token {
2828
arrow,
2929
coloncolon,
3030
eof,
31+
float_constant,
3132
identifier,
33+
integer_constant,
3234
l_paren,
3335
l_square,
3436
minus,
35-
numeric_constant,
3637
period,
38+
plus,
3739
r_paren,
3840
r_square,
3941
star,

lldb/include/lldb/ValueObject/DILParser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ class DILParser {
9696
std::string ParseIdExpression();
9797
std::string ParseUnqualifiedId();
9898
std::optional<int64_t> ParseIntegerConstant();
99+
ASTNodeUP ParseNumericLiteral();
100+
ASTNodeUP ParseIntegerLiteral();
101+
ASTNodeUP ParseFloatingPointLiteral();
99102

100103
void BailOut(const std::string &error, uint32_t loc, uint16_t err_len);
101104

lldb/source/ValueObject/DILAST.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,13 @@ BitFieldExtractionNode::Accept(Visitor *v) const {
3737
return v->Visit(this);
3838
}
3939

40+
llvm::Expected<lldb::ValueObjectSP>
41+
IntegerLiteralNode::Accept(Visitor *v) const {
42+
return v->Visit(this);
43+
}
44+
45+
llvm::Expected<lldb::ValueObjectSP> FloatLiteralNode::Accept(Visitor *v) const {
46+
return v->Visit(this);
47+
}
48+
4049
} // namespace lldb_private::dil

lldb/source/ValueObject/DILEval.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "lldb/ValueObject/DILEval.h"
10+
#include "lldb/Core/Module.h"
1011
#include "lldb/Symbol/CompileUnit.h"
12+
#include "lldb/Symbol/TypeSystem.h"
1113
#include "lldb/Symbol/VariableList.h"
1214
#include "lldb/Target/RegisterContext.h"
1315
#include "lldb/ValueObject/DILAST.h"
@@ -497,4 +499,107 @@ Interpreter::Visit(const BitFieldExtractionNode *node) {
497499
return child_valobj_sp;
498500
}
499501

502+
static llvm::Expected<lldb::TypeSystemSP>
503+
GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) {
504+
SymbolContext symbol_context =
505+
ctx->GetSymbolContext(lldb::eSymbolContextCompUnit);
506+
lldb::LanguageType language = symbol_context.comp_unit->GetLanguage();
507+
508+
symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule);
509+
return symbol_context.module_sp->GetTypeSystemForLanguage(language);
510+
}
511+
512+
static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
513+
lldb::BasicType basic_type) {
514+
if (type_system)
515+
return type_system.get()->GetBasicTypeFromAST(basic_type);
516+
517+
return CompilerType();
518+
}
519+
520+
llvm::Expected<CompilerType>
521+
Interpreter::PickIntegerType(lldb::TypeSystemSP type_system,
522+
std::shared_ptr<ExecutionContextScope> ctx,
523+
const IntegerLiteralNode *literal) {
524+
// Binary, Octal, Hexadecimal and literals with a U suffix are allowed to be
525+
// an unsigned integer.
526+
bool unsigned_is_allowed = literal->IsUnsigned() || literal->GetRadix() != 10;
527+
llvm::APInt apint = literal->GetValue();
528+
529+
llvm::SmallVector<std::pair<lldb::BasicType, lldb::BasicType>, 3> candidates;
530+
if (literal->GetTypeSuffix() <= IntegerTypeSuffix::None)
531+
candidates.emplace_back(lldb::eBasicTypeInt,
532+
unsigned_is_allowed ? lldb::eBasicTypeUnsignedInt
533+
: lldb::eBasicTypeInvalid);
534+
if (literal->GetTypeSuffix() <= IntegerTypeSuffix::Long)
535+
candidates.emplace_back(lldb::eBasicTypeLong,
536+
unsigned_is_allowed ? lldb::eBasicTypeUnsignedLong
537+
: lldb::eBasicTypeInvalid);
538+
candidates.emplace_back(lldb::eBasicTypeLongLong,
539+
lldb::eBasicTypeUnsignedLongLong);
540+
for (auto [signed_, unsigned_] : candidates) {
541+
CompilerType signed_type = type_system->GetBasicTypeFromAST(signed_);
542+
if (!signed_type)
543+
continue;
544+
llvm::Expected<uint64_t> size = signed_type.GetBitSize(ctx.get());
545+
if (!size)
546+
return size.takeError();
547+
if (!literal->IsUnsigned() && apint.isIntN(*size - 1))
548+
return signed_type;
549+
if (unsigned_ != lldb::eBasicTypeInvalid && apint.isIntN(*size))
550+
return type_system->GetBasicTypeFromAST(unsigned_);
551+
}
552+
553+
return llvm::make_error<DILDiagnosticError>(
554+
m_expr,
555+
"integer literal is too large to be represented in any integer type",
556+
literal->GetLocation());
557+
}
558+
559+
llvm::Expected<lldb::ValueObjectSP>
560+
Interpreter::Visit(const IntegerLiteralNode *node) {
561+
llvm::Expected<lldb::TypeSystemSP> type_system =
562+
GetTypeSystemFromCU(m_exe_ctx_scope);
563+
if (!type_system)
564+
return type_system.takeError();
565+
566+
llvm::Expected<CompilerType> type =
567+
PickIntegerType(*type_system, m_exe_ctx_scope, node);
568+
if (!type)
569+
return type.takeError();
570+
571+
Scalar scalar = node->GetValue();
572+
// APInt from StringRef::getAsInteger comes with just enough bitwidth to
573+
// hold the value. This adjusts APInt bitwidth to match the compiler type.
574+
llvm::Expected<uint64_t> type_bitsize =
575+
type->GetBitSize(m_exe_ctx_scope.get());
576+
if (!type_bitsize)
577+
return type_bitsize.takeError();
578+
scalar.TruncOrExtendTo(*type_bitsize, false);
579+
return ValueObject::CreateValueObjectFromScalar(m_target, scalar, *type,
580+
"result");
581+
}
582+
583+
llvm::Expected<lldb::ValueObjectSP>
584+
Interpreter::Visit(const FloatLiteralNode *node) {
585+
llvm::Expected<lldb::TypeSystemSP> type_system =
586+
GetTypeSystemFromCU(m_exe_ctx_scope);
587+
if (!type_system)
588+
return type_system.takeError();
589+
590+
bool isFloat =
591+
&node->GetValue().getSemantics() == &llvm::APFloat::IEEEsingle();
592+
lldb::BasicType basic_type =
593+
isFloat ? lldb::eBasicTypeFloat : lldb::eBasicTypeDouble;
594+
CompilerType type = GetBasicType(*type_system, basic_type);
595+
596+
if (!type)
597+
return llvm::make_error<DILDiagnosticError>(
598+
m_expr, "unable to create a const literal", node->GetLocation());
599+
600+
Scalar scalar = node->GetValue();
601+
return ValueObject::CreateValueObjectFromScalar(m_target, scalar, type,
602+
"result");
603+
}
604+
500605
} // namespace lldb_private::dil

lldb/source/ValueObject/DILLexer.cpp

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,23 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
2828
return "coloncolon";
2929
case Kind::eof:
3030
return "eof";
31+
case Kind::float_constant:
32+
return "float_constant";
3133
case Kind::identifier:
3234
return "identifier";
35+
case Kind::integer_constant:
36+
return "integer_constant";
3337
case Kind::l_paren:
3438
return "l_paren";
3539
case Kind::l_square:
3640
return "l_square";
3741
case Kind::minus:
3842
return "minus";
39-
case Kind::numeric_constant:
40-
return "numeric_constant";
4143
case Kind::period:
4244
return "period";
45+
return "l_square";
46+
case Kind::plus:
47+
return "plus";
4348
case Kind::r_paren:
4449
return "r_paren";
4550
case Kind::r_square:
@@ -70,13 +75,32 @@ static std::optional<llvm::StringRef> IsWord(llvm::StringRef expr,
7075
return candidate;
7176
}
7277

73-
static bool IsNumberBodyChar(char ch) { return IsDigit(ch) || IsLetter(ch); }
78+
static bool IsNumberBodyChar(char ch) {
79+
return IsDigit(ch) || IsLetter(ch) || ch == '.';
80+
}
7481

75-
static std::optional<llvm::StringRef> IsNumber(llvm::StringRef expr,
76-
llvm::StringRef &remainder) {
77-
if (IsDigit(remainder[0])) {
78-
llvm::StringRef number = remainder.take_while(IsNumberBodyChar);
79-
remainder = remainder.drop_front(number.size());
82+
static std::optional<llvm::StringRef> IsNumber(llvm::StringRef &remainder,
83+
bool &isFloat) {
84+
llvm::StringRef tail = remainder;
85+
llvm::StringRef body = tail.take_while(IsNumberBodyChar);
86+
size_t dots = body.count('.');
87+
if (dots > 1 || dots == body.size())
88+
return std::nullopt;
89+
if (IsDigit(body.front()) || (body[0] == '.' && IsDigit(body[1]))) {
90+
isFloat = dots == 1;
91+
tail = tail.drop_front(body.size());
92+
bool isHex = body.contains_insensitive('x');
93+
bool hasExp = !isHex && body.contains_insensitive('e');
94+
bool hasHexExp = isHex && body.contains_insensitive('p');
95+
if (hasExp || hasHexExp) {
96+
isFloat = true; // This marks numbers like 0x1p1 and 1e1 as float
97+
if (body.ends_with_insensitive("e") || body.ends_with_insensitive("p"))
98+
if (tail.consume_front("+") || tail.consume_front("-"))
99+
tail = tail.drop_while(IsNumberBodyChar);
100+
}
101+
size_t number_length = remainder.size() - tail.size();
102+
llvm::StringRef number = remainder.take_front(number_length);
103+
remainder = remainder.drop_front(number_length);
80104
return number;
81105
}
82106
return std::nullopt;
@@ -106,18 +130,21 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
106130
return Token(Token::eof, "", (uint32_t)expr.size());
107131

108132
uint32_t position = cur_pos - expr.begin();
109-
std::optional<llvm::StringRef> maybe_number = IsNumber(expr, remainder);
110-
if (maybe_number)
111-
return Token(Token::numeric_constant, maybe_number->str(), position);
133+
bool isFloat = false;
134+
std::optional<llvm::StringRef> maybe_number = IsNumber(remainder, isFloat);
135+
if (maybe_number) {
136+
auto kind = isFloat ? Token::float_constant : Token::integer_constant;
137+
return Token(kind, maybe_number->str(), position);
138+
}
112139
std::optional<llvm::StringRef> maybe_word = IsWord(expr, remainder);
113140
if (maybe_word)
114141
return Token(Token::identifier, maybe_word->str(), position);
115142

116143
constexpr std::pair<Token::Kind, const char *> operators[] = {
117-
{Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
118-
{Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
119-
{Token::period, "."}, {Token::r_paren, ")"}, {Token::r_square, "]"},
120-
{Token::star, "*"},
144+
{Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
145+
{Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
146+
{Token::period, "."}, {Token::plus, "+"}, {Token::r_paren, ")"},
147+
{Token::r_square, "]"}, {Token::star, "*"},
121148
};
122149
for (auto [kind, str] : operators) {
123150
if (remainder.consume_front(str))

0 commit comments

Comments
 (0)