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