19dba64beSDimitry Andric //===- LLDBPropertyDefEmitter.cpp -----------------------------------------===//
29dba64beSDimitry Andric //
39dba64beSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49dba64beSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
59dba64beSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69dba64beSDimitry Andric //
79dba64beSDimitry Andric //===----------------------------------------------------------------------===//
89dba64beSDimitry Andric //
99dba64beSDimitry Andric // These tablegen backends emits LLDB's PropertyDefinition values.
109dba64beSDimitry Andric //
119dba64beSDimitry Andric //===----------------------------------------------------------------------===//
129dba64beSDimitry Andric
139dba64beSDimitry Andric #include "LLDBTableGenBackends.h"
149dba64beSDimitry Andric #include "LLDBTableGenUtils.h"
159dba64beSDimitry Andric #include "llvm/ADT/StringExtras.h"
169dba64beSDimitry Andric #include "llvm/TableGen/Record.h"
179dba64beSDimitry Andric #include "llvm/TableGen/StringMatcher.h"
189dba64beSDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
199dba64beSDimitry Andric #include <vector>
209dba64beSDimitry Andric
219dba64beSDimitry Andric using namespace llvm;
229dba64beSDimitry Andric using namespace lldb_private;
239dba64beSDimitry Andric
emitPropertyEnum(Record * Property,raw_ostream & OS)249dba64beSDimitry Andric static void emitPropertyEnum(Record *Property, raw_ostream &OS) {
259dba64beSDimitry Andric OS << "eProperty";
269dba64beSDimitry Andric OS << Property->getName();
279dba64beSDimitry Andric OS << ",\n";
289dba64beSDimitry Andric }
299dba64beSDimitry Andric
emitProperty(Record * Property,raw_ostream & OS)309dba64beSDimitry Andric static void emitProperty(Record *Property, raw_ostream &OS) {
319dba64beSDimitry Andric OS << " {";
329dba64beSDimitry Andric
339dba64beSDimitry Andric // Emit the property name.
349dba64beSDimitry Andric OS << "\"" << Property->getValueAsString("Name") << "\"";
359dba64beSDimitry Andric OS << ", ";
369dba64beSDimitry Andric
379dba64beSDimitry Andric // Emit the property type.
385ffd83dbSDimitry Andric llvm::StringRef type = Property->getValueAsString("Type");
399dba64beSDimitry Andric OS << "OptionValue::eType";
405ffd83dbSDimitry Andric OS << type;
419dba64beSDimitry Andric OS << ", ";
429dba64beSDimitry Andric
439dba64beSDimitry Andric // Emit the property's global value.
449dba64beSDimitry Andric OS << (Property->getValue("Global") ? "true" : "false");
459dba64beSDimitry Andric OS << ", ";
469dba64beSDimitry Andric
479dba64beSDimitry Andric bool hasDefaultUnsignedValue = Property->getValue("HasDefaultUnsignedValue");
489dba64beSDimitry Andric bool hasDefaultEnumValue = Property->getValue("HasDefaultEnumValue");
499dba64beSDimitry Andric bool hasDefaultStringValue = Property->getValue("HasDefaultStringValue");
505ffd83dbSDimitry Andric bool hasElementType = Property->getValue("HasElementType");
519dba64beSDimitry Andric
529dba64beSDimitry Andric // Guarantee that every property has a default value.
539dba64beSDimitry Andric assert((hasDefaultUnsignedValue || hasDefaultEnumValue ||
545ffd83dbSDimitry Andric hasDefaultStringValue || hasElementType) &&
555ffd83dbSDimitry Andric "Property must have a default value or an element type");
569dba64beSDimitry Andric
579dba64beSDimitry Andric // Guarantee that no property has both a default unsigned value and a default
589dba64beSDimitry Andric // enum value, since they're bothed stored in the same field.
599dba64beSDimitry Andric assert(!(hasDefaultUnsignedValue && hasDefaultEnumValue) &&
609dba64beSDimitry Andric "Property cannot have both a unsigned and enum default value.");
619dba64beSDimitry Andric
62480093f4SDimitry Andric // Guarantee that every boolean property has a boolean default value.
63480093f4SDimitry Andric assert(!(Property->getValueAsString("Type") == "Boolean" &&
64480093f4SDimitry Andric !Property->getValue("HasDefaultBooleanValue")) &&
65480093f4SDimitry Andric "Boolean property must have a boolean default value.");
66480093f4SDimitry Andric
67480093f4SDimitry Andric // Guarantee that every string property has a string default value.
68480093f4SDimitry Andric assert(!(Property->getValueAsString("Type") == "String" &&
69480093f4SDimitry Andric !hasDefaultStringValue) &&
70480093f4SDimitry Andric "String property must have a string default value.");
71480093f4SDimitry Andric
72480093f4SDimitry Andric // Guarantee that every enum property has an enum default value.
73480093f4SDimitry Andric assert(
74480093f4SDimitry Andric !(Property->getValueAsString("Type") == "Enum" && !hasDefaultEnumValue) &&
75480093f4SDimitry Andric "Enum property must have a enum default value.");
76480093f4SDimitry Andric
775ffd83dbSDimitry Andric // Guarantee that only arrays and dictionaries have an element type;
785ffd83dbSDimitry Andric assert(((type != "Array" && type != "Dictionary") || hasElementType) &&
795ffd83dbSDimitry Andric "Only dictionaries and arrays can have an element type.");
805ffd83dbSDimitry Andric
819dba64beSDimitry Andric // Emit the default uint value.
829dba64beSDimitry Andric if (hasDefaultUnsignedValue) {
839dba64beSDimitry Andric OS << std::to_string(Property->getValueAsInt("DefaultUnsignedValue"));
849dba64beSDimitry Andric } else if (hasDefaultEnumValue) {
859dba64beSDimitry Andric OS << Property->getValueAsString("DefaultEnumValue");
865ffd83dbSDimitry Andric } else if (hasElementType) {
875ffd83dbSDimitry Andric OS << "OptionValue::eType";
885ffd83dbSDimitry Andric OS << Property->getValueAsString("ElementType");
899dba64beSDimitry Andric } else {
909dba64beSDimitry Andric OS << "0";
919dba64beSDimitry Andric }
929dba64beSDimitry Andric OS << ", ";
939dba64beSDimitry Andric
949dba64beSDimitry Andric // Emit the default string value.
959dba64beSDimitry Andric if (hasDefaultStringValue) {
969dba64beSDimitry Andric if (auto D = Property->getValue("DefaultStringValue")) {
979dba64beSDimitry Andric OS << "\"";
989dba64beSDimitry Andric OS << D->getValue()->getAsUnquotedString();
999dba64beSDimitry Andric OS << "\"";
1009dba64beSDimitry Andric } else {
1019dba64beSDimitry Andric OS << "\"\"";
1029dba64beSDimitry Andric }
1039dba64beSDimitry Andric } else {
1049dba64beSDimitry Andric OS << "nullptr";
1059dba64beSDimitry Andric }
1069dba64beSDimitry Andric OS << ", ";
1079dba64beSDimitry Andric
1089dba64beSDimitry Andric // Emit the enum values value.
1099dba64beSDimitry Andric if (Property->getValue("EnumValues"))
1109dba64beSDimitry Andric OS << Property->getValueAsString("EnumValues");
1119dba64beSDimitry Andric else
1129dba64beSDimitry Andric OS << "{}";
1139dba64beSDimitry Andric OS << ", ";
1149dba64beSDimitry Andric
1159dba64beSDimitry Andric // Emit the property description.
1169dba64beSDimitry Andric if (auto D = Property->getValue("Description")) {
1179dba64beSDimitry Andric OS << "\"";
1189dba64beSDimitry Andric OS << D->getValue()->getAsUnquotedString();
1199dba64beSDimitry Andric OS << "\"";
1209dba64beSDimitry Andric } else {
1219dba64beSDimitry Andric OS << "\"\"";
1229dba64beSDimitry Andric }
1239dba64beSDimitry Andric
1249dba64beSDimitry Andric OS << "},\n";
1259dba64beSDimitry Andric }
1269dba64beSDimitry Andric
1279dba64beSDimitry Andric /// Emits all property initializers to the raw_ostream.
emityProperties(std::string PropertyName,std::vector<Record * > PropertyRecords,raw_ostream & OS)1289dba64beSDimitry Andric static void emityProperties(std::string PropertyName,
1299dba64beSDimitry Andric std::vector<Record *> PropertyRecords,
1309dba64beSDimitry Andric raw_ostream &OS) {
1319dba64beSDimitry Andric // Generate the macro that the user needs to define before including the
1329dba64beSDimitry Andric // *.inc file.
1339dba64beSDimitry Andric std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName;
1349dba64beSDimitry Andric std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_');
1359dba64beSDimitry Andric
1369dba64beSDimitry Andric // All options are in one file, so we need put them behind macros and ask the
1379dba64beSDimitry Andric // user to define the macro for the options that are needed.
1389dba64beSDimitry Andric OS << "// Property definitions for " << PropertyName << "\n";
1399dba64beSDimitry Andric OS << "#ifdef " << NeededMacro << "\n";
1409dba64beSDimitry Andric OS << "static constexpr PropertyDefinition g_" << PropertyName
1419dba64beSDimitry Andric << "_properties[] = {\n";
1429dba64beSDimitry Andric for (Record *R : PropertyRecords)
1439dba64beSDimitry Andric emitProperty(R, OS);
1449dba64beSDimitry Andric OS << "};\n";
1459dba64beSDimitry Andric // We undefine the macro for the user like Clang's include files are doing it.
1469dba64beSDimitry Andric OS << "#undef " << NeededMacro << "\n";
1479dba64beSDimitry Andric OS << "#endif // " << PropertyName << " Property\n\n";
1489dba64beSDimitry Andric }
1499dba64beSDimitry Andric
1509dba64beSDimitry Andric /// Emits all property initializers to the raw_ostream.
emitPropertyEnum(std::string PropertyName,std::vector<Record * > PropertyRecords,raw_ostream & OS)1519dba64beSDimitry Andric static void emitPropertyEnum(std::string PropertyName,
1529dba64beSDimitry Andric std::vector<Record *> PropertyRecords,
1539dba64beSDimitry Andric raw_ostream &OS) {
1549dba64beSDimitry Andric // Generate the macro that the user needs to define before including the
1559dba64beSDimitry Andric // *.inc file.
1569dba64beSDimitry Andric std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName;
1579dba64beSDimitry Andric std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_');
1589dba64beSDimitry Andric
1599dba64beSDimitry Andric // All options are in one file, so we need put them behind macros and ask the
1609dba64beSDimitry Andric // user to define the macro for the options that are needed.
1619dba64beSDimitry Andric OS << "// Property enum cases for " << PropertyName << "\n";
1629dba64beSDimitry Andric OS << "#ifdef " << NeededMacro << "\n";
1639dba64beSDimitry Andric for (Record *R : PropertyRecords)
1649dba64beSDimitry Andric emitPropertyEnum(R, OS);
1659dba64beSDimitry Andric // We undefine the macro for the user like Clang's include files are doing it.
1669dba64beSDimitry Andric OS << "#undef " << NeededMacro << "\n";
1679dba64beSDimitry Andric OS << "#endif // " << PropertyName << " Property\n\n";
1689dba64beSDimitry Andric }
1699dba64beSDimitry Andric
EmitPropertyDefs(RecordKeeper & Records,raw_ostream & OS)1709dba64beSDimitry Andric void lldb_private::EmitPropertyDefs(RecordKeeper &Records, raw_ostream &OS) {
171*5f757f3fSDimitry Andric emitSourceFileHeader("Property definitions for LLDB.", OS, Records);
1729dba64beSDimitry Andric
1739dba64beSDimitry Andric std::vector<Record *> Properties =
1749dba64beSDimitry Andric Records.getAllDerivedDefinitions("Property");
1759dba64beSDimitry Andric for (auto &PropertyRecordPair : getRecordsByName(Properties, "Definition")) {
1769dba64beSDimitry Andric emityProperties(PropertyRecordPair.first, PropertyRecordPair.second, OS);
1779dba64beSDimitry Andric }
1789dba64beSDimitry Andric }
1799dba64beSDimitry Andric
EmitPropertyEnumDefs(RecordKeeper & Records,raw_ostream & OS)1809dba64beSDimitry Andric void lldb_private::EmitPropertyEnumDefs(RecordKeeper &Records,
1819dba64beSDimitry Andric raw_ostream &OS) {
182*5f757f3fSDimitry Andric emitSourceFileHeader("Property definition enum for LLDB.", OS, Records);
1839dba64beSDimitry Andric
1849dba64beSDimitry Andric std::vector<Record *> Properties =
1859dba64beSDimitry Andric Records.getAllDerivedDefinitions("Property");
1869dba64beSDimitry Andric for (auto &PropertyRecordPair : getRecordsByName(Properties, "Definition")) {
1879dba64beSDimitry Andric emitPropertyEnum(PropertyRecordPair.first, PropertyRecordPair.second, OS);
1889dba64beSDimitry Andric }
1899dba64beSDimitry Andric }
190