| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| //===-- llvm/Remarks/Remark.h - The remark type -----------------*- C++/-*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file provides an interface for parsing remarks in LLVM. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_REMARKS_REMARK_PARSER_H | ||
| #define LLVM_REMARKS_REMARK_PARSER_H | ||
|
|
||
| #include "llvm/ADT/StringRef.h" | ||
| #include "llvm/Remarks/Remark.h" | ||
| #include "llvm/Support/Error.h" | ||
| #include <memory> | ||
|
|
||
| namespace llvm { | ||
| namespace remarks { | ||
|
|
||
| struct ParserImpl; | ||
|
|
||
| /// Parser used to parse a raw buffer to remarks::Remark objects. | ||
| struct Parser { | ||
| /// The hidden implementation of the parser. | ||
| std::unique_ptr<ParserImpl> Impl; | ||
|
|
||
| /// Create a parser parsing \p Buffer to Remark objects. | ||
| /// This constructor should be only used for parsing YAML remarks. | ||
| Parser(StringRef Buffer); | ||
|
|
||
| // Needed because ParserImpl is an incomplete type. | ||
| ~Parser(); | ||
|
|
||
| /// Returns an empty Optional if it reached the end. | ||
| /// Returns a valid remark otherwise. | ||
| Expected<const Remark *> getNext() const; | ||
| }; | ||
|
|
||
| } // end namespace remarks | ||
| } // end namespace llvm | ||
|
|
||
| #endif /* LLVM_REMARKS_REMARK_PARSER_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| add_llvm_library(LLVMRemarks | ||
| Remark.cpp | ||
| RemarkParser.cpp | ||
| YAMLRemarkParser.cpp | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| //===- Remark.cpp ---------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Implementation of the Remark type and the C API. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "llvm/Remarks/Remark.h" | ||
| #include "llvm-c/Remarks.h" | ||
| #include "llvm/Support/CBindingWrapping.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
|
|
||
| using namespace llvm; | ||
| using namespace llvm::remarks; | ||
|
|
||
| std::string Remark::getArgsAsMsg() const { | ||
| std::string Str; | ||
| raw_string_ostream OS(Str); | ||
| for (const Argument &Arg : Args) | ||
| OS << Arg.Val; | ||
| return OS.str(); | ||
| } | ||
|
|
||
| // Create wrappers for C Binding types (see CBindingWrapping.h). | ||
| DEFINE_SIMPLE_CONVERSION_FUNCTIONS(StringRef, LLVMRemarkStringRef) | ||
|
|
||
| extern "C" const char *LLVMRemarkStringGetData(LLVMRemarkStringRef String) { | ||
| return unwrap(String)->data(); | ||
| } | ||
|
|
||
| extern "C" uint32_t LLVMRemarkStringGetLen(LLVMRemarkStringRef String) { | ||
| return unwrap(String)->size(); | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkStringRef | ||
| LLVMRemarkDebugLocGetSourceFilePath(LLVMRemarkDebugLocRef DL) { | ||
| return wrap(&unwrap(DL)->SourceFilePath); | ||
| } | ||
|
|
||
| extern "C" uint32_t LLVMRemarkDebugLocGetSourceLine(LLVMRemarkDebugLocRef DL) { | ||
| return unwrap(DL)->SourceLine; | ||
| } | ||
|
|
||
| extern "C" uint32_t | ||
| LLVMRemarkDebugLocGetSourceColumn(LLVMRemarkDebugLocRef DL) { | ||
| return unwrap(DL)->SourceColumn; | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkStringRef LLVMRemarkArgGetKey(LLVMRemarkArgRef Arg) { | ||
| return wrap(&unwrap(Arg)->Key); | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkStringRef LLVMRemarkArgGetValue(LLVMRemarkArgRef Arg) { | ||
| return wrap(&unwrap(Arg)->Val); | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkDebugLocRef | ||
| LLVMRemarkArgGetDebugLoc(LLVMRemarkArgRef Arg) { | ||
| if (const Optional<RemarkLocation> &Loc = unwrap(Arg)->Loc) | ||
| return wrap(&*Loc); | ||
| return nullptr; | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkType LLVMRemarkEntryGetType(LLVMRemarkEntryRef Remark) { | ||
| // Assume here that the enums can be converted both ways. | ||
| return static_cast<LLVMRemarkType>(unwrap(Remark)->RemarkType); | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkStringRef | ||
| LLVMRemarkEntryGetPassName(LLVMRemarkEntryRef Remark) { | ||
| return wrap(&unwrap(Remark)->PassName); | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkStringRef | ||
| LLVMRemarkEntryGetRemarkName(LLVMRemarkEntryRef Remark) { | ||
| return wrap(&unwrap(Remark)->RemarkName); | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkStringRef | ||
| LLVMRemarkEntryGetFunctionName(LLVMRemarkEntryRef Remark) { | ||
| return wrap(&unwrap(Remark)->FunctionName); | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkDebugLocRef | ||
| LLVMRemarkEntryGetDebugLoc(LLVMRemarkEntryRef Remark) { | ||
| if (const Optional<RemarkLocation> &Loc = unwrap(Remark)->Loc) | ||
| return wrap(&*Loc); | ||
| return nullptr; | ||
| } | ||
|
|
||
| extern "C" uint64_t LLVMRemarkEntryGetHotness(LLVMRemarkEntryRef Remark) { | ||
| if (const Optional<uint64_t> &Hotness = unwrap(Remark)->Hotness) | ||
| return *Hotness; | ||
| return 0; | ||
| } | ||
|
|
||
| extern "C" uint32_t LLVMRemarkEntryGetNumArgs(LLVMRemarkEntryRef Remark) { | ||
| return unwrap(Remark)->Args.size(); | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkArgRef | ||
| LLVMRemarkEntryGetFirstArg(LLVMRemarkEntryRef Remark) { | ||
| ArrayRef<Argument> Args = unwrap(Remark)->Args; | ||
| // No arguments to iterate on. | ||
| if (Args.empty()) | ||
| return NULL; | ||
| return reinterpret_cast<LLVMRemarkArgRef>( | ||
| const_cast<Argument *>(Args.begin())); | ||
| } | ||
|
|
||
| extern "C" LLVMRemarkArgRef | ||
| LLVMRemarkEntryGetNextArg(LLVMRemarkArgRef ArgIt, LLVMRemarkEntryRef Remark) { | ||
| // No more arguments to iterate on. | ||
| if (ArgIt == NULL) | ||
| return NULL; | ||
|
|
||
| auto It = (ArrayRef<Argument>::const_iterator)ArgIt; | ||
| auto Next = std::next(It); | ||
| if (Next == unwrap(Remark)->Args.end()) | ||
| return NULL; | ||
|
|
||
| return reinterpret_cast<LLVMRemarkArgRef>(const_cast<Argument *>(Next)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| //===-- RemarkParserImpl.h - Implementation details -------------*- C++/-*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file provides implementation details for the remark parser. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_REMARKS_REMARK_PARSER_IMPL_H | ||
| #define LLVM_REMARKS_REMARK_PARSER_IMPL_H | ||
|
|
||
| namespace llvm { | ||
| namespace remarks { | ||
| /// This is used as a base for any parser implementation. | ||
| struct ParserImpl { | ||
| enum class Kind { YAML }; | ||
|
|
||
| // The parser kind. This is used as a tag to safely cast between | ||
| // implementations. | ||
| enum Kind Kind; | ||
| }; | ||
| } // end namespace remarks | ||
| } // end namespace llvm | ||
|
|
||
| #endif /* LLVM_REMARKS_REMARK_PARSER_IMPL_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,261 @@ | ||
| //===- YAMLRemarkParser.cpp -----------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file provides utility methods used by clients that want to use the | ||
| // parser for remark diagnostics in LLVM. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "YAMLRemarkParser.h" | ||
| #include "llvm/ADT/StringSwitch.h" | ||
| #include "llvm/Remarks/RemarkParser.h" | ||
|
|
||
| using namespace llvm; | ||
| using namespace llvm::remarks; | ||
|
|
||
| char YAMLParseError::ID = 0; | ||
|
|
||
| Error YAMLRemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) { | ||
| if (auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey())) { | ||
| Result = Key->getRawValue(); | ||
| return Error::success(); | ||
| } | ||
|
|
||
| return make_error<YAMLParseError>("key is not a string.", Node); | ||
| } | ||
|
|
||
| template <typename T> | ||
| Error YAMLRemarkParser::parseStr(T &Result, yaml::KeyValueNode &Node) { | ||
| auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); | ||
| if (!Value) | ||
| return make_error<YAMLParseError>("expected a value of scalar type.", Node); | ||
| StringRef Tmp = Value->getRawValue(); | ||
|
|
||
| if (Tmp.front() == '\'') | ||
| Tmp = Tmp.drop_front(); | ||
|
|
||
| if (Tmp.back() == '\'') | ||
| Tmp = Tmp.drop_back(); | ||
|
|
||
| Result = Tmp; | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| template <typename T> | ||
| Error YAMLRemarkParser::parseUnsigned(T &Result, yaml::KeyValueNode &Node) { | ||
| SmallVector<char, 4> Tmp; | ||
| auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); | ||
| if (!Value) | ||
| return make_error<YAMLParseError>("expected a value of scalar type.", Node); | ||
| unsigned UnsignedValue = 0; | ||
| if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue)) | ||
| return make_error<YAMLParseError>("expected a value of integer type.", | ||
| *Value); | ||
| Result = UnsignedValue; | ||
| return Error::success(); | ||
| } | ||
|
|
||
| Error YAMLRemarkParser::parseType(Type &Result, yaml::MappingNode &Node) { | ||
| auto Type = StringSwitch<remarks::Type>(Node.getRawTag()) | ||
| .Case("!Passed", Type::Passed) | ||
| .Case("!Missed", Type::Missed) | ||
| .Case("!Analysis", Type::Analysis) | ||
| .Case("!AnalysisFPCommute", Type::AnalysisFPCommute) | ||
| .Case("!AnalysisAliasing", Type::AnalysisAliasing) | ||
| .Case("!Failure", Type::Failure) | ||
| .Default(Type::Unknown); | ||
| if (Type == Type::Unknown) | ||
| return make_error<YAMLParseError>("expected a remark tag.", Node); | ||
| Result = Type; | ||
| return Error::success(); | ||
| } | ||
|
|
||
| Error YAMLRemarkParser::parseDebugLoc(Optional<RemarkLocation> &Result, | ||
| yaml::KeyValueNode &Node) { | ||
| auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue()); | ||
| if (!DebugLoc) | ||
| return make_error<YAMLParseError>("expected a value of mapping type.", | ||
| Node); | ||
|
|
||
| Optional<StringRef> File; | ||
| Optional<unsigned> Line; | ||
| Optional<unsigned> Column; | ||
|
|
||
| for (yaml::KeyValueNode &DLNode : *DebugLoc) { | ||
| StringRef KeyName; | ||
| if (Error E = parseKey(KeyName, DLNode)) | ||
| return E; | ||
| if (KeyName == "File") { | ||
| if (Error E = parseStr(File, DLNode)) | ||
| return E; | ||
| } else if (KeyName == "Column") { | ||
| if (Error E = parseUnsigned(Column, DLNode)) | ||
| return E; | ||
| } else if (KeyName == "Line") { | ||
| if (Error E = parseUnsigned(Line, DLNode)) | ||
| return E; | ||
| } else { | ||
| return make_error<YAMLParseError>("unknown entry in DebugLoc map.", | ||
| DLNode); | ||
| } | ||
| } | ||
|
|
||
| // If any of the debug loc fields is missing, return an error. | ||
| if (!File || !Line || !Column) | ||
| return make_error<YAMLParseError>("DebugLoc node incomplete.", Node); | ||
|
|
||
| Result = RemarkLocation{*File, *Line, *Column}; | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| Error YAMLRemarkParser::parseRemarkField(yaml::KeyValueNode &RemarkField) { | ||
|
|
||
| StringRef KeyName; | ||
| if (Error E = parseKey(KeyName, RemarkField)) | ||
| return E; | ||
|
|
||
| if (KeyName == "Pass") { | ||
| if (Error E = parseStr(State->Remark.PassName, RemarkField)) | ||
| return E; | ||
| } else if (KeyName == "Name") { | ||
| if (Error E = parseStr(State->Remark.RemarkName, RemarkField)) | ||
| return E; | ||
| } else if (KeyName == "Function") { | ||
| if (Error E = parseStr(State->Remark.FunctionName, RemarkField)) | ||
| return E; | ||
| } else if (KeyName == "Hotness") { | ||
| State->Remark.Hotness = 0; | ||
| if (Error E = parseUnsigned(*State->Remark.Hotness, RemarkField)) | ||
| return E; | ||
| } else if (KeyName == "DebugLoc") { | ||
| if (Error E = parseDebugLoc(State->Remark.Loc, RemarkField)) | ||
| return E; | ||
| } else if (KeyName == "Args") { | ||
| auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue()); | ||
| if (!Args) | ||
| return make_error<YAMLParseError>("wrong value type for key.", | ||
| RemarkField); | ||
|
|
||
| for (yaml::Node &Arg : *Args) | ||
| if (Error E = parseArg(State->Args, Arg)) | ||
| return E; | ||
|
|
||
| State->Remark.Args = State->Args; | ||
| } else { | ||
| return make_error<YAMLParseError>("unknown key.", RemarkField); | ||
| } | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| Error YAMLRemarkParser::parseArg(SmallVectorImpl<Argument> &Args, | ||
| yaml::Node &Node) { | ||
| auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node); | ||
| if (!ArgMap) | ||
| return make_error<YAMLParseError>("expected a value of mapping type.", | ||
| Node); | ||
|
|
||
| StringRef KeyStr; | ||
| StringRef ValueStr; | ||
| Optional<RemarkLocation> Loc; | ||
|
|
||
| for (yaml::KeyValueNode &ArgEntry : *ArgMap) | ||
| if (Error E = parseArgEntry(ArgEntry, KeyStr, ValueStr, Loc)) | ||
| return E; | ||
|
|
||
| if (KeyStr.empty()) | ||
| return make_error<YAMLParseError>("argument key is missing.", *ArgMap); | ||
| if (ValueStr.empty()) | ||
| return make_error<YAMLParseError>("argument value is missing.", *ArgMap); | ||
|
|
||
| Args.push_back(Argument{KeyStr, ValueStr, Loc}); | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| Error YAMLRemarkParser::parseArgEntry(yaml::KeyValueNode &ArgEntry, | ||
| StringRef &KeyStr, StringRef &ValueStr, | ||
| Optional<RemarkLocation> &Loc) { | ||
| StringRef KeyName; | ||
| if (Error E = parseKey(KeyName, ArgEntry)) | ||
| return E; | ||
|
|
||
| // Try to parse debug locs. | ||
| if (KeyName == "DebugLoc") { | ||
| // Can't have multiple DebugLoc entries per argument. | ||
| if (Loc) | ||
| return make_error<YAMLParseError>( | ||
| "only one DebugLoc entry is allowed per argument.", ArgEntry); | ||
|
|
||
| if (Error E = parseDebugLoc(Loc, ArgEntry)) | ||
| return E; | ||
| return Error::success(); | ||
| } | ||
|
|
||
| // If we already have a string, error out. | ||
| if (!ValueStr.empty()) | ||
| return make_error<YAMLParseError>( | ||
| "only one string entry is allowed per argument.", ArgEntry); | ||
|
|
||
| // Try to parse a string. | ||
| if (Error E = parseStr(ValueStr, ArgEntry)) | ||
| return E; | ||
|
|
||
| // Keep the key from the string. | ||
| KeyStr = KeyName; | ||
| return Error::success(); | ||
| } | ||
|
|
||
| Error YAMLRemarkParser::parseYAMLElement(yaml::Document &Remark) { | ||
| // Parsing a new remark, clear the previous one by re-constructing the state | ||
| // in-place in the Optional. | ||
| State.emplace(TmpArgs); | ||
|
|
||
| yaml::Node *YAMLRoot = Remark.getRoot(); | ||
| if (!YAMLRoot) | ||
| return createStringError(std::make_error_code(std::errc::invalid_argument), | ||
| "not a valid YAML file."); | ||
|
|
||
| auto *Root = dyn_cast<yaml::MappingNode>(YAMLRoot); | ||
| if (!Root) | ||
| return make_error<YAMLParseError>("document root is not of mapping type.", | ||
| *YAMLRoot); | ||
|
|
||
| if (Error E = parseType(State->Remark.RemarkType, *Root)) | ||
| return E; | ||
|
|
||
| for (yaml::KeyValueNode &RemarkField : *Root) | ||
| if (Error E = parseRemarkField(RemarkField)) | ||
| return E; | ||
|
|
||
| // If the YAML parsing failed, don't even continue parsing. We might | ||
| // encounter malformed YAML. | ||
| if (Stream.failed()) | ||
| return make_error<YAMLParseError>("YAML parsing failed.", | ||
| *Remark.getRoot()); | ||
|
|
||
| // Check if any of the mandatory fields are missing. | ||
| if (State->Remark.RemarkType == Type::Unknown || | ||
| State->Remark.PassName.empty() || State->Remark.RemarkName.empty() || | ||
| State->Remark.FunctionName.empty()) | ||
| return make_error<YAMLParseError>("Type, Pass, Name or Function missing.", | ||
| *Remark.getRoot()); | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| /// Handle a diagnostic from the YAML stream. Records the error in the | ||
| /// YAMLRemarkParser class. | ||
| void YAMLRemarkParser::HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx) { | ||
| assert(Ctx && "Expected non-null Ctx in diagnostic handler."); | ||
| auto *Parser = static_cast<YAMLRemarkParser *>(Ctx); | ||
| Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false, | ||
| /*ShowKindLabels*/ true); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| //===-- YAMLRemarkParser.h - Parser for YAML remarks ------------*- C++/-*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file provides the impementation of the YAML remark parser. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_REMARKS_YAML_REMARK_PARSER_H | ||
| #define LLVM_REMARKS_YAML_REMARK_PARSER_H | ||
|
|
||
| #include "RemarkParserImpl.h" | ||
| #include "llvm/ADT/Optional.h" | ||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "llvm/Remarks/Remark.h" | ||
| #include "llvm/Support/Error.h" | ||
| #include "llvm/Support/SourceMgr.h" | ||
| #include "llvm/Support/YAMLParser.h" | ||
| #include "llvm/Support/YAMLTraits.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
| #include <string> | ||
|
|
||
| namespace llvm { | ||
| namespace remarks { | ||
| /// Parses and holds the state of the latest parsed remark. | ||
| struct YAMLRemarkParser { | ||
| /// Source manager for better error messages. | ||
| SourceMgr SM; | ||
| /// Stream for yaml parsing. | ||
| yaml::Stream Stream; | ||
| /// Storage for the error stream. | ||
| std::string ErrorString; | ||
| /// The error stream. | ||
| raw_string_ostream ErrorStream; | ||
| /// Temporary parsing buffer for the arguments. | ||
| SmallVector<Argument, 8> TmpArgs; | ||
|
|
||
| /// The state used by the parser to parse a remark entry. Invalidated with | ||
| /// every call to `parseYAMLElement`. | ||
| struct ParseState { | ||
| /// Temporary parsing buffer for the arguments. | ||
| /// The parser itself is owning this buffer in order to reduce the number of | ||
| /// allocations. | ||
| SmallVectorImpl<Argument> &Args; | ||
| Remark Remark; | ||
|
|
||
| ParseState(SmallVectorImpl<Argument> &Args) : Args(Args) {} | ||
| /// Use Args only as a **temporary** buffer. | ||
| ~ParseState() { Args.clear(); } | ||
| }; | ||
|
|
||
| /// The current state of the parser. If the parsing didn't start yet, it will | ||
| /// not be containing any value. | ||
| Optional<ParseState> State; | ||
|
|
||
| YAMLRemarkParser(StringRef Buf) | ||
| : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString), | ||
| TmpArgs() { | ||
| SM.setDiagHandler(YAMLRemarkParser::HandleDiagnostic, this); | ||
| } | ||
|
|
||
| /// Parse a YAML element. | ||
| Error parseYAMLElement(yaml::Document &Remark); | ||
|
|
||
| private: | ||
| /// Parse one key to a string. | ||
| /// otherwise. | ||
| Error parseKey(StringRef &Result, yaml::KeyValueNode &Node); | ||
| /// Parse one value to a string. | ||
| template <typename T> Error parseStr(T &Result, yaml::KeyValueNode &Node); | ||
| /// Parse one value to an unsigned. | ||
| template <typename T> | ||
| Error parseUnsigned(T &Result, yaml::KeyValueNode &Node); | ||
| /// Parse the type of a remark to an enum type. | ||
| Error parseType(Type &Result, yaml::MappingNode &Node); | ||
| /// Parse a debug location. | ||
| Error parseDebugLoc(Optional<RemarkLocation> &Result, | ||
| yaml::KeyValueNode &Node); | ||
| /// Parse a remark field and update the parsing state. | ||
| Error parseRemarkField(yaml::KeyValueNode &RemarkField); | ||
| /// Parse an argument. | ||
| Error parseArg(SmallVectorImpl<Argument> &TmpArgs, yaml::Node &Node); | ||
| /// Parse an entry from the contents of an argument. | ||
| Error parseArgEntry(yaml::KeyValueNode &ArgEntry, StringRef &KeyStr, | ||
| StringRef &ValueStr, Optional<RemarkLocation> &Loc); | ||
|
|
||
| /// Handle a diagnostic from the YAML stream. Records the error in the | ||
| /// YAMLRemarkParser class. | ||
| static void HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx); | ||
| }; | ||
|
|
||
| class YAMLParseError : public ErrorInfo<YAMLParseError> { | ||
| public: | ||
| static char ID; | ||
|
|
||
| YAMLParseError(StringRef Message, yaml::Node &Node) | ||
| : Message(Message), Node(Node) {} | ||
|
|
||
| void log(raw_ostream &OS) const override { OS << Message; } | ||
| std::error_code convertToErrorCode() const override { | ||
| return inconvertibleErrorCode(); | ||
| } | ||
|
|
||
| StringRef getMessage() const { return Message; } | ||
| yaml::Node &getNode() const { return Node; } | ||
|
|
||
| private: | ||
| StringRef Message; // No need to hold a full copy of the buffer. | ||
| yaml::Node &Node; | ||
| }; | ||
|
|
||
| /// Regular YAML to Remark parser. | ||
| struct YAMLParserImpl : public ParserImpl { | ||
| /// The object parsing the YAML. | ||
| YAMLRemarkParser YAMLParser; | ||
| /// Iterator in the YAML stream. | ||
| yaml::document_iterator YAMLIt; | ||
| /// Set to `true` if we had any errors during parsing. | ||
| bool HasErrors = false; | ||
|
|
||
| YAMLParserImpl(StringRef Buf) | ||
| : ParserImpl{ParserImpl::Kind::YAML}, YAMLParser(Buf), | ||
| YAMLIt(YAMLParser.Stream.begin()), HasErrors(false) {} | ||
|
|
||
| static bool classof(const ParserImpl *PI) { | ||
| return PI->Kind == ParserImpl::Kind::YAML; | ||
| } | ||
| }; | ||
| } // end namespace remarks | ||
| } // end namespace llvm | ||
|
|
||
| #endif /* LLVM_REMARKS_YAML_REMARK_PARSER_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,5 +4,5 @@ set(LLVM_LINK_COMPONENTS | |
| ) | ||
|
|
||
| add_llvm_unittest(RemarksTests | ||
| YAMLRemarksParsingTest.cpp | ||
| ) | ||