https://github.com/kuilpd created 
https://github.com/llvm/llvm-project/pull/138551

None

>From cfe7359bd16c1e87932e2ebb8bcdfc88130e9729 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuk...@accesssoftek.com>
Date: Wed, 30 Apr 2025 22:03:50 +0500
Subject: [PATCH] [LLDB] Add array subscription and integer parsing to DIL

---
 lldb/docs/dil-expr-lang.ebnf                  |  12 +-
 lldb/include/lldb/ValueObject/DILAST.h        |  46 +++++
 lldb/include/lldb/ValueObject/DILEval.h       |   6 +
 lldb/include/lldb/ValueObject/DILLexer.h      |   3 +
 lldb/include/lldb/ValueObject/DILParser.h     |   3 +
 lldb/source/ValueObject/DILAST.cpp            |  10 ++
 lldb/source/ValueObject/DILEval.cpp           | 159 ++++++++++++++++++
 lldb/source/ValueObject/DILLexer.cpp          |  43 ++++-
 lldb/source/ValueObject/DILParser.cpp         |  79 ++++++++-
 .../var-dil/basics/ArraySubscript/Makefile    |   3 +
 .../TestFrameVarDILArraySubscript.py          |  88 ++++++++++
 .../var-dil/basics/ArraySubscript/main.cpp    |  31 ++++
 lldb/unittests/ValueObject/DILLexerTests.cpp  |  34 +++-
 13 files changed, 506 insertions(+), 11 deletions(-)
 create mode 100644 
lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/Makefile
 create mode 100644 
lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py
 create mode 100644 
lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/main.cpp

diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index c8bf4231b3e4a..0cbb5403785db 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -6,16 +6,20 @@
 expression = unary_expression ;
 
 unary_expression = unary_operator expression
-                 | primary_expression ;
+                 | postfix_expression ;
 
 unary_operator = "*" | "&" ;
 
-primary_expression = id_expression
+postfix_expression = primary_expression
+                   | postfix_expression "[" expression "]";
+
+primary_expression = numeric_literal
+                   | id_expression
                    | "(" expression ")";
 
 id_expression = unqualified_id
               | qualified_id
-             | register ;
+              | register ;
 
 unqualified_id = identifier ;
 
@@ -24,6 +28,8 @@ qualified_id = ["::"] [nested_name_specifier] unqualified_id
 
 identifier = ? C99 Identifier ? ;
 
+numeric_literal = ? C99 Integer constant ? ;
+
 register = "$" ? Register name ? ;
 
 nested_name_specifier = type_name "::"
diff --git a/lldb/include/lldb/ValueObject/DILAST.h 
b/lldb/include/lldb/ValueObject/DILAST.h
index fe3827ef0516a..6908deed7aee3 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -18,8 +18,10 @@ namespace lldb_private::dil {
 
 /// The various types DIL AST nodes (used by the DIL parser).
 enum class NodeKind {
+  eArraySubscriptNode,
   eErrorNode,
   eIdentifierNode,
+  eScalarLiteralNode,
   eUnaryOpNode,
 };
 
@@ -71,6 +73,26 @@ class ErrorNode : public ASTNode {
   }
 };
 
+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 IdentifierNode : public ASTNode {
 public:
   IdentifierNode(uint32_t location, std::string name)
@@ -108,6 +130,26 @@ class UnaryOpNode : public ASTNode {
   ASTNodeUP m_operand;
 };
 
+class ArraySubscriptNode : public ASTNode {
+public:
+  ArraySubscriptNode(uint32_t location, ASTNodeUP lhs, ASTNodeUP rhs)
+      : ASTNode(location, NodeKind::eArraySubscriptNode), 
m_lhs(std::move(lhs)),
+        m_rhs(std::move(rhs)) {}
+
+  llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
+
+  ASTNode *lhs() const { return m_lhs.get(); }
+  ASTNode *rhs() const { return m_rhs.get(); }
+
+  static bool classof(const ASTNode *node) {
+    return node->GetKind() == NodeKind::eArraySubscriptNode;
+  }
+
+private:
+  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
@@ -116,9 +158,13 @@ class Visitor {
 public:
   virtual ~Visitor() = default;
   virtual llvm::Expected<lldb::ValueObjectSP>
+  Visit(const ScalarLiteralNode *node) = 0;
+  virtual llvm::Expected<lldb::ValueObjectSP>
   Visit(const IdentifierNode *node) = 0;
   virtual llvm::Expected<lldb::ValueObjectSP>
   Visit(const UnaryOpNode *node) = 0;
+  virtual llvm::Expected<lldb::ValueObjectSP>
+  Visit(const ArraySubscriptNode *node) = 0;
 };
 
 } // namespace lldb_private::dil
diff --git a/lldb/include/lldb/ValueObject/DILEval.h 
b/lldb/include/lldb/ValueObject/DILEval.h
index b1dd3fdb49739..e3df80862b082 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -47,9 +47,15 @@ class Interpreter : Visitor {
   llvm::Expected<lldb::ValueObjectSP> Evaluate(const ASTNode *node);
 
 private:
+  llvm::Expected<lldb::ValueObjectSP>
+  Visit(const ScalarLiteralNode *node) override;
   llvm::Expected<lldb::ValueObjectSP>
   Visit(const IdentifierNode *node) override;
   llvm::Expected<lldb::ValueObjectSP> Visit(const UnaryOpNode *node) override;
+  llvm::Expected<lldb::ValueObjectSP>
+  Visit(const ArraySubscriptNode *node) override;
+
+  lldb::ValueObjectSP PointerAdd(lldb::ValueObjectSP lhs, int64_t offset);
 
   // 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 3508b8b7a85c6..0176db73835e9 100644
--- a/lldb/include/lldb/ValueObject/DILLexer.h
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -29,7 +29,10 @@ class Token {
     eof,
     identifier,
     l_paren,
+    l_square,
+    numeric_constant,
     r_paren,
+    r_square,
     star,
   };
 
diff --git a/lldb/include/lldb/ValueObject/DILParser.h 
b/lldb/include/lldb/ValueObject/DILParser.h
index f5c00b1040ef4..af237ece0228d 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -84,12 +84,15 @@ class DILParser {
 
   ASTNodeUP ParseExpression();
   ASTNodeUP ParseUnaryExpression();
+  ASTNodeUP ParsePostfixExpression();
   ASTNodeUP ParsePrimaryExpression();
 
   std::string ParseNestedNameSpecifier();
 
   std::string ParseIdExpression();
   std::string ParseUnqualifiedId();
+  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 ea847587501ee..ceb4a4aa99c4f 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -15,6 +15,11 @@ llvm::Expected<lldb::ValueObjectSP> 
ErrorNode::Accept(Visitor *v) const {
   llvm_unreachable("Attempting to Visit a DIL ErrorNode.");
 }
 
+llvm::Expected<lldb::ValueObjectSP>
+ScalarLiteralNode::Accept(Visitor *v) const {
+  return v->Visit(this);
+}
+
 llvm::Expected<lldb::ValueObjectSP> IdentifierNode::Accept(Visitor *v) const {
   return v->Visit(this);
 }
@@ -23,4 +28,9 @@ llvm::Expected<lldb::ValueObjectSP> 
UnaryOpNode::Accept(Visitor *v) const {
   return v->Visit(this);
 }
 
+llvm::Expected<lldb::ValueObjectSP>
+ArraySubscriptNode::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 15a66d4866305..527017da7c019 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -18,6 +18,22 @@
 
 namespace lldb_private::dil {
 
+static lldb::ValueObjectSP
+ArrayToPointerConversion(lldb::ValueObjectSP valobj,
+                         std::shared_ptr<ExecutionContextScope> ctx) {
+  assert(valobj->IsArrayType() &&
+         "an argument to array-to-pointer conversion must be an array");
+
+  uint64_t addr = valobj->GetLoadAddress();
+  llvm::StringRef name = "result";
+  ExecutionContext exe_ctx;
+  ctx->CalculateExecutionContext(exe_ctx);
+  return ValueObject::CreateValueObjectFromAddress(
+      name, addr, exe_ctx,
+      
valobj->GetCompilerType().GetArrayElementType(ctx.get()).GetPointerType(),
+      /* do_deref */ false);
+}
+
 static lldb::ValueObjectSP LookupStaticIdentifier(
     VariableList &variable_list, std::shared_ptr<StackFrame> exe_scope,
     llvm::StringRef name_ref, llvm::StringRef unqualified_name) {
@@ -214,6 +230,45 @@ llvm::Expected<lldb::ValueObjectSP> 
Interpreter::Evaluate(const ASTNode *node) {
   return value_or_error;
 }
 
+static CompilerType GetBasicType(std::shared_ptr<ExecutionContextScope> ctx,
+                                 lldb::BasicType basic_type) {
+  static std::unordered_map<lldb::BasicType, CompilerType> basic_types;
+  auto type = basic_types.find(basic_type);
+  if (type != basic_types.end()) {
+    std::string type_name((type->second).GetTypeName().AsCString());
+    // Only return the found type if it's valid.
+    if (type_name != "<invalid>")
+      return type->second;
+  }
+
+  lldb::TargetSP target_sp = ctx->CalculateTarget();
+  if (target_sp) {
+    for (auto type_system_sp : target_sp->GetScratchTypeSystems())
+      if (auto compiler_type =
+              type_system_sp->GetBasicTypeFromAST(basic_type)) {
+        basic_types.insert({basic_type, compiler_type});
+        return compiler_type;
+      }
+  }
+  CompilerType empty_type;
+  return empty_type;
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const ScalarLiteralNode *node) {
+  CompilerType result_type = GetBasicType(m_exe_ctx_scope, node->GetType());
+  Scalar value = node->GetValue();
+
+  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();
+}
+
 llvm::Expected<lldb::ValueObjectSP>
 Interpreter::Visit(const IdentifierNode *node) {
   lldb::DynamicValueType use_dynamic = m_default_dynamic;
@@ -272,4 +327,108 @@ Interpreter::Visit(const UnaryOpNode *node) {
       m_expr, "invalid ast: unexpected binary operator", node->GetLocation());
 }
 
+lldb::ValueObjectSP Interpreter::PointerAdd(lldb::ValueObjectSP lhs,
+                                            int64_t offset) {
+  uint64_t byte_size = 0;
+  if (auto temp = lhs->GetCompilerType().GetPointeeType().GetByteSize(
+          lhs->GetTargetSP().get()))
+    byte_size = *temp;
+  uintptr_t addr = lhs->GetValueAsUnsigned(0) + offset * byte_size;
+
+  llvm::StringRef name = "result";
+  ExecutionContext exe_ctx(m_target.get(), false);
+  return ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx,
+                                                   lhs->GetCompilerType(),
+                                                   /* do_deref */ false);
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const ArraySubscriptNode *node) {
+  auto lhs_or_err = Evaluate(node->lhs());
+  if (!lhs_or_err) {
+    return lhs_or_err;
+  }
+  lldb::ValueObjectSP base = *lhs_or_err;
+  auto rhs_or_err = Evaluate(node->rhs());
+  if (!rhs_or_err) {
+    return rhs_or_err;
+  }
+  lldb::ValueObjectSP index = *rhs_or_err;
+
+  Status error;
+  if (base->GetCompilerType().IsReferenceType()) {
+    base = base->Dereference(error);
+    if (error.Fail())
+      return error.ToError();
+  }
+  if (index->GetCompilerType().IsReferenceType()) {
+    index = index->Dereference(error);
+    if (error.Fail())
+      return error.ToError();
+  }
+
+  auto index_type = index->GetCompilerType();
+  if (!index_type.IsIntegerOrUnscopedEnumerationType())
+    return llvm::make_error<DILDiagnosticError>(
+        m_expr, "array subscript is not an integer", node->GetLocation());
+
+  // Check to see if 'base' has a synthetic value; if so, try using that.
+  if (base->HasSyntheticValue()) {
+    lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
+    if (synthetic && synthetic != base) {
+      uint32_t num_children = synthetic->GetNumChildrenIgnoringErrors();
+      // Verify that the 'index' is not out-of-range for the declared type.
+      if (index->GetValueAsSigned(0) >= num_children) {
+        auto message =
+            llvm::formatv("array index {0} is not valid for \"({1}) {2}\"",
+                          index->GetValueAsSigned(0),
+                          base->GetTypeName().AsCString("<invalid type>"),
+                          base->GetName().AsCString());
+        return llvm::make_error<DILDiagnosticError>(m_expr, message,
+                                                    node->GetLocation());
+      }
+
+      uint64_t child_idx = index->GetValueAsUnsigned(0);
+      if (static_cast<uint32_t>(child_idx) <
+          synthetic->GetNumChildrenIgnoringErrors()) {
+        lldb::ValueObjectSP child_valobj_sp =
+            synthetic->GetChildAtIndex(child_idx);
+        if (child_valobj_sp) {
+          return child_valobj_sp;
+        }
+      }
+    }
+  }
+
+  auto base_type = base->GetCompilerType();
+  if (!base_type.IsPointerType() && !base_type.IsArrayType())
+    return llvm::make_error<DILDiagnosticError>(
+        m_expr, "subscripted value is not an array or pointer",
+        node->GetLocation());
+  if (base_type.IsPointerToVoid())
+    return llvm::make_error<DILDiagnosticError>(
+        m_expr, "subscript of pointer to incomplete type 'void'",
+        node->GetLocation());
+
+  if (base_type.IsArrayType())
+    base = ArrayToPointerConversion(base, m_exe_ctx_scope);
+
+  CompilerType item_type = base->GetCompilerType().GetPointeeType();
+  lldb::addr_t base_addr = base->GetValueAsUnsigned(0);
+
+  llvm::StringRef name = "result";
+  ExecutionContext exe_ctx(m_target.get(), false);
+  // Create a pointer and add the index, i.e. "base + index".
+  lldb::ValueObjectSP value =
+      PointerAdd(ValueObject::CreateValueObjectFromAddress(
+                     name, base_addr, exe_ctx, item_type.GetPointerType(),
+                     /*do_deref=*/false),
+                 index->GetValueAsSigned(0));
+
+  lldb::ValueObjectSP val2 = value->Dereference(error);
+  if (error.Fail())
+    return error.ToError();
+  return val2;
+}
+
 } // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILLexer.cpp 
b/lldb/source/ValueObject/DILLexer.cpp
index b9c2e7971e3b4..3222032feef19 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -13,6 +13,7 @@
 
 #include "lldb/ValueObject/DILLexer.h"
 #include "lldb/Utility/Status.h"
+#include "lldb/ValueObject/DILParser.h"
 #include "llvm/ADT/StringSwitch.h"
 
 namespace lldb_private::dil {
@@ -29,8 +30,14 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "identifier";
   case Kind::l_paren:
     return "l_paren";
+  case Kind::l_square:
+    return "l_square";
+  case Kind::numeric_constant:
+    return "numeric_constant";
   case Kind::r_paren:
     return "r_paren";
+  case Kind::r_square:
+    return "r_square";
   case Token::star:
     return "star";
   }
@@ -57,6 +64,29 @@ static std::optional<llvm::StringRef> IsWord(llvm::StringRef 
expr,
   return candidate;
 }
 
+static void ConsumeNumberBody(char &prev_ch, llvm::StringRef::iterator 
&cur_pos,
+                              llvm::StringRef expr) {
+  while (cur_pos != expr.end() &&
+         (IsDigit(*cur_pos) || IsLetter(*cur_pos) || *cur_pos == '_')) {
+    prev_ch = *cur_pos;
+    cur_pos++;
+  }
+}
+
+static std::optional<llvm::StringRef> IsNumber(llvm::StringRef expr,
+                                               llvm::StringRef &remainder) {
+  llvm::StringRef::iterator cur_pos = remainder.begin();
+  llvm::StringRef::iterator start = cur_pos;
+  char prev_ch = 0;
+  if (IsDigit(*start)) {
+    ConsumeNumberBody(prev_ch, cur_pos, expr);
+    llvm::StringRef number = expr.substr(start - expr.begin(), cur_pos - 
start);
+    if (remainder.consume_front(number))
+      return number;
+  }
+  return std::nullopt;
+}
+
 llvm::Expected<DILLexer> DILLexer::Create(llvm::StringRef expr) {
   std::vector<Token> tokens;
   llvm::StringRef remainder = expr;
@@ -81,13 +111,19 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
     return Token(Token::eof, "", (uint32_t)expr.size());
 
   uint32_t position = cur_pos - expr.begin();
+  std::optional<llvm::StringRef> maybe_number = IsNumber(expr, remainder);
+  if (maybe_number) {
+    std::string number = (*maybe_number).str();
+    return Token(Token::numeric_constant, number, position);
+  }
   std::optional<llvm::StringRef> maybe_word = IsWord(expr, remainder);
   if (maybe_word)
     return Token(Token::identifier, maybe_word->str(), position);
 
   constexpr std::pair<Token::Kind, const char *> operators[] = {
-      {Token::amp, "&"},     {Token::coloncolon, "::"}, {Token::l_paren, "("},
-      {Token::r_paren, ")"}, {Token::star, "*"},
+      {Token::amp, "&"},      {Token::coloncolon, "::"}, {Token::l_paren, "("},
+      {Token::l_square, "["}, {Token::r_paren, ")"},     {Token::r_square, 
"]"},
+      {Token::star, "*"},
   };
   for (auto [kind, str] : operators) {
     if (remainder.consume_front(str))
@@ -95,7 +131,8 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
   }
 
   // Unrecognized character(s) in string; unable to lex it.
-  return llvm::createStringError("Unable to lex input string");
+  return llvm::make_error<DILDiagnosticError>(expr, "unrecognized token",
+                                              position);
 }
 
 } // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index 2c78eae8cf6bf..24a6f0c909a0a 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -111,7 +111,36 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
       llvm_unreachable("invalid token kind");
     }
   }
-  return ParsePrimaryExpression();
+  return ParsePostfixExpression();
+}
+
+// Parse a postfix_expression.
+//
+//  postfix_expression:
+//    primary_expression
+//    postfix_expression "[" expression "]"
+//
+ASTNodeUP DILParser::ParsePostfixExpression() {
+  ASTNodeUP lhs = ParsePrimaryExpression();
+  while (CurToken().Is(Token::l_square)) {
+    uint32_t loc = CurToken().GetLocation();
+    Token token = CurToken();
+    switch (token.GetKind()) {
+    case Token::l_square: {
+      m_dil_lexer.Advance();
+      auto rhs = ParseExpression();
+      Expect(Token::r_square);
+      m_dil_lexer.Advance();
+      lhs = std::make_unique<ArraySubscriptNode>(loc, std::move(lhs),
+                                                 std::move(rhs));
+      break;
+    }
+    default:
+      llvm_unreachable("invalid token");
+    }
+  }
+
+  return lhs;
 }
 
 // Parse a primary_expression.
@@ -121,6 +150,8 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
 //    "(" expression ")"
 //
 ASTNodeUP DILParser::ParsePrimaryExpression() {
+  if (CurToken().Is(Token::numeric_constant))
+    return ParseNumericLiteral();
   if (CurToken().IsOneOf({Token::coloncolon, Token::identifier})) {
     // Save the source location for the diagnostics message.
     uint32_t loc = CurToken().GetLocation();
@@ -280,6 +311,52 @@ void DILParser::BailOut(const std::string &error, uint32_t 
loc,
   m_dil_lexer.ResetTokenIdx(m_dil_lexer.NumLexedTokens() - 1);
 }
 
+// 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()),
diff --git 
a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/Makefile 
b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git 
a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py
 
b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py
new file mode 100644
index 0000000000000..e142889124613
--- /dev/null
+++ 
b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py
@@ -0,0 +1,88 @@
+"""
+Test DIL array subscript.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+
+class TestFrameVarDILGlobalVariableLookup(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def expect_var_path(self, expr, compare_to_framevar=False, value=None, 
type=None):
+        value_dil = super().expect_var_path(expr, value=value, type=type)
+        if compare_to_framevar:
+            self.runCmd("settings set target.experimental.use-DIL false")
+            value_frv = super().expect_var_path(expr, value=value, type=type)
+            self.runCmd("settings set target.experimental.use-DIL true")
+            self.assertEqual(value_dil.GetValue(), value_frv.GetValue())
+
+    def test_dereference(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.runCmd("settings set target.experimental.use-DIL true")
+
+        # Test int[] and int*
+        self.expect_var_path("int_arr[0]", True, value="1")
+        self.expect_var_path("int_ptr[1]", True, value="2")
+        self.expect_var_path("int_arr[enum_one]", value="2")
+
+        # Test when base and index are references.
+        self.expect_var_path("int_arr[0]", True, value="1")
+        self.expect_var_path("int_arr[idx_1_ref]", value="2")
+        self.expect_var_path("int_arr[enum_ref]", value="2")
+        self.expect_var_path("int_arr_ref[0]", value="1")
+        self.expect_var_path("int_arr_ref[idx_1_ref]", value="2")
+        self.expect_var_path("int_arr_ref[enum_ref]", value="2")
+
+        # Test when base and index are typedefs.
+        self.expect_var_path("td_int_arr[0]", True, value="1")
+        self.expect_var_path("td_int_arr[td_int_idx_1]", value="2")
+        self.expect_var_path("td_int_arr[td_td_int_idx_2]", value="3")
+        self.expect_var_path("td_int_ptr[0]", True, value="1")
+        self.expect_var_path("td_int_ptr[td_int_idx_1]", value="2")
+        self.expect_var_path("td_int_ptr[td_td_int_idx_2]", value="3")
+
+        # Both typedefs and refs
+        self.expect_var_path("td_int_arr_ref[td_int_idx_1_ref]", value="2")
+
+        # Test for index out of bounds.
+        self.expect_var_path("int_arr[42]", True, type="int")
+        self.expect_var_path("int_arr[100]", True, type="int")
+
+        # Test address-of of the subscripted value.
+        self.expect_var_path("*(&int_arr[1])", value="2")
+
+        # Test synthetic value subscription
+        self.expect_var_path("vector[1]", value="2")
+
+        # Test for negative index.
+        self.expect(
+            "frame var 'int_arr[-1]'",
+            error=True,
+            substrs=["unrecognized token"],
+        )
+
+        # Test for floating point index
+        self.expect(
+            "frame var 'int_arr[1.0]'",
+            error=True,
+            substrs=["unrecognized token"],
+        )
+
+        # Base should be a "pointer to T" and index should be of an integral 
type.
+        self.expect(
+            "frame var 'int_arr[int_ptr]'",
+            error=True,
+            substrs=["array subscript is not an integer"],
+        )
+        self.expect(
+            "frame var '1[2]'",
+            error=True,
+            substrs=["subscripted value is not an array or pointer"],
+        )
diff --git 
a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/main.cpp 
b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/main.cpp
new file mode 100644
index 0000000000000..b34e4670b9db6
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/main.cpp
@@ -0,0 +1,31 @@
+#include <vector>
+
+int main(int argc, char **argv) {
+  int int_arr[] = {1, 2, 3};
+  int *int_ptr = int_arr;
+  int(&int_arr_ref)[3] = int_arr;
+
+  int idx_1 = 1;
+  const int &idx_1_ref = idx_1;
+
+  typedef int td_int_t;
+  typedef td_int_t td_td_int_t;
+  typedef int *td_int_ptr_t;
+  typedef int &td_int_ref_t;
+
+  td_int_t td_int_idx_1 = 1;
+  td_td_int_t td_td_int_idx_2 = 2;
+
+  td_int_t td_int_arr[3] = {1, 2, 3};
+  td_int_ptr_t td_int_ptr = td_int_arr;
+
+  td_int_ref_t td_int_idx_1_ref = td_int_idx_1;
+  td_int_t(&td_int_arr_ref)[3] = td_int_arr;
+
+  enum Enum { kZero, kOne } enum_one = kOne;
+  Enum &enum_ref = enum_one;
+
+  std::vector<int> vector = {1, 2, 3};
+
+  return 0; // Set a breakpoint here
+}
diff --git a/lldb/unittests/ValueObject/DILLexerTests.cpp 
b/lldb/unittests/ValueObject/DILLexerTests.cpp
index 9afa957901ae7..203763b91afc4 100644
--- a/lldb/unittests/ValueObject/DILLexerTests.cpp
+++ b/lldb/unittests/ValueObject/DILLexerTests.cpp
@@ -121,11 +121,11 @@ TEST(DILLexerTests, IdentifiersTest) {
       "a_b",       "this", "self", "a", "MyName", "namespace"};
 
   // The lexer can lex these strings, but they should not be identifiers.
-  std::vector<std::string> invalid_identifiers = {"", "::", "(", ")"};
+  std::vector<std::string> invalid_identifiers = {"", "::", "(", ")", "0abc"};
 
   // The lexer is expected to fail attempting to lex these strings (it cannot
   // create valid tokens out of them).
-  std::vector<std::string> invalid_tok_strings = {"234", "2a", "2", "1MyName"};
+  std::vector<std::string> invalid_tok_strings = {"#include", "a@a"};
 
   // Verify that all of the valid identifiers come out as identifier tokens.
   for (auto &str : valid_identifiers) {
@@ -150,7 +150,33 @@ TEST(DILLexerTests, IdentifiersTest) {
     DILLexer lexer(*maybe_lexer);
     Token token = lexer.GetCurrentToken();
     EXPECT_TRUE(token.IsNot(Token::identifier));
-    EXPECT_TRUE(token.IsOneOf(
-        {Token::eof, Token::coloncolon, Token::l_paren, Token::r_paren}));
+    EXPECT_TRUE(token.IsOneOf({Token::eof, Token::coloncolon, Token::l_paren,
+                               Token::r_paren, Token::numeric_constant}));
+  }
+}
+
+TEST(DILLexerTests, NumbersTest) {
+  // These strings should lex into number tokens.
+  std::vector<std::string> valid_numbers = {"123", "0x123", "0123", "0b101",
+                                            "1_000"};
+
+  // The lexer can lex these strings, but they should not be numbers.
+  std::vector<std::string> invalid_numbers = {"", "x123", "b123"};
+
+  for (auto &str : valid_numbers) {
+    SCOPED_TRACE(str);
+    EXPECT_THAT_EXPECTED(ExtractTokenData(str),
+                         llvm::HasValue(testing::ElementsAre(
+                             testing::Pair(Token::numeric_constant, str))));
+  }
+  // Verify that none of the invalid numbers come out as numeric tokens.
+  for (auto &str : invalid_numbers) {
+    SCOPED_TRACE(str);
+    llvm::Expected<DILLexer> maybe_lexer = DILLexer::Create(str);
+    EXPECT_THAT_EXPECTED(maybe_lexer, llvm::Succeeded());
+    DILLexer lexer(*maybe_lexer);
+    Token token = lexer.GetCurrentToken();
+    EXPECT_TRUE(token.IsNot(Token::numeric_constant));
+    EXPECT_TRUE(token.IsOneOf({Token::eof, Token::identifier}));
   }
 }

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to