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 "YAMLRemarkParser.h"
16 #include "llvm-c/Remarks.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/Support/CBindingWrapping.h"
21 using namespace llvm::remarks
;
23 char EndOfFileError::ID
= 0;
25 ParsedStringTable::ParsedStringTable(StringRef InBuffer
) : Buffer(InBuffer
) {
26 while (!InBuffer
.empty()) {
27 // Strings are separated by '\0' bytes.
28 std::pair
<StringRef
, StringRef
> Split
= InBuffer
.split('\0');
29 // We only store the offset from the beginning of the buffer.
30 Offsets
.push_back(Split
.first
.data() - Buffer
.data());
31 InBuffer
= Split
.second
;
35 Expected
<StringRef
> ParsedStringTable::operator[](size_t Index
) const {
36 if (Index
>= Offsets
.size())
37 return createStringError(
38 std::make_error_code(std::errc::invalid_argument
),
39 "String with index %u is out of bounds (size = %u).", Index
,
42 size_t Offset
= Offsets
[Index
];
43 // If it's the last offset, we can't use the next offset to know the size of
46 (Index
== Offsets
.size() - 1) ? Buffer
.size() : Offsets
[Index
+ 1];
47 return StringRef(Buffer
.data() + Offset
, NextOffset
- Offset
- 1);
50 Expected
<std::unique_ptr
<RemarkParser
>>
51 llvm::remarks::createRemarkParser(Format ParserFormat
, StringRef Buf
) {
52 switch (ParserFormat
) {
54 return std::make_unique
<YAMLRemarkParser
>(Buf
);
55 case Format::YAMLStrTab
:
56 return createStringError(
57 std::make_error_code(std::errc::invalid_argument
),
58 "The YAML with string table format requires a parsed string table.");
59 case Format::Bitstream
:
60 return createStringError(std::make_error_code(std::errc::invalid_argument
),
61 "Parsing bitstream remarks is not supported.");
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 createStringError(std::make_error_code(std::errc::invalid_argument
),
81 "Parsing bitstream remarks is not supported.");
83 return createStringError(std::make_error_code(std::errc::invalid_argument
),
84 "Unknown remark parser format.");
86 llvm_unreachable("unhandled ParseFormat");
89 Expected
<std::unique_ptr
<RemarkParser
>>
90 llvm::remarks::createRemarkParserFromMeta(Format ParserFormat
, StringRef Buf
,
91 Optional
<ParsedStringTable
> StrTab
) {
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 case Format::Bitstream
:
99 return createStringError(std::make_error_code(std::errc::invalid_argument
),
100 "Parsing bitstream remarks is not supported.");
101 case Format::Unknown
:
102 return createStringError(std::make_error_code(std::errc::invalid_argument
),
103 "Unknown remark parser format.");
105 llvm_unreachable("unhandled ParseFormat");
109 // Wrapper that holds the state needed to interact with the C API.
111 std::unique_ptr
<RemarkParser
> TheParser
;
112 Optional
<std::string
> Err
;
114 CParser(Format ParserFormat
, StringRef Buf
,
115 Optional
<ParsedStringTable
> StrTab
= None
)
116 : TheParser(cantFail(
117 StrTab
? createRemarkParser(ParserFormat
, Buf
, std::move(*StrTab
))
118 : createRemarkParser(ParserFormat
, Buf
))) {}
120 void handleError(Error E
) { Err
.emplace(toString(std::move(E
))); }
121 bool hasError() const { return Err
.hasValue(); }
122 const char *getMessage() const { return Err
? Err
->c_str() : nullptr; };
126 // Create wrappers for C Binding types (see CBindingWrapping.h).
127 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser
, LLVMRemarkParserRef
)
129 extern "C" LLVMRemarkParserRef
LLVMRemarkParserCreateYAML(const void *Buf
,
131 return wrap(new CParser(Format::YAML
,
132 StringRef(static_cast<const char *>(Buf
), Size
)));
135 extern "C" LLVMRemarkEntryRef
136 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser
) {
137 CParser
&TheCParser
= *unwrap(Parser
);
138 remarks::RemarkParser
&TheParser
= *TheCParser
.TheParser
;
140 Expected
<std::unique_ptr
<Remark
>> MaybeRemark
= TheParser
.next();
141 if (Error E
= MaybeRemark
.takeError()) {
142 if (E
.isA
<EndOfFileError
>()) {
143 consumeError(std::move(E
));
147 // Handle the error. Allow it to be checked through HasError and
149 TheCParser
.handleError(std::move(E
));
154 return wrap(MaybeRemark
->release());
157 extern "C" LLVMBool
LLVMRemarkParserHasError(LLVMRemarkParserRef Parser
) {
158 return unwrap(Parser
)->hasError();
161 extern "C" const char *
162 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser
) {
163 return unwrap(Parser
)->getMessage();
166 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser
) {
167 delete unwrap(Parser
);