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(FieldName: "Name" ) << "\"" ; |
35 | OS << ", " ; |
36 | |
37 | // Emit the property type. |
38 | llvm::StringRef type = Property->getValueAsString(FieldName: "Type" ); |
39 | OS << "OptionValue::eType" ; |
40 | OS << type; |
41 | OS << ", " ; |
42 | |
43 | // Emit the property's global value. |
44 | OS << (Property->getValue(Name: "Global" ) ? "true" : "false" ); |
45 | OS << ", " ; |
46 | |
47 | bool hasDefaultUnsignedValue = Property->getValue(Name: "HasDefaultUnsignedValue" ); |
48 | bool hasDefaultEnumValue = Property->getValue(Name: "HasDefaultEnumValue" ); |
49 | bool hasDefaultStringValue = Property->getValue(Name: "HasDefaultStringValue" ); |
50 | bool hasElementType = Property->getValue(Name: "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(val: Property->getValueAsInt(FieldName: "DefaultUnsignedValue" )); |
84 | } else if (hasDefaultEnumValue) { |
85 | OS << Property->getValueAsString(FieldName: "DefaultEnumValue" ); |
86 | } else if (hasElementType) { |
87 | OS << "OptionValue::eType" ; |
88 | OS << Property->getValueAsString(FieldName: "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(Name: "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(Name: "EnumValues" )) |
110 | OS << Property->getValueAsString(FieldName: "EnumValues" ); |
111 | else |
112 | OS << "{}" ; |
113 | OS << ", " ; |
114 | |
115 | // Emit the property description. |
116 | if (auto D = Property->getValue(Name: "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(first: NeededMacro.begin(), last: NeededMacro.end(), old_value: ' ', new_value: '_'); |
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(Property: 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(first: NeededMacro.begin(), last: NeededMacro.end(), old_value: ' ', new_value: '_'); |
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(Property: 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(Desc: "Property definitions for LLDB." , OS, Record: Records); |
172 | |
173 | std::vector<Record *> Properties = |
174 | Records.getAllDerivedDefinitions(ClassName: "Property" ); |
175 | for (auto &PropertyRecordPair : getRecordsByName(Records: Properties, "Definition" )) { |
176 | emityProperties(PropertyName: PropertyRecordPair.first, PropertyRecords: PropertyRecordPair.second, OS); |
177 | } |
178 | } |
179 | |
180 | void lldb_private::EmitPropertyEnumDefs(RecordKeeper &Records, |
181 | raw_ostream &OS) { |
182 | emitSourceFileHeader(Desc: "Property definition enum for LLDB." , OS, Record: Records); |
183 | |
184 | std::vector<Record *> Properties = |
185 | Records.getAllDerivedDefinitions(ClassName: "Property" ); |
186 | for (auto &PropertyRecordPair : getRecordsByName(Records: Properties, "Definition" )) { |
187 | emitPropertyEnum(PropertyName: PropertyRecordPair.first, PropertyRecords: PropertyRecordPair.second, OS); |
188 | } |
189 | } |
190 | |