xref: /freebsd/contrib/llvm-project/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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   llvm::StringRef type = Property->getValueAsString("Type");
39   OS << "OptionValue::eType";
40   OS << type;
41   OS << ", ";
42 
43   // Emit the property's global value.
44   OS << (Property->getValue("Global") ? "true" : "false");
45   OS << ", ";
46 
47   bool hasDefaultUnsignedValue = Property->getValue("HasDefaultUnsignedValue");
48   bool hasDefaultEnumValue = Property->getValue("HasDefaultEnumValue");
49   bool hasDefaultStringValue = Property->getValue("HasDefaultStringValue");
50   bool hasElementType = Property->getValue("HasElementType");
51 
52   // Guarantee that every property has a default value.
53   assert((hasDefaultUnsignedValue || hasDefaultEnumValue ||
54           hasDefaultStringValue || hasElementType) &&
55          "Property must have a default value or an element type");
56 
57   // Guarantee that no property has both a default unsigned value and a default
58   // enum value, since they're bothed stored in the same field.
59   assert(!(hasDefaultUnsignedValue && hasDefaultEnumValue) &&
60          "Property cannot have both a unsigned and enum default value.");
61 
62   // Guarantee that every boolean property has a boolean default value.
63   assert(!(Property->getValueAsString("Type") == "Boolean" &&
64            !Property->getValue("HasDefaultBooleanValue")) &&
65          "Boolean property must have a boolean default value.");
66 
67   // Guarantee that every string property has a string default value.
68   assert(!(Property->getValueAsString("Type") == "String" &&
69            !hasDefaultStringValue) &&
70          "String property must have a string default value.");
71 
72   // Guarantee that every enum property has an enum default value.
73   assert(
74       !(Property->getValueAsString("Type") == "Enum" && !hasDefaultEnumValue) &&
75       "Enum property must have a enum default value.");
76 
77   // Guarantee that only arrays and dictionaries have an element type;
78   assert(((type != "Array" && type != "Dictionary") || hasElementType) &&
79          "Only dictionaries and arrays can have an element type.");
80 
81   // Emit the default uint value.
82   if (hasDefaultUnsignedValue) {
83     OS << std::to_string(Property->getValueAsInt("DefaultUnsignedValue"));
84   } else if (hasDefaultEnumValue) {
85     OS << Property->getValueAsString("DefaultEnumValue");
86   } else if (hasElementType) {
87     OS << "OptionValue::eType";
88     OS << Property->getValueAsString("ElementType");
89   } else {
90     OS << "0";
91   }
92   OS << ", ";
93 
94   // Emit the default string value.
95   if (hasDefaultStringValue) {
96     if (auto D = Property->getValue("DefaultStringValue")) {
97       OS << "\"";
98       OS << D->getValue()->getAsUnquotedString();
99       OS << "\"";
100     } else {
101       OS << "\"\"";
102     }
103   } else {
104     OS << "nullptr";
105   }
106   OS << ", ";
107 
108   // Emit the enum values value.
109   if (Property->getValue("EnumValues"))
110     OS << Property->getValueAsString("EnumValues");
111   else
112     OS << "{}";
113   OS << ", ";
114 
115   // Emit the property description.
116   if (auto D = Property->getValue("Description")) {
117     OS << "\"";
118     OS << D->getValue()->getAsUnquotedString();
119     OS << "\"";
120   } else {
121     OS << "\"\"";
122   }
123 
124   OS << "},\n";
125 }
126 
127 /// Emits all property initializers to the raw_ostream.
128 static void emityProperties(std::string PropertyName,
129                             std::vector<Record *> PropertyRecords,
130                             raw_ostream &OS) {
131   // Generate the macro that the user needs to define before including the
132   // *.inc file.
133   std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName;
134   std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_');
135 
136   // All options are in one file, so we need put them behind macros and ask the
137   // user to define the macro for the options that are needed.
138   OS << "// Property definitions for " << PropertyName << "\n";
139   OS << "#ifdef " << NeededMacro << "\n";
140   OS << "static constexpr PropertyDefinition g_" << PropertyName
141      << "_properties[] = {\n";
142   for (Record *R : PropertyRecords)
143     emitProperty(R, OS);
144   OS << "};\n";
145   // We undefine the macro for the user like Clang's include files are doing it.
146   OS << "#undef " << NeededMacro << "\n";
147   OS << "#endif // " << PropertyName << " Property\n\n";
148 }
149 
150 /// Emits all property initializers to the raw_ostream.
151 static void emitPropertyEnum(std::string PropertyName,
152                              std::vector<Record *> PropertyRecords,
153                              raw_ostream &OS) {
154   // Generate the macro that the user needs to define before including the
155   // *.inc file.
156   std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName;
157   std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_');
158 
159   // All options are in one file, so we need put them behind macros and ask the
160   // user to define the macro for the options that are needed.
161   OS << "// Property enum cases for " << PropertyName << "\n";
162   OS << "#ifdef " << NeededMacro << "\n";
163   for (Record *R : PropertyRecords)
164     emitPropertyEnum(R, OS);
165   // We undefine the macro for the user like Clang's include files are doing it.
166   OS << "#undef " << NeededMacro << "\n";
167   OS << "#endif // " << PropertyName << " Property\n\n";
168 }
169 
170 void lldb_private::EmitPropertyDefs(RecordKeeper &Records, raw_ostream &OS) {
171   emitSourceFileHeader("Property definitions for LLDB.", OS, Records);
172 
173   std::vector<Record *> Properties =
174       Records.getAllDerivedDefinitions("Property");
175   for (auto &PropertyRecordPair : getRecordsByName(Properties, "Definition")) {
176     emityProperties(PropertyRecordPair.first, PropertyRecordPair.second, OS);
177   }
178 }
179 
180 void lldb_private::EmitPropertyEnumDefs(RecordKeeper &Records,
181                                         raw_ostream &OS) {
182   emitSourceFileHeader("Property definition enum for LLDB.", OS, Records);
183 
184   std::vector<Record *> Properties =
185       Records.getAllDerivedDefinitions("Property");
186   for (auto &PropertyRecordPair : getRecordsByName(Properties, "Definition")) {
187     emitPropertyEnum(PropertyRecordPair.first, PropertyRecordPair.second, OS);
188   }
189 }
190