166d00febSPaula Toth //===-- Implementation of the main header generation class ----------------===//
2b47f9eb5SSiva Chandra Reddy //
3b47f9eb5SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b47f9eb5SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5b47f9eb5SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b47f9eb5SSiva Chandra Reddy //
7b47f9eb5SSiva Chandra Reddy //===----------------------------------------------------------------------===//
8b47f9eb5SSiva Chandra Reddy 
9b47f9eb5SSiva Chandra Reddy #include "Generator.h"
10b47f9eb5SSiva Chandra Reddy 
11b47f9eb5SSiva Chandra Reddy #include "IncludeFileCommand.h"
12b47f9eb5SSiva Chandra Reddy #include "PublicAPICommand.h"
13b47f9eb5SSiva Chandra Reddy 
14b47f9eb5SSiva Chandra Reddy #include "llvm/ADT/StringRef.h"
15b47f9eb5SSiva Chandra Reddy #include "llvm/Support/MemoryBuffer.h"
16b47f9eb5SSiva Chandra Reddy #include "llvm/Support/SourceMgr.h"
17b47f9eb5SSiva Chandra Reddy #include "llvm/Support/raw_ostream.h"
18b47f9eb5SSiva Chandra Reddy 
19b47f9eb5SSiva Chandra Reddy #include <cstdlib>
20b47f9eb5SSiva Chandra Reddy #include <memory>
21b47f9eb5SSiva Chandra Reddy 
22b47f9eb5SSiva Chandra Reddy static const char CommandPrefix[] = "%%";
23b47f9eb5SSiva Chandra Reddy static const size_t CommandPrefixSize = llvm::StringRef(CommandPrefix).size();
24b47f9eb5SSiva Chandra Reddy 
25b47f9eb5SSiva Chandra Reddy static const char CommentPrefix[] = "<!>";
26b47f9eb5SSiva Chandra Reddy 
27b47f9eb5SSiva Chandra Reddy static const char ParamNamePrefix[] = "${";
28b47f9eb5SSiva Chandra Reddy static const size_t ParamNamePrefixSize =
29b47f9eb5SSiva Chandra Reddy     llvm::StringRef(ParamNamePrefix).size();
30b47f9eb5SSiva Chandra Reddy static const char ParamNameSuffix[] = "}";
31b47f9eb5SSiva Chandra Reddy static const size_t ParamNameSuffixSize =
32b47f9eb5SSiva Chandra Reddy     llvm::StringRef(ParamNameSuffix).size();
33b47f9eb5SSiva Chandra Reddy 
34b47f9eb5SSiva Chandra Reddy namespace llvm_libc {
35b47f9eb5SSiva Chandra Reddy 
getCommandHandler(llvm::StringRef CommandName)36b47f9eb5SSiva Chandra Reddy Command *Generator::getCommandHandler(llvm::StringRef CommandName) {
37b47f9eb5SSiva Chandra Reddy   if (CommandName == IncludeFileCommand::Name) {
38b47f9eb5SSiva Chandra Reddy     if (!IncludeFileCmd)
39b47f9eb5SSiva Chandra Reddy       IncludeFileCmd = std::make_unique<IncludeFileCommand>();
40b47f9eb5SSiva Chandra Reddy     return IncludeFileCmd.get();
41b47f9eb5SSiva Chandra Reddy   } else if (CommandName == PublicAPICommand::Name) {
42b47f9eb5SSiva Chandra Reddy     if (!PublicAPICmd)
43*f6bf2823SMichael Jones       PublicAPICmd = std::make_unique<PublicAPICommand>(EntrypointNameList);
44b47f9eb5SSiva Chandra Reddy     return PublicAPICmd.get();
45b47f9eb5SSiva Chandra Reddy   } else {
46b47f9eb5SSiva Chandra Reddy     return nullptr;
47b47f9eb5SSiva Chandra Reddy   }
48b47f9eb5SSiva Chandra Reddy }
49b47f9eb5SSiva Chandra Reddy 
parseCommandArgs(llvm::StringRef ArgStr,ArgVector & Args)50b47f9eb5SSiva Chandra Reddy void Generator::parseCommandArgs(llvm::StringRef ArgStr, ArgVector &Args) {
51b47f9eb5SSiva Chandra Reddy   if (!ArgStr.contains(',') && ArgStr.trim(' ').trim('\t').size() == 0) {
52b47f9eb5SSiva Chandra Reddy     // If it is just space between the parenthesis
53b47f9eb5SSiva Chandra Reddy     return;
54b47f9eb5SSiva Chandra Reddy   }
55b47f9eb5SSiva Chandra Reddy 
56b47f9eb5SSiva Chandra Reddy   ArgStr.split(Args, ",");
57b47f9eb5SSiva Chandra Reddy   for (llvm::StringRef &A : Args) {
58b47f9eb5SSiva Chandra Reddy     A = A.trim(' ');
59b47f9eb5SSiva Chandra Reddy     if (A.startswith(ParamNamePrefix) && A.endswith(ParamNameSuffix)) {
60b47f9eb5SSiva Chandra Reddy       A = A.drop_front(ParamNamePrefixSize).drop_back(ParamNameSuffixSize);
61b9826408SSiva Chandra Reddy       A = ArgMap[std::string(A)];
62b47f9eb5SSiva Chandra Reddy     }
63b47f9eb5SSiva Chandra Reddy   }
64b47f9eb5SSiva Chandra Reddy }
65b47f9eb5SSiva Chandra Reddy 
generate(llvm::raw_ostream & OS,llvm::RecordKeeper & Records)66b47f9eb5SSiva Chandra Reddy void Generator::generate(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {
67b47f9eb5SSiva Chandra Reddy   auto DefFileBuffer = llvm::MemoryBuffer::getFile(HeaderDefFile);
68b47f9eb5SSiva Chandra Reddy   if (!DefFileBuffer) {
69b47f9eb5SSiva Chandra Reddy     llvm::errs() << "Unable to open " << HeaderDefFile << ".\n";
70b47f9eb5SSiva Chandra Reddy     std::exit(1);
71b47f9eb5SSiva Chandra Reddy   }
72b47f9eb5SSiva Chandra Reddy   llvm::SourceMgr SrcMgr;
73b47f9eb5SSiva Chandra Reddy   unsigned DefFileID = SrcMgr.AddNewSourceBuffer(
74b47f9eb5SSiva Chandra Reddy       std::move(DefFileBuffer.get()), llvm::SMLoc::getFromPointer(nullptr));
75b47f9eb5SSiva Chandra Reddy 
76b47f9eb5SSiva Chandra Reddy   llvm::StringRef Content = SrcMgr.getMemoryBuffer(DefFileID)->getBuffer();
77b47f9eb5SSiva Chandra Reddy   while (true) {
78b47f9eb5SSiva Chandra Reddy     std::pair<llvm::StringRef, llvm::StringRef> P = Content.split('\n');
79b47f9eb5SSiva Chandra Reddy     Content = P.second;
80b47f9eb5SSiva Chandra Reddy 
81b47f9eb5SSiva Chandra Reddy     llvm::StringRef Line = P.first.trim(' ');
82b47f9eb5SSiva Chandra Reddy     if (Line.startswith(CommandPrefix)) {
83b47f9eb5SSiva Chandra Reddy       Line = Line.drop_front(CommandPrefixSize);
84b47f9eb5SSiva Chandra Reddy 
85b47f9eb5SSiva Chandra Reddy       P = Line.split("(");
86b47f9eb5SSiva Chandra Reddy       if (P.second.empty() || P.second[P.second.size() - 1] != ')') {
87b47f9eb5SSiva Chandra Reddy         SrcMgr.PrintMessage(llvm::SMLoc::getFromPointer(P.second.data()),
88b47f9eb5SSiva Chandra Reddy                             llvm::SourceMgr::DK_Error,
89b47f9eb5SSiva Chandra Reddy                             "Command argument list should begin with '(' "
90b47f9eb5SSiva Chandra Reddy                             "and end with ')'.");
91b47f9eb5SSiva Chandra Reddy         std::exit(1);
92b47f9eb5SSiva Chandra Reddy       }
93b47f9eb5SSiva Chandra Reddy       llvm::StringRef CommandName = P.first;
94b47f9eb5SSiva Chandra Reddy       Command *Cmd = getCommandHandler(CommandName);
95b47f9eb5SSiva Chandra Reddy       if (Cmd == nullptr) {
96b47f9eb5SSiva Chandra Reddy         SrcMgr.PrintMessage(llvm::SMLoc::getFromPointer(CommandName.data()),
97b47f9eb5SSiva Chandra Reddy                             llvm::SourceMgr::DK_Error,
98b47f9eb5SSiva Chandra Reddy                             "Unknown command '%%" + CommandName + "'.");
99b47f9eb5SSiva Chandra Reddy         std::exit(1);
100b47f9eb5SSiva Chandra Reddy       }
101b47f9eb5SSiva Chandra Reddy 
102b47f9eb5SSiva Chandra Reddy       llvm::StringRef ArgStr = P.second.drop_back(1);
103b47f9eb5SSiva Chandra Reddy       ArgVector Args;
104b47f9eb5SSiva Chandra Reddy       parseCommandArgs(ArgStr, Args);
105b47f9eb5SSiva Chandra Reddy 
106b47f9eb5SSiva Chandra Reddy       Command::ErrorReporter Reporter(
107b47f9eb5SSiva Chandra Reddy           llvm::SMLoc::getFromPointer(CommandName.data()), SrcMgr);
108b47f9eb5SSiva Chandra Reddy       Cmd->run(OS, Args, StdHeader, Records, Reporter);
109b47f9eb5SSiva Chandra Reddy     } else if (!Line.startswith(CommentPrefix)) {
110b47f9eb5SSiva Chandra Reddy       // There is no comment or command on this line so we just write it as is.
111b47f9eb5SSiva Chandra Reddy       OS << P.first << "\n";
112b47f9eb5SSiva Chandra Reddy     }
113b47f9eb5SSiva Chandra Reddy 
114b47f9eb5SSiva Chandra Reddy     if (P.second.empty())
115b47f9eb5SSiva Chandra Reddy       break;
116b47f9eb5SSiva Chandra Reddy   }
117b47f9eb5SSiva Chandra Reddy }
118b47f9eb5SSiva Chandra Reddy 
119b47f9eb5SSiva Chandra Reddy } // namespace llvm_libc
120