1 //===- Diagnostic.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 #include "Diagnostics.h"
10 #include "mlir/Query/Matcher/ErrorBuilder.h"
11
12 namespace mlir::query::matcher::internal {
13
14 Diagnostics::ArgStream &
operator <<(const llvm::Twine & arg)15 Diagnostics::ArgStream::operator<<(const llvm::Twine &arg) {
16 out->push_back(arg.str());
17 return *this;
18 }
19
addError(SourceRange range,ErrorType error)20 Diagnostics::ArgStream Diagnostics::addError(SourceRange range,
21 ErrorType error) {
22 errorValues.emplace_back();
23 ErrorContent &last = errorValues.back();
24 last.contextStack = contextStack;
25 last.messages.emplace_back();
26 last.messages.back().range = range;
27 last.messages.back().type = error;
28 return ArgStream(&last.messages.back().args);
29 }
30
errorTypeToFormatString(ErrorType type)31 static llvm::StringRef errorTypeToFormatString(ErrorType type) {
32 switch (type) {
33 case ErrorType::RegistryMatcherNotFound:
34 return "Matcher not found: $0";
35 case ErrorType::RegistryWrongArgCount:
36 return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
37 case ErrorType::RegistryWrongArgType:
38 return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
39 case ErrorType::RegistryValueNotFound:
40 return "Value not found: $0";
41 case ErrorType::RegistryNotBindable:
42 return "Matcher does not support binding.";
43
44 case ErrorType::ParserStringError:
45 return "Error parsing string token: <$0>";
46 case ErrorType::ParserNoOpenParen:
47 return "Error parsing matcher. Found token <$0> while looking for '('.";
48 case ErrorType::ParserNoCloseParen:
49 return "Error parsing matcher. Found end-of-code while looking for ')'.";
50 case ErrorType::ParserNoComma:
51 return "Error parsing matcher. Found token <$0> while looking for ','.";
52 case ErrorType::ParserNoCode:
53 return "End of code found while looking for token.";
54 case ErrorType::ParserNotAMatcher:
55 return "Input value is not a matcher expression.";
56 case ErrorType::ParserInvalidToken:
57 return "Invalid token <$0> found when looking for a value.";
58 case ErrorType::ParserTrailingCode:
59 return "Unexpected end of code.";
60 case ErrorType::ParserOverloadedType:
61 return "Input value has unresolved overloaded type: $0";
62 case ErrorType::ParserMalformedChainedExpr:
63 return "Period not followed by valid chained call.";
64 case ErrorType::ParserChainedExprInvalidArg:
65 return "Missing/Invalid argument for the chained call.";
66 case ErrorType::ParserChainedExprNoCloseParen:
67 return "Missing ')' for the chained call.";
68 case ErrorType::ParserChainedExprNoOpenParen:
69 return "Missing '(' for the chained call.";
70 case ErrorType::ParserFailedToBuildMatcher:
71 return "Failed to build matcher: $0.";
72
73 case ErrorType::None:
74 return "<N/A>";
75 }
76 llvm_unreachable("Unknown ErrorType value.");
77 }
78
formatErrorString(llvm::StringRef formatString,llvm::ArrayRef<std::string> args,llvm::raw_ostream & os)79 static void formatErrorString(llvm::StringRef formatString,
80 llvm::ArrayRef<std::string> args,
81 llvm::raw_ostream &os) {
82 while (!formatString.empty()) {
83 std::pair<llvm::StringRef, llvm::StringRef> pieces =
84 formatString.split("$");
85 os << pieces.first.str();
86 if (pieces.second.empty())
87 break;
88
89 const char next = pieces.second.front();
90 formatString = pieces.second.drop_front();
91 if (next >= '0' && next <= '9') {
92 const unsigned index = next - '0';
93 if (index < args.size()) {
94 os << args[index];
95 } else {
96 os << "<Argument_Not_Provided>";
97 }
98 }
99 }
100 }
101
maybeAddLineAndColumn(SourceRange range,llvm::raw_ostream & os)102 static void maybeAddLineAndColumn(SourceRange range, llvm::raw_ostream &os) {
103 if (range.start.line > 0 && range.start.column > 0) {
104 os << range.start.line << ":" << range.start.column << ": ";
105 }
106 }
107
printMessage(const Diagnostics::ErrorContent::Message & message,const llvm::Twine prefix,llvm::raw_ostream & os) const108 void Diagnostics::printMessage(
109 const Diagnostics::ErrorContent::Message &message, const llvm::Twine prefix,
110 llvm::raw_ostream &os) const {
111 maybeAddLineAndColumn(message.range, os);
112 os << prefix;
113 formatErrorString(errorTypeToFormatString(message.type), message.args, os);
114 }
115
printErrorContent(const Diagnostics::ErrorContent & content,llvm::raw_ostream & os) const116 void Diagnostics::printErrorContent(const Diagnostics::ErrorContent &content,
117 llvm::raw_ostream &os) const {
118 if (content.messages.size() == 1) {
119 printMessage(content.messages[0], "", os);
120 } else {
121 for (size_t i = 0, e = content.messages.size(); i != e; ++i) {
122 if (i != 0)
123 os << "\n";
124 printMessage(content.messages[i],
125 "Candidate " + llvm::Twine(i + 1) + ": ", os);
126 }
127 }
128 }
129
print(llvm::raw_ostream & os) const130 void Diagnostics::print(llvm::raw_ostream &os) const {
131 for (const ErrorContent &error : errorValues) {
132 if (&error != &errorValues.front())
133 os << "\n";
134 printErrorContent(error, os);
135 }
136 }
137
138 } // namespace mlir::query::matcher::internal
139