Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions lldb/docs/dil-expr-lang.ebnf
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
(* This is currently a subset of the final DIL Language, matching the current
DIL implementation. *)

expression = unary_expression ;
expression = cast_expression;

cast_expression = unary_expression
| "(" type_id ")" cast_expression;

unary_expression = postfix_expression
| unary_operator expression ;
| unary_operator cast_expression ;

unary_operator = "*" | "&" ;

Expand Down Expand Up @@ -44,6 +47,31 @@ nested_name_specifier = type_name "::"
| namespace_name '::'
| nested_name_specifier identifier "::" ;

type_id = type_specifier_seq [abstract_declarator] ;

type_specifier_seq = type_specifier [type_specifier];

type_specifier = ["::"] [nested_name_specifier] type_name;
| "char"
| "bool"
| "short"
| "int"
| "long"
| "signed"
| "unsigned"
| "float"
| "double"
| "void" ;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I have a problem with hardcoding C type names in the grammar itself. I believe this should be an identifier and it should be up to TypeSystem to recognize these. Is that feasible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is in fact the way the (updated) implementation works: Just expecting identifiers and using calls to LLDB's type system to determine if the name is for a builtin type or not. I just forgot to update the grammar here when I changed the implementation to work that way. I will update the grammar (thanks for catching this).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See DILParser::ParseBuiltinType, around line 396 of DILParser.cpp


nested_name_specifier = type_name "::"
| namespace_name "::"
| nested_name_specifier identifier "::" ;

abstract_declarator = ptr_operator [abstract_declarator] ;

ptr_operator = "*"
| "&";

type_name = class_name
| enum_name
| typedef_name;
Expand Down
41 changes: 41 additions & 0 deletions lldb/include/lldb/ValueObject/DILAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum class NodeKind {
eArraySubscriptNode,
eBitExtractionNode,
eBooleanLiteralNode,
eCStyleCastNode,
eErrorNode,
eFloatLiteralNode,
eIdentifierNode,
Expand All @@ -29,6 +30,21 @@ enum class NodeKind {
eUnaryOpNode,
};

/// The C-Style casts allowed by DIL.
enum class CStyleCastKind {
eEnumeration,
eNullptr,
eReference,
eNone,
};

/// Promotions for C-Style casts in DIL.
enum class CastPromoKind {
eArithmetic,
ePointer,
eNone,
};

/// The Unary operators recognized by DIL.
enum class UnaryOpKind {
AddrOf, // "&"
Expand Down Expand Up @@ -244,6 +260,29 @@ class BooleanLiteralNode : public ASTNode {
bool m_value;
};

class CStyleCastNode : public ASTNode {
public:
CStyleCastNode(uint32_t location, CompilerType type, ASTNodeUP operand,
CStyleCastKind kind)
: ASTNode(location, NodeKind::eCStyleCastNode), m_type(type),
m_operand(std::move(operand)), m_cast_kind(kind) {}

llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;

CompilerType GetType() const { return m_type; }
ASTNode *GetOperand() const { return m_operand.get(); }
CStyleCastKind GetCastKind() const { return m_cast_kind; }

static bool classof(const ASTNode *node) {
return node->GetKind() == NodeKind::eCStyleCastNode;
}

private:
CompilerType m_type;
ASTNodeUP m_operand;
CStyleCastKind m_cast_kind;
};

/// 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
Expand All @@ -267,6 +306,8 @@ class Visitor {
Visit(const FloatLiteralNode *node) = 0;
virtual llvm::Expected<lldb::ValueObjectSP>
Visit(const BooleanLiteralNode *node) = 0;
virtual llvm::Expected<lldb::ValueObjectSP>
Visit(const CStyleCastNode *node) = 0;
};

} // namespace lldb_private::dil
Expand Down
7 changes: 7 additions & 0 deletions lldb/include/lldb/ValueObject/DILEval.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,19 @@ class Interpreter : Visitor {
Visit(const FloatLiteralNode *node) override;
llvm::Expected<lldb::ValueObjectSP>
Visit(const BooleanLiteralNode *node) override;
llvm::Expected<lldb::ValueObjectSP>
Visit(const CStyleCastNode *node) override;

llvm::Expected<CompilerType>
PickIntegerType(lldb::TypeSystemSP type_system,
std::shared_ptr<ExecutionContextScope> ctx,
const IntegerLiteralNode *literal);

llvm::Expected<CompilerType>
VerifyCStyleCastType(lldb::ValueObjectSP &operand, CompilerType &op_type,
CompilerType target_type, CastPromoKind &promo_kind,
CStyleCastKind &cast_kind, int location);

// Used by the interpreter to create objects, perform casts, etc.
lldb::TargetSP m_target;
llvm::StringRef m_expr;
Expand Down
131 changes: 131 additions & 0 deletions lldb/include/lldb/ValueObject/DILParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLDB_VALUEOBJECT_DILPARSER_H

#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Utility/DiagnosticsRendering.h"
#include "lldb/Utility/Status.h"
#include "lldb/ValueObject/DILAST.h"
Expand All @@ -31,6 +32,9 @@ enum class ErrorCode : unsigned char {
kUnknown,
};

llvm::Expected<lldb::TypeSystemSP>
DILGetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering, do we need the DIL prefix here? It just retrieves the type system from the compile unit, nothing specific to DIL itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough; I'll remove it.


// The following is modeled on class OptionParseError.
class DILDiagnosticError
: public llvm::ErrorInfo<DILDiagnosticError, DiagnosticError> {
Expand All @@ -55,6 +59,61 @@ class DILDiagnosticError

std::string message() const override { return m_detail.rendered; }
};
/// TypeDeclaration builds information about the literal type definition as
/// type is being parsed. It doesn't perform semantic analysis for non-basic
/// types -- e.g. "char&&&" is a valid type declaration.
/// NOTE: CV qualifiers are ignored.
class TypeDeclaration {
public:
enum class TypeSpecifier {
kBool,
kChar,
kDouble,
kFloat,
kInt,
kLong,
kLongDouble,
kLongLong,
kShort,
kUnknown,
kVoid,
};

enum class SignSpecifier {
kUnknown,
kSigned,
kUnsigned,
};

bool IsEmpty() const { return !m_is_builtin && !m_is_user_type; }

lldb::BasicType GetBasicType() const;

public:
// Indicates user-defined typename (e.g. "MyClass", "MyTmpl<int>").
std::string m_user_typename;

// Basic type specifier ("void", "char", "intr", "float", "long long", etc.).
TypeSpecifier m_type_specifier = TypeSpecifier::kUnknown;

// Signedness specifier ("signed", "unsigned").
SignSpecifier m_sign_specifier = SignSpecifier::kUnknown;

// Does the type declaration includes "int" specifier?
// This is different than `type_specifier_` and is used to detect "int"
// duplication for types that can be combined with "int" specifier (e.g.
// "short int", "long int").
bool m_has_int_specifier = false;

// Indicates whether there was an error during parsing.
bool m_has_error = false;

// Indicates whether this declaration describes a builtin type.
bool m_is_builtin = false;

// Indicates whether this declaration describes a user type.
bool m_is_user_type = false;
}; // class TypeDeclaration

/// Pure recursive descent parser for C++ like expressions.
/// EBNF grammar for the parser is described in lldb/docs/dil-expr-lang.ebnf
Expand Down Expand Up @@ -101,6 +160,16 @@ class DILParser {
ASTNodeUP ParseFloatingPointLiteral();
ASTNodeUP ParseBooleanLiteral();

ASTNodeUP ParseCastExpression();
std::optional<CompilerType> ParseTypeId(bool must_be_type_id = false);
void ParseTypeSpecifierSeq(TypeDeclaration *type_decl);
bool ParseTypeSpecifier(TypeDeclaration *type_decl);
std::string ParseTypeName();
CompilerType ResolveTypeDeclarators(CompilerType type,
const std::vector<Token> &ptr_operators);
bool IsSimpleTypeSpecifierKeyword(Token token) const;
bool HandleSimpleTypeSpecifier(TypeDeclaration *type_decl);

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

void Expect(Token::Kind kind);
Expand Down Expand Up @@ -135,4 +204,66 @@ class DILParser {

} // namespace lldb_private::dil

namespace llvm {
template <>
struct format_provider<lldb_private::dil::TypeDeclaration::TypeSpecifier> {
static void format(const lldb_private::dil::TypeDeclaration::TypeSpecifier &t,
raw_ostream &OS, llvm::StringRef Options) {
switch (t) {
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kVoid:
OS << "void";
break;
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kBool:
OS << "bool";
break;
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kChar:
OS << "char";
break;
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kInt:
OS << "int";
break;
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kFloat:
OS << "float";
break;
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kShort:
OS << "short";
break;
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLong:
OS << "long";
break;
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLongLong:
OS << "long long";
break;
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kDouble:
OS << "double";
break;
case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLongDouble:
OS << "long double";
break;
default:
OS << "invalid type specifier";
break;
}
}
};

template <>
struct format_provider<lldb_private::dil::TypeDeclaration::SignSpecifier> {
static void format(const lldb_private::dil::TypeDeclaration::SignSpecifier &t,
raw_ostream &OS, llvm::StringRef Options) {
switch (t) {
case lldb_private::dil::TypeDeclaration::SignSpecifier::kSigned:
OS << "signed";
break;
case lldb_private::dil::TypeDeclaration::SignSpecifier::kUnsigned:
OS << "unsigned";
break;
default:
OS << "invalid sign specifier";
break;
}
}
};
} // namespace llvm

#endif // LLDB_VALUEOBJECT_DILPARSER_H
4 changes: 4 additions & 0 deletions lldb/source/ValueObject/DILAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ BooleanLiteralNode::Accept(Visitor *v) const {
return v->Visit(this);
}

llvm::Expected<lldb::ValueObjectSP> CStyleCastNode::Accept(Visitor *v) const {
return v->Visit(this);
}

} // namespace lldb_private::dil
Loading
Loading