87b188ca8c02b6f75007c6b9453bd74a7c2f4ce1
[lldb.git] / libc / utils / HdrGen / PublicAPICommand.cpp
1 //===-- Implementation of PublicAPICommand --------------------------------===//
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 #include "PublicAPICommand.h"
10
11 #include "utils/LibcTableGenUtil/APIIndexer.h"
12
13 #include "llvm/ADT/StringExtras.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "llvm/TableGen/Record.h"
17
18 // Text blocks for macro definitions and type decls can be indented to
19 // suit the surrounding tablegen listing. We need to dedent such blocks
20 // before writing them out.
21 static void dedentAndWrite(llvm::StringRef Text, llvm::raw_ostream &OS) {
22   llvm::SmallVector<llvm::StringRef, 10> Lines;
23   llvm::SplitString(Text, Lines, "\n");
24   size_t shortest_indent = 1024;
25   for (llvm::StringRef L : Lines) {
26     llvm::StringRef Indent = L.take_while([](char c) { return c == ' '; });
27     size_t IndentSize = Indent.size();
28     if (Indent.size() == L.size()) {
29       // Line is all spaces so no point noting the indent.
30       continue;
31     }
32     if (IndentSize < shortest_indent)
33       shortest_indent = IndentSize;
34   }
35   for (llvm::StringRef L : Lines) {
36     if (L.size() >= shortest_indent)
37       OS << L.drop_front(shortest_indent) << '\n';
38   }
39 }
40
41 namespace llvm_libc {
42
43 void writeAPIFromIndex(APIIndexer &G, llvm::raw_ostream &OS) {
44   for (auto &Pair : G.MacroDefsMap) {
45     const std::string &Name = Pair.first;
46     if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
47       llvm::PrintFatalError(Name + " not found in any standard spec.\n");
48
49     llvm::Record *MacroDef = Pair.second;
50     dedentAndWrite(MacroDef->getValueAsString("Defn"), OS);
51
52     OS << '\n';
53   }
54
55   for (auto &Pair : G.TypeDeclsMap) {
56     const std::string &Name = Pair.first;
57     if (G.TypeSpecMap.find(Name) == G.TypeSpecMap.end())
58       llvm::PrintFatalError(Name + " not found in any standard spec.\n");
59
60     llvm::Record *TypeDecl = Pair.second;
61     dedentAndWrite(TypeDecl->getValueAsString("Decl"), OS);
62
63     OS << '\n';
64   }
65
66   if (G.Enumerations.size() != 0)
67     OS << "enum {" << '\n';
68   for (const auto &Name : G.Enumerations) {
69     if (G.EnumerationSpecMap.find(Name) == G.EnumerationSpecMap.end())
70       llvm::PrintFatalError(
71           Name + " is not listed as an enumeration in any standard spec.\n");
72
73     llvm::Record *EnumerationSpec = G.EnumerationSpecMap[Name];
74     OS << "  " << EnumerationSpec->getValueAsString("Name");
75     auto Value = EnumerationSpec->getValueAsString("Value");
76     if (Value == "__default__") {
77       OS << ",\n";
78     } else {
79       OS << " = " << Value << ",\n";
80     }
81   }
82   if (G.Enumerations.size() != 0)
83     OS << "};\n\n";
84
85   OS << "__BEGIN_C_DECLS\n\n";
86   for (auto &Name : G.Functions) {
87     if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end())
88       llvm::PrintFatalError(Name + " not found in any standard spec.\n");
89
90     llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
91     llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
92     llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
93
94     OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
95
96     auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
97     for (size_t i = 0; i < ArgsList.size(); ++i) {
98       llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType");
99       OS << G.getTypeAsString(ArgType);
100       if (i < ArgsList.size() - 1)
101         OS << ", ";
102     }
103
104     OS << ");\n\n";
105   }
106   OS << "__END_C_DECLS\n";
107 }
108
109 void writePublicAPI(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}
110
111 const char PublicAPICommand::Name[] = "public_api";
112
113 void PublicAPICommand::run(llvm::raw_ostream &OS, const ArgVector &Args,
114                            llvm::StringRef StdHeader,
115                            llvm::RecordKeeper &Records,
116                            const Command::ErrorReporter &Reporter) const {
117   if (Args.size() != 0) {
118     Reporter.printFatalError("public_api command does not take any arguments.");
119   }
120
121   APIIndexer G(StdHeader, Records);
122   writeAPIFromIndex(G, OS);
123 }
124
125 } // namespace llvm_libc