[Lldb-commits] [lldb] [LLDB] Add DIL code for handling plain variable names. (PR #120971)

via lldb-commits lldb-commits at lists.llvm.org
Tue Jan 14 16:51:40 PST 2025


https://github.com/cmtice updated https://github.com/llvm/llvm-project/pull/120971

>From c14a0e3f80c1cc49a6717b41c8b90e2258168399 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 23 Dec 2024 06:41:46 -0800
Subject: [PATCH 1/2] [LLDB] Add DIL code for handling plain variable names.

Add the Data Inspection Language (DIL) implementation pieces for handling
plain local and global variable names.

See https://discourse.llvm.org/t/rfc-data-inspection-language/69893 for
information about DIL.

This change includes the basic AST, Lexer, Parser and Evaluator pieces,
as well as some tests.
---
 lldb/docs/dil-expr-lang.ebnf                  |  40 ++
 lldb/include/lldb/ValueObject/DILAST.h        | 161 ++++++++
 lldb/include/lldb/ValueObject/DILEval.h       |  62 +++
 lldb/include/lldb/ValueObject/DILLexer.h      | 166 ++++++++
 lldb/include/lldb/ValueObject/DILParser.h     | 105 ++++++
 lldb/source/Target/StackFrame.cpp             |  52 ++-
 lldb/source/ValueObject/CMakeLists.txt        |   4 +
 lldb/source/ValueObject/DILAST.cpp            | 228 +++++++++++
 lldb/source/ValueObject/DILEval.cpp           | 117 ++++++
 lldb/source/ValueObject/DILLexer.cpp          | 191 ++++++++++
 lldb/source/ValueObject/DILParser.cpp         | 356 ++++++++++++++++++
 .../basics/GlobalVariableLookup/Makefile      |   3 +
 .../TestFrameVarDILGlobalVariableLookup.py    |  82 ++++
 .../basics/GlobalVariableLookup/main.cpp      |  18 +
 .../var-dil/basics/InstanceVariables/Makefile |   3 +
 .../TestFrameVarDILInstanceVariables.py       |  62 +++
 .../var-dil/basics/InstanceVariables/main.cpp |  25 ++
 .../frame/var-dil/basics/LocalVars/Makefile   |   3 +
 .../LocalVars/TestFrameVarDILLocalVars.py     |  65 ++++
 .../frame/var-dil/basics/LocalVars/main.cpp   |  26 ++
 20 files changed, 1762 insertions(+), 7 deletions(-)
 create mode 100644 lldb/docs/dil-expr-lang.ebnf
 create mode 100644 lldb/include/lldb/ValueObject/DILAST.h
 create mode 100644 lldb/include/lldb/ValueObject/DILEval.h
 create mode 100644 lldb/include/lldb/ValueObject/DILLexer.h
 create mode 100644 lldb/include/lldb/ValueObject/DILParser.h
 create mode 100644 lldb/source/ValueObject/DILAST.cpp
 create mode 100644 lldb/source/ValueObject/DILEval.cpp
 create mode 100644 lldb/source/ValueObject/DILLexer.cpp
 create mode 100644 lldb/source/ValueObject/DILParser.cpp
 create mode 100644 lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/Makefile
 create mode 100644 lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py
 create mode 100644 lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/main.cpp
 create mode 100644 lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/Makefile
 create mode 100644 lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/TestFrameVarDILInstanceVariables.py
 create mode 100644 lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/main.cpp
 create mode 100644 lldb/test/API/commands/frame/var-dil/basics/LocalVars/Makefile
 create mode 100644 lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
 create mode 100644 lldb/test/API/commands/frame/var-dil/basics/LocalVars/main.cpp

diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
new file mode 100644
index 00000000000000..64b3e7758229c2
--- /dev/null
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -0,0 +1,40 @@
+(* Data Inspection Language (DIL) definition - LLDB Debug Expressions *)
+
+(* This is currently a subset of the final DIL Language, matching the current
+   DIL implementation. *)
+
+expression = primary_expression ;
+
+primary_expression = id_expression
+                   | "this"
+                   | "(" expression ")";
+
+id_expression = unqualified_id
+              | qualified_id ;
+
+unqualified_id = identifier ;
+
+qualified_id = ["::"] [nested_name_specifier] unqualified_id
+             | ["::"] identifier ;
+
+identifier = ? dil::TokenKind::identifier ? ;
+
+nested_name_specifier = type_name "::"
+                      | namespace_name '::'
+                      | nested_name_specifier identifier "::" ;
+
+type_name = class_name
+          | enum_name
+          | typedef_name;
+
+class_name = identifier ;
+
+enum_name = identifier ;
+
+typedef_name = identifier ;
+
+namespace_name = identifier ;
+
+
+
+
diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h
new file mode 100644
index 00000000000000..9f0a1a2221e388
--- /dev/null
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -0,0 +1,161 @@
+//===-- DILAST.h ------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_VALUEOBJECT_DILAST_H
+#define LLDB_VALUEOBJECT_DILAST_H
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "lldb/ValueObject/ValueObject.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+/// The various types DIL AST nodes (used by the DIL parser).
+enum class NodeKind {
+  eErrorNode,
+  eIdentifierNode,
+};
+
+/// Class used to store & manipulate information about identifiers.
+class IdentifierInfo {
+public:
+  enum class Kind {
+    eValue,
+    eContextArg,
+  };
+
+  static std::unique_ptr<IdentifierInfo> FromValue(ValueObject &valobj) {
+    CompilerType type;
+    type = valobj.GetCompilerType();
+    return std::unique_ptr<IdentifierInfo>(
+        new IdentifierInfo(Kind::eValue, type, valobj.GetSP(), {}));
+  }
+
+  static std::unique_ptr<IdentifierInfo> FromContextArg(CompilerType type) {
+    lldb::ValueObjectSP empty_value;
+    return std::unique_ptr<IdentifierInfo>(
+        new IdentifierInfo(Kind::eContextArg, type, empty_value, {}));
+  }
+
+  Kind GetKind() const { return m_kind; }
+  lldb::ValueObjectSP GetValue() const { return m_value; }
+
+  CompilerType GetType() { return m_type; }
+  bool IsValid() const { return m_type.IsValid(); }
+
+  IdentifierInfo(Kind kind, CompilerType type, lldb::ValueObjectSP value,
+                 std::vector<uint32_t> path)
+      : m_kind(kind), m_type(type), m_value(std::move(value)) {}
+
+private:
+  Kind m_kind;
+  CompilerType m_type;
+  lldb::ValueObjectSP m_value;
+};
+
+/// Given the name of an identifier (variable name, member name, type name,
+/// etc.), find the ValueObject for that name (if it exists) and create and
+/// return an IdentifierInfo object containing all the relevant information
+/// about that object (for DIL parsing and evaluating).
+std::unique_ptr<IdentifierInfo> LookupIdentifier(
+    const std::string &name, std::shared_ptr<ExecutionContextScope> ctx_scope,
+    lldb::DynamicValueType use_dynamic, CompilerType *scope_ptr = nullptr);
+
+/// Forward declaration, for use in DIL AST nodes. Definition is at the very
+/// end of this file.
+class Visitor;
+
+/// The rest of the classes in this file, except for the Visitor class at the
+/// very end, define all the types of AST nodes used by the DIL parser and
+/// expression evaluator. The DIL parser parses the input string and creates
+/// the AST parse tree from the AST nodes. The resulting AST node tree gets
+/// passed to the DIL expression evaluator, which evaluates the DIL AST nodes
+/// and creates/returns a ValueObjectSP containing the result.
+
+/// Base class for AST nodes used by the Data Inspection Language (DIL) parser.
+/// All of the specialized types of AST nodes inherit from this (virtual) base
+/// class.
+class DILASTNode {
+public:
+  DILASTNode(uint32_t location, NodeKind kind)
+      : m_location(location), m_kind(kind) {}
+  virtual ~DILASTNode() = default;
+
+  virtual void Accept(Visitor *v) const = 0;
+
+  uint32_t GetLocation() const { return m_location; }
+  NodeKind GetKind() const { return m_kind; }
+
+private:
+  uint32_t m_location;
+  const NodeKind m_kind;
+};
+
+using DILASTNodeUP = std::unique_ptr<DILASTNode>;
+
+class ErrorNode : public DILASTNode {
+public:
+  ErrorNode(CompilerType empty_type)
+      : DILASTNode(0, NodeKind::eErrorNode), m_empty_type(empty_type) {}
+  void Accept(Visitor *v) const override;
+
+  static bool classof(const DILASTNode *node) {
+    return node->GetKind() == NodeKind::eErrorNode;
+  }
+
+private:
+  CompilerType m_empty_type;
+};
+
+class IdentifierNode : public DILASTNode {
+public:
+  IdentifierNode(uint32_t location, std::string name,
+                 lldb::DynamicValueType use_dynamic,
+                 std::shared_ptr<ExecutionContextScope> exe_ctx_scope)
+      : DILASTNode(location, NodeKind::eIdentifierNode),
+        m_name(std::move(name)), m_use_dynamic(use_dynamic),
+        m_ctx_scope(exe_ctx_scope) {}
+
+  void Accept(Visitor *v) const override;
+
+  lldb::DynamicValueType use_dynamic() const { return m_use_dynamic; }
+  std::string name() const { return m_name; }
+  std::shared_ptr<ExecutionContextScope> get_exe_context() const {
+    return m_ctx_scope;
+  }
+
+  static bool classof(const DILASTNode *node) {
+    return node->GetKind() == NodeKind::eIdentifierNode;
+  }
+
+private:
+  std::string m_name;
+  lldb::DynamicValueType m_use_dynamic;
+  std::shared_ptr<ExecutionContextScope> m_ctx_scope;
+};
+
+/// 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
+/// type of AST node.
+class Visitor {
+public:
+  virtual ~Visitor() = default;
+  virtual void Visit(const ErrorNode *node) = 0;
+  virtual void Visit(const IdentifierNode *node) = 0;
+};
+
+} // namespace dil
+
+} // namespace lldb_private
+
+#endif // LLDB_VALUEOBJECT_DILAST_H
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
new file mode 100644
index 00000000000000..4006bb10630f24
--- /dev/null
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -0,0 +1,62 @@
+//===-- DILEval.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_VALUEOBJECT_DILEVAL_H_
+#define LLDB_VALUEOBJECT_DILEVAL_H_
+
+#include <memory>
+#include <vector>
+
+#include "lldb/ValueObject/DILAST.h"
+#include "lldb/ValueObject/DILParser.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+class DILInterpreter : Visitor {
+public:
+  DILInterpreter(lldb::TargetSP target, std::shared_ptr<std::string> sm);
+  DILInterpreter(lldb::TargetSP target, std::shared_ptr<std::string> sm,
+                 lldb::ValueObjectSP scope);
+  DILInterpreter(lldb::TargetSP target, std::shared_ptr<std::string> sm,
+                 lldb::DynamicValueType use_dynamic);
+
+  lldb::ValueObjectSP DILEval(const DILASTNode *tree, lldb::TargetSP target_sp,
+                              Status &error);
+
+private:
+  lldb::ValueObjectSP DILEvalNode(const DILASTNode *node);
+
+  bool Success() { return m_error.Success(); }
+
+  void SetError(ErrorCode error_code, std::string error, uint32_t loc);
+
+  void Visit(const ErrorNode *node) override;
+  void Visit(const IdentifierNode *node) override;
+
+private:
+  // Used by the interpreter to create objects, perform casts, etc.
+  lldb::TargetSP m_target;
+
+  std::shared_ptr<std::string> m_sm;
+
+  lldb::ValueObjectSP m_result;
+
+  lldb::ValueObjectSP m_scope;
+
+  lldb::DynamicValueType m_default_dynamic;
+
+  Status m_error;
+};
+
+} // namespace dil
+
+} // namespace lldb_private
+
+#endif // LLDB_VALUEOBJECT_DILEVAL_H_
diff --git a/lldb/include/lldb/ValueObject/DILLexer.h b/lldb/include/lldb/ValueObject/DILLexer.h
new file mode 100644
index 00000000000000..c794fb2bfc0ed3
--- /dev/null
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -0,0 +1,166 @@
+//===-- DILLexer.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_VALUEOBJECT_DILLEXER_H_
+#define LLDB_VALUEOBJECT_DILLEXER_H_
+
+#include <limits.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "llvm/ADT/StringRef.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+enum class TokenKind {
+  coloncolon,
+  eof,
+  identifier,
+  invalid,
+  kw_namespace,
+  kw_this,
+  l_paren,
+  none,
+  r_paren,
+  unknown,
+};
+
+/// Class defining the tokens generated by the DIL lexer and used by the
+/// DIL parser.
+class DILToken {
+public:
+  DILToken(dil::TokenKind kind, std::string spelling, uint32_t start,
+           uint32_t len)
+      : m_kind(kind), m_spelling(spelling), m_start_pos(start), m_length(len) {}
+
+  DILToken()
+      : m_kind(dil::TokenKind::none), m_spelling(""), m_start_pos(0),
+        m_length(0) {}
+
+  void setKind(dil::TokenKind kind) { m_kind = kind; }
+  dil::TokenKind getKind() const { return m_kind; }
+
+  std::string getSpelling() const { return m_spelling; }
+
+  uint32_t getLength() const { return m_length; }
+
+  bool is(dil::TokenKind kind) const { return m_kind == kind; }
+
+  bool isNot(dil::TokenKind kind) const { return m_kind != kind; }
+
+  bool isOneOf(dil::TokenKind kind1, dil::TokenKind kind2) const {
+    return is(kind1) || is(kind2);
+  }
+
+  template <typename... Ts> bool isOneOf(dil::TokenKind kind, Ts... Ks) const {
+    return is(kind) || isOneOf(Ks...);
+  }
+
+  uint32_t getLocation() const { return m_start_pos; }
+
+  void setValues(dil::TokenKind kind, std::string spelling, uint32_t start,
+                 uint32_t len) {
+    m_kind = kind;
+    m_spelling = spelling;
+    m_start_pos = start;
+    m_length = len;
+  }
+
+  static const std::string getTokenName(dil::TokenKind kind);
+
+private:
+  dil::TokenKind m_kind;
+  std::string m_spelling;
+  uint32_t m_start_pos; // within entire expression string
+  uint32_t m_length;
+};
+
+/// Class for doing the simple lexing required by DIL.
+class DILLexer {
+public:
+  DILLexer(std::shared_ptr<std::string> dil_sm) : m_expr(*dil_sm) {
+    m_cur_pos = m_expr.begin();
+    // Use UINT_MAX to indicate invalid/uninitialized value.
+    m_tokens_idx = UINT_MAX;
+  }
+
+  bool Lex(DILToken &result, bool look_ahead = false);
+
+  bool Is_Word(std::string::iterator start, uint32_t &length);
+
+  uint32_t GetLocation() { return m_cur_pos - m_expr.begin(); }
+
+  /// Update 'result' with the other paremeter values, create a
+  /// duplicate token, and push the duplicate token onto the vector of
+  /// lexed tokens.
+  void UpdateLexedTokens(DILToken &result, dil::TokenKind tok_kind,
+                         std::string tok_str, uint32_t tok_pos,
+                         uint32_t tok_len);
+
+  /// Return the lexed token N+1 positions ahead of the 'current' token
+  /// being handled by the DIL parser.
+  const DILToken &LookAhead(uint32_t N);
+
+  const DILToken &AcceptLookAhead(uint32_t N);
+
+  /// Return the index for the 'current' token being handled by the DIL parser.
+  uint32_t GetCurrentTokenIdx() { return m_tokens_idx; }
+
+  /// Return the current token to be handled by the DIL parser.
+  DILToken &GetCurrentToken() { return m_lexed_tokens[m_tokens_idx]; }
+
+  /// Update the index for the 'current' token, to point to the next lexed
+  /// token.
+  bool IncrementTokenIdx() {
+    if (m_tokens_idx >= m_lexed_tokens.size() - 1)
+      return false;
+
+    m_tokens_idx++;
+    return true;
+  }
+
+  /// Set the index for the 'current' token (to be handled by the parser)
+  /// to a particular position. Used for either committing 'look ahead' parsing
+  /// or rolling back tentative parsing.
+  bool ResetTokenIdx(uint32_t new_value) {
+    if (new_value > m_lexed_tokens.size() - 1)
+      return false;
+
+    m_tokens_idx = new_value;
+    return true;
+  }
+
+private:
+  // The input string we are lexing & parsing.
+  std::string m_expr;
+
+  // The current position of the lexer within m_expr (the character position,
+  // within the string, of the next item to be lexed).
+  std::string::iterator m_cur_pos;
+
+  // Holds all of the tokens lexed so far.
+  std::vector<DILToken> m_lexed_tokens;
+
+  // Index into m_lexed_tokens; indicates which token the DIL parser is
+  // currently trying to parse/handle.
+  uint32_t m_tokens_idx;
+
+  // "invalid" token; to be returned by lexer when 'look ahead' fails.
+  DILToken m_invalid_token;
+};
+
+} // namespace dil
+
+} // namespace lldb_private
+
+#endif // LLDB_VALUEOBJECT_DILLEXER_H_
diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h
new file mode 100644
index 00000000000000..b718903b7bea49
--- /dev/null
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -0,0 +1,105 @@
+//===-- DILParser.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_VALUEOBJECT_DILPARSER_H_
+#define LLDB_VALUEOBJECT_DILPARSER_H_
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/ValueObject/DILAST.h"
+#include "lldb/ValueObject/DILLexer.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+enum class ErrorCode : unsigned char {
+  kOk = 0,
+  kInvalidExpressionSyntax,
+  kUndeclaredIdentifier,
+  kUnknown,
+};
+
+std::string FormatDiagnostics(std::shared_ptr<std::string> input_expr,
+                              const std::string &message, uint32_t loc);
+
+/// Pure recursive descent parser for C++ like expressions.
+/// EBNF grammar for the parser is described in lldb/docs/dil-expr-lang.ebnf
+class DILParser {
+public:
+  explicit DILParser(std::shared_ptr<std::string> dil_input_expr,
+                     std::shared_ptr<ExecutionContextScope> exe_ctx_scope,
+                     lldb::DynamicValueType use_dynamic, bool use_synthetic,
+                     bool fragile_ivar, bool check_ptr_vs_member);
+
+  DILASTNodeUP Run(Status &error);
+
+  ~DILParser() { m_ctx_scope.reset(); }
+
+  bool UseSynthetic() { return m_use_synthetic; }
+
+  lldb::DynamicValueType UseDynamic() { return m_use_dynamic; }
+
+  using PtrOperator = std::tuple<dil::TokenKind, uint32_t>;
+
+private:
+  DILASTNodeUP ParseExpression();
+  DILASTNodeUP ParsePrimaryExpression();
+
+  std::string ParseNestedNameSpecifier();
+
+  std::string ParseIdExpression();
+  std::string ParseUnqualifiedId();
+
+  void ConsumeToken();
+
+  void BailOut(ErrorCode error_code, const std::string &error, uint32_t loc);
+
+  void BailOut(Status error);
+
+  void Expect(dil::TokenKind kind);
+
+  std::string TokenDescription(const DILToken &token);
+
+  template <typename... Ts> void ExpectOneOf(dil::TokenKind k, Ts... ks);
+
+  void TentativeParsingRollback(uint32_t saved_idx) {
+    m_error.Clear();
+    m_dil_lexer.ResetTokenIdx(saved_idx);
+    m_dil_token = m_dil_lexer.GetCurrentToken();
+  }
+
+  // Parser doesn't own the evaluation context. The produced AST may depend on
+  // it (for example, for source locations), so it's expected that expression
+  // context will outlive the parser.
+  std::shared_ptr<ExecutionContextScope> m_ctx_scope;
+
+  std::shared_ptr<std::string> m_input_expr;
+  // The token lexer is stopped at (aka "current token").
+  DILToken m_dil_token;
+  // Holds an error if it occures during parsing.
+  Status m_error;
+
+  lldb::DynamicValueType m_use_dynamic;
+  bool m_use_synthetic;
+  bool m_fragile_ivar;
+  bool m_check_ptr_vs_member;
+  DILLexer m_dil_lexer;
+}; // class DILParser
+
+} // namespace dil
+
+} // namespace lldb_private
+
+#endif // LLDB_VALUEOBJECT_DILPARSER_H_
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 2633c976c13bf4..28450b1d1c1c1e 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -31,6 +31,8 @@
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/RegisterValue.h"
+#include "lldb/ValueObject/DILEval.h"
+#include "lldb/ValueObject/DILParser.h"
 #include "lldb/ValueObject/ValueObjectConstResult.h"
 #include "lldb/ValueObject/ValueObjectMemory.h"
 #include "lldb/ValueObject/ValueObjectVariable.h"
@@ -511,22 +513,58 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
     VariableSP &var_sp, Status &error) {
   ExecutionContext exe_ctx;
   CalculateExecutionContext(exe_ctx);
+
   bool use_DIL = exe_ctx.GetTargetRef().GetUseDIL(&exe_ctx);
+
   if (use_DIL)
     return DILGetValueForVariableExpressionPath(var_expr, use_dynamic, options,
                                                 var_sp, error);
-
-  return LegacyGetValueForVariableExpressionPath(var_expr, use_dynamic, options,
-                                                 var_sp, error);
+  else
+    return LegacyGetValueForVariableExpressionPath(var_expr, use_dynamic,
+                                                   options, var_sp, error);
 }
 
 ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
     llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
     uint32_t options, lldb::VariableSP &var_sp, Status &error) {
-  // This is a place-holder for the calls into the DIL parser and
-  // evaluator.  For now, just call the "real" frame variable implementation.
-  return LegacyGetValueForVariableExpressionPath(var_expr, use_dynamic, options,
-                                                 var_sp, error);
+  ValueObjectSP ret_val;
+  std::shared_ptr<std::string> source =
+      std::make_shared<std::string>(var_expr.data());
+
+  const bool check_ptr_vs_member =
+      (options & eExpressionPathOptionCheckPtrVsMember) != 0;
+  const bool no_fragile_ivar =
+      (options & eExpressionPathOptionsNoFragileObjcIvar) != 0;
+  const bool no_synth_child =
+      (options & eExpressionPathOptionsNoSyntheticChildren) != 0;
+
+  // Parse the expression.
+  Status parse_error, eval_error;
+  dil::DILParser parser(source, shared_from_this(), use_dynamic,
+                        !no_synth_child, !no_fragile_ivar, check_ptr_vs_member);
+  dil::DILASTNodeUP tree = parser.Run(parse_error);
+  if (parse_error.Fail()) {
+    error = std::move(parse_error);
+    return ValueObjectSP();
+  }
+
+  // Evaluate the parsed expression.
+  lldb::TargetSP target = this->CalculateTarget();
+  dil::DILInterpreter interpreter(target, source, use_dynamic);
+
+  ret_val = interpreter.DILEval(tree.get(), target, eval_error);
+  if (eval_error.Fail()) {
+    error = std::move(eval_error);
+    return ValueObjectSP();
+  }
+
+  if (ret_val) {
+    var_sp = ret_val->GetVariable();
+    if (!var_sp && ret_val->GetParent()) {
+      var_sp = ret_val->GetParent()->GetVariable();
+    }
+  }
+  return ret_val;
 }
 
 ValueObjectSP StackFrame::LegacyGetValueForVariableExpressionPath(
diff --git a/lldb/source/ValueObject/CMakeLists.txt b/lldb/source/ValueObject/CMakeLists.txt
index 70cb3d6d53f071..92683916f5a522 100644
--- a/lldb/source/ValueObject/CMakeLists.txt
+++ b/lldb/source/ValueObject/CMakeLists.txt
@@ -1,4 +1,8 @@
 add_lldb_library(lldbValueObject
+  DILAST.cpp
+  DILEval.cpp
+  DILLexer.cpp
+  DILParser.cpp
   ValueObject.cpp
   ValueObjectCast.cpp
   ValueObjectChild.cpp
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
new file mode 100644
index 00000000000000..1af0dc57ddcea7
--- /dev/null
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -0,0 +1,228 @@
+//===-- DILAST.cpp --------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/ValueObject/DILAST.h"
+
+#include "lldb/API/SBType.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/ValueObject/ValueObjectRegister.h"
+#include "lldb/ValueObject/ValueObjectVariable.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <vector>
+
+namespace lldb_private {
+
+namespace dil {
+
+static lldb::ValueObjectSP
+LookupStaticIdentifier(lldb::TargetSP target_sp,
+                       const llvm::StringRef &name_ref,
+                       ConstString unqualified_name) {
+  // List global variable with the same "basename". There can be many matches
+  // from other scopes (namespaces, classes), so we do additional filtering
+  // later.
+  VariableList variable_list;
+  ConstString name(name_ref);
+  target_sp->GetImages().FindGlobalVariables(name, 1, variable_list);
+  if (!variable_list.Empty()) {
+    ExecutionContextScope *exe_scope = target_sp->GetProcessSP().get();
+    if (exe_scope == nullptr)
+      exe_scope = target_sp.get();
+    for (const lldb::VariableSP &var_sp : variable_list) {
+      lldb::ValueObjectSP valobj_sp(
+          ValueObjectVariable::Create(exe_scope, var_sp));
+      if (valobj_sp && valobj_sp->GetVariable() &&
+          (valobj_sp->GetVariable()->NameMatches(unqualified_name) ||
+           valobj_sp->GetVariable()->NameMatches(ConstString(name_ref))))
+        return valobj_sp;
+    }
+  }
+  return nullptr;
+}
+
+static lldb::VariableSP DILFindVariable(ConstString name,
+                                        VariableList *variable_list) {
+  lldb::VariableSP exact_match;
+  std::vector<lldb::VariableSP> possible_matches;
+
+  typedef std::vector<lldb::VariableSP> collection;
+  typedef collection::iterator iterator;
+
+  iterator pos, end = variable_list->end();
+  for (pos = variable_list->begin(); pos != end; ++pos) {
+    llvm::StringRef str_ref_name = pos->get()->GetName().GetStringRef();
+    // Check for global vars, which might start with '::'.
+    str_ref_name.consume_front("::");
+
+    if (str_ref_name == name.GetStringRef())
+      possible_matches.push_back(*pos);
+    else if (pos->get()->NameMatches(name))
+      possible_matches.push_back(*pos);
+  }
+
+  // Look for exact matches (favors local vars over global vars)
+  auto exact_match_it =
+      llvm::find_if(possible_matches, [&](lldb::VariableSP var_sp) {
+        return var_sp->GetName() == name;
+      });
+
+  if (exact_match_it != llvm::adl_end(possible_matches))
+    exact_match = *exact_match_it;
+
+  if (!exact_match)
+    // Look for a global var exact match.
+    for (auto var_sp : possible_matches) {
+      llvm::StringRef str_ref_name = var_sp->GetName().GetStringRef();
+      if (str_ref_name.size() > 2 && str_ref_name[0] == ':' &&
+          str_ref_name[1] == ':')
+        str_ref_name = str_ref_name.drop_front(2);
+      ConstString tmp_name(str_ref_name);
+      if (tmp_name == name) {
+        exact_match = var_sp;
+        break;
+      }
+    }
+
+  // Take any match at this point.
+  if (!exact_match && possible_matches.size() > 0)
+    exact_match = possible_matches[0];
+
+  return exact_match;
+}
+
+std::unique_ptr<IdentifierInfo>
+LookupIdentifier(const std::string &name,
+                 std::shared_ptr<ExecutionContextScope> ctx_scope,
+                 lldb::DynamicValueType use_dynamic, CompilerType *scope_ptr) {
+  ConstString name_str(name);
+  llvm::StringRef name_ref = name_str.GetStringRef();
+
+  // Support $rax as a special syntax for accessing registers.
+  // Will return an invalid value in case the requested register doesn't exist.
+  if (name_ref.starts_with("$")) {
+    lldb::ValueObjectSP value_sp;
+    const char *reg_name = name_ref.drop_front(1).data();
+    Target *target = ctx_scope->CalculateTarget().get();
+    Process *process = ctx_scope->CalculateProcess().get();
+    if (target && process) {
+      StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
+      if (stack_frame) {
+        lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
+        if (reg_ctx) {
+          if (const RegisterInfo *reg_info =
+                  reg_ctx->GetRegisterInfoByName(reg_name))
+            value_sp =
+                ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
+        }
+      }
+    }
+    if (value_sp)
+      return IdentifierInfo::FromValue(*value_sp);
+    else
+      return nullptr;
+  }
+
+  // Internally values don't have global scope qualifier in their names and
+  // LLDB doesn't support queries with it too.
+  bool global_scope = false;
+  if (name_ref.starts_with("::")) {
+    name_ref = name_ref.drop_front(2);
+    global_scope = true;
+  }
+
+  // If the identifier doesn't refer to the global scope and doesn't have any
+  // other scope qualifiers, try looking among the local and instance variables.
+  if (!global_scope && !name_ref.contains("::")) {
+    if (!scope_ptr || !scope_ptr->IsValid()) {
+      // Lookup in the current frame.
+      lldb::StackFrameSP frame = ctx_scope->CalculateStackFrame();
+      // Try looking for a local variable in current scope.
+      lldb::ValueObjectSP value_sp;
+      lldb::VariableListSP var_list_sp(frame->GetInScopeVariableList(true));
+      VariableList *variable_list = var_list_sp.get();
+      if (variable_list) {
+        lldb::VariableSP var_sp =
+            DILFindVariable(ConstString(name_ref), variable_list);
+        if (var_sp)
+          value_sp = frame->GetValueObjectForFrameVariable(var_sp, use_dynamic);
+      }
+      if (!value_sp)
+        value_sp = frame->FindVariable(ConstString(name_ref));
+
+      if (value_sp)
+        // Force static value, otherwise we can end up with the "real" type.
+        return IdentifierInfo::FromValue(*value_sp);
+
+      // Try looking for an instance variable (class member).
+      ConstString this_string("this");
+      value_sp = frame->FindVariable(this_string);
+      if (value_sp)
+        value_sp = value_sp->GetChildMemberWithName(name_ref.data());
+
+      if (value_sp)
+        // Force static value, otherwise we can end up with the "real" type.
+        return IdentifierInfo::FromValue(*(value_sp->GetStaticValue()));
+    }
+  }
+
+  // Try looking for a global or static variable.
+
+  lldb::ValueObjectSP value;
+  if (!global_scope) {
+    // Try looking for static member of the current scope value, e.g.
+    // `ScopeType::NAME`. NAME can include nested struct (`Nested::SUBNAME`),
+    // but it cannot be part of the global scope (start with "::").
+    const char *type_name = "";
+    if (scope_ptr)
+      type_name = scope_ptr->GetCanonicalType().GetTypeName().AsCString();
+    std::string name_with_type_prefix =
+        llvm::formatv("{0}::{1}", type_name, name_ref).str();
+    value = LookupStaticIdentifier(ctx_scope->CalculateTarget(),
+                                   name_with_type_prefix, name_str);
+  }
+
+  // Lookup a regular global variable.
+  if (!value)
+    value = LookupStaticIdentifier(ctx_scope->CalculateTarget(), name_ref,
+                                   name_str);
+
+  // Last resort, lookup as a register (e.g. `rax` or `rip`).
+  if (!value) {
+    Target *target = ctx_scope->CalculateTarget().get();
+    Process *process = ctx_scope->CalculateProcess().get();
+    if (target && process) {
+      StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
+      if (stack_frame) {
+        lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
+        if (reg_ctx) {
+          if (const RegisterInfo *reg_info =
+                  reg_ctx->GetRegisterInfoByName(name_ref.data()))
+            value = ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
+        }
+      }
+    }
+  }
+
+  // Force static value, otherwise we can end up with the "real" type.
+  if (value)
+    return IdentifierInfo::FromValue(*value);
+  else
+    return nullptr;
+}
+
+void ErrorNode::Accept(Visitor *v) const { v->Visit(this); }
+
+void IdentifierNode::Accept(Visitor *v) const { v->Visit(this); }
+
+} // namespace dil
+
+} // namespace lldb_private
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
new file mode 100644
index 00000000000000..01da8521536503
--- /dev/null
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -0,0 +1,117 @@
+//===-- DILEval.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/ValueObject/DILEval.h"
+
+#include <memory>
+
+#include "lldb/ValueObject/DILAST.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include "llvm/Support/FormatAdapters.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+DILInterpreter::DILInterpreter(lldb::TargetSP target,
+                               std::shared_ptr<std::string> sm)
+    : m_target(std::move(target)), m_sm(std::move(sm)) {
+  m_default_dynamic = lldb::eNoDynamicValues;
+}
+
+DILInterpreter::DILInterpreter(lldb::TargetSP target,
+                               std::shared_ptr<std::string> sm,
+                               lldb::DynamicValueType use_dynamic)
+    : m_target(std::move(target)), m_sm(std::move(sm)),
+      m_default_dynamic(use_dynamic) {}
+
+DILInterpreter::DILInterpreter(lldb::TargetSP target,
+                               std::shared_ptr<std::string> sm,
+                               lldb::ValueObjectSP scope)
+    : m_target(std::move(target)), m_sm(std::move(sm)),
+      m_scope(std::move(scope)) {
+  m_default_dynamic = lldb::eNoDynamicValues;
+  // If `m_scope` is a reference, dereference it. All operations on a reference
+  // should be operations on the referent.
+  if (m_scope->GetCompilerType().IsValid() &&
+      m_scope->GetCompilerType().IsReferenceType()) {
+    Status error;
+    m_scope = m_scope->Dereference(error);
+  }
+}
+
+lldb::ValueObjectSP DILInterpreter::DILEval(const DILASTNode *tree,
+                                            lldb::TargetSP target_sp,
+                                            Status &error) {
+  m_error.Clear();
+  // Evaluate an AST.
+  DILEvalNode(tree);
+  // Set the error.
+  error = std::move(m_error);
+  // Return the computed result. If there was an error, it will be invalid.
+  return m_result;
+}
+
+lldb::ValueObjectSP DILInterpreter::DILEvalNode(const DILASTNode *node) {
+
+  // Traverse an AST pointed by the `node`.
+  node->Accept(this);
+
+  // Return the computed value for convenience. The caller is responsible for
+  // checking if an error occured during the evaluation.
+  return m_result;
+}
+
+void DILInterpreter::SetError(ErrorCode code, std::string error, uint32_t loc) {
+  assert(m_error.Success() && "interpreter can error only once");
+  m_error = Status((uint32_t)code, lldb::eErrorTypeGeneric,
+                   FormatDiagnostics(m_sm, error, loc));
+}
+
+void DILInterpreter::Visit(const ErrorNode *node) {
+  // The AST is not valid.
+  m_result = lldb::ValueObjectSP();
+}
+
+void DILInterpreter::Visit(const IdentifierNode *node) {
+  std::shared_ptr<ExecutionContextScope> exe_ctx_scope =
+      node->get_exe_context();
+  lldb::DynamicValueType use_dynamic = node->use_dynamic();
+
+  std::unique_ptr<IdentifierInfo> identifier =
+      LookupIdentifier(node->name(), exe_ctx_scope, use_dynamic);
+
+  if (!identifier) {
+    std::string errMsg;
+    std::string name = node->name();
+    if (name == "this")
+      errMsg = "invalid use of 'this' outside of a non-static member function";
+    else
+      errMsg = llvm::formatv("use of undeclared identifier '{0}'", name);
+    SetError(ErrorCode::kUndeclaredIdentifier, errMsg, node->GetLocation());
+    m_result = lldb::ValueObjectSP();
+    return;
+  }
+  lldb::ValueObjectSP val;
+  lldb::TargetSP target_sp;
+  Status error;
+
+  assert(identifier->GetKind() == IdentifierInfo::Kind::eValue &&
+         "Unrecognized identifier kind");
+
+  val = identifier->GetValue();
+  target_sp = val->GetTargetSP();
+  assert(target_sp && target_sp->IsValid() &&
+         "identifier doesn't resolve to a valid value");
+
+  m_result = val;
+}
+
+} // namespace dil
+
+} // namespace lldb_private
diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp
new file mode 100644
index 00000000000000..c63a83bea6f1df
--- /dev/null
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -0,0 +1,191 @@
+//===-- DILLexer.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This implements the recursive descent parser for the Data Inspection
+// Language (DIL), and its helper functions, which will eventually underlie the
+// 'frame variable' command. The language that this parser recognizes is
+// described in lldb/docs/dil-expr-lang.ebnf
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/ValueObject/DILLexer.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+const std::string DILToken::getTokenName(dil::TokenKind kind) {
+  std::string retval;
+  switch (kind) {
+  case dil::TokenKind::coloncolon:
+    retval = "coloncolon";
+    break;
+  case dil::TokenKind::eof:
+    retval = "eof";
+    break;
+  case dil::TokenKind::identifier:
+    retval = "identifier";
+    break;
+  case dil::TokenKind::kw_namespace:
+    retval = "namespace";
+    break;
+  case dil::TokenKind::kw_this:
+    retval = "this";
+    break;
+  case dil::TokenKind::l_paren:
+    retval = "l_paren";
+    break;
+  case dil::TokenKind::r_paren:
+    retval = "r_paren";
+    break;
+  case dil::TokenKind::unknown:
+    retval = "unknown";
+    break;
+  default:
+    retval = "token_name";
+    break;
+  }
+  return retval;
+}
+
+static bool Is_Letter(char c) {
+  if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+    return true;
+  return false;
+}
+
+static bool Is_Digit(char c) { return ('0' <= c && c <= '9'); }
+
+bool DILLexer::Is_Word(std::string::iterator start, uint32_t &length) {
+  bool done = false;
+  for (; m_cur_pos != m_expr.end() && !done; ++m_cur_pos) {
+    char c = *m_cur_pos;
+    if (!Is_Letter(c) && !Is_Digit(c) && c != '_') {
+      done = true;
+      break;
+    } else
+      length++;
+  }
+  if (length > 0)
+    return true;
+  else
+    m_cur_pos = start;
+  return false;
+}
+
+void DILLexer::UpdateLexedTokens(DILToken &result, dil::TokenKind tok_kind,
+                                 std::string tok_str, uint32_t tok_pos,
+                                 uint32_t tok_len) {
+  DILToken new_token;
+  result.setValues(tok_kind, tok_str, tok_pos, tok_len);
+  new_token = result;
+  m_lexed_tokens.push_back(std::move(new_token));
+}
+
+bool DILLexer::Lex(DILToken &result, bool look_ahead) {
+  bool retval = true;
+
+  if (!look_ahead) {
+    // We're being asked for the 'next' token, and not a part of a LookAhead.
+    // Check to see if we've already lexed it and pushed it onto our tokens
+    // vector; if so, return the next token from the vector, rather than doing
+    // more lexing.
+    if ((m_tokens_idx != UINT_MAX) &&
+        (m_tokens_idx < m_lexed_tokens.size() - 1)) {
+      result = m_lexed_tokens[m_tokens_idx + 1];
+      return retval;
+    }
+  }
+
+  // Skip over whitespace (spaces).
+  while (m_cur_pos != m_expr.end() && *m_cur_pos == ' ')
+    m_cur_pos++;
+
+  // Check to see if we've reached the end of our input string.
+  if (m_cur_pos == m_expr.end()) {
+    UpdateLexedTokens(result, dil::TokenKind::eof, "", m_expr.length(), 0);
+    return retval;
+  }
+
+  uint32_t position = m_cur_pos - m_expr.begin();
+  ;
+  std::string::iterator start = m_cur_pos;
+  uint32_t length = 0;
+  if (Is_Word(start, length)) {
+    dil::TokenKind kind;
+    std::string word = m_expr.substr(position, length);
+    if (word == "this")
+      kind = dil::TokenKind::kw_this;
+    else if (word == "namespace")
+      kind = dil::TokenKind::kw_namespace;
+    else
+      kind = dil::TokenKind::identifier;
+
+    UpdateLexedTokens(result, kind, word, position, length);
+    return true;
+  }
+
+  switch (*m_cur_pos) {
+  case '(':
+    m_cur_pos++;
+    UpdateLexedTokens(result, dil::TokenKind::l_paren, "(", position, 1);
+    return true;
+  case ')':
+    m_cur_pos++;
+    UpdateLexedTokens(result, dil::TokenKind::r_paren, ")", position, 1);
+    return true;
+  case ':':
+    if (position + 1 < m_expr.size() && m_expr[position + 1] == ':') {
+      m_cur_pos += 2;
+      UpdateLexedTokens(result, dil::TokenKind::coloncolon, "::", position, 2);
+      return true;
+    }
+    break;
+  default:
+    break;
+  }
+  // Empty Token
+  result.setValues(dil::TokenKind::none, "", m_expr.length(), 0);
+  return false;
+}
+
+const DILToken &DILLexer::LookAhead(uint32_t N) {
+  uint32_t extra_lexed_tokens = m_lexed_tokens.size() - m_tokens_idx - 1;
+
+  if (N + 1 < extra_lexed_tokens)
+    return m_lexed_tokens[m_tokens_idx + N + 1];
+
+  uint32_t remaining_tokens =
+      (m_tokens_idx + N + 1) - m_lexed_tokens.size() + 1;
+
+  bool done = false;
+  bool look_ahead = true;
+  while (!done && remaining_tokens > 0) {
+    DILToken tok;
+    Lex(tok, look_ahead);
+    if (tok.getKind() == dil::TokenKind::eof)
+      done = true;
+    remaining_tokens--;
+  };
+
+  if (remaining_tokens > 0) {
+    m_invalid_token.setValues(dil::TokenKind::invalid, "", 0, 0);
+    return m_invalid_token;
+  } else
+    return m_lexed_tokens[m_tokens_idx + N + 1];
+}
+
+const DILToken &DILLexer::AcceptLookAhead(uint32_t N) {
+  if (m_tokens_idx + N + 1 > m_lexed_tokens.size())
+    return m_invalid_token;
+
+  m_tokens_idx += N + 1;
+  return m_lexed_tokens[m_tokens_idx];
+}
+
+} // namespace dil
+
+} // namespace lldb_private
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
new file mode 100644
index 00000000000000..eb36de80be76a5
--- /dev/null
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -0,0 +1,356 @@
+//===-- DILParser.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This implements the recursive descent parser for the Data Inspection
+// Language (DIL), and its helper functions, which will eventually underlie the
+// 'frame variable' command. The language that this parser recognizes is
+// described in lldb/docs/dil-expr-lang.ebnf
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/ValueObject/DILParser.h"
+
+#include <limits.h>
+#include <stdlib.h>
+
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/ValueObject/DILAST.h"
+#include "lldb/ValueObject/DILEval.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatAdapters.h"
+
+namespace lldb_private {
+
+namespace dil {
+
+inline void TokenKindsJoinImpl(std::ostringstream &os, dil::TokenKind k) {
+  os << "'" << DILToken::getTokenName(k) << "'";
+}
+
+template <typename... Ts>
+inline void TokenKindsJoinImpl(std::ostringstream &os, dil::TokenKind k,
+                               Ts... ks) {
+  TokenKindsJoinImpl(os, k);
+  os << ", ";
+  TokenKindsJoinImpl(os, ks...);
+}
+
+template <typename... Ts>
+inline std::string TokenKindsJoin(dil::TokenKind k, Ts... ks) {
+  std::ostringstream os;
+  TokenKindsJoinImpl(os, k, ks...);
+
+  return os.str();
+}
+
+std::string FormatDiagnostics(std::shared_ptr<std::string> input_expr,
+                              const std::string &message, uint32_t loc) {
+  // Get the source buffer and the location of the current token.
+  llvm::StringRef text(*input_expr);
+  size_t loc_offset = (size_t)loc;
+
+  // Look for the start of the line.
+  size_t line_start = text.rfind('\n', loc_offset);
+  line_start = line_start == llvm::StringRef::npos ? 0 : line_start + 1;
+
+  // Look for the end of the line.
+  size_t line_end = text.find('\n', loc_offset);
+  line_end = line_end == llvm::StringRef::npos ? text.size() : line_end;
+
+  // Get a view of the current line in the source code and the position of the
+  // diagnostics pointer.
+  llvm::StringRef line = text.slice(line_start, line_end);
+  int32_t arrow = loc + 1; // Column offset starts at 1, not 0.
+
+  // Calculate the padding in case we point outside of the expression (this can
+  // happen if the parser expected something, but got EOF).˚
+  size_t expr_rpad = std::max(0, arrow - static_cast<int32_t>(line.size()));
+  size_t arrow_rpad = std::max(0, static_cast<int32_t>(line.size()) - arrow);
+
+  return llvm::formatv("<expr:1:{0}>: {1}\n{2}\n{3}", loc, message,
+                       llvm::fmt_pad(line, 0, expr_rpad),
+                       llvm::fmt_pad("^", arrow - 1, arrow_rpad));
+}
+
+DILParser::DILParser(std::shared_ptr<std::string> dil_input_expr,
+                     std::shared_ptr<ExecutionContextScope> exe_ctx_scope,
+                     lldb::DynamicValueType use_dynamic, bool use_synthetic,
+                     bool fragile_ivar, bool check_ptr_vs_member)
+    : m_ctx_scope(exe_ctx_scope), m_input_expr(dil_input_expr),
+      m_use_dynamic(use_dynamic), m_use_synthetic(use_synthetic),
+      m_fragile_ivar(fragile_ivar), m_check_ptr_vs_member(check_ptr_vs_member),
+      m_dil_lexer(DILLexer(dil_input_expr)) {
+  // Initialize the token.
+  m_dil_token.setKind(dil::TokenKind::unknown);
+}
+
+DILASTNodeUP DILParser::Run(Status &error) {
+  ConsumeToken();
+
+  DILASTNodeUP expr;
+
+  expr = ParseExpression();
+
+  Expect(dil::TokenKind::eof);
+
+  error = std::move(m_error);
+  m_error.Clear();
+
+  // Explicitly return ErrorNode if there was an error during the parsing.
+  // Some routines raise an error, but don't change the return value (e.g.
+  // Expect).
+  if (error.Fail()) {
+    CompilerType bad_type;
+    return std::make_unique<ErrorNode>(bad_type);
+  }
+  return expr;
+}
+
+// Parse an expression.
+//
+//  expression:
+//    primary_expression
+//
+DILASTNodeUP DILParser::ParseExpression() { return ParsePrimaryExpression(); }
+
+// Parse a primary_expression.
+//
+//  primary_expression:
+//    id_expression
+//    "this"
+//    "(" expression ")"
+//
+DILASTNodeUP DILParser::ParsePrimaryExpression() {
+  CompilerType bad_type;
+  if (m_dil_token.isOneOf(dil::TokenKind::coloncolon,
+                          dil::TokenKind::identifier)) {
+    // Save the source location for the diagnostics message.
+    uint32_t loc = m_dil_token.getLocation();
+    auto identifier = ParseIdExpression();
+
+    return std::make_unique<IdentifierNode>(loc, identifier, m_use_dynamic,
+                                            m_ctx_scope);
+  } else if (m_dil_token.is(dil::TokenKind::kw_this)) {
+    // Save the source location for the diagnostics message.
+    uint32_t loc = m_dil_token.getLocation();
+    ConsumeToken();
+
+    // Special case for "this" pointer. As per C++ standard, it's a prvalue.
+    return std::make_unique<IdentifierNode>(loc, "this", m_use_dynamic,
+                                            m_ctx_scope);
+  } else if (m_dil_token.is(dil::TokenKind::l_paren)) {
+    ConsumeToken();
+    auto expr = ParseExpression();
+    Expect(dil::TokenKind::r_paren);
+    ConsumeToken();
+    return expr;
+  }
+
+  BailOut(ErrorCode::kInvalidExpressionSyntax,
+          llvm::formatv("Unexpected token: {0}", TokenDescription(m_dil_token)),
+          m_dil_token.getLocation());
+  return std::make_unique<ErrorNode>(bad_type);
+}
+
+// Parse nested_name_specifier.
+//
+//  nested_name_specifier:
+//    type_name "::"
+//    namespace_name "::"
+//    nested_name_specifier identifier "::"
+//
+std::string DILParser::ParseNestedNameSpecifier() {
+  // The first token in nested_name_specifier is always an identifier, or
+  // '(anonymous namespace)'.
+  if (m_dil_token.isNot(dil::TokenKind::identifier) &&
+      m_dil_token.isNot(dil::TokenKind::l_paren)) {
+    return "";
+  }
+
+  // Anonymous namespaces need to be treated specially: They are represented
+  // the the string '(anonymous namespace)', which has a space in it (throwing
+  // off normal parsing) and is not actually proper C++> Check to see if we're
+  // looking at '(anonymous namespace)::...'
+  if (m_dil_token.is(dil::TokenKind::l_paren)) {
+    // Look for all the pieces, in order:
+    // l_paren 'anonymous' 'namespace' r_paren coloncolon
+    if (m_dil_lexer.LookAhead(0).is(dil::TokenKind::identifier) &&
+        (((DILToken)m_dil_lexer.LookAhead(0)).getSpelling() == "anonymous") &&
+        m_dil_lexer.LookAhead(1).is(dil::TokenKind::kw_namespace) &&
+        m_dil_lexer.LookAhead(2).is(dil::TokenKind::r_paren) &&
+        m_dil_lexer.LookAhead(3).is(dil::TokenKind::coloncolon)) {
+      m_dil_token = m_dil_lexer.AcceptLookAhead(3);
+
+      assert((m_dil_token.is(dil::TokenKind::identifier) ||
+              m_dil_token.is(dil::TokenKind::l_paren)) &&
+             "Expected an identifier or anonymous namespace, but not found.");
+      // Continue parsing the nested_namespace_specifier.
+      std::string identifier2 = ParseNestedNameSpecifier();
+      if (identifier2.empty()) {
+        Expect(dil::TokenKind::identifier);
+        identifier2 = m_dil_token.getSpelling();
+        ConsumeToken();
+      }
+      return "(anonymous namespace)::" + identifier2;
+    } else {
+      return "";
+    }
+  } // end of special handling for '(anonymous namespace)'
+
+  // If the next token is scope ("::"), then this is indeed a
+  // nested_name_specifier
+  if (m_dil_lexer.LookAhead(0).is(dil::TokenKind::coloncolon)) {
+    // This nested_name_specifier is a single identifier.
+    std::string identifier = m_dil_token.getSpelling();
+    m_dil_token = m_dil_lexer.AcceptLookAhead(0);
+    Expect(dil::TokenKind::coloncolon);
+    ConsumeToken();
+    // Continue parsing the nested_name_specifier.
+    return identifier + "::" + ParseNestedNameSpecifier();
+  }
+
+  return "";
+}
+
+// Parse an id_expression.
+//
+//  id_expression:
+//    unqualified_id
+//    qualified_id
+//
+//  qualified_id:
+//    ["::"] [nested_name_specifier] unqualified_id
+//    ["::"] identifier
+//
+//  identifier:
+//    ? dil::TokenKind::identifier ?
+//
+std::string DILParser::ParseIdExpression() {
+  // Try parsing optional global scope operator.
+  bool global_scope = false;
+  if (m_dil_token.is(dil::TokenKind::coloncolon)) {
+    global_scope = true;
+    ConsumeToken();
+  }
+
+  // Try parsing optional nested_name_specifier.
+  auto nested_name_specifier = ParseNestedNameSpecifier();
+
+  // If nested_name_specifier is present, then it's qualified_id production.
+  // Follow the first production rule.
+  if (!nested_name_specifier.empty()) {
+    // Parse unqualified_id and construct a fully qualified id expression.
+    auto unqualified_id = ParseUnqualifiedId();
+
+    return llvm::formatv("{0}{1}{2}", global_scope ? "::" : "",
+                         nested_name_specifier, unqualified_id);
+  }
+
+  // No nested_name_specifier, but with global scope -- this is also a
+  // qualified_id production. Follow the second production rule.
+  else if (global_scope) {
+    Expect(dil::TokenKind::identifier);
+    std::string identifier = m_dil_token.getSpelling();
+    ConsumeToken();
+    return llvm::formatv("{0}{1}", global_scope ? "::" : "", identifier);
+  }
+
+  // This is unqualified_id production.
+  return ParseUnqualifiedId();
+}
+
+// Parse an unqualified_id.
+//
+//  unqualified_id:
+//    identifier
+//
+//  identifier:
+//    ? dil::TokenKind::identifier ?
+//
+std::string DILParser::ParseUnqualifiedId() {
+  Expect(dil::TokenKind::identifier);
+  std::string identifier = m_dil_token.getSpelling();
+  ConsumeToken();
+  return identifier;
+}
+
+void DILParser::BailOut(ErrorCode code, const std::string &error,
+                        uint32_t loc) {
+  if (m_error.Fail()) {
+    // If error is already set, then the parser is in the "bail-out" mode. Don't
+    // do anything and keep the original error.
+    return;
+  }
+
+  m_error = Status((uint32_t)code, lldb::eErrorTypeGeneric,
+                   FormatDiagnostics(m_input_expr, error, loc));
+  m_dil_token.setKind(dil::TokenKind::eof);
+}
+
+void DILParser::BailOut(Status error) {
+  if (m_error.Fail()) {
+    // If error is already set, then the parser is in the "bail-out" mode. Don't
+    // do anything and keep the original error.
+    return;
+  }
+  m_error = std::move(error);
+  m_dil_token.setKind(dil::TokenKind::eof);
+}
+
+void DILParser::ConsumeToken() {
+  if (m_dil_token.is(dil::TokenKind::eof)) {
+    // Don't do anything if we're already at eof. This can happen if an error
+    // occurred during parsing and we're trying to bail out.
+    return;
+  }
+  bool all_ok;
+  m_dil_lexer.Lex(m_dil_token);
+  if (m_dil_lexer.GetCurrentTokenIdx() == UINT_MAX)
+    all_ok = m_dil_lexer.ResetTokenIdx(0);
+  else
+    all_ok = m_dil_lexer.IncrementTokenIdx();
+  if (!all_ok)
+    BailOut(ErrorCode::kUnknown, "Invalid lexer token index", 0);
+}
+
+void DILParser::Expect(dil::TokenKind kind) {
+  if (m_dil_token.isNot(kind)) {
+    BailOut(ErrorCode::kUnknown,
+            llvm::formatv("expected {0}, got: {1}", TokenKindsJoin(kind),
+                          TokenDescription(m_dil_token)),
+            m_dil_token.getLocation());
+  }
+}
+
+template <typename... Ts>
+void DILParser::ExpectOneOf(dil::TokenKind k, Ts... ks) {
+  static_assert((std::is_same_v<Ts, dil::TokenKind> && ...),
+                "ExpectOneOf can be only called with values of type "
+                "dil::TokenKind");
+
+  if (!m_dil_token.isOneOf(k, ks...)) {
+    BailOut(ErrorCode::kUnknown,
+            llvm::formatv("expected any of ({0}), got: {1}",
+                          TokenKindsJoin(k, ks...),
+                          TokenDescription(m_dil_token)),
+            m_dil_token.getLocation());
+  }
+}
+
+std::string DILParser::TokenDescription(const DILToken &token) {
+  const auto &spelling = ((DILToken)token).getSpelling();
+  const std::string kind_name =
+      DILToken::getTokenName(((DILToken)token).getKind());
+  return llvm::formatv("<'{0}' ({1})>", spelling, kind_name);
+}
+
+} // namespace dil
+
+} // namespace lldb_private
diff --git a/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/Makefile b/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/Makefile
new file mode 100644
index 00000000000000..99998b20bcb050
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py b/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py
new file mode 100644
index 00000000000000..b87de2ab27ebb2
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py
@@ -0,0 +1,82 @@
+"""
+Make sure 'frame var' using DIL parser/evaultor works for local variables.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+import os
+import shutil
+import time
+
+class TestFrameVarDILGlobalVariableLookup(TestBase):
+    # If your test case doesn't stress debug info, then
+    # set this to true.  That way it won't be run once for
+    # each debug info format.
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_frame_var(self):
+        self.build()
+        self.do_test()
+
+    def do_test(self):
+        target = self.createTestTarget()
+
+        # Now create a breakpoint in main.c at the source matching
+        # "Set a breakpoint here"
+        breakpoint = target.BreakpointCreateBySourceRegex(
+            "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+        self.assertTrue(
+            breakpoint and breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT
+        )
+
+        error = lldb.SBError()
+        # This is the launch info.  If you want to launch with arguments or
+        # environment variables, add them using SetArguments or
+        # SetEnvironmentEntries
+
+        launch_info = target.GetLaunchInfo()
+        process = target.Launch(launch_info, error)
+        self.assertTrue(process, PROCESS_IS_VALID)
+
+        # Did we hit our breakpoint?
+        from lldbsuite.test.lldbutil import get_threads_stopped_at_breakpoint
+
+        threads = get_threads_stopped_at_breakpoint(process, breakpoint)
+        self.assertEqual(
+            len(threads), 1, "There should be a thread stopped at our breakpoint"
+        )
+       # The hit count for the breakpoint should be 1.
+        self.assertEquals(breakpoint.GetHitCount(), 1)
+
+        frame = threads[0].GetFrameAtIndex(0)
+        command_result = lldb.SBCommandReturnObject()
+        interp = self.dbg.GetCommandInterpreter()
+
+
+        self.expect("settings set target.experimental.use-DIL true",
+                    substrs=[""])
+        self.expect("frame variable 'globalVar'", substrs=["-559038737"])  # 0xDEADBEEF
+        self.expect("frame variable 'globalPtr'", patterns=["0x[0-9]+"])
+        self.expect("frame variable 'globalRef'", substrs=["-559038737"])
+        self.expect("frame variable '::globalPtr'", patterns=["0x[0-9]+"])
+        self.expect("frame variable '::globalRef'", substrs=["-559038737"])
+
+        self.expect("frame variable 'externGlobalVar'", error=True,
+                    substrs=["use of undeclared identifier"])  # 0x00C0FFEE
+                    #substrs=["no variable named 'externGlobalVar' found in this frame"])  # 0x00C0FFEE
+        self.expect("frame variable '::externGlobalVar'", error=True,
+                    substrs=["use of undeclared identifier"]) # ["12648430"])
+                    #substrs=["no variable named '::externGlobalVar' found in this frame"]) # ["12648430"])
+        # "use of undeclared identifier"
+
+        self.expect("frame variable 'ns::globalVar'", substrs=["13"])
+        self.expect("frame variable 'ns::globalPtr'",
+                    patterns=["0x[0-9]+"])
+        self.expect("frame variable 'ns::globalRef'", substrs=["13"])
+        self.expect("frame variable '::ns::globalVar'", substrs=["13"])
+        self.expect("frame variable '::ns::globalPtr'",
+                    patterns=["0x[0-9]+"])
diff --git a/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/main.cpp
new file mode 100644
index 00000000000000..605142d169db28
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/main.cpp
@@ -0,0 +1,18 @@
+int globalVar = 0xDEADBEEF;
+extern int externGlobalVar;
+
+int* globalPtr = &globalVar;
+int& globalRef = globalVar;
+
+namespace ns {
+int globalVar = 13;
+int* globalPtr = &globalVar;
+int& globalRef = globalVar;
+}  // namespace ns
+
+int
+main(int argc, char **argv)
+{
+
+  return 0; // Set a breakpoint here
+}
diff --git a/lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/Makefile b/lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/Makefile
new file mode 100644
index 00000000000000..99998b20bcb050
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/TestFrameVarDILInstanceVariables.py b/lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/TestFrameVarDILInstanceVariables.py
new file mode 100644
index 00000000000000..dcc408f1f37bd1
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/TestFrameVarDILInstanceVariables.py
@@ -0,0 +1,62 @@
+"""
+Make sure 'frame var' using DIL parser/evaultor works for local variables.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+import os
+import shutil
+import time
+
+class TestFrameVarDILInstanceVariables(TestBase):
+    # If your test case doesn't stress debug info, then
+    # set this to true.  That way it won't be run once for
+    # each debug info format.
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_frame_var(self):
+        self.build()
+        self.do_test()
+
+    def do_test(self):
+        target = self.createTestTarget()
+
+        # Now create a breakpoint in main.c at the source matching
+        # "Set a breakpoint here"
+        breakpoint = target.BreakpointCreateBySourceRegex(
+            "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+        self.assertTrue(
+            breakpoint and breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT
+        )
+
+        error = lldb.SBError()
+        # This is the launch info.  If you want to launch with arguments or
+        # environment variables, add them using SetArguments or
+        # SetEnvironmentEntries
+
+        launch_info = target.GetLaunchInfo()
+        process = target.Launch(launch_info, error)
+        self.assertTrue(process, PROCESS_IS_VALID)
+
+        # Did we hit our breakpoint?
+        from lldbsuite.test.lldbutil import get_threads_stopped_at_breakpoint
+
+        threads = get_threads_stopped_at_breakpoint(process, breakpoint)
+        self.assertEqual(
+            len(threads), 1, "There should be a thread stopped at our breakpoint"
+        )
+       # The hit count for the breakpoint should be 1.
+        self.assertEquals(breakpoint.GetHitCount(), 1)
+
+        frame = threads[0].GetFrameAtIndex(0)
+        command_result = lldb.SBCommandReturnObject()
+        interp = self.dbg.GetCommandInterpreter()
+
+        self.expect("settings set target.experimental.use-DIL true",
+                    substrs=[""])
+        self.expect("frame variable 'this'", patterns=["0x[0-9]+"])
+        self.expect("frame variable 'c'", substrs=["(field_ = -1)"])
diff --git a/lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/main.cpp
new file mode 100644
index 00000000000000..276166f97a7bda
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/InstanceVariables/main.cpp
@@ -0,0 +1,25 @@
+#include <string>
+
+class C {
+ public:
+  int field_ = 1337;
+};
+
+class TestMethods {
+ public:
+  void TestInstanceVariables() {
+    C c;
+    c.field_ = -1;
+
+    return; // Set a breakpoint here
+  }
+};
+
+int
+main(int argc, char **argv)
+{
+  TestMethods tm;
+
+  tm.TestInstanceVariables();
+  return 0;
+}
diff --git a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/Makefile b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/Makefile
new file mode 100644
index 00000000000000..99998b20bcb050
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
new file mode 100644
index 00000000000000..c19f09f2f06b68
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
@@ -0,0 +1,65 @@
+"""
+Make sure 'frame var' using DIL parser/evaultor works for local variables.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+import os
+import shutil
+import time
+
+class TestFrameVarDILLocalVars(TestBase):
+    # If your test case doesn't stress debug info, then
+    # set this to true.  That way it won't be run once for
+    # each debug info format.
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_frame_var(self):
+        self.build()
+        self.do_test()
+
+    def do_test(self):
+        target = self.createTestTarget()
+
+        # Now create a breakpoint in main.c at the source matching
+        # "Set a breakpoint here"
+        breakpoint = target.BreakpointCreateBySourceRegex(
+            "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+        self.assertTrue(
+            breakpoint and breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT
+        )
+
+        error = lldb.SBError()
+        # This is the launch info.  If you want to launch with arguments or
+        # environment variables, add them using SetArguments or
+        # SetEnvironmentEntries
+
+        launch_info = target.GetLaunchInfo()
+        process = target.Launch(launch_info, error)
+        self.assertTrue(process, PROCESS_IS_VALID)
+
+        # Did we hit our breakpoint?
+        from lldbsuite.test.lldbutil import get_threads_stopped_at_breakpoint
+
+        threads = get_threads_stopped_at_breakpoint(process, breakpoint)
+        self.assertEqual(
+            len(threads), 1, "There should be a thread stopped at our breakpoint"
+        )
+       # The hit count for the breakpoint should be 1.
+        self.assertEquals(breakpoint.GetHitCount(), 1)
+
+        frame = threads[0].GetFrameAtIndex(0)
+        command_result = lldb.SBCommandReturnObject()
+        interp = self.dbg.GetCommandInterpreter()
+
+        # Test 'a' is 1
+        self.expect("settings set target.experimental.use-DIL true",
+                    substrs=[""])
+        self.expect("frame variable a", substrs=["1"])
+        self.expect("frame variable b", substrs=["2"])
+        self.expect("frame variable c", substrs=["\\xfd"])
+        self.expect("frame variable s", substrs=["4"])
diff --git a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/main.cpp
new file mode 100644
index 00000000000000..c0dd24291429a3
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/main.cpp
@@ -0,0 +1,26 @@
+int
+main(int argc, char **argv)
+{
+  int a = 1;
+  int b = 2;
+
+  char c = -3;
+  unsigned short s = 4;
+
+  return 0; // Set a breakpoint here
+}
+
+/*
+TEST_F(EvalTest, TestLocalVariables) {
+  EXPECT_THAT(Eval("a"), IsEqual("1"));
+  EXPECT_THAT(Eval("b"), IsEqual("2"));
+  EXPECT_THAT(Eval("a + b"), IsEqual("3"));
+
+  EXPECT_THAT(Eval("c + 1"), IsEqual("-2"));
+  EXPECT_THAT(Eval("s + 1"), IsEqual("5"));
+  EXPECT_THAT(Eval("c + s"), IsEqual("1"));
+
+  EXPECT_THAT(Eval("__test_non_variable + 1"),
+              IsError("use of undeclared identifier '__test_non_variable'"));
+}
+*/

>From 680f558bb6e8e0d802f47380f3fa2324d4b3e79f Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 14 Jan 2025 16:50:02 -0800
Subject: [PATCH 2/2] [LLDB] Add DIL code for handling plain variable names.

Address	many review comments.

- Move class IdentifierInfo & funciton LookupIdentifier from DILAST to DILEval.
- Fix include statement	formatting.
- Use .str() instead of	.data()	when converting StringRefs to strings.
- Remove 'else'	stmts immediatly following 'return' stmts.
- Clean	up some	things accidentally left in the	code.
- Remove extra,	unused DILInterpreter constructors.
- Convert use of std::shared_ptr<std::string> to llvm::StringRef
- Remove unnecessary length member from	DILToken class
- Remove currently ununsed function 'ExpectOneOf' from parser
- Update grammar: Remove 'this', use 'C99 Identifier' to define	identifier.
- Rename use_dynamic()	and name() to	GetUseDynamic()	and GetName()
- Return strings directly rather than through a	return variable
- Remove special handling for "this" from Lexer	& from Parser
- Remove unneeded casts for DILToken (old leftover code)
- Small	cleanups in tests (removing unneeded comments)
---
 lldb/docs/dil-expr-lang.ebnf                  |   3 +-
 lldb/include/lldb/ValueObject/DILAST.h        |  60 +----
 lldb/include/lldb/ValueObject/DILEval.h       |  62 ++++-
 lldb/include/lldb/ValueObject/DILLexer.h      |  27 +-
 lldb/include/lldb/ValueObject/DILParser.h     |  17 +-
 lldb/source/Target/StackFrame.cpp             |   7 +-
 lldb/source/ValueObject/DILAST.cpp            | 207 ---------------
 lldb/source/ValueObject/DILEval.cpp           | 236 +++++++++++++++---
 lldb/source/ValueObject/DILLexer.cpp          |  61 ++---
 lldb/source/ValueObject/DILParser.cpp         |  64 ++---
 .../TestFrameVarDILGlobalVariableLookup.py    |   4 -
 .../LocalVars/TestFrameVarDILLocalVars.py     |   1 -
 .../frame/var-dil/basics/LocalVars/main.cpp   |  15 --
 13 files changed, 324 insertions(+), 440 deletions(-)

diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 64b3e7758229c2..7aca2b34a4929f 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -6,7 +6,6 @@
 expression = primary_expression ;
 
 primary_expression = id_expression
-                   | "this"
                    | "(" expression ")";
 
 id_expression = unqualified_id
@@ -17,7 +16,7 @@ unqualified_id = identifier ;
 qualified_id = ["::"] [nested_name_specifier] unqualified_id
              | ["::"] identifier ;
 
-identifier = ? dil::TokenKind::identifier ? ;
+identifier = ? C99 Identifier ? ;
 
 nested_name_specifier = type_name "::"
                       | namespace_name '::'
diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h
index 9f0a1a2221e388..dd041483b835b9 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -9,11 +9,8 @@
 #ifndef LLDB_VALUEOBJECT_DILAST_H
 #define LLDB_VALUEOBJECT_DILAST_H
 
-#include <memory>
-#include <string>
-#include <vector>
-
 #include "lldb/ValueObject/ValueObject.h"
+#include <string>
 
 namespace lldb_private {
 
@@ -25,51 +22,6 @@ enum class NodeKind {
   eIdentifierNode,
 };
 
-/// Class used to store & manipulate information about identifiers.
-class IdentifierInfo {
-public:
-  enum class Kind {
-    eValue,
-    eContextArg,
-  };
-
-  static std::unique_ptr<IdentifierInfo> FromValue(ValueObject &valobj) {
-    CompilerType type;
-    type = valobj.GetCompilerType();
-    return std::unique_ptr<IdentifierInfo>(
-        new IdentifierInfo(Kind::eValue, type, valobj.GetSP(), {}));
-  }
-
-  static std::unique_ptr<IdentifierInfo> FromContextArg(CompilerType type) {
-    lldb::ValueObjectSP empty_value;
-    return std::unique_ptr<IdentifierInfo>(
-        new IdentifierInfo(Kind::eContextArg, type, empty_value, {}));
-  }
-
-  Kind GetKind() const { return m_kind; }
-  lldb::ValueObjectSP GetValue() const { return m_value; }
-
-  CompilerType GetType() { return m_type; }
-  bool IsValid() const { return m_type.IsValid(); }
-
-  IdentifierInfo(Kind kind, CompilerType type, lldb::ValueObjectSP value,
-                 std::vector<uint32_t> path)
-      : m_kind(kind), m_type(type), m_value(std::move(value)) {}
-
-private:
-  Kind m_kind;
-  CompilerType m_type;
-  lldb::ValueObjectSP m_value;
-};
-
-/// Given the name of an identifier (variable name, member name, type name,
-/// etc.), find the ValueObject for that name (if it exists) and create and
-/// return an IdentifierInfo object containing all the relevant information
-/// about that object (for DIL parsing and evaluating).
-std::unique_ptr<IdentifierInfo> LookupIdentifier(
-    const std::string &name, std::shared_ptr<ExecutionContextScope> ctx_scope,
-    lldb::DynamicValueType use_dynamic, CompilerType *scope_ptr = nullptr);
-
 /// Forward declaration, for use in DIL AST nodes. Definition is at the very
 /// end of this file.
 class Visitor;
@@ -104,16 +56,12 @@ using DILASTNodeUP = std::unique_ptr<DILASTNode>;
 
 class ErrorNode : public DILASTNode {
 public:
-  ErrorNode(CompilerType empty_type)
-      : DILASTNode(0, NodeKind::eErrorNode), m_empty_type(empty_type) {}
+  ErrorNode() : DILASTNode(0, NodeKind::eErrorNode) {}
   void Accept(Visitor *v) const override;
 
   static bool classof(const DILASTNode *node) {
     return node->GetKind() == NodeKind::eErrorNode;
   }
-
-private:
-  CompilerType m_empty_type;
 };
 
 class IdentifierNode : public DILASTNode {
@@ -127,8 +75,8 @@ class IdentifierNode : public DILASTNode {
 
   void Accept(Visitor *v) const override;
 
-  lldb::DynamicValueType use_dynamic() const { return m_use_dynamic; }
-  std::string name() const { return m_name; }
+  lldb::DynamicValueType GetUseDynamic() const { return m_use_dynamic; }
+  std::string GetName() const { return m_name; }
   std::shared_ptr<ExecutionContextScope> get_exe_context() const {
     return m_ctx_scope;
   }
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index 4006bb10630f24..6bb9a76cd81521 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -9,23 +9,65 @@
 #ifndef LLDB_VALUEOBJECT_DILEVAL_H_
 #define LLDB_VALUEOBJECT_DILEVAL_H_
 
-#include <memory>
-#include <vector>
-
 #include "lldb/ValueObject/DILAST.h"
 #include "lldb/ValueObject/DILParser.h"
+#include <memory>
+#include <vector>
 
 namespace lldb_private {
 
 namespace dil {
 
+/// Class used to store & manipulate information about identifiers.
+class IdentifierInfo {
+public:
+  enum class Kind {
+    eValue,
+    eContextArg,
+  };
+
+  static std::unique_ptr<IdentifierInfo> FromValue(ValueObject &valobj) {
+    CompilerType type;
+    type = valobj.GetCompilerType();
+    return std::unique_ptr<IdentifierInfo>(
+        new IdentifierInfo(Kind::eValue, type, valobj.GetSP(), {}));
+  }
+
+  static std::unique_ptr<IdentifierInfo> FromContextArg(CompilerType type) {
+    lldb::ValueObjectSP empty_value;
+    return std::unique_ptr<IdentifierInfo>(
+        new IdentifierInfo(Kind::eContextArg, type, empty_value, {}));
+  }
+
+  Kind GetKind() const { return m_kind; }
+  lldb::ValueObjectSP GetValue() const { return m_value; }
+
+  CompilerType GetType() { return m_type; }
+  bool IsValid() const { return m_type.IsValid(); }
+
+  IdentifierInfo(Kind kind, CompilerType type, lldb::ValueObjectSP value,
+                 std::vector<uint32_t> path)
+      : m_kind(kind), m_type(type), m_value(std::move(value)) {}
+
+private:
+  Kind m_kind;
+  CompilerType m_type;
+  lldb::ValueObjectSP m_value;
+};
+
+/// Given the name of an identifier (variable name, member name, type name,
+/// etc.), find the ValueObject for that name (if it exists) and create and
+/// return an IdentifierInfo object containing all the relevant information
+/// about that object (for DIL parsing and evaluating).
+std::unique_ptr<IdentifierInfo> LookupIdentifier(
+    const std::string &name, std::shared_ptr<ExecutionContextScope> ctx_scope,
+    lldb::DynamicValueType use_dynamic, CompilerType *scope_ptr = nullptr);
+
 class DILInterpreter : Visitor {
 public:
-  DILInterpreter(lldb::TargetSP target, std::shared_ptr<std::string> sm);
-  DILInterpreter(lldb::TargetSP target, std::shared_ptr<std::string> sm,
-                 lldb::ValueObjectSP scope);
-  DILInterpreter(lldb::TargetSP target, std::shared_ptr<std::string> sm,
-                 lldb::DynamicValueType use_dynamic);
+  DILInterpreter(lldb::TargetSP target, llvm::StringRef expr,
+                 lldb::DynamicValueType use_dynamic,
+                 std::shared_ptr<ExecutionContextScope> exe_ctx_scope);
 
   lldb::ValueObjectSP DILEval(const DILASTNode *tree, lldb::TargetSP target_sp,
                               Status &error);
@@ -44,7 +86,7 @@ class DILInterpreter : Visitor {
   // Used by the interpreter to create objects, perform casts, etc.
   lldb::TargetSP m_target;
 
-  std::shared_ptr<std::string> m_sm;
+  llvm::StringRef m_expr;
 
   lldb::ValueObjectSP m_result;
 
@@ -53,6 +95,8 @@ class DILInterpreter : Visitor {
   lldb::DynamicValueType m_default_dynamic;
 
   Status m_error;
+
+  std::shared_ptr<ExecutionContextScope> m_exe_ctx_scope;
 };
 
 } // namespace dil
diff --git a/lldb/include/lldb/ValueObject/DILLexer.h b/lldb/include/lldb/ValueObject/DILLexer.h
index c794fb2bfc0ed3..669ddfb2d4a4b3 100644
--- a/lldb/include/lldb/ValueObject/DILLexer.h
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -9,15 +9,13 @@
 #ifndef LLDB_VALUEOBJECT_DILLEXER_H_
 #define LLDB_VALUEOBJECT_DILLEXER_H_
 
-#include <limits.h>
-
+#include "llvm/ADT/StringRef.h"
 #include <cstdint>
+#include <limits.h>
 #include <memory>
 #include <string>
 #include <vector>
 
-#include "llvm/ADT/StringRef.h"
-
 namespace lldb_private {
 
 namespace dil {
@@ -39,20 +37,17 @@ enum class TokenKind {
 /// DIL parser.
 class DILToken {
 public:
-  DILToken(dil::TokenKind kind, std::string spelling, uint32_t start,
-           uint32_t len)
-      : m_kind(kind), m_spelling(spelling), m_start_pos(start), m_length(len) {}
+  DILToken(dil::TokenKind kind, std::string spelling, uint32_t start)
+      : m_kind(kind), m_spelling(spelling), m_start_pos(start) {}
 
-  DILToken()
-      : m_kind(dil::TokenKind::none), m_spelling(""), m_start_pos(0),
-        m_length(0) {}
+  DILToken() : m_kind(dil::TokenKind::none), m_spelling(""), m_start_pos(0) {}
 
   void setKind(dil::TokenKind kind) { m_kind = kind; }
   dil::TokenKind getKind() const { return m_kind; }
 
   std::string getSpelling() const { return m_spelling; }
 
-  uint32_t getLength() const { return m_length; }
+  uint32_t getLength() const { return m_spelling.size(); }
 
   bool is(dil::TokenKind kind) const { return m_kind == kind; }
 
@@ -68,12 +63,10 @@ class DILToken {
 
   uint32_t getLocation() const { return m_start_pos; }
 
-  void setValues(dil::TokenKind kind, std::string spelling, uint32_t start,
-                 uint32_t len) {
+  void setValues(dil::TokenKind kind, std::string spelling, uint32_t start) {
     m_kind = kind;
     m_spelling = spelling;
     m_start_pos = start;
-    m_length = len;
   }
 
   static const std::string getTokenName(dil::TokenKind kind);
@@ -82,13 +75,12 @@ class DILToken {
   dil::TokenKind m_kind;
   std::string m_spelling;
   uint32_t m_start_pos; // within entire expression string
-  uint32_t m_length;
 };
 
 /// Class for doing the simple lexing required by DIL.
 class DILLexer {
 public:
-  DILLexer(std::shared_ptr<std::string> dil_sm) : m_expr(*dil_sm) {
+  DILLexer(llvm::StringRef dil_expr) : m_expr(dil_expr.str()) {
     m_cur_pos = m_expr.begin();
     // Use UINT_MAX to indicate invalid/uninitialized value.
     m_tokens_idx = UINT_MAX;
@@ -104,8 +96,7 @@ class DILLexer {
   /// duplicate token, and push the duplicate token onto the vector of
   /// lexed tokens.
   void UpdateLexedTokens(DILToken &result, dil::TokenKind tok_kind,
-                         std::string tok_str, uint32_t tok_pos,
-                         uint32_t tok_len);
+                         std::string tok_str, uint32_t tok_pos);
 
   /// Return the lexed token N+1 positions ahead of the 'current' token
   /// being handled by the DIL parser.
diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h
index b718903b7bea49..f8db81b1aee5b3 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -9,17 +9,16 @@
 #ifndef LLDB_VALUEOBJECT_DILPARSER_H_
 #define LLDB_VALUEOBJECT_DILPARSER_H_
 
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/ValueObject/DILAST.h"
+#include "lldb/ValueObject/DILLexer.h"
 #include <memory>
 #include <optional>
 #include <string>
 #include <tuple>
 #include <vector>
 
-#include "lldb/Target/ExecutionContextScope.h"
-#include "lldb/Utility/Status.h"
-#include "lldb/ValueObject/DILAST.h"
-#include "lldb/ValueObject/DILLexer.h"
-
 namespace lldb_private {
 
 namespace dil {
@@ -31,14 +30,14 @@ enum class ErrorCode : unsigned char {
   kUnknown,
 };
 
-std::string FormatDiagnostics(std::shared_ptr<std::string> input_expr,
+std::string FormatDiagnostics(llvm::StringRef input_expr,
                               const std::string &message, uint32_t loc);
 
 /// Pure recursive descent parser for C++ like expressions.
 /// EBNF grammar for the parser is described in lldb/docs/dil-expr-lang.ebnf
 class DILParser {
 public:
-  explicit DILParser(std::shared_ptr<std::string> dil_input_expr,
+  explicit DILParser(llvm::StringRef dil_input_expr,
                      std::shared_ptr<ExecutionContextScope> exe_ctx_scope,
                      lldb::DynamicValueType use_dynamic, bool use_synthetic,
                      bool fragile_ivar, bool check_ptr_vs_member);
@@ -72,8 +71,6 @@ class DILParser {
 
   std::string TokenDescription(const DILToken &token);
 
-  template <typename... Ts> void ExpectOneOf(dil::TokenKind k, Ts... ks);
-
   void TentativeParsingRollback(uint32_t saved_idx) {
     m_error.Clear();
     m_dil_lexer.ResetTokenIdx(saved_idx);
@@ -85,7 +82,7 @@ class DILParser {
   // context will outlive the parser.
   std::shared_ptr<ExecutionContextScope> m_ctx_scope;
 
-  std::shared_ptr<std::string> m_input_expr;
+  llvm::StringRef m_input_expr;
   // The token lexer is stopped at (aka "current token").
   DILToken m_dil_token;
   // Holds an error if it occures during parsing.
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 28450b1d1c1c1e..357ec2e47a5328 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -528,8 +528,6 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
     llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
     uint32_t options, lldb::VariableSP &var_sp, Status &error) {
   ValueObjectSP ret_val;
-  std::shared_ptr<std::string> source =
-      std::make_shared<std::string>(var_expr.data());
 
   const bool check_ptr_vs_member =
       (options & eExpressionPathOptionCheckPtrVsMember) != 0;
@@ -540,7 +538,7 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
 
   // Parse the expression.
   Status parse_error, eval_error;
-  dil::DILParser parser(source, shared_from_this(), use_dynamic,
+  dil::DILParser parser(var_expr, shared_from_this(), use_dynamic,
                         !no_synth_child, !no_fragile_ivar, check_ptr_vs_member);
   dil::DILASTNodeUP tree = parser.Run(parse_error);
   if (parse_error.Fail()) {
@@ -550,7 +548,8 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath(
 
   // Evaluate the parsed expression.
   lldb::TargetSP target = this->CalculateTarget();
-  dil::DILInterpreter interpreter(target, source, use_dynamic);
+  dil::DILInterpreter interpreter(target, var_expr, use_dynamic,
+                                  shared_from_this());
 
   ret_val = interpreter.DILEval(tree.get(), target, eval_error);
   if (eval_error.Fail()) {
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index 1af0dc57ddcea7..9aebe7e2ca4f94 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -8,217 +8,10 @@
 
 #include "lldb/ValueObject/DILAST.h"
 
-#include "lldb/API/SBType.h"
-#include "lldb/Symbol/TypeList.h"
-#include "lldb/Symbol/VariableList.h"
-#include "lldb/Target/LanguageRuntime.h"
-#include "lldb/Target/RegisterContext.h"
-#include "lldb/ValueObject/ValueObjectRegister.h"
-#include "lldb/ValueObject/ValueObjectVariable.h"
-#include "llvm/ADT/StringRef.h"
-
-#include <vector>
-
 namespace lldb_private {
 
 namespace dil {
 
-static lldb::ValueObjectSP
-LookupStaticIdentifier(lldb::TargetSP target_sp,
-                       const llvm::StringRef &name_ref,
-                       ConstString unqualified_name) {
-  // List global variable with the same "basename". There can be many matches
-  // from other scopes (namespaces, classes), so we do additional filtering
-  // later.
-  VariableList variable_list;
-  ConstString name(name_ref);
-  target_sp->GetImages().FindGlobalVariables(name, 1, variable_list);
-  if (!variable_list.Empty()) {
-    ExecutionContextScope *exe_scope = target_sp->GetProcessSP().get();
-    if (exe_scope == nullptr)
-      exe_scope = target_sp.get();
-    for (const lldb::VariableSP &var_sp : variable_list) {
-      lldb::ValueObjectSP valobj_sp(
-          ValueObjectVariable::Create(exe_scope, var_sp));
-      if (valobj_sp && valobj_sp->GetVariable() &&
-          (valobj_sp->GetVariable()->NameMatches(unqualified_name) ||
-           valobj_sp->GetVariable()->NameMatches(ConstString(name_ref))))
-        return valobj_sp;
-    }
-  }
-  return nullptr;
-}
-
-static lldb::VariableSP DILFindVariable(ConstString name,
-                                        VariableList *variable_list) {
-  lldb::VariableSP exact_match;
-  std::vector<lldb::VariableSP> possible_matches;
-
-  typedef std::vector<lldb::VariableSP> collection;
-  typedef collection::iterator iterator;
-
-  iterator pos, end = variable_list->end();
-  for (pos = variable_list->begin(); pos != end; ++pos) {
-    llvm::StringRef str_ref_name = pos->get()->GetName().GetStringRef();
-    // Check for global vars, which might start with '::'.
-    str_ref_name.consume_front("::");
-
-    if (str_ref_name == name.GetStringRef())
-      possible_matches.push_back(*pos);
-    else if (pos->get()->NameMatches(name))
-      possible_matches.push_back(*pos);
-  }
-
-  // Look for exact matches (favors local vars over global vars)
-  auto exact_match_it =
-      llvm::find_if(possible_matches, [&](lldb::VariableSP var_sp) {
-        return var_sp->GetName() == name;
-      });
-
-  if (exact_match_it != llvm::adl_end(possible_matches))
-    exact_match = *exact_match_it;
-
-  if (!exact_match)
-    // Look for a global var exact match.
-    for (auto var_sp : possible_matches) {
-      llvm::StringRef str_ref_name = var_sp->GetName().GetStringRef();
-      if (str_ref_name.size() > 2 && str_ref_name[0] == ':' &&
-          str_ref_name[1] == ':')
-        str_ref_name = str_ref_name.drop_front(2);
-      ConstString tmp_name(str_ref_name);
-      if (tmp_name == name) {
-        exact_match = var_sp;
-        break;
-      }
-    }
-
-  // Take any match at this point.
-  if (!exact_match && possible_matches.size() > 0)
-    exact_match = possible_matches[0];
-
-  return exact_match;
-}
-
-std::unique_ptr<IdentifierInfo>
-LookupIdentifier(const std::string &name,
-                 std::shared_ptr<ExecutionContextScope> ctx_scope,
-                 lldb::DynamicValueType use_dynamic, CompilerType *scope_ptr) {
-  ConstString name_str(name);
-  llvm::StringRef name_ref = name_str.GetStringRef();
-
-  // Support $rax as a special syntax for accessing registers.
-  // Will return an invalid value in case the requested register doesn't exist.
-  if (name_ref.starts_with("$")) {
-    lldb::ValueObjectSP value_sp;
-    const char *reg_name = name_ref.drop_front(1).data();
-    Target *target = ctx_scope->CalculateTarget().get();
-    Process *process = ctx_scope->CalculateProcess().get();
-    if (target && process) {
-      StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
-      if (stack_frame) {
-        lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
-        if (reg_ctx) {
-          if (const RegisterInfo *reg_info =
-                  reg_ctx->GetRegisterInfoByName(reg_name))
-            value_sp =
-                ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
-        }
-      }
-    }
-    if (value_sp)
-      return IdentifierInfo::FromValue(*value_sp);
-    else
-      return nullptr;
-  }
-
-  // Internally values don't have global scope qualifier in their names and
-  // LLDB doesn't support queries with it too.
-  bool global_scope = false;
-  if (name_ref.starts_with("::")) {
-    name_ref = name_ref.drop_front(2);
-    global_scope = true;
-  }
-
-  // If the identifier doesn't refer to the global scope and doesn't have any
-  // other scope qualifiers, try looking among the local and instance variables.
-  if (!global_scope && !name_ref.contains("::")) {
-    if (!scope_ptr || !scope_ptr->IsValid()) {
-      // Lookup in the current frame.
-      lldb::StackFrameSP frame = ctx_scope->CalculateStackFrame();
-      // Try looking for a local variable in current scope.
-      lldb::ValueObjectSP value_sp;
-      lldb::VariableListSP var_list_sp(frame->GetInScopeVariableList(true));
-      VariableList *variable_list = var_list_sp.get();
-      if (variable_list) {
-        lldb::VariableSP var_sp =
-            DILFindVariable(ConstString(name_ref), variable_list);
-        if (var_sp)
-          value_sp = frame->GetValueObjectForFrameVariable(var_sp, use_dynamic);
-      }
-      if (!value_sp)
-        value_sp = frame->FindVariable(ConstString(name_ref));
-
-      if (value_sp)
-        // Force static value, otherwise we can end up with the "real" type.
-        return IdentifierInfo::FromValue(*value_sp);
-
-      // Try looking for an instance variable (class member).
-      ConstString this_string("this");
-      value_sp = frame->FindVariable(this_string);
-      if (value_sp)
-        value_sp = value_sp->GetChildMemberWithName(name_ref.data());
-
-      if (value_sp)
-        // Force static value, otherwise we can end up with the "real" type.
-        return IdentifierInfo::FromValue(*(value_sp->GetStaticValue()));
-    }
-  }
-
-  // Try looking for a global or static variable.
-
-  lldb::ValueObjectSP value;
-  if (!global_scope) {
-    // Try looking for static member of the current scope value, e.g.
-    // `ScopeType::NAME`. NAME can include nested struct (`Nested::SUBNAME`),
-    // but it cannot be part of the global scope (start with "::").
-    const char *type_name = "";
-    if (scope_ptr)
-      type_name = scope_ptr->GetCanonicalType().GetTypeName().AsCString();
-    std::string name_with_type_prefix =
-        llvm::formatv("{0}::{1}", type_name, name_ref).str();
-    value = LookupStaticIdentifier(ctx_scope->CalculateTarget(),
-                                   name_with_type_prefix, name_str);
-  }
-
-  // Lookup a regular global variable.
-  if (!value)
-    value = LookupStaticIdentifier(ctx_scope->CalculateTarget(), name_ref,
-                                   name_str);
-
-  // Last resort, lookup as a register (e.g. `rax` or `rip`).
-  if (!value) {
-    Target *target = ctx_scope->CalculateTarget().get();
-    Process *process = ctx_scope->CalculateProcess().get();
-    if (target && process) {
-      StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
-      if (stack_frame) {
-        lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
-        if (reg_ctx) {
-          if (const RegisterInfo *reg_info =
-                  reg_ctx->GetRegisterInfoByName(name_ref.data()))
-            value = ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
-        }
-      }
-    }
-  }
-
-  // Force static value, otherwise we can end up with the "real" type.
-  if (value)
-    return IdentifierInfo::FromValue(*value);
-  else
-    return nullptr;
-}
-
 void ErrorNode::Accept(Visitor *v) const { v->Visit(this); }
 
 void IdentifierNode::Accept(Visitor *v) const { v->Visit(this); }
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 01da8521536503..7a6fcca58a2b9e 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -7,44 +7,222 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/ValueObject/DILEval.h"
-
-#include <memory>
-
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/RegisterContext.h"
 #include "lldb/ValueObject/DILAST.h"
 #include "lldb/ValueObject/ValueObject.h"
+#include "lldb/ValueObject/ValueObjectRegister.h"
+#include "lldb/ValueObject/ValueObjectVariable.h"
 #include "llvm/Support/FormatAdapters.h"
+#include <memory>
 
 namespace lldb_private {
 
 namespace dil {
 
-DILInterpreter::DILInterpreter(lldb::TargetSP target,
-                               std::shared_ptr<std::string> sm)
-    : m_target(std::move(target)), m_sm(std::move(sm)) {
-  m_default_dynamic = lldb::eNoDynamicValues;
+static lldb::ValueObjectSP
+LookupStaticIdentifier(lldb::TargetSP target_sp,
+                       const llvm::StringRef &name_ref,
+                       ConstString unqualified_name) {
+  // List global variable with the same "basename". There can be many matches
+  // from other scopes (namespaces, classes), so we do additional filtering
+  // later.
+  VariableList variable_list;
+  ConstString name(name_ref);
+  target_sp->GetImages().FindGlobalVariables(name, 1, variable_list);
+  if (!variable_list.Empty()) {
+    ExecutionContextScope *exe_scope = target_sp->GetProcessSP().get();
+    if (exe_scope == nullptr)
+      exe_scope = target_sp.get();
+    for (const lldb::VariableSP &var_sp : variable_list) {
+      lldb::ValueObjectSP valobj_sp(
+          ValueObjectVariable::Create(exe_scope, var_sp));
+      if (valobj_sp && valobj_sp->GetVariable() &&
+          (valobj_sp->GetVariable()->NameMatches(unqualified_name) ||
+           valobj_sp->GetVariable()->NameMatches(ConstString(name_ref))))
+        return valobj_sp;
+    }
+  }
+  return nullptr;
 }
 
-DILInterpreter::DILInterpreter(lldb::TargetSP target,
-                               std::shared_ptr<std::string> sm,
-                               lldb::DynamicValueType use_dynamic)
-    : m_target(std::move(target)), m_sm(std::move(sm)),
-      m_default_dynamic(use_dynamic) {}
-
-DILInterpreter::DILInterpreter(lldb::TargetSP target,
-                               std::shared_ptr<std::string> sm,
-                               lldb::ValueObjectSP scope)
-    : m_target(std::move(target)), m_sm(std::move(sm)),
-      m_scope(std::move(scope)) {
-  m_default_dynamic = lldb::eNoDynamicValues;
-  // If `m_scope` is a reference, dereference it. All operations on a reference
-  // should be operations on the referent.
-  if (m_scope->GetCompilerType().IsValid() &&
-      m_scope->GetCompilerType().IsReferenceType()) {
-    Status error;
-    m_scope = m_scope->Dereference(error);
+static lldb::VariableSP DILFindVariable(ConstString name,
+                                        VariableList *variable_list) {
+  lldb::VariableSP exact_match;
+  std::vector<lldb::VariableSP> possible_matches;
+
+  typedef std::vector<lldb::VariableSP> collection;
+  typedef collection::iterator iterator;
+
+  iterator pos, end = variable_list->end();
+  for (pos = variable_list->begin(); pos != end; ++pos) {
+    llvm::StringRef str_ref_name = pos->get()->GetName().GetStringRef();
+    // Check for global vars, which might start with '::'.
+    str_ref_name.consume_front("::");
+
+    if (str_ref_name == name.GetStringRef())
+      possible_matches.push_back(*pos);
+    else if (pos->get()->NameMatches(name))
+      possible_matches.push_back(*pos);
+  }
+
+  // Look for exact matches (favors local vars over global vars)
+  auto exact_match_it =
+      llvm::find_if(possible_matches, [&](lldb::VariableSP var_sp) {
+        return var_sp->GetName() == name;
+      });
+
+  if (exact_match_it != llvm::adl_end(possible_matches))
+    exact_match = *exact_match_it;
+
+  if (!exact_match)
+    // Look for a global var exact match.
+    for (auto var_sp : possible_matches) {
+      llvm::StringRef str_ref_name = var_sp->GetName().GetStringRef();
+      if (str_ref_name.size() > 2 && str_ref_name[0] == ':' &&
+          str_ref_name[1] == ':')
+        str_ref_name = str_ref_name.drop_front(2);
+      ConstString tmp_name(str_ref_name);
+      if (tmp_name == name) {
+        exact_match = var_sp;
+        break;
+      }
+    }
+
+  // Take any match at this point.
+  if (!exact_match && possible_matches.size() > 0)
+    exact_match = possible_matches[0];
+
+  return exact_match;
+}
+
+std::unique_ptr<IdentifierInfo>
+LookupIdentifier(const std::string &name,
+                 std::shared_ptr<ExecutionContextScope> ctx_scope,
+                 lldb::DynamicValueType use_dynamic, CompilerType *scope_ptr) {
+  ConstString name_str(name);
+  llvm::StringRef name_ref = name_str.GetStringRef();
+
+  // Support $rax as a special syntax for accessing registers.
+  // Will return an invalid value in case the requested register doesn't exist.
+  if (name_ref.starts_with("$")) {
+    lldb::ValueObjectSP value_sp;
+    const char *reg_name = name_ref.drop_front(1).data();
+    Target *target = ctx_scope->CalculateTarget().get();
+    Process *process = ctx_scope->CalculateProcess().get();
+    if (target && process) {
+      StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
+      if (stack_frame) {
+        lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
+        if (reg_ctx) {
+          if (const RegisterInfo *reg_info =
+                  reg_ctx->GetRegisterInfoByName(reg_name))
+            value_sp =
+                ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
+        }
+      }
+    }
+    if (value_sp)
+      return IdentifierInfo::FromValue(*value_sp);
+
+    return nullptr;
+  }
+
+  // Internally values don't have global scope qualifier in their names and
+  // LLDB doesn't support queries with it too.
+  bool global_scope = false;
+  if (name_ref.starts_with("::")) {
+    name_ref = name_ref.drop_front(2);
+    global_scope = true;
   }
+
+  // If the identifier doesn't refer to the global scope and doesn't have any
+  // other scope qualifiers, try looking among the local and instance variables.
+  if (!global_scope && !name_ref.contains("::")) {
+    if (!scope_ptr || !scope_ptr->IsValid()) {
+      // Lookup in the current frame.
+      lldb::StackFrameSP frame = ctx_scope->CalculateStackFrame();
+      // Try looking for a local variable in current scope.
+      lldb::ValueObjectSP value_sp;
+      lldb::VariableListSP var_list_sp(frame->GetInScopeVariableList(true));
+      VariableList *variable_list = var_list_sp.get();
+      if (variable_list) {
+        lldb::VariableSP var_sp =
+            DILFindVariable(ConstString(name_ref), variable_list);
+        if (var_sp)
+          value_sp = frame->GetValueObjectForFrameVariable(var_sp, use_dynamic);
+      }
+      if (!value_sp)
+        value_sp = frame->FindVariable(ConstString(name_ref));
+
+      if (value_sp)
+        // Force static value, otherwise we can end up with the "real" type.
+        return IdentifierInfo::FromValue(*value_sp);
+
+      // Try looking for an instance variable (class member).
+      ConstString this_string("this");
+      value_sp = frame->FindVariable(this_string);
+      if (value_sp)
+        value_sp = value_sp->GetChildMemberWithName(name_ref);
+
+      if (value_sp)
+        // Force static value, otherwise we can end up with the "real" type.
+        return IdentifierInfo::FromValue(*(value_sp->GetStaticValue()));
+    }
+  }
+
+  // Try looking for a global or static variable.
+
+  lldb::ValueObjectSP value;
+  if (!global_scope) {
+    // Try looking for static member of the current scope value, e.g.
+    // `ScopeType::NAME`. NAME can include nested struct (`Nested::SUBNAME`),
+    // but it cannot be part of the global scope (start with "::").
+    const char *type_name = "";
+    if (scope_ptr)
+      type_name = scope_ptr->GetCanonicalType().GetTypeName().AsCString();
+    std::string name_with_type_prefix =
+        llvm::formatv("{0}::{1}", type_name, name_ref).str();
+    value = LookupStaticIdentifier(ctx_scope->CalculateTarget(),
+                                   name_with_type_prefix, name_str);
+  }
+
+  // Lookup a regular global variable.
+  if (!value)
+    value = LookupStaticIdentifier(ctx_scope->CalculateTarget(), name_ref,
+                                   name_str);
+
+  // Last resort, lookup as a register (e.g. `rax` or `rip`).
+  if (!value) {
+    Target *target = ctx_scope->CalculateTarget().get();
+    Process *process = ctx_scope->CalculateProcess().get();
+    if (target && process) {
+      StackFrame *stack_frame = ctx_scope->CalculateStackFrame().get();
+      if (stack_frame) {
+        lldb::RegisterContextSP reg_ctx(stack_frame->GetRegisterContext());
+        if (reg_ctx) {
+          if (const RegisterInfo *reg_info =
+                  reg_ctx->GetRegisterInfoByName(name_ref))
+            value = ValueObjectRegister::Create(stack_frame, reg_ctx, reg_info);
+        }
+      }
+    }
+  }
+
+  // Force static value, otherwise we can end up with the "real" type.
+  if (value)
+    return IdentifierInfo::FromValue(*value);
+
+  return nullptr;
 }
 
+DILInterpreter::DILInterpreter(
+    lldb::TargetSP target, llvm::StringRef expr,
+    lldb::DynamicValueType use_dynamic,
+    std::shared_ptr<ExecutionContextScope> exe_ctx_scope)
+    : m_target(std::move(target)), m_expr(expr), m_default_dynamic(use_dynamic),
+      m_exe_ctx_scope(exe_ctx_scope) {}
+
 lldb::ValueObjectSP DILInterpreter::DILEval(const DILASTNode *tree,
                                             lldb::TargetSP target_sp,
                                             Status &error) {
@@ -70,7 +248,7 @@ lldb::ValueObjectSP DILInterpreter::DILEvalNode(const DILASTNode *node) {
 void DILInterpreter::SetError(ErrorCode code, std::string error, uint32_t loc) {
   assert(m_error.Success() && "interpreter can error only once");
   m_error = Status((uint32_t)code, lldb::eErrorTypeGeneric,
-                   FormatDiagnostics(m_sm, error, loc));
+                   FormatDiagnostics(m_expr, error, loc));
 }
 
 void DILInterpreter::Visit(const ErrorNode *node) {
@@ -81,14 +259,14 @@ void DILInterpreter::Visit(const ErrorNode *node) {
 void DILInterpreter::Visit(const IdentifierNode *node) {
   std::shared_ptr<ExecutionContextScope> exe_ctx_scope =
       node->get_exe_context();
-  lldb::DynamicValueType use_dynamic = node->use_dynamic();
+  lldb::DynamicValueType use_dynamic = node->GetUseDynamic();
 
   std::unique_ptr<IdentifierInfo> identifier =
-      LookupIdentifier(node->name(), exe_ctx_scope, use_dynamic);
+      LookupIdentifier(node->GetName(), exe_ctx_scope, use_dynamic);
 
   if (!identifier) {
     std::string errMsg;
-    std::string name = node->name();
+    std::string name = node->GetName();
     if (name == "this")
       errMsg = "invalid use of 'this' outside of a non-static member function";
     else
diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp
index c63a83bea6f1df..79b699d0d2d2da 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -18,37 +18,24 @@ namespace lldb_private {
 namespace dil {
 
 const std::string DILToken::getTokenName(dil::TokenKind kind) {
-  std::string retval;
   switch (kind) {
   case dil::TokenKind::coloncolon:
-    retval = "coloncolon";
-    break;
+    return "coloncolon";
   case dil::TokenKind::eof:
-    retval = "eof";
-    break;
+    return "eof";
   case dil::TokenKind::identifier:
-    retval = "identifier";
-    break;
+    return "identifier";
   case dil::TokenKind::kw_namespace:
-    retval = "namespace";
-    break;
-  case dil::TokenKind::kw_this:
-    retval = "this";
-    break;
+    return "namespace";
   case dil::TokenKind::l_paren:
-    retval = "l_paren";
-    break;
+    return "l_paren";
   case dil::TokenKind::r_paren:
-    retval = "r_paren";
-    break;
+    return "r_paren";
   case dil::TokenKind::unknown:
-    retval = "unknown";
-    break;
+    return "unknown";
   default:
-    retval = "token_name";
-    break;
+    return "token_name";
   }
-  return retval;
 }
 
 static bool Is_Letter(char c) {
@@ -71,16 +58,15 @@ bool DILLexer::Is_Word(std::string::iterator start, uint32_t &length) {
   }
   if (length > 0)
     return true;
-  else
-    m_cur_pos = start;
+
+  m_cur_pos = start;
   return false;
 }
 
 void DILLexer::UpdateLexedTokens(DILToken &result, dil::TokenKind tok_kind,
-                                 std::string tok_str, uint32_t tok_pos,
-                                 uint32_t tok_len) {
+                                 std::string tok_str, uint32_t tok_pos) {
   DILToken new_token;
-  result.setValues(tok_kind, tok_str, tok_pos, tok_len);
+  result.setValues(tok_kind, tok_str, tok_pos);
   new_token = result;
   m_lexed_tokens.push_back(std::move(new_token));
 }
@@ -106,7 +92,7 @@ bool DILLexer::Lex(DILToken &result, bool look_ahead) {
 
   // Check to see if we've reached the end of our input string.
   if (m_cur_pos == m_expr.end()) {
-    UpdateLexedTokens(result, dil::TokenKind::eof, "", m_expr.length(), 0);
+    UpdateLexedTokens(result, dil::TokenKind::eof, "", m_expr.length());
     return retval;
   }
 
@@ -117,30 +103,28 @@ bool DILLexer::Lex(DILToken &result, bool look_ahead) {
   if (Is_Word(start, length)) {
     dil::TokenKind kind;
     std::string word = m_expr.substr(position, length);
-    if (word == "this")
-      kind = dil::TokenKind::kw_this;
-    else if (word == "namespace")
+    if (word == "namespace")
       kind = dil::TokenKind::kw_namespace;
     else
       kind = dil::TokenKind::identifier;
 
-    UpdateLexedTokens(result, kind, word, position, length);
+    UpdateLexedTokens(result, kind, word, position);
     return true;
   }
 
   switch (*m_cur_pos) {
   case '(':
     m_cur_pos++;
-    UpdateLexedTokens(result, dil::TokenKind::l_paren, "(", position, 1);
+    UpdateLexedTokens(result, dil::TokenKind::l_paren, "(", position);
     return true;
   case ')':
     m_cur_pos++;
-    UpdateLexedTokens(result, dil::TokenKind::r_paren, ")", position, 1);
+    UpdateLexedTokens(result, dil::TokenKind::r_paren, ")", position);
     return true;
   case ':':
     if (position + 1 < m_expr.size() && m_expr[position + 1] == ':') {
       m_cur_pos += 2;
-      UpdateLexedTokens(result, dil::TokenKind::coloncolon, "::", position, 2);
+      UpdateLexedTokens(result, dil::TokenKind::coloncolon, "::", position);
       return true;
     }
     break;
@@ -148,7 +132,7 @@ bool DILLexer::Lex(DILToken &result, bool look_ahead) {
     break;
   }
   // Empty Token
-  result.setValues(dil::TokenKind::none, "", m_expr.length(), 0);
+  result.setValues(dil::TokenKind::none, "", m_expr.length());
   return false;
 }
 
@@ -172,10 +156,11 @@ const DILToken &DILLexer::LookAhead(uint32_t N) {
   };
 
   if (remaining_tokens > 0) {
-    m_invalid_token.setValues(dil::TokenKind::invalid, "", 0, 0);
+    m_invalid_token.setValues(dil::TokenKind::invalid, "", 0);
     return m_invalid_token;
-  } else
-    return m_lexed_tokens[m_tokens_idx + N + 1];
+  }
+
+  return m_lexed_tokens[m_tokens_idx + N + 1];
 }
 
 const DILToken &DILLexer::AcceptLookAhead(uint32_t N) {
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index eb36de80be76a5..147a76ba8f9d63 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -12,19 +12,16 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/ValueObject/DILParser.h"
-
-#include <limits.h>
-#include <stdlib.h>
-
-#include <memory>
-#include <sstream>
-#include <string>
-
 #include "lldb/Target/ExecutionContextScope.h"
 #include "lldb/ValueObject/DILAST.h"
 #include "lldb/ValueObject/DILEval.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/FormatAdapters.h"
+#include <limits.h>
+#include <memory>
+#include <sstream>
+#include <stdlib.h>
+#include <string>
 
 namespace lldb_private {
 
@@ -50,10 +47,9 @@ inline std::string TokenKindsJoin(dil::TokenKind k, Ts... ks) {
   return os.str();
 }
 
-std::string FormatDiagnostics(std::shared_ptr<std::string> input_expr,
-                              const std::string &message, uint32_t loc) {
+std::string FormatDiagnostics(llvm::StringRef text, const std::string &message,
+                              uint32_t loc) {
   // Get the source buffer and the location of the current token.
-  llvm::StringRef text(*input_expr);
   size_t loc_offset = (size_t)loc;
 
   // Look for the start of the line.
@@ -79,7 +75,7 @@ std::string FormatDiagnostics(std::shared_ptr<std::string> input_expr,
                        llvm::fmt_pad("^", arrow - 1, arrow_rpad));
 }
 
-DILParser::DILParser(std::shared_ptr<std::string> dil_input_expr,
+DILParser::DILParser(llvm::StringRef dil_input_expr,
                      std::shared_ptr<ExecutionContextScope> exe_ctx_scope,
                      lldb::DynamicValueType use_dynamic, bool use_synthetic,
                      bool fragile_ivar, bool check_ptr_vs_member)
@@ -106,10 +102,9 @@ DILASTNodeUP DILParser::Run(Status &error) {
   // Explicitly return ErrorNode if there was an error during the parsing.
   // Some routines raise an error, but don't change the return value (e.g.
   // Expect).
-  if (error.Fail()) {
-    CompilerType bad_type;
-    return std::make_unique<ErrorNode>(bad_type);
-  }
+  if (error.Fail())
+    return std::make_unique<ErrorNode>();
+
   return expr;
 }
 
@@ -128,7 +123,6 @@ DILASTNodeUP DILParser::ParseExpression() { return ParsePrimaryExpression(); }
 //    "(" expression ")"
 //
 DILASTNodeUP DILParser::ParsePrimaryExpression() {
-  CompilerType bad_type;
   if (m_dil_token.isOneOf(dil::TokenKind::coloncolon,
                           dil::TokenKind::identifier)) {
     // Save the source location for the diagnostics message.
@@ -137,14 +131,6 @@ DILASTNodeUP DILParser::ParsePrimaryExpression() {
 
     return std::make_unique<IdentifierNode>(loc, identifier, m_use_dynamic,
                                             m_ctx_scope);
-  } else if (m_dil_token.is(dil::TokenKind::kw_this)) {
-    // Save the source location for the diagnostics message.
-    uint32_t loc = m_dil_token.getLocation();
-    ConsumeToken();
-
-    // Special case for "this" pointer. As per C++ standard, it's a prvalue.
-    return std::make_unique<IdentifierNode>(loc, "this", m_use_dynamic,
-                                            m_ctx_scope);
   } else if (m_dil_token.is(dil::TokenKind::l_paren)) {
     ConsumeToken();
     auto expr = ParseExpression();
@@ -156,7 +142,7 @@ DILASTNodeUP DILParser::ParsePrimaryExpression() {
   BailOut(ErrorCode::kInvalidExpressionSyntax,
           llvm::formatv("Unexpected token: {0}", TokenDescription(m_dil_token)),
           m_dil_token.getLocation());
-  return std::make_unique<ErrorNode>(bad_type);
+  return std::make_unique<ErrorNode>();
 }
 
 // Parse nested_name_specifier.
@@ -182,7 +168,7 @@ std::string DILParser::ParseNestedNameSpecifier() {
     // Look for all the pieces, in order:
     // l_paren 'anonymous' 'namespace' r_paren coloncolon
     if (m_dil_lexer.LookAhead(0).is(dil::TokenKind::identifier) &&
-        (((DILToken)m_dil_lexer.LookAhead(0)).getSpelling() == "anonymous") &&
+        ((m_dil_lexer.LookAhead(0)).getSpelling() == "anonymous") &&
         m_dil_lexer.LookAhead(1).is(dil::TokenKind::kw_namespace) &&
         m_dil_lexer.LookAhead(2).is(dil::TokenKind::r_paren) &&
         m_dil_lexer.LookAhead(3).is(dil::TokenKind::coloncolon)) {
@@ -199,9 +185,9 @@ std::string DILParser::ParseNestedNameSpecifier() {
         ConsumeToken();
       }
       return "(anonymous namespace)::" + identifier2;
-    } else {
-      return "";
     }
+
+    return "";
   } // end of special handling for '(anonymous namespace)'
 
   // If the next token is scope ("::"), then this is indeed a
@@ -329,25 +315,9 @@ void DILParser::Expect(dil::TokenKind kind) {
   }
 }
 
-template <typename... Ts>
-void DILParser::ExpectOneOf(dil::TokenKind k, Ts... ks) {
-  static_assert((std::is_same_v<Ts, dil::TokenKind> && ...),
-                "ExpectOneOf can be only called with values of type "
-                "dil::TokenKind");
-
-  if (!m_dil_token.isOneOf(k, ks...)) {
-    BailOut(ErrorCode::kUnknown,
-            llvm::formatv("expected any of ({0}), got: {1}",
-                          TokenKindsJoin(k, ks...),
-                          TokenDescription(m_dil_token)),
-            m_dil_token.getLocation());
-  }
-}
-
 std::string DILParser::TokenDescription(const DILToken &token) {
-  const auto &spelling = ((DILToken)token).getSpelling();
-  const std::string kind_name =
-      DILToken::getTokenName(((DILToken)token).getKind());
+  const auto &spelling = token.getSpelling();
+  const std::string kind_name = DILToken::getTokenName(token.getKind());
   return llvm::formatv("<'{0}' ({1})>", spelling, kind_name);
 }
 
diff --git a/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py b/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py
index b87de2ab27ebb2..252dcacb13bbd9 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/GlobalVariableLookup/TestFrameVarDILGlobalVariableLookup.py
@@ -67,12 +67,8 @@ def do_test(self):
 
         self.expect("frame variable 'externGlobalVar'", error=True,
                     substrs=["use of undeclared identifier"])  # 0x00C0FFEE
-                    #substrs=["no variable named 'externGlobalVar' found in this frame"])  # 0x00C0FFEE
         self.expect("frame variable '::externGlobalVar'", error=True,
                     substrs=["use of undeclared identifier"]) # ["12648430"])
-                    #substrs=["no variable named '::externGlobalVar' found in this frame"]) # ["12648430"])
-        # "use of undeclared identifier"
-
         self.expect("frame variable 'ns::globalVar'", substrs=["13"])
         self.expect("frame variable 'ns::globalPtr'",
                     patterns=["0x[0-9]+"])
diff --git a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
index c19f09f2f06b68..b2f1d3a07912ac 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
@@ -56,7 +56,6 @@ def do_test(self):
         command_result = lldb.SBCommandReturnObject()
         interp = self.dbg.GetCommandInterpreter()
 
-        # Test 'a' is 1
         self.expect("settings set target.experimental.use-DIL true",
                     substrs=[""])
         self.expect("frame variable a", substrs=["1"])
diff --git a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/main.cpp
index c0dd24291429a3..21f0fd6d62c4af 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/main.cpp
+++ b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/main.cpp
@@ -9,18 +9,3 @@ main(int argc, char **argv)
 
   return 0; // Set a breakpoint here
 }
-
-/*
-TEST_F(EvalTest, TestLocalVariables) {
-  EXPECT_THAT(Eval("a"), IsEqual("1"));
-  EXPECT_THAT(Eval("b"), IsEqual("2"));
-  EXPECT_THAT(Eval("a + b"), IsEqual("3"));
-
-  EXPECT_THAT(Eval("c + 1"), IsEqual("-2"));
-  EXPECT_THAT(Eval("s + 1"), IsEqual("5"));
-  EXPECT_THAT(Eval("c + s"), IsEqual("1"));
-
-  EXPECT_THAT(Eval("__test_non_variable + 1"),
-              IsError("use of undeclared identifier '__test_non_variable'"));
-}
-*/



More information about the lldb-commits mailing list