1 //===- RemarkParser.cpp --------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file provides utility methods used by clients that want to use the
10 // parser for remark diagnostics in LLVM.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Remarks/RemarkParser.h"
15 #include "BitstreamRemarkParser.h"
16 #include "YAMLRemarkParser.h"
17 #include "llvm-c/Remarks.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/Support/CBindingWrapping.h"
22 using namespace llvm::remarks
;
24 char EndOfFileError::ID
= 0;
26 ParsedStringTable::ParsedStringTable(StringRef InBuffer
) : Buffer(InBuffer
) {
27 while (!InBuffer
.empty()) {
28 // Strings are separated by '\0' bytes.
29 std::pair
<StringRef
, StringRef
> Split
= InBuffer
.split('\0');
30 // We only store the offset from the beginning of the buffer.
31 Offsets
.push_back(Split
.first
.data() - Buffer
.data());
32 InBuffer
= Split
.second
;
36 Expected
<StringRef
> ParsedStringTable::operator[](size_t Index
) const {
37 if (Index
>= Offsets
.size())
38 return createStringError(
39 std::make_error_code(std::errc::invalid_argument
),
40 "String with index %u is out of bounds (size = %u).", Index
,
43 size_t Offset
= Offsets
[Index
];
44 // If it's the last offset, we can't use the next offset to know the size of
47 (Index
== Offsets
.size() - 1) ? Buffer
.size() : Offsets
[Index
+ 1];
48 return StringRef(Buffer
.data() + Offset
, NextOffset
- Offset
- 1);
51 Expected
<std::unique_ptr
<RemarkParser
>>
52 llvm::remarks::createRemarkParser(Format ParserFormat
, StringRef Buf
) {
53 switch (ParserFormat
) {
55 return std::make_unique
<YAMLRemarkParser
>(Buf
);
56 case Format::YAMLStrTab
:
57 return createStringError(
58 std::make_error_code(std::errc::invalid_argument
),
59 "The YAML with string table format requires a parsed string table.");
60 case Format::Bitstream
:
61 return std::make_unique
<BitstreamRemarkParser
>(Buf
);
63 return createStringError(std::make_error_code(std::errc::invalid_argument
),
64 "Unknown remark parser format.");
66 llvm_unreachable("unhandled ParseFormat");
69 Expected
<std::unique_ptr
<RemarkParser
>>
70 llvm::remarks::createRemarkParser(Format ParserFormat
, StringRef Buf
,
71 ParsedStringTable StrTab
) {
72 switch (ParserFormat
) {
74 return createStringError(std::make_error_code(std::errc::invalid_argument
),
75 "The YAML format can't be used with a string "
76 "table. Use yaml-strtab instead.");
77 case Format::YAMLStrTab
:
78 return std::make_unique
<YAMLStrTabRemarkParser
>(Buf
, std::move(StrTab
));
79 case Format::Bitstream
:
80 return std::make_unique
<BitstreamRemarkParser
>(Buf
, std::move(StrTab
));
82 return createStringError(std::make_error_code(std::errc::invalid_argument
),
83 "Unknown remark parser format.");
85 llvm_unreachable("unhandled ParseFormat");
88 Expected
<std::unique_ptr
<RemarkParser
>>
89 llvm::remarks::createRemarkParserFromMeta(
90 Format ParserFormat
, StringRef Buf
, Optional
<ParsedStringTable
> StrTab
,
91 Optional
<StringRef
> ExternalFilePrependPath
) {
92 switch (ParserFormat
) {
93 // Depending on the metadata, the format can be either yaml or yaml-strtab,
94 // regardless of the input argument.
96 case Format::YAMLStrTab
:
97 return createYAMLParserFromMeta(Buf
, std::move(StrTab
),
98 std::move(ExternalFilePrependPath
));
99 case Format::Bitstream
:
100 return createBitstreamParserFromMeta(Buf
, std::move(StrTab
),
101 std::move(ExternalFilePrependPath
));
102 case Format::Unknown
:
103 return createStringError(std::make_error_code(std::errc::invalid_argument
),
104 "Unknown remark parser format.");
106 llvm_unreachable("unhandled ParseFormat");
110 // Wrapper that holds the state needed to interact with the C API.
112 std::unique_ptr
<RemarkParser
> TheParser
;
113 Optional
<std::string
> Err
;
115 CParser(Format ParserFormat
, StringRef Buf
,
116 Optional
<ParsedStringTable
> StrTab
= None
)
117 : TheParser(cantFail(
118 StrTab
? createRemarkParser(ParserFormat
, Buf
, std::move(*StrTab
))
119 : createRemarkParser(ParserFormat
, Buf
))) {}
121 void handleError(Error E
) { Err
.emplace(toString(std::move(E
))); }
122 bool hasError() const { return Err
.hasValue(); }
123 const char *getMessage() const { return Err
? Err
->c_str() : nullptr; };
127 // Create wrappers for C Binding types (see CBindingWrapping.h).
128 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser
, LLVMRemarkParserRef
)
130 extern "C" LLVMRemarkParserRef
LLVMRemarkParserCreateYAML(const void *Buf
,
132 return wrap(new CParser(Format::YAML
,
133 StringRef(static_cast<const char *>(Buf
), Size
)));
136 extern "C" LLVMRemarkParserRef
LLVMRemarkParserCreateBitstream(const void *Buf
,
138 return wrap(new CParser(Format::Bitstream
,
139 StringRef(static_cast<const char *>(Buf
), Size
)));
142 extern "C" LLVMRemarkEntryRef
143 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser
) {
144 CParser
&TheCParser
= *unwrap(Parser
);
145 remarks::RemarkParser
&TheParser
= *TheCParser
.TheParser
;
147 Expected
<std::unique_ptr
<Remark
>> MaybeRemark
= TheParser
.next();
148 if (Error E
= MaybeRemark
.takeError()) {
149 if (E
.isA
<EndOfFileError
>()) {
150 consumeError(std::move(E
));
154 // Handle the error. Allow it to be checked through HasError and
156 TheCParser
.handleError(std::move(E
));
161 return wrap(MaybeRemark
->release());
164 extern "C" LLVMBool
LLVMRemarkParserHasError(LLVMRemarkParserRef Parser
) {
165 return unwrap(Parser
)->hasError();
168 extern "C" const char *
169 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser
) {
170 return unwrap(Parser
)->getMessage();
173 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser
) {
174 delete unwrap(Parser
);