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
21using namespace llvm;
22using namespace lldb_private;
23
24static void emitPropertyEnum(Record *Property, raw_ostream &OS) {
25  OS << "eProperty";
26  OS << Property->getName();
27  OS << ",\n";
28}
29
30static 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.
128static 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.
151static 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
170void lldb_private::EmitPropertyDefs(RecordKeeper &Records, raw_ostream &OS) {
171  emitSourceFileHeader("Property definitions for LLDB.", OS);
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
180void lldb_private::EmitPropertyEnumDefs(RecordKeeper &Records,
181                                        raw_ostream &OS) {
182  emitSourceFileHeader("Property definition enum for LLDB.", OS);
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