| //===- LLDBPropertyDefEmitter.cpp -----------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // These tablegen backends emits LLDB's PropertyDefinition values. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "LLDBTableGenBackends.h" | |
| #include "LLDBTableGenUtils.h" | |
| #include "llvm/ADT/StringExtras.h" | |
| #include "llvm/TableGen/Record.h" | |
| #include "llvm/TableGen/StringMatcher.h" | |
| #include "llvm/TableGen/TableGenBackend.h" | |
| #include <optional> | |
| #include <vector> | |
| using namespace llvm; | |
| using namespace lldb_private; | |
| static void emitPropertyEnum(const Record *Property, raw_ostream &OS) { | |
| OS << "eProperty"; | |
| OS << Property->getName(); | |
| OS << ",\n"; | |
| } | |
| static void emitProperty(const Record *Property, raw_ostream &OS) { | |
| OS << " {"; | |
| // Emit the property name. | |
| OS << "\"" << Property->getValueAsString("Name") << "\""; | |
| OS << ", "; | |
| // Emit the property type. | |
| llvm::StringRef type = Property->getValueAsString("Type"); | |
| OS << "OptionValue::eType"; | |
| OS << type; | |
| OS << ", "; | |
| // Emit the property's global value. | |
| OS << (Property->getValue("Global") ? "true" : "false"); | |
| OS << ", "; | |
| bool hasDefaultUnsignedValue = Property->getValue("HasDefaultUnsignedValue"); | |
| bool hasDefaultEnumValue = Property->getValue("HasDefaultEnumValue"); | |
| bool hasDefaultStringValue = Property->getValue("HasDefaultStringValue"); | |
| bool hasElementType = Property->getValue("HasElementType"); | |
| // Guarantee that every property has a default value. | |
| assert((hasDefaultUnsignedValue || hasDefaultEnumValue || | |
| hasDefaultStringValue || hasElementType) && | |
| "Property must have a default value or an element type"); | |
| // Guarantee that no property has both a default unsigned value and a default | |
| // enum value, since they're bothed stored in the same field. | |
| assert(!(hasDefaultUnsignedValue && hasDefaultEnumValue) && | |
| "Property cannot have both a unsigned and enum default value."); | |
| // Guarantee that every boolean property has a boolean default value. | |
| assert(!(Property->getValueAsString("Type") == "Boolean" && | |
| !Property->getValue("HasDefaultBooleanValue")) && | |
| "Boolean property must have a boolean default value."); | |
| // Guarantee that every string property has a string default value. | |
| assert(!(Property->getValueAsString("Type") == "String" && | |
| !hasDefaultStringValue) && | |
| "String property must have a string default value."); | |
| // Guarantee that every enum property has an enum default value. | |
| assert( | |
| !(Property->getValueAsString("Type") == "Enum" && !hasDefaultEnumValue) && | |
| "Enum property must have a enum default value."); | |
| // Guarantee that only arrays and dictionaries have an element type; | |
| assert(((type != "Array" && type != "Dictionary") || hasElementType) && | |
| "Only dictionaries and arrays can have an element type."); | |
| // Emit the default uint value. | |
| if (hasDefaultUnsignedValue) { | |
| OS << std::to_string(Property->getValueAsInt("DefaultUnsignedValue")); | |
| } else if (hasDefaultEnumValue) { | |
| OS << Property->getValueAsString("DefaultEnumValue"); | |
| } else if (hasElementType) { | |
| OS << "OptionValue::eType"; | |
| OS << Property->getValueAsString("ElementType"); | |
| } else { | |
| OS << "0"; | |
| } | |
| OS << ", "; | |
| // Emit the default string value. | |
| if (hasDefaultStringValue) { | |
| if (auto D = Property->getValue("DefaultStringValue")) { | |
| OS << "\""; | |
| OS << D->getValue()->getAsUnquotedString(); | |
| OS << "\""; | |
| } else { | |
| OS << "\"\""; | |
| } | |
| } else { | |
| OS << "nullptr"; | |
| } | |
| OS << ", "; | |
| // Emit the enum values value. | |
| if (Property->getValue("EnumValues")) | |
| OS << Property->getValueAsString("EnumValues"); | |
| else | |
| OS << "{}"; | |
| OS << ", "; | |
| // Emit the property description. | |
| if (auto D = Property->getValue("Description")) { | |
| OS << "\""; | |
| OS << D->getValue()->getAsUnquotedString(); | |
| OS << "\""; | |
| } else { | |
| OS << "\"\""; | |
| } | |
| OS << "},\n"; | |
| } | |
| static std::optional<StringRef> | |
| getPropertyPath(const std::vector<const Record *> &PropertyRecords) { | |
| std::optional<StringRef> Path; | |
| for (const Record *R : PropertyRecords) { | |
| StringRef P = R->getValueAsString("Path"); | |
| if (!Path) | |
| Path.emplace(P); | |
| assert(*Path == P && | |
| "All records with one definition should have the same path"); | |
| } | |
| return Path; | |
| } | |
| /// Emits all property initializers to the raw_ostream. | |
| static void emityProperties(std::string PropertyName, | |
| const std::vector<const Record *> &PropertyRecords, | |
| raw_ostream &OS) { | |
| // Generate the macro that the user needs to define before including the | |
| // *.inc file. | |
| std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName; | |
| llvm::replace(NeededMacro, ' ', '_'); | |
| std::optional<StringRef> Path = getPropertyPath(PropertyRecords); | |
| // All options are in one file, so we need put them behind macros and ask the | |
| // user to define the macro for the options that are needed. | |
| OS << "// Property definitions for " << PropertyName << "\n"; | |
| OS << "#ifdef " << NeededMacro << "\n"; | |
| OS << "static constexpr PropertyDefinition g_" << PropertyName | |
| << "_properties[] = {\n"; | |
| for (const Record *R : PropertyRecords) | |
| emitProperty(R, OS); | |
| OS << "};\n"; | |
| OS << "static constexpr PropertyCollectionDefinition g_" << PropertyName | |
| << "_properties_def = {\n"; | |
| OS << "/*properties=*/g_" << PropertyName << "_properties,\n"; | |
| if (Path) | |
| OS << "/*expected_path=*/\"" << *Path << "\",\n"; | |
| OS << "};\n"; | |
| // We undefine the macro for the user like Clang's include files are doing it. | |
| OS << "#undef " << NeededMacro << "\n"; | |
| OS << "#endif // " << PropertyName << " Property\n\n"; | |
| } | |
| /// Emits all property initializers to the raw_ostream. | |
| static void emitPropertyEnum(std::string PropertyName, | |
| ArrayRef<const Record *> PropertyRecords, | |
| raw_ostream &OS) { | |
| // Generate the macro that the user needs to define before including the | |
| // *.inc file. | |
| std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName; | |
| llvm::replace(NeededMacro, ' ', '_'); | |
| // All options are in one file, so we need put them behind macros and ask the | |
| // user to define the macro for the options that are needed. | |
| OS << "// Property enum cases for " << PropertyName << "\n"; | |
| OS << "#ifdef " << NeededMacro << "\n"; | |
| for (const Record *R : PropertyRecords) | |
| emitPropertyEnum(R, OS); | |
| // We undefine the macro for the user like Clang's include files are doing it. | |
| OS << "#undef " << NeededMacro << "\n"; | |
| OS << "#endif // " << PropertyName << " Property\n\n"; | |
| } | |
| void lldb_private::EmitPropertyDefs(const RecordKeeper &Records, | |
| raw_ostream &OS) { | |
| emitSourceFileHeader("Property definitions for LLDB.", OS, Records); | |
| ArrayRef<const Record *> Properties = | |
| Records.getAllDerivedDefinitions("Property"); | |
| for (auto &PropertyRecordPair : getRecordsByName(Properties, "Definition")) { | |
| emityProperties(PropertyRecordPair.first, PropertyRecordPair.second, OS); | |
| } | |
| } | |
| void lldb_private::EmitPropertyEnumDefs(const RecordKeeper &Records, | |
| raw_ostream &OS) { | |
| emitSourceFileHeader("Property definition enum for LLDB.", OS, Records); | |
| ArrayRef<const Record *> Properties = | |
| Records.getAllDerivedDefinitions("Property"); | |
| for (auto &PropertyRecordPair : getRecordsByName(Properties, "Definition")) { | |
| emitPropertyEnum(PropertyRecordPair.first, PropertyRecordPair.second, OS); | |
| } | |
| } |