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
<Parser
>>
51 llvm::remarks::createRemarkParser(Format ParserFormat
, StringRef Buf
) {
52 switch (ParserFormat
) {
54 return llvm::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.");
60 return createStringError(std::make_error_code(std::errc::invalid_argument
),
61 "Unknown remark parser format.");
63 llvm_unreachable("unhandled ParseFormat");
66 Expected
<std::unique_ptr
<Parser
>>
67 llvm::remarks::createRemarkParser(Format ParserFormat
, StringRef Buf
,
68 ParsedStringTable StrTab
) {
69 switch (ParserFormat
) {
71 return createStringError(std::make_error_code(std::errc::invalid_argument
),
72 "The YAML format can't be used with a string "
73 "table. Use yaml-strtab instead.");
74 case Format::YAMLStrTab
:
75 return llvm::make_unique
<YAMLStrTabRemarkParser
>(Buf
, std::move(StrTab
));
77 return createStringError(std::make_error_code(std::errc::invalid_argument
),
78 "Unknown remark parser format.");
80 llvm_unreachable("unhandled ParseFormat");
83 // Wrapper that holds the state needed to interact with the C API.
85 std::unique_ptr
<Parser
> TheParser
;
86 Optional
<std::string
> Err
;
88 CParser(Format ParserFormat
, StringRef Buf
,
89 Optional
<ParsedStringTable
> StrTab
= None
)
91 StrTab
? createRemarkParser(ParserFormat
, Buf
, std::move(*StrTab
))
92 : createRemarkParser(ParserFormat
, Buf
))) {}
94 void handleError(Error E
) { Err
.emplace(toString(std::move(E
))); }
95 bool hasError() const { return Err
.hasValue(); }
96 const char *getMessage() const { return Err
? Err
->c_str() : nullptr; };
99 // Create wrappers for C Binding types (see CBindingWrapping.h).
100 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser
, LLVMRemarkParserRef
)
102 extern "C" LLVMRemarkParserRef
LLVMRemarkParserCreateYAML(const void *Buf
,
104 return wrap(new CParser(Format::YAML
,
105 StringRef(static_cast<const char *>(Buf
), Size
)));
108 extern "C" LLVMRemarkEntryRef
109 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser
) {
110 CParser
&TheCParser
= *unwrap(Parser
);
111 remarks::Parser
&TheParser
= *TheCParser
.TheParser
;
113 Expected
<std::unique_ptr
<Remark
>> MaybeRemark
= TheParser
.next();
114 if (Error E
= MaybeRemark
.takeError()) {
115 if (E
.isA
<EndOfFileError
>()) {
116 consumeError(std::move(E
));
120 // Handle the error. Allow it to be checked through HasError and
122 TheCParser
.handleError(std::move(E
));
127 return wrap(MaybeRemark
->release());
130 extern "C" LLVMBool
LLVMRemarkParserHasError(LLVMRemarkParserRef Parser
) {
131 return unwrap(Parser
)->hasError();
134 extern "C" const char *
135 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser
) {
136 return unwrap(Parser
)->getMessage();
139 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser
) {
140 delete unwrap(Parser
);