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(Format ParserFormat
, StringRef Buf
,
90 Optional
<ParsedStringTable
> StrTab
) {
91 switch (ParserFormat
) {
92 // Depending on the metadata, the format can be either yaml or yaml-strtab,
93 // regardless of the input argument.
95 case Format::YAMLStrTab
:
96 return createYAMLParserFromMeta(Buf
, std::move(StrTab
));
97 case Format::Bitstream
:
98 return createBitstreamParserFromMeta(Buf
, std::move(StrTab
));
100 return createStringError(std::make_error_code(std::errc::invalid_argument
),
101 "Unknown remark parser format.");
103 llvm_unreachable("unhandled ParseFormat");
107 // Wrapper that holds the state needed to interact with the C API.
109 std::unique_ptr
<RemarkParser
> TheParser
;
110 Optional
<std::string
> Err
;
112 CParser(Format ParserFormat
, StringRef Buf
,
113 Optional
<ParsedStringTable
> StrTab
= None
)
114 : TheParser(cantFail(
115 StrTab
? createRemarkParser(ParserFormat
, Buf
, std::move(*StrTab
))
116 : createRemarkParser(ParserFormat
, Buf
))) {}
118 void handleError(Error E
) { Err
.emplace(toString(std::move(E
))); }
119 bool hasError() const { return Err
.hasValue(); }
120 const char *getMessage() const { return Err
? Err
->c_str() : nullptr; };
124 // Create wrappers for C Binding types (see CBindingWrapping.h).
125 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser
, LLVMRemarkParserRef
)
127 extern "C" LLVMRemarkParserRef
LLVMRemarkParserCreateYAML(const void *Buf
,
129 return wrap(new CParser(Format::YAML
,
130 StringRef(static_cast<const char *>(Buf
), Size
)));
133 extern "C" LLVMRemarkParserRef
LLVMRemarkParserCreateBitstream(const void *Buf
,
135 return wrap(new CParser(Format::Bitstream
,
136 StringRef(static_cast<const char *>(Buf
), Size
)));
139 extern "C" LLVMRemarkEntryRef
140 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser
) {
141 CParser
&TheCParser
= *unwrap(Parser
);
142 remarks::RemarkParser
&TheParser
= *TheCParser
.TheParser
;
144 Expected
<std::unique_ptr
<Remark
>> MaybeRemark
= TheParser
.next();
145 if (Error E
= MaybeRemark
.takeError()) {
146 if (E
.isA
<EndOfFileError
>()) {
147 consumeError(std::move(E
));
151 // Handle the error. Allow it to be checked through HasError and
153 TheCParser
.handleError(std::move(E
));
158 return wrap(MaybeRemark
->release());
161 extern "C" LLVMBool
LLVMRemarkParserHasError(LLVMRemarkParserRef Parser
) {
162 return unwrap(Parser
)->hasError();
165 extern "C" const char *
166 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser
) {
167 return unwrap(Parser
)->getMessage();
170 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser
) {
171 delete unwrap(Parser
);