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 Parser::Parser(StringRef Buf) : Impl(llvm::make_unique<YAMLParserImpl>(Buf)) {} 24 25 Parser::~Parser() = default; 26 27 static Expected<const Remark *> getNextYAML(YAMLParserImpl &Impl) { 28 YAMLRemarkParser &YAMLParser = Impl.YAMLParser; 29 // Check for EOF. 30 if (Impl.YAMLIt == Impl.YAMLParser.Stream.end()) 31 return nullptr; 32 33 auto CurrentIt = Impl.YAMLIt; 34 35 // Try to parse an entry. 36 if (Error E = YAMLParser.parseYAMLElement(*CurrentIt)) { 37 // Set the iterator to the end, in case the user calls getNext again. 38 Impl.YAMLIt = Impl.YAMLParser.Stream.end(); 39 return std::move(E); 40 } 41 42 // Move on. 43 ++Impl.YAMLIt; 44 45 // Return the just-parsed remark. 46 if (const Optional<YAMLRemarkParser::ParseState> &State = YAMLParser.State) 47 return &State->TheRemark; 48 else 49 return createStringError(std::make_error_code(std::errc::invalid_argument), 50 "unexpected error while parsing."); 51 } 52 53 Expected<const Remark *> Parser::getNext() const { 54 if (auto *Impl = dyn_cast<YAMLParserImpl>(this->Impl.get())) 55 return getNextYAML(*Impl); 56 llvm_unreachable("Get next called with an unknown parsing implementation."); 57 } 58 59 // Create wrappers for C Binding types (see CBindingWrapping.h). 60 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(remarks::Parser, LLVMRemarkParserRef) 61 62 extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf, 63 uint64_t Size) { 64 return wrap( 65 new remarks::Parser(StringRef(static_cast<const char *>(Buf), Size))); 66 } 67 68 static void handleYAMLError(remarks::YAMLParserImpl &Impl, Error E) { 69 handleAllErrors( 70 std::move(E), 71 [&](const YAMLParseError &PE) { 72 Impl.YAMLParser.Stream.printError(&PE.getNode(), 73 Twine(PE.getMessage()) + Twine('\n')); 74 }, 75 [&](const ErrorInfoBase &EIB) { EIB.log(Impl.YAMLParser.ErrorStream); }); 76 Impl.HasErrors = true; 77 } 78 79 extern "C" LLVMRemarkEntryRef 80 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) { 81 remarks::Parser &TheParser = *unwrap(Parser); 82 83 Expected<const remarks::Remark *> RemarkOrErr = TheParser.getNext(); 84 if (!RemarkOrErr) { 85 // Error during parsing. 86 if (auto *Impl = dyn_cast<remarks::YAMLParserImpl>(TheParser.Impl.get())) 87 handleYAMLError(*Impl, RemarkOrErr.takeError()); 88 else 89 llvm_unreachable("unkown parser implementation."); 90 return nullptr; 91 } 92 93 if (*RemarkOrErr == nullptr) 94 return nullptr; 95 // Valid remark. 96 return wrap(*RemarkOrErr); 97 } 98 99 extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) { 100 if (auto *Impl = 101 dyn_cast<remarks::YAMLParserImpl>(unwrap(Parser)->Impl.get())) 102 return Impl->HasErrors; 103 llvm_unreachable("unkown parser implementation."); 104 } 105 106 extern "C" const char * 107 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) { 108 if (auto *Impl = 109 dyn_cast<remarks::YAMLParserImpl>(unwrap(Parser)->Impl.get())) 110 return Impl->YAMLParser.ErrorStream.str().c_str(); 111 llvm_unreachable("unkown parser implementation."); 112 } 113 114 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) { 115 delete unwrap(Parser); 116 } 117