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