10b57cec5SDimitry Andric //===- YAMLRemarkParser.cpp -----------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file provides utility methods used by clients that want to use the 100b57cec5SDimitry Andric // parser for remark diagnostics in LLVM. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "YAMLRemarkParser.h" 15*06c3fb27SDimitry Andric #include "llvm/ADT/SmallString.h" 160b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 178bcb0991SDimitry Andric #include "llvm/Support/Endian.h" 188bcb0991SDimitry Andric #include "llvm/Support/Path.h" 19bdd1243dSDimitry Andric #include <optional> 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric using namespace llvm::remarks; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric char YAMLParseError::ID = 0; 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric static void handleDiagnostic(const SMDiagnostic &Diag, void *Ctx) { 270b57cec5SDimitry Andric assert(Ctx && "Expected non-null Ctx in diagnostic handler."); 280b57cec5SDimitry Andric std::string &Message = *static_cast<std::string *>(Ctx); 290b57cec5SDimitry Andric assert(Message.empty() && "Expected an empty string."); 300b57cec5SDimitry Andric raw_string_ostream OS(Message); 310b57cec5SDimitry Andric Diag.print(/*ProgName=*/nullptr, OS, /*ShowColors*/ false, 320b57cec5SDimitry Andric /*ShowKindLabels*/ true); 330b57cec5SDimitry Andric OS << '\n'; 340b57cec5SDimitry Andric OS.flush(); 350b57cec5SDimitry Andric } 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric YAMLParseError::YAMLParseError(StringRef Msg, SourceMgr &SM, 380b57cec5SDimitry Andric yaml::Stream &Stream, yaml::Node &Node) { 390b57cec5SDimitry Andric // 1) Set up a diagnostic handler to avoid errors being printed out to 400b57cec5SDimitry Andric // stderr. 410b57cec5SDimitry Andric // 2) Use the stream to print the error with the associated node. 420b57cec5SDimitry Andric // 3) The stream will use the source manager to print the error, which will 430b57cec5SDimitry Andric // call the diagnostic handler. 440b57cec5SDimitry Andric // 4) The diagnostic handler will stream the error directly into this object's 450b57cec5SDimitry Andric // Message member, which is used when logging is asked for. 460b57cec5SDimitry Andric auto OldDiagHandler = SM.getDiagHandler(); 470b57cec5SDimitry Andric auto OldDiagCtx = SM.getDiagContext(); 480b57cec5SDimitry Andric SM.setDiagHandler(handleDiagnostic, &Message); 490b57cec5SDimitry Andric Stream.printError(&Node, Twine(Msg) + Twine('\n')); 500b57cec5SDimitry Andric // Restore the old handlers. 510b57cec5SDimitry Andric SM.setDiagHandler(OldDiagHandler, OldDiagCtx); 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric static SourceMgr setupSM(std::string &LastErrorMessage) { 550b57cec5SDimitry Andric SourceMgr SM; 560b57cec5SDimitry Andric SM.setDiagHandler(handleDiagnostic, &LastErrorMessage); 570b57cec5SDimitry Andric return SM; 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric 608bcb0991SDimitry Andric // Parse the magic number. This function returns true if this represents remark 618bcb0991SDimitry Andric // metadata, false otherwise. 628bcb0991SDimitry Andric static Expected<bool> parseMagic(StringRef &Buf) { 638bcb0991SDimitry Andric if (!Buf.consume_front(remarks::Magic)) 648bcb0991SDimitry Andric return false; 658bcb0991SDimitry Andric 668bcb0991SDimitry Andric if (Buf.size() < 1 || !Buf.consume_front(StringRef("\0", 1))) 678bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence, 688bcb0991SDimitry Andric "Expecting \\0 after magic number."); 698bcb0991SDimitry Andric return true; 708bcb0991SDimitry Andric } 718bcb0991SDimitry Andric 728bcb0991SDimitry Andric static Expected<uint64_t> parseVersion(StringRef &Buf) { 738bcb0991SDimitry Andric if (Buf.size() < sizeof(uint64_t)) 748bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence, 758bcb0991SDimitry Andric "Expecting version number."); 768bcb0991SDimitry Andric 778bcb0991SDimitry Andric uint64_t Version = 788bcb0991SDimitry Andric support::endian::read<uint64_t, support::little, support::unaligned>( 798bcb0991SDimitry Andric Buf.data()); 808bcb0991SDimitry Andric if (Version != remarks::CurrentRemarkVersion) 818bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence, 828bcb0991SDimitry Andric "Mismatching remark version. Got %" PRId64 838bcb0991SDimitry Andric ", expected %" PRId64 ".", 848bcb0991SDimitry Andric Version, remarks::CurrentRemarkVersion); 858bcb0991SDimitry Andric Buf = Buf.drop_front(sizeof(uint64_t)); 868bcb0991SDimitry Andric return Version; 878bcb0991SDimitry Andric } 888bcb0991SDimitry Andric 898bcb0991SDimitry Andric static Expected<uint64_t> parseStrTabSize(StringRef &Buf) { 908bcb0991SDimitry Andric if (Buf.size() < sizeof(uint64_t)) 918bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence, 928bcb0991SDimitry Andric "Expecting string table size."); 938bcb0991SDimitry Andric uint64_t StrTabSize = 948bcb0991SDimitry Andric support::endian::read<uint64_t, support::little, support::unaligned>( 958bcb0991SDimitry Andric Buf.data()); 968bcb0991SDimitry Andric Buf = Buf.drop_front(sizeof(uint64_t)); 978bcb0991SDimitry Andric return StrTabSize; 988bcb0991SDimitry Andric } 998bcb0991SDimitry Andric 1008bcb0991SDimitry Andric static Expected<ParsedStringTable> parseStrTab(StringRef &Buf, 1018bcb0991SDimitry Andric uint64_t StrTabSize) { 1028bcb0991SDimitry Andric if (Buf.size() < StrTabSize) 1038bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence, 1048bcb0991SDimitry Andric "Expecting string table."); 1058bcb0991SDimitry Andric 1068bcb0991SDimitry Andric // Attach the string table to the parser. 1078bcb0991SDimitry Andric ParsedStringTable Result(StringRef(Buf.data(), StrTabSize)); 1088bcb0991SDimitry Andric Buf = Buf.drop_front(StrTabSize); 1098bcb0991SDimitry Andric return Expected<ParsedStringTable>(std::move(Result)); 1108bcb0991SDimitry Andric } 1118bcb0991SDimitry Andric 112bdd1243dSDimitry Andric Expected<std::unique_ptr<YAMLRemarkParser>> remarks::createYAMLParserFromMeta( 113bdd1243dSDimitry Andric StringRef Buf, std::optional<ParsedStringTable> StrTab, 114bdd1243dSDimitry Andric std::optional<StringRef> ExternalFilePrependPath) { 1158bcb0991SDimitry Andric // We now have a magic number. The metadata has to be correct. 1168bcb0991SDimitry Andric Expected<bool> isMeta = parseMagic(Buf); 1178bcb0991SDimitry Andric if (!isMeta) 1188bcb0991SDimitry Andric return isMeta.takeError(); 1198bcb0991SDimitry Andric // If it's not recognized as metadata, roll back. 1208bcb0991SDimitry Andric std::unique_ptr<MemoryBuffer> SeparateBuf; 1218bcb0991SDimitry Andric if (*isMeta) { 1228bcb0991SDimitry Andric Expected<uint64_t> Version = parseVersion(Buf); 1238bcb0991SDimitry Andric if (!Version) 1248bcb0991SDimitry Andric return Version.takeError(); 1258bcb0991SDimitry Andric 1268bcb0991SDimitry Andric Expected<uint64_t> StrTabSize = parseStrTabSize(Buf); 1278bcb0991SDimitry Andric if (!StrTabSize) 1288bcb0991SDimitry Andric return StrTabSize.takeError(); 1298bcb0991SDimitry Andric 1308bcb0991SDimitry Andric // If the size of string table is not 0, try to build one. 1318bcb0991SDimitry Andric if (*StrTabSize != 0) { 1328bcb0991SDimitry Andric if (StrTab) 1338bcb0991SDimitry Andric return createStringError(std::errc::illegal_byte_sequence, 1348bcb0991SDimitry Andric "String table already provided."); 1358bcb0991SDimitry Andric Expected<ParsedStringTable> MaybeStrTab = parseStrTab(Buf, *StrTabSize); 1368bcb0991SDimitry Andric if (!MaybeStrTab) 1378bcb0991SDimitry Andric return MaybeStrTab.takeError(); 1388bcb0991SDimitry Andric StrTab = std::move(*MaybeStrTab); 1398bcb0991SDimitry Andric } 1408bcb0991SDimitry Andric // If it starts with "---", there is no external file. 1418bcb0991SDimitry Andric if (!Buf.startswith("---")) { 1428bcb0991SDimitry Andric // At this point, we expect Buf to contain the external file path. 1438bcb0991SDimitry Andric StringRef ExternalFilePath = Buf; 1448bcb0991SDimitry Andric SmallString<80> FullPath; 1458bcb0991SDimitry Andric if (ExternalFilePrependPath) 1468bcb0991SDimitry Andric FullPath = *ExternalFilePrependPath; 1478bcb0991SDimitry Andric sys::path::append(FullPath, ExternalFilePath); 1488bcb0991SDimitry Andric 1498bcb0991SDimitry Andric // Try to open the file and start parsing from there. 1508bcb0991SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 1518bcb0991SDimitry Andric MemoryBuffer::getFile(FullPath); 1528bcb0991SDimitry Andric if (std::error_code EC = BufferOrErr.getError()) 1538bcb0991SDimitry Andric return createFileError(FullPath, EC); 1548bcb0991SDimitry Andric 1558bcb0991SDimitry Andric // Keep the buffer alive. 1568bcb0991SDimitry Andric SeparateBuf = std::move(*BufferOrErr); 1578bcb0991SDimitry Andric Buf = SeparateBuf->getBuffer(); 1588bcb0991SDimitry Andric } 1598bcb0991SDimitry Andric } 1608bcb0991SDimitry Andric 1618bcb0991SDimitry Andric std::unique_ptr<YAMLRemarkParser> Result = 1628bcb0991SDimitry Andric StrTab 1638bcb0991SDimitry Andric ? std::make_unique<YAMLStrTabRemarkParser>(Buf, std::move(*StrTab)) 1648bcb0991SDimitry Andric : std::make_unique<YAMLRemarkParser>(Buf); 1658bcb0991SDimitry Andric if (SeparateBuf) 1668bcb0991SDimitry Andric Result->SeparateBuf = std::move(SeparateBuf); 1678bcb0991SDimitry Andric return std::move(Result); 1688bcb0991SDimitry Andric } 1698bcb0991SDimitry Andric 1708bcb0991SDimitry Andric YAMLRemarkParser::YAMLRemarkParser(StringRef Buf) 171bdd1243dSDimitry Andric : YAMLRemarkParser(Buf, std::nullopt) {} 1728bcb0991SDimitry Andric 1730b57cec5SDimitry Andric YAMLRemarkParser::YAMLRemarkParser(StringRef Buf, 174bdd1243dSDimitry Andric std::optional<ParsedStringTable> StrTab) 17504eeddc0SDimitry Andric : RemarkParser{Format::YAML}, StrTab(std::move(StrTab)), 1760b57cec5SDimitry Andric SM(setupSM(LastErrorMessage)), Stream(Buf, SM), YAMLIt(Stream.begin()) {} 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric Error YAMLRemarkParser::error(StringRef Message, yaml::Node &Node) { 1790b57cec5SDimitry Andric return make_error<YAMLParseError>(Message, SM, Stream, Node); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric Error YAMLRemarkParser::error() { 1830b57cec5SDimitry Andric if (LastErrorMessage.empty()) 1840b57cec5SDimitry Andric return Error::success(); 1850b57cec5SDimitry Andric Error E = make_error<YAMLParseError>(LastErrorMessage); 1860b57cec5SDimitry Andric LastErrorMessage.clear(); 1870b57cec5SDimitry Andric return E; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>> 1910b57cec5SDimitry Andric YAMLRemarkParser::parseRemark(yaml::Document &RemarkEntry) { 1920b57cec5SDimitry Andric if (Error E = error()) 1930b57cec5SDimitry Andric return std::move(E); 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric yaml::Node *YAMLRoot = RemarkEntry.getRoot(); 1960b57cec5SDimitry Andric if (!YAMLRoot) { 1970b57cec5SDimitry Andric return createStringError(std::make_error_code(std::errc::invalid_argument), 1980b57cec5SDimitry Andric "not a valid YAML file."); 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric auto *Root = dyn_cast<yaml::MappingNode>(YAMLRoot); 2020b57cec5SDimitry Andric if (!Root) 2030b57cec5SDimitry Andric return error("document root is not of mapping type.", *YAMLRoot); 2040b57cec5SDimitry Andric 2058bcb0991SDimitry Andric std::unique_ptr<Remark> Result = std::make_unique<Remark>(); 2060b57cec5SDimitry Andric Remark &TheRemark = *Result; 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric // First, the type. It needs special handling since is not part of the 2090b57cec5SDimitry Andric // key-value stream. 2100b57cec5SDimitry Andric Expected<Type> T = parseType(*Root); 2110b57cec5SDimitry Andric if (!T) 2120b57cec5SDimitry Andric return T.takeError(); 2130b57cec5SDimitry Andric else 2140b57cec5SDimitry Andric TheRemark.RemarkType = *T; 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric // Then, parse the fields, one by one. 2170b57cec5SDimitry Andric for (yaml::KeyValueNode &RemarkField : *Root) { 2180b57cec5SDimitry Andric Expected<StringRef> MaybeKey = parseKey(RemarkField); 2190b57cec5SDimitry Andric if (!MaybeKey) 2200b57cec5SDimitry Andric return MaybeKey.takeError(); 2210b57cec5SDimitry Andric StringRef KeyName = *MaybeKey; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric if (KeyName == "Pass") { 2240b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(RemarkField)) 2250b57cec5SDimitry Andric TheRemark.PassName = *MaybeStr; 2260b57cec5SDimitry Andric else 2270b57cec5SDimitry Andric return MaybeStr.takeError(); 2280b57cec5SDimitry Andric } else if (KeyName == "Name") { 2290b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(RemarkField)) 2300b57cec5SDimitry Andric TheRemark.RemarkName = *MaybeStr; 2310b57cec5SDimitry Andric else 2320b57cec5SDimitry Andric return MaybeStr.takeError(); 2330b57cec5SDimitry Andric } else if (KeyName == "Function") { 2340b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(RemarkField)) 2350b57cec5SDimitry Andric TheRemark.FunctionName = *MaybeStr; 2360b57cec5SDimitry Andric else 2370b57cec5SDimitry Andric return MaybeStr.takeError(); 2380b57cec5SDimitry Andric } else if (KeyName == "Hotness") { 2390b57cec5SDimitry Andric if (Expected<unsigned> MaybeU = parseUnsigned(RemarkField)) 2400b57cec5SDimitry Andric TheRemark.Hotness = *MaybeU; 2410b57cec5SDimitry Andric else 2420b57cec5SDimitry Andric return MaybeU.takeError(); 2430b57cec5SDimitry Andric } else if (KeyName == "DebugLoc") { 2440b57cec5SDimitry Andric if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(RemarkField)) 2450b57cec5SDimitry Andric TheRemark.Loc = *MaybeLoc; 2460b57cec5SDimitry Andric else 2470b57cec5SDimitry Andric return MaybeLoc.takeError(); 2480b57cec5SDimitry Andric } else if (KeyName == "Args") { 2490b57cec5SDimitry Andric auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue()); 2500b57cec5SDimitry Andric if (!Args) 2510b57cec5SDimitry Andric return error("wrong value type for key.", RemarkField); 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric for (yaml::Node &Arg : *Args) { 2540b57cec5SDimitry Andric if (Expected<Argument> MaybeArg = parseArg(Arg)) 2550b57cec5SDimitry Andric TheRemark.Args.push_back(*MaybeArg); 2560b57cec5SDimitry Andric else 2570b57cec5SDimitry Andric return MaybeArg.takeError(); 2580b57cec5SDimitry Andric } 2590b57cec5SDimitry Andric } else { 2600b57cec5SDimitry Andric return error("unknown key.", RemarkField); 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric // Check if any of the mandatory fields are missing. 2650b57cec5SDimitry Andric if (TheRemark.RemarkType == Type::Unknown || TheRemark.PassName.empty() || 2660b57cec5SDimitry Andric TheRemark.RemarkName.empty() || TheRemark.FunctionName.empty()) 2670b57cec5SDimitry Andric return error("Type, Pass, Name or Function missing.", 2680b57cec5SDimitry Andric *RemarkEntry.getRoot()); 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric return std::move(Result); 2710b57cec5SDimitry Andric } 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric Expected<Type> YAMLRemarkParser::parseType(yaml::MappingNode &Node) { 2740b57cec5SDimitry Andric auto Type = StringSwitch<remarks::Type>(Node.getRawTag()) 2750b57cec5SDimitry Andric .Case("!Passed", remarks::Type::Passed) 2760b57cec5SDimitry Andric .Case("!Missed", remarks::Type::Missed) 2770b57cec5SDimitry Andric .Case("!Analysis", remarks::Type::Analysis) 2780b57cec5SDimitry Andric .Case("!AnalysisFPCommute", remarks::Type::AnalysisFPCommute) 2790b57cec5SDimitry Andric .Case("!AnalysisAliasing", remarks::Type::AnalysisAliasing) 2800b57cec5SDimitry Andric .Case("!Failure", remarks::Type::Failure) 2810b57cec5SDimitry Andric .Default(remarks::Type::Unknown); 2820b57cec5SDimitry Andric if (Type == remarks::Type::Unknown) 2830b57cec5SDimitry Andric return error("expected a remark tag.", Node); 2840b57cec5SDimitry Andric return Type; 2850b57cec5SDimitry Andric } 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric Expected<StringRef> YAMLRemarkParser::parseKey(yaml::KeyValueNode &Node) { 2880b57cec5SDimitry Andric if (auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey())) 2890b57cec5SDimitry Andric return Key->getRawValue(); 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric return error("key is not a string.", Node); 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric Expected<StringRef> YAMLRemarkParser::parseStr(yaml::KeyValueNode &Node) { 2950b57cec5SDimitry Andric auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 296*06c3fb27SDimitry Andric yaml::BlockScalarNode *ValueBlock; 297*06c3fb27SDimitry Andric StringRef Result; 298*06c3fb27SDimitry Andric if (!Value) { 299*06c3fb27SDimitry Andric // Try to parse the value as a block node. 300*06c3fb27SDimitry Andric ValueBlock = dyn_cast<yaml::BlockScalarNode>(Node.getValue()); 301*06c3fb27SDimitry Andric if (!ValueBlock) 3020b57cec5SDimitry Andric return error("expected a value of scalar type.", Node); 303*06c3fb27SDimitry Andric Result = ValueBlock->getValue(); 304*06c3fb27SDimitry Andric } else 305*06c3fb27SDimitry Andric Result = Value->getRawValue(); 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric if (Result.front() == '\'') 3080b57cec5SDimitry Andric Result = Result.drop_front(); 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric if (Result.back() == '\'') 3110b57cec5SDimitry Andric Result = Result.drop_back(); 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric return Result; 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric Expected<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) { 3170b57cec5SDimitry Andric SmallVector<char, 4> Tmp; 3180b57cec5SDimitry Andric auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 3190b57cec5SDimitry Andric if (!Value) 3200b57cec5SDimitry Andric return error("expected a value of scalar type.", Node); 3210b57cec5SDimitry Andric unsigned UnsignedValue = 0; 3220b57cec5SDimitry Andric if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue)) 3230b57cec5SDimitry Andric return error("expected a value of integer type.", *Value); 3240b57cec5SDimitry Andric return UnsignedValue; 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric Expected<RemarkLocation> 3280b57cec5SDimitry Andric YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode &Node) { 3290b57cec5SDimitry Andric auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue()); 3300b57cec5SDimitry Andric if (!DebugLoc) 3310b57cec5SDimitry Andric return error("expected a value of mapping type.", Node); 3320b57cec5SDimitry Andric 333bdd1243dSDimitry Andric std::optional<StringRef> File; 334bdd1243dSDimitry Andric std::optional<unsigned> Line; 335bdd1243dSDimitry Andric std::optional<unsigned> Column; 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric for (yaml::KeyValueNode &DLNode : *DebugLoc) { 3380b57cec5SDimitry Andric Expected<StringRef> MaybeKey = parseKey(DLNode); 3390b57cec5SDimitry Andric if (!MaybeKey) 3400b57cec5SDimitry Andric return MaybeKey.takeError(); 3410b57cec5SDimitry Andric StringRef KeyName = *MaybeKey; 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric if (KeyName == "File") { 3440b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(DLNode)) 3450b57cec5SDimitry Andric File = *MaybeStr; 3460b57cec5SDimitry Andric else 3470b57cec5SDimitry Andric return MaybeStr.takeError(); 3480b57cec5SDimitry Andric } else if (KeyName == "Column") { 3490b57cec5SDimitry Andric if (Expected<unsigned> MaybeU = parseUnsigned(DLNode)) 3500b57cec5SDimitry Andric Column = *MaybeU; 3510b57cec5SDimitry Andric else 3520b57cec5SDimitry Andric return MaybeU.takeError(); 3530b57cec5SDimitry Andric } else if (KeyName == "Line") { 3540b57cec5SDimitry Andric if (Expected<unsigned> MaybeU = parseUnsigned(DLNode)) 3550b57cec5SDimitry Andric Line = *MaybeU; 3560b57cec5SDimitry Andric else 3570b57cec5SDimitry Andric return MaybeU.takeError(); 3580b57cec5SDimitry Andric } else { 3590b57cec5SDimitry Andric return error("unknown entry in DebugLoc map.", DLNode); 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric // If any of the debug loc fields is missing, return an error. 3640b57cec5SDimitry Andric if (!File || !Line || !Column) 3650b57cec5SDimitry Andric return error("DebugLoc node incomplete.", Node); 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric return RemarkLocation{*File, *Line, *Column}; 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric Expected<Argument> YAMLRemarkParser::parseArg(yaml::Node &Node) { 3710b57cec5SDimitry Andric auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node); 3720b57cec5SDimitry Andric if (!ArgMap) 3730b57cec5SDimitry Andric return error("expected a value of mapping type.", Node); 3740b57cec5SDimitry Andric 375bdd1243dSDimitry Andric std::optional<StringRef> KeyStr; 376bdd1243dSDimitry Andric std::optional<StringRef> ValueStr; 377bdd1243dSDimitry Andric std::optional<RemarkLocation> Loc; 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric for (yaml::KeyValueNode &ArgEntry : *ArgMap) { 3800b57cec5SDimitry Andric Expected<StringRef> MaybeKey = parseKey(ArgEntry); 3810b57cec5SDimitry Andric if (!MaybeKey) 3820b57cec5SDimitry Andric return MaybeKey.takeError(); 3830b57cec5SDimitry Andric StringRef KeyName = *MaybeKey; 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric // Try to parse debug locs. 3860b57cec5SDimitry Andric if (KeyName == "DebugLoc") { 3870b57cec5SDimitry Andric // Can't have multiple DebugLoc entries per argument. 3880b57cec5SDimitry Andric if (Loc) 3890b57cec5SDimitry Andric return error("only one DebugLoc entry is allowed per argument.", 3900b57cec5SDimitry Andric ArgEntry); 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(ArgEntry)) { 3930b57cec5SDimitry Andric Loc = *MaybeLoc; 3940b57cec5SDimitry Andric continue; 3950b57cec5SDimitry Andric } else 3960b57cec5SDimitry Andric return MaybeLoc.takeError(); 3970b57cec5SDimitry Andric } 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric // If we already have a string, error out. 4000b57cec5SDimitry Andric if (ValueStr) 4010b57cec5SDimitry Andric return error("only one string entry is allowed per argument.", ArgEntry); 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric // Try to parse the value. 4040b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(ArgEntry)) 4050b57cec5SDimitry Andric ValueStr = *MaybeStr; 4060b57cec5SDimitry Andric else 4070b57cec5SDimitry Andric return MaybeStr.takeError(); 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric // Keep the key from the string. 4100b57cec5SDimitry Andric KeyStr = KeyName; 4110b57cec5SDimitry Andric } 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric if (!KeyStr) 4140b57cec5SDimitry Andric return error("argument key is missing.", *ArgMap); 4150b57cec5SDimitry Andric if (!ValueStr) 4160b57cec5SDimitry Andric return error("argument value is missing.", *ArgMap); 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric return Argument{*KeyStr, *ValueStr, Loc}; 4190b57cec5SDimitry Andric } 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>> YAMLRemarkParser::next() { 4220b57cec5SDimitry Andric if (YAMLIt == Stream.end()) 4230b57cec5SDimitry Andric return make_error<EndOfFileError>(); 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>> MaybeResult = parseRemark(*YAMLIt); 4260b57cec5SDimitry Andric if (!MaybeResult) { 4270b57cec5SDimitry Andric // Avoid garbage input, set the iterator to the end. 4280b57cec5SDimitry Andric YAMLIt = Stream.end(); 4290b57cec5SDimitry Andric return MaybeResult.takeError(); 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric ++YAMLIt; 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric return std::move(*MaybeResult); 4350b57cec5SDimitry Andric } 4368bcb0991SDimitry Andric 4378bcb0991SDimitry Andric Expected<StringRef> YAMLStrTabRemarkParser::parseStr(yaml::KeyValueNode &Node) { 4388bcb0991SDimitry Andric auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 439*06c3fb27SDimitry Andric yaml::BlockScalarNode *ValueBlock; 4408bcb0991SDimitry Andric StringRef Result; 441*06c3fb27SDimitry Andric if (!Value) { 442*06c3fb27SDimitry Andric // Try to parse the value as a block node. 443*06c3fb27SDimitry Andric ValueBlock = dyn_cast<yaml::BlockScalarNode>(Node.getValue()); 444*06c3fb27SDimitry Andric if (!ValueBlock) 445*06c3fb27SDimitry Andric return error("expected a value of scalar type.", Node); 446*06c3fb27SDimitry Andric Result = ValueBlock->getValue(); 447*06c3fb27SDimitry Andric } else 448*06c3fb27SDimitry Andric Result = Value->getRawValue(); 4498bcb0991SDimitry Andric // If we have a string table, parse it as an unsigned. 4508bcb0991SDimitry Andric unsigned StrID = 0; 4518bcb0991SDimitry Andric if (Expected<unsigned> MaybeStrID = parseUnsigned(Node)) 4528bcb0991SDimitry Andric StrID = *MaybeStrID; 4538bcb0991SDimitry Andric else 4548bcb0991SDimitry Andric return MaybeStrID.takeError(); 4558bcb0991SDimitry Andric 4568bcb0991SDimitry Andric if (Expected<StringRef> Str = (*StrTab)[StrID]) 4578bcb0991SDimitry Andric Result = *Str; 4588bcb0991SDimitry Andric else 4598bcb0991SDimitry Andric return Str.takeError(); 4608bcb0991SDimitry Andric 4618bcb0991SDimitry Andric if (Result.front() == '\'') 4628bcb0991SDimitry Andric Result = Result.drop_front(); 4638bcb0991SDimitry Andric 4648bcb0991SDimitry Andric if (Result.back() == '\'') 4658bcb0991SDimitry Andric Result = Result.drop_back(); 4668bcb0991SDimitry Andric 4678bcb0991SDimitry Andric return Result; 4688bcb0991SDimitry Andric } 469