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