| Francis Visoiu Mistrih | 1c4bab3 | 2019-03-05 20:45:17 +0000 | [diff] [blame] | 1 | //===- RemarkParser.cpp --------------------------------------------------===// | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 2 | // | 
| Chandler Carruth | 57b08b0 | 2019-01-19 10:56:40 +0000 | [diff] [blame] | 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 | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 6 | // | 
|  | 7 | //===----------------------------------------------------------------------===// | 
|  | 8 | // | 
|  | 9 | // This file provides utility methods used by clients that want to use the | 
| Francis Visoiu Mistrih | 1c4bab3 | 2019-03-05 20:45:17 +0000 | [diff] [blame] | 10 | // parser for remark diagnostics in LLVM. | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 11 | // | 
|  | 12 | //===----------------------------------------------------------------------===// | 
|  | 13 |  | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 14 | #include "llvm/Remarks/RemarkParser.h" | 
|  | 15 | #include "YAMLRemarkParser.h" | 
| Francis Visoiu Mistrih | 1c4bab3 | 2019-03-05 20:45:17 +0000 | [diff] [blame] | 16 | #include "llvm-c/Remarks.h" | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 17 | #include "llvm/ADT/STLExtras.h" | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 18 | #include "llvm/Support/CBindingWrapping.h" | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 19 |  | 
|  | 20 | using namespace llvm; | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 21 | using namespace llvm::remarks; | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 22 |  | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 23 | Parser::Parser(StringRef Buf) : Impl(llvm::make_unique<YAMLParserImpl>(Buf)) {} | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 24 |  | 
| Francis Visoiu Mistrih | e6ba313 | 2019-07-04 00:30:58 +0000 | [diff] [blame^] | 25 | Parser::Parser(StringRef Buf, const ParsedStringTable &StrTab) | 
|  | 26 | : Impl(llvm::make_unique<YAMLParserImpl>(Buf, &StrTab)) {} | 
| Francis Visoiu Mistrih | 7fee2b8 | 2019-04-24 00:06:24 +0000 | [diff] [blame] | 27 |  | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 28 | Parser::~Parser() = default; | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 29 |  | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 30 | static Expected<const Remark *> getNextYAML(YAMLParserImpl &Impl) { | 
|  | 31 | YAMLRemarkParser &YAMLParser = Impl.YAMLParser; | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 32 | // Check for EOF. | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 33 | if (Impl.YAMLIt == Impl.YAMLParser.Stream.end()) | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 34 | return nullptr; | 
|  | 35 |  | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 36 | auto CurrentIt = Impl.YAMLIt; | 
|  | 37 |  | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 38 | // Try to parse an entry. | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 39 | if (Error E = YAMLParser.parseYAMLElement(*CurrentIt)) { | 
|  | 40 | // Set the iterator to the end, in case the user calls getNext again. | 
|  | 41 | Impl.YAMLIt = Impl.YAMLParser.Stream.end(); | 
|  | 42 | return std::move(E); | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 43 | } | 
|  | 44 |  | 
|  | 45 | // Move on. | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 46 | ++Impl.YAMLIt; | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 47 |  | 
|  | 48 | // Return the just-parsed remark. | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 49 | if (const Optional<YAMLRemarkParser::ParseState> &State = YAMLParser.State) | 
|  | 50 | return &State->TheRemark; | 
|  | 51 | else | 
|  | 52 | return createStringError(std::make_error_code(std::errc::invalid_argument), | 
|  | 53 | "unexpected error while parsing."); | 
|  | 54 | } | 
|  | 55 |  | 
|  | 56 | Expected<const Remark *> Parser::getNext() const { | 
|  | 57 | if (auto *Impl = dyn_cast<YAMLParserImpl>(this->Impl.get())) | 
|  | 58 | return getNextYAML(*Impl); | 
|  | 59 | llvm_unreachable("Get next called with an unknown parsing implementation."); | 
|  | 60 | } | 
|  | 61 |  | 
| Francis Visoiu Mistrih | 7fee2b8 | 2019-04-24 00:06:24 +0000 | [diff] [blame] | 62 | ParsedStringTable::ParsedStringTable(StringRef InBuffer) : Buffer(InBuffer) { | 
|  | 63 | while (!InBuffer.empty()) { | 
|  | 64 | // Strings are separated by '\0' bytes. | 
|  | 65 | std::pair<StringRef, StringRef> Split = InBuffer.split('\0'); | 
|  | 66 | // We only store the offset from the beginning of the buffer. | 
|  | 67 | Offsets.push_back(Split.first.data() - Buffer.data()); | 
|  | 68 | InBuffer = Split.second; | 
|  | 69 | } | 
|  | 70 | } | 
|  | 71 |  | 
| Francis Visoiu Mistrih | e6ba313 | 2019-07-04 00:30:58 +0000 | [diff] [blame^] | 72 | Expected<StringRef> ParsedStringTable::operator[](size_t Index) const { | 
| Francis Visoiu Mistrih | 7fee2b8 | 2019-04-24 00:06:24 +0000 | [diff] [blame] | 73 | if (Index >= Offsets.size()) | 
|  | 74 | return createStringError( | 
|  | 75 | std::make_error_code(std::errc::invalid_argument), | 
|  | 76 | "String with index %u is out of bounds (size = %u).", Index, | 
|  | 77 | Offsets.size()); | 
|  | 78 |  | 
|  | 79 | size_t Offset = Offsets[Index]; | 
|  | 80 | // If it's the last offset, we can't use the next offset to know the size of | 
|  | 81 | // the string. | 
|  | 82 | size_t NextOffset = | 
|  | 83 | (Index == Offsets.size() - 1) ? Buffer.size() : Offsets[Index + 1]; | 
|  | 84 | return StringRef(Buffer.data() + Offset, NextOffset - Offset - 1); | 
|  | 85 | } | 
|  | 86 |  | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 87 | // Create wrappers for C Binding types (see CBindingWrapping.h). | 
|  | 88 | DEFINE_SIMPLE_CONVERSION_FUNCTIONS(remarks::Parser, LLVMRemarkParserRef) | 
|  | 89 |  | 
|  | 90 | extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf, | 
|  | 91 | uint64_t Size) { | 
|  | 92 | return wrap( | 
|  | 93 | new remarks::Parser(StringRef(static_cast<const char *>(Buf), Size))); | 
|  | 94 | } | 
|  | 95 |  | 
|  | 96 | static void handleYAMLError(remarks::YAMLParserImpl &Impl, Error E) { | 
|  | 97 | handleAllErrors( | 
|  | 98 | std::move(E), | 
|  | 99 | [&](const YAMLParseError &PE) { | 
|  | 100 | Impl.YAMLParser.Stream.printError(&PE.getNode(), | 
|  | 101 | Twine(PE.getMessage()) + Twine('\n')); | 
|  | 102 | }, | 
|  | 103 | [&](const ErrorInfoBase &EIB) { EIB.log(Impl.YAMLParser.ErrorStream); }); | 
|  | 104 | Impl.HasErrors = true; | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | extern "C" LLVMRemarkEntryRef | 
|  | 108 | LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) { | 
|  | 109 | remarks::Parser &TheParser = *unwrap(Parser); | 
|  | 110 |  | 
|  | 111 | Expected<const remarks::Remark *> RemarkOrErr = TheParser.getNext(); | 
|  | 112 | if (!RemarkOrErr) { | 
|  | 113 | // Error during parsing. | 
|  | 114 | if (auto *Impl = dyn_cast<remarks::YAMLParserImpl>(TheParser.Impl.get())) | 
|  | 115 | handleYAMLError(*Impl, RemarkOrErr.takeError()); | 
|  | 116 | else | 
|  | 117 | llvm_unreachable("unkown parser implementation."); | 
|  | 118 | return nullptr; | 
|  | 119 | } | 
|  | 120 |  | 
|  | 121 | if (*RemarkOrErr == nullptr) | 
|  | 122 | return nullptr; | 
|  | 123 | // Valid remark. | 
|  | 124 | return wrap(*RemarkOrErr); | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 125 | } | 
|  | 126 |  | 
| Francis Visoiu Mistrih | 1c4bab3 | 2019-03-05 20:45:17 +0000 | [diff] [blame] | 127 | extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) { | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 128 | if (auto *Impl = | 
|  | 129 | dyn_cast<remarks::YAMLParserImpl>(unwrap(Parser)->Impl.get())) | 
|  | 130 | return Impl->HasErrors; | 
|  | 131 | llvm_unreachable("unkown parser implementation."); | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 132 | } | 
|  | 133 |  | 
|  | 134 | extern "C" const char * | 
| Francis Visoiu Mistrih | 1c4bab3 | 2019-03-05 20:45:17 +0000 | [diff] [blame] | 135 | LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) { | 
| Francis Visoiu Mistrih | 5a05cc0 | 2019-03-19 21:11:07 +0000 | [diff] [blame] | 136 | if (auto *Impl = | 
|  | 137 | dyn_cast<remarks::YAMLParserImpl>(unwrap(Parser)->Impl.get())) | 
|  | 138 | return Impl->YAMLParser.ErrorStream.str().c_str(); | 
|  | 139 | llvm_unreachable("unkown parser implementation."); | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 140 | } | 
|  | 141 |  | 
| Francis Visoiu Mistrih | 1c4bab3 | 2019-03-05 20:45:17 +0000 | [diff] [blame] | 142 | extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) { | 
| Francis Visoiu Mistrih | 2e76cab | 2018-10-10 18:43:42 +0000 | [diff] [blame] | 143 | delete unwrap(Parser); | 
|  | 144 | } |