1 //===- LLDBPropertyDefEmitter.cpp -----------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // These tablegen backends emits LLDB's PropertyDefinition values.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "LLDBTableGenBackends.h"
14 #include "LLDBTableGenUtils.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/TableGen/Record.h"
17 #include "llvm/TableGen/StringMatcher.h"
18 #include "llvm/TableGen/TableGenBackend.h"
19 #include <vector>
20 
21 using namespace llvm;
22 using namespace lldb_private;
23 
24 static void emitPropertyEnum(Record *Property, raw_ostream &OS) {
25   OS << "eProperty";
26   OS << Property->getName();
27   OS << ",\n";
28 }
29 
30 static void emitProperty(Record *Property, raw_ostream &OS) {
31   OS << "  {";
32 
33   // Emit the property name.
34   OS << "\"" << Property->getValueAsString("Name") << "\"";
35   OS << ", ";
36 
37   // Emit the property type.
38   OS << "OptionValue::eType";
39   OS << Property->getValueAsString("Type");
40   OS << ", ";
41 
42   // Emit the property's global value.
43   OS << (Property->getValue("Global") ? "true" : "false");
44   OS << ", ";
45 
46   bool hasDefaultUnsignedValue = Property->getValue("HasDefaultUnsignedValue");
47   bool hasDefaultEnumValue = Property->getValue("HasDefaultEnumValue");
48   bool hasDefaultStringValue = Property->getValue("HasDefaultStringValue");
49   bool hasDefaultBooleanValue = Property->getValue("HasDefaultBooleanValue");
50 
51   // Guarantee that every property has a default value.
52   assert((hasDefaultUnsignedValue || hasDefaultEnumValue ||
53           hasDefaultStringValue) &&
54          "Property must have a default value");
55 
56   // Guarantee that no property has both a default unsigned value and a default
57   // enum value, since they're bothed stored in the same field.
58   assert(!(hasDefaultUnsignedValue && hasDefaultEnumValue) &&
59          "Property cannot have both a unsigned and enum default value.");
60 
61   // Guarantee that every boolean property has a boolean default value.
62   assert(!(Property->getValueAsString("Type") == "Boolean" &&
63            !hasDefaultBooleanValue) &&
64          "Boolean property must have a boolean default value.");
65 
66   // Guarantee that every string property has a string default value.
67   assert(!(Property->getValueAsString("Type") == "String" &&
68            !hasDefaultStringValue) &&
69          "String property must have a string default value.");
70 
71   // Guarantee that every enum property has an enum default value.
72   assert(
73       !(Property->getValueAsString("Type") == "Enum" && !hasDefaultEnumValue) &&
74       "Enum property must have a enum default value.");
75 
76   // Emit the default uint value.
77   if (hasDefaultUnsignedValue) {
78     OS << std::to_string(Property->getValueAsInt("DefaultUnsignedValue"));
79   } else if (hasDefaultEnumValue) {
80     OS << Property->getValueAsString("DefaultEnumValue");
81   } else {
82     OS << "0";
83   }
84   OS << ", ";
85 
86   // Emit the default string value.
87   if (hasDefaultStringValue) {
88     if (auto D = Property->getValue("DefaultStringValue")) {
89       OS << "\"";
90       OS << D->getValue()->getAsUnquotedString();
91       OS << "\"";
92     } else {
93       OS << "\"\"";
94     }
95   } else {
96     OS << "nullptr";
97   }
98   OS << ", ";
99 
100   // Emit the enum values value.
101   if (Property->getValue("EnumValues"))
102     OS << Property->getValueAsString("EnumValues");
103   else
104     OS << "{}";
105   OS << ", ";
106 
107   // Emit the property description.
108   if (auto D = Property->getValue("Description")) {
109     OS << "\"";
110     OS << D->getValue()->getAsUnquotedString();
111     OS << "\"";
112   } else {
113     OS << "\"\"";
114   }
115 
116   OS << "},\n";
117 }
118 
119 /// Emits all property initializers to the raw_ostream.
120 static void emityProperties(std::string PropertyName,
121                             std::vector<Record *> PropertyRecords,
122                             raw_ostream &OS) {
123   // Generate the macro that the user needs to define before including the
124   // *.inc file.
125   std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName;
126   std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_');
127 
128   // All options are in one file, so we need put them behind macros and ask the
129   // user to define the macro for the options that are needed.
130   OS << "// Property definitions for " << PropertyName << "\n";
131   OS << "#ifdef " << NeededMacro << "\n";
132   OS << "static constexpr PropertyDefinition g_" << PropertyName
133      << "_properties[] = {\n";
134   for (Record *R : PropertyRecords)
135     emitProperty(R, OS);
136   OS << "};\n";
137   // We undefine the macro for the user like Clang's include files are doing it.
138   OS << "#undef " << NeededMacro << "\n";
139   OS << "#endif // " << PropertyName << " Property\n\n";
140 }
141 
142 /// Emits all property initializers to the raw_ostream.
143 static void emitPropertyEnum(std::string PropertyName,
144                              std::vector<Record *> PropertyRecords,
145                              raw_ostream &OS) {
146   // Generate the macro that the user needs to define before including the
147   // *.inc file.
148   std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName;
149   std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_');
150 
151   // All options are in one file, so we need put them behind macros and ask the
152   // user to define the macro for the options that are needed.
153   OS << "// Property enum cases for " << PropertyName << "\n";
154   OS << "#ifdef " << NeededMacro << "\n";
155   for (Record *R : PropertyRecords)
156     emitPropertyEnum(R, OS);
157   // We undefine the macro for the user like Clang's include files are doing it.
158   OS << "#undef " << NeededMacro << "\n";
159   OS << "#endif // " << PropertyName << " Property\n\n";
160 }
161 
162 void lldb_private::EmitPropertyDefs(RecordKeeper &Records, raw_ostream &OS) {
163   emitSourceFileHeader("Property definitions for LLDB.", OS);
164 
165   std::vector<Record *> Properties =
166       Records.getAllDerivedDefinitions("Property");
167   for (auto &PropertyRecordPair : getRecordsByName(Properties, "Definition")) {
168     emityProperties(PropertyRecordPair.first, PropertyRecordPair.second, OS);
169   }
170 }
171 
172 void lldb_private::EmitPropertyEnumDefs(RecordKeeper &Records,
173                                         raw_ostream &OS) {
174   emitSourceFileHeader("Property definition enum for LLDB.", OS);
175 
176   std::vector<Record *> Properties =
177       Records.getAllDerivedDefinitions("Property");
178   for (auto &PropertyRecordPair : getRecordsByName(Properties, "Definition")) {
179     emitPropertyEnum(PropertyRecordPair.first, PropertyRecordPair.second, OS);
180   }
181 }
182