summaryrefslogtreecommitdiffstats
path: root/libc/utils/HdrGen/Generator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libc/utils/HdrGen/Generator.cpp')
-rw-r--r--libc/utils/HdrGen/Generator.cpp119
1 files changed, 119 insertions, 0 deletions
diff --git a/libc/utils/HdrGen/Generator.cpp b/libc/utils/HdrGen/Generator.cpp
new file mode 100644
index 00000000000..996f3bf2699
--- /dev/null
+++ b/libc/utils/HdrGen/Generator.cpp
@@ -0,0 +1,119 @@
+//===---- Implementation of the main header generation class -----*- C++ -*===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "Generator.h"
+
+#include "IncludeFileCommand.h"
+#include "PublicAPICommand.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <cstdlib>
+#include <memory>
+
+static const char CommandPrefix[] = "%%";
+static const size_t CommandPrefixSize = llvm::StringRef(CommandPrefix).size();
+
+static const char CommentPrefix[] = "<!>";
+
+static const char ParamNamePrefix[] = "${";
+static const size_t ParamNamePrefixSize =
+ llvm::StringRef(ParamNamePrefix).size();
+static const char ParamNameSuffix[] = "}";
+static const size_t ParamNameSuffixSize =
+ llvm::StringRef(ParamNameSuffix).size();
+
+namespace llvm_libc {
+
+Command *Generator::getCommandHandler(llvm::StringRef CommandName) {
+ if (CommandName == IncludeFileCommand::Name) {
+ if (!IncludeFileCmd)
+ IncludeFileCmd = std::make_unique<IncludeFileCommand>();
+ return IncludeFileCmd.get();
+ } else if (CommandName == PublicAPICommand::Name) {
+ if (!PublicAPICmd)
+ PublicAPICmd = std::make_unique<PublicAPICommand>();
+ return PublicAPICmd.get();
+ } else {
+ return nullptr;
+ }
+}
+
+void Generator::parseCommandArgs(llvm::StringRef ArgStr, ArgVector &Args) {
+ if (!ArgStr.contains(',') && ArgStr.trim(' ').trim('\t').size() == 0) {
+ // If it is just space between the parenthesis
+ return;
+ }
+
+ ArgStr.split(Args, ",");
+ for (llvm::StringRef &A : Args) {
+ A = A.trim(' ');
+ if (A.startswith(ParamNamePrefix) && A.endswith(ParamNameSuffix)) {
+ A = A.drop_front(ParamNamePrefixSize).drop_back(ParamNameSuffixSize);
+ A = ArgMap[A];
+ }
+ }
+}
+
+void Generator::generate(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {
+ auto DefFileBuffer = llvm::MemoryBuffer::getFile(HeaderDefFile);
+ if (!DefFileBuffer) {
+ llvm::errs() << "Unable to open " << HeaderDefFile << ".\n";
+ std::exit(1);
+ }
+ llvm::SourceMgr SrcMgr;
+ unsigned DefFileID = SrcMgr.AddNewSourceBuffer(
+ std::move(DefFileBuffer.get()), llvm::SMLoc::getFromPointer(nullptr));
+
+ llvm::StringRef Content = SrcMgr.getMemoryBuffer(DefFileID)->getBuffer();
+ while (true) {
+ std::pair<llvm::StringRef, llvm::StringRef> P = Content.split('\n');
+ Content = P.second;
+
+ llvm::StringRef Line = P.first.trim(' ');
+ if (Line.startswith(CommandPrefix)) {
+ Line = Line.drop_front(CommandPrefixSize);
+
+ P = Line.split("(");
+ if (P.second.empty() || P.second[P.second.size() - 1] != ')') {
+ SrcMgr.PrintMessage(llvm::SMLoc::getFromPointer(P.second.data()),
+ llvm::SourceMgr::DK_Error,
+ "Command argument list should begin with '(' "
+ "and end with ')'.");
+ std::exit(1);
+ }
+ llvm::StringRef CommandName = P.first;
+ Command *Cmd = getCommandHandler(CommandName);
+ if (Cmd == nullptr) {
+ SrcMgr.PrintMessage(llvm::SMLoc::getFromPointer(CommandName.data()),
+ llvm::SourceMgr::DK_Error,
+ "Unknown command '%%" + CommandName + "'.");
+ std::exit(1);
+ }
+
+ llvm::StringRef ArgStr = P.second.drop_back(1);
+ ArgVector Args;
+ parseCommandArgs(ArgStr, Args);
+
+ Command::ErrorReporter Reporter(
+ llvm::SMLoc::getFromPointer(CommandName.data()), SrcMgr);
+ Cmd->run(OS, Args, StdHeader, Records, Reporter);
+ } else if (!Line.startswith(CommentPrefix)) {
+ // There is no comment or command on this line so we just write it as is.
+ OS << P.first << "\n";
+ }
+
+ if (P.second.empty())
+ break;
+ }
+}
+
+} // namespace llvm_libc
OpenPOWER on IntegriCloud