1 //===-- PostfixExpressionTest.cpp -----------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Symbol/PostfixExpression.h"
10 #include "lldb/Utility/DataExtractor.h"
11 #include "lldb/Utility/StreamString.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/DebugInfo/DIContext.h"
14 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
15 #include "llvm/Support/FormatVariadic.h"
16 #include "llvm/Support/raw_ostream.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
20 using namespace lldb_private
;
21 using namespace lldb_private::postfix
;
23 static std::string
ToString(BinaryOpNode::OpType type
) {
25 case BinaryOpNode::Align
:
27 case BinaryOpNode::Minus
:
29 case BinaryOpNode::Plus
:
32 llvm_unreachable("Fully covered switch!");
35 static std::string
ToString(UnaryOpNode::OpType type
) {
37 case UnaryOpNode::Deref
:
40 llvm_unreachable("Fully covered switch!");
43 struct ASTPrinter
: public Visitor
<std::string
> {
45 std::string
Visit(BinaryOpNode
&binary
, Node
*&) override
{
47 llvm::formatv("{0}({1}, {2})", ToString(binary
.GetOpType()),
48 Dispatch(binary
.Left()), Dispatch(binary
.Right())));
51 std::string
Visit(InitialValueNode
&, Node
*&) override
{ return "InitialValue"; }
53 std::string
Visit(IntegerNode
&integer
, Node
*&) override
{
54 return std::string(llvm::formatv("int({0})", integer
.GetValue()));
57 std::string
Visit(RegisterNode
®
, Node
*&) override
{
58 return std::string(llvm::formatv("reg({0})", reg
.GetRegNum()));
61 std::string
Visit(SymbolNode
&symbol
, Node
*&) override
{
62 return std::string(symbol
.GetName());
65 std::string
Visit(UnaryOpNode
&unary
, Node
*&) override
{
66 return std::string(llvm::formatv("{0}({1})", ToString(unary
.GetOpType()),
67 Dispatch(unary
.Operand())));
71 static std::string
Print(Node
*node
) {
73 return ASTPrinter().Dispatch(node
);
78 static std::string
ParseOneAndStringify(llvm::StringRef expr
) {
79 llvm::BumpPtrAllocator alloc
;
80 return ASTPrinter::Print(ParseOneExpression(expr
, alloc
));
83 TEST(PostfixExpression
, ParseOneExpression
) {
84 EXPECT_EQ("int(47)", ParseOneAndStringify("47"));
85 EXPECT_EQ("$foo", ParseOneAndStringify("$foo"));
86 EXPECT_EQ("+(int(1), int(2))", ParseOneAndStringify("1 2 +"));
87 EXPECT_EQ("-(int(1), int(2))", ParseOneAndStringify("1 2 -"));
88 EXPECT_EQ("@(int(1), int(2))", ParseOneAndStringify("1 2 @"));
89 EXPECT_EQ("+(int(1), +(int(2), int(3)))", ParseOneAndStringify("1 2 3 + +"));
90 EXPECT_EQ("+(+(int(1), int(2)), int(3))", ParseOneAndStringify("1 2 + 3 +"));
91 EXPECT_EQ("^(int(1))", ParseOneAndStringify("1 ^"));
92 EXPECT_EQ("^(^(int(1)))", ParseOneAndStringify("1 ^ ^"));
93 EXPECT_EQ("^(+(int(1), ^(int(2))))", ParseOneAndStringify("1 2 ^ + ^"));
94 EXPECT_EQ("-($foo, int(47))", ParseOneAndStringify("$foo 47 -"));
95 EXPECT_EQ("+(int(47), int(-42))", ParseOneAndStringify("47 -42 +"));
97 EXPECT_EQ("nullptr", ParseOneAndStringify("+"));
98 EXPECT_EQ("nullptr", ParseOneAndStringify("^"));
99 EXPECT_EQ("nullptr", ParseOneAndStringify("1 +"));
100 EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 ^"));
101 EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 3 +"));
102 EXPECT_EQ("nullptr", ParseOneAndStringify("^ 1"));
103 EXPECT_EQ("nullptr", ParseOneAndStringify("+ 1 2"));
104 EXPECT_EQ("nullptr", ParseOneAndStringify("1 + 2"));
105 EXPECT_EQ("nullptr", ParseOneAndStringify("1 2"));
106 EXPECT_EQ("nullptr", ParseOneAndStringify(""));
109 static std::vector
<std::pair
<std::string
, std::string
>>
110 ParseFPOAndStringify(llvm::StringRef prog
) {
111 llvm::BumpPtrAllocator alloc
;
112 std::vector
<std::pair
<llvm::StringRef
, Node
*>> parsed
=
113 ParseFPOProgram(prog
, alloc
);
114 std::vector
<std::pair
<std::string
, std::string
>> result
;
115 for (const auto &p
: parsed
)
116 result
.emplace_back(p
.first
.str(), ASTPrinter::Print(p
.second
));
120 TEST(PostfixExpression
, ParseFPOProgram
) {
121 EXPECT_THAT(ParseFPOAndStringify("a 1 ="),
122 testing::ElementsAre(std::make_pair("a", "int(1)")));
123 EXPECT_THAT(ParseFPOAndStringify("a 1 = b 2 3 + ="),
124 testing::ElementsAre(std::make_pair("a", "int(1)"),
125 std::make_pair("b", "+(int(2), int(3))")));
127 EXPECT_THAT(ParseFPOAndStringify(""), testing::IsEmpty());
128 EXPECT_THAT(ParseFPOAndStringify("="), testing::IsEmpty());
129 EXPECT_THAT(ParseFPOAndStringify("a 1"), testing::IsEmpty());
130 EXPECT_THAT(ParseFPOAndStringify("a 1 = ="), testing::IsEmpty());
131 EXPECT_THAT(ParseFPOAndStringify("a 1 + ="), testing::IsEmpty());
132 EXPECT_THAT(ParseFPOAndStringify("= a 1 ="), testing::IsEmpty());
135 static std::string
ParseAndGenerateDWARF(llvm::StringRef expr
) {
136 llvm::BumpPtrAllocator alloc
;
137 Node
*ast
= ParseOneExpression(expr
, alloc
);
139 return "Parse failed.";
140 if (!ResolveSymbols(ast
, [&](SymbolNode
&symbol
) -> Node
* {
141 if (symbol
.GetName() == "INIT")
142 return MakeNode
<InitialValueNode
>(alloc
);
145 if (to_integer(symbol
.GetName().drop_front(), num
))
146 return MakeNode
<RegisterNode
>(alloc
, num
);
149 return "Resolution failed.";
152 const size_t addr_size
= 4;
153 StreamString
dwarf(Stream::eBinary
, addr_size
, lldb::eByteOrderLittle
);
154 ToDWARF(*ast
, dwarf
);
156 // print dwarf expression to comparable textual representation
157 llvm::DataExtractor
extractor(dwarf
.GetString(), /*IsLittleEndian=*/true,
161 llvm::raw_string_ostream
os(result
);
162 llvm::DWARFExpression(extractor
, addr_size
, llvm::dwarf::DWARF32
)
163 .print(os
, llvm::DIDumpOptions(), nullptr);
164 return std::move(os
.str());
167 TEST(PostfixExpression
, ToDWARF
) {
168 EXPECT_EQ("DW_OP_consts +0", ParseAndGenerateDWARF("0"));
170 EXPECT_EQ("DW_OP_breg1 +0", ParseAndGenerateDWARF("R1"));
172 EXPECT_EQ("DW_OP_bregx 0x41 +0", ParseAndGenerateDWARF("R65"));
174 EXPECT_EQ("DW_OP_pick 0x0", ParseAndGenerateDWARF("INIT"));
176 EXPECT_EQ("DW_OP_pick 0x0, DW_OP_pick 0x1, DW_OP_plus",
177 ParseAndGenerateDWARF("INIT INIT +"));
179 EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x1, DW_OP_plus",
180 ParseAndGenerateDWARF("R1 INIT +"));
182 EXPECT_EQ("DW_OP_consts +1, DW_OP_pick 0x1, DW_OP_deref, DW_OP_plus",
183 ParseAndGenerateDWARF("1 INIT ^ +"));
185 EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_plus",
186 ParseAndGenerateDWARF("4 5 +"));
188 EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_minus",
189 ParseAndGenerateDWARF("4 5 -"));
191 EXPECT_EQ("DW_OP_consts +4, DW_OP_deref", ParseAndGenerateDWARF("4 ^"));
193 EXPECT_EQ("DW_OP_breg6 +0, DW_OP_consts +128, DW_OP_lit1, DW_OP_minus, "
194 "DW_OP_not, DW_OP_and",
195 ParseAndGenerateDWARF("R6 128 @"));