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