| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| /*! |
| * \file diagnostic.h |
| * \brief A new diagnostic interface for TVM error reporting. |
| * |
| * A prototype of the new diagnostic reporting interface for TVM. |
| * |
| * Eventually we hope to promote this file to the top-level and |
| * replace the existing errors.h. |
| */ |
| |
| #ifndef TVM_PARSER_DIAGNOSTIC_H_ |
| #define TVM_PARSER_DIAGNOSTIC_H_ |
| |
| #include <tvm/ir/span.h> |
| #include <tvm/parser/source_map.h> |
| #include <tvm/runtime/container.h> |
| #include <tvm/runtime/object.h> |
| |
| #include <fstream> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| namespace tvm { |
| namespace parser { |
| |
| /*! \brief The diagnostic level, controls the printing of the message. */ |
| enum class DiagnosticLevel { |
| kBug, |
| kError, |
| kWarning, |
| kNote, |
| kHelp, |
| }; |
| |
| struct DiagnosticBuilder; |
| |
| /*! \brief A diagnostic message. */ |
| struct Diagnostic { |
| /*! \brief The level. */ |
| DiagnosticLevel level; |
| /*! \brief The span at which to report an error. */ |
| Span span; |
| /*! \brief The diagnostic message. */ |
| std::string message; |
| |
| Diagnostic(DiagnosticLevel level, Span span, const std::string& message) |
| : level(level), span(span), message(message) {} |
| |
| static DiagnosticBuilder Bug(Span span); |
| static DiagnosticBuilder Error(Span span); |
| static DiagnosticBuilder Warning(Span span); |
| static DiagnosticBuilder Note(Span span); |
| static DiagnosticBuilder Help(Span span); |
| }; |
| |
| /*! |
| * \brief A wrapper around std::stringstream to build a diagnostic. |
| * |
| * \code |
| * |
| * void ReportError(const Error& err); |
| * |
| * void Test(int number) { |
| * // Use error reporter to construct an error. |
| * ReportError(ErrorBuilder() << "This is an error number=" << number); |
| * } |
| * |
| * \endcode |
| */ |
| struct DiagnosticBuilder { |
| public: |
| /*! \brief The level. */ |
| DiagnosticLevel level; |
| |
| /*! \brief The source name. */ |
| SourceName source_name; |
| |
| /*! \brief The span of the diagnostic. */ |
| Span span; |
| |
| template <typename T> |
| DiagnosticBuilder& operator<<(const T& val) { // NOLINT(*) |
| stream_ << val; |
| return *this; |
| } |
| |
| DiagnosticBuilder() : level(DiagnosticLevel::kError), source_name(), span(Span()) {} |
| |
| DiagnosticBuilder(const DiagnosticBuilder& builder) |
| : level(builder.level), source_name(builder.source_name), span(builder.span) {} |
| |
| DiagnosticBuilder(DiagnosticLevel level, Span span) : level(level), span(span) {} |
| |
| operator Diagnostic() { return Diagnostic(this->level, this->span, this->stream_.str()); } |
| |
| private: |
| std::stringstream stream_; |
| friend struct Diagnostic; |
| }; |
| |
| DiagnosticBuilder Diagnostic::Bug(Span span) { |
| return DiagnosticBuilder(DiagnosticLevel::kBug, span); |
| } |
| |
| DiagnosticBuilder Diagnostic::Error(Span span) { |
| return DiagnosticBuilder(DiagnosticLevel::kError, span); |
| } |
| |
| DiagnosticBuilder Diagnostic::Warning(Span span) { |
| return DiagnosticBuilder(DiagnosticLevel::kWarning, span); |
| } |
| |
| DiagnosticBuilder Diagnostic::Note(Span span) { |
| return DiagnosticBuilder(DiagnosticLevel::kNote, span); |
| } |
| |
| DiagnosticBuilder Diagnostic::Help(Span span) { |
| return DiagnosticBuilder(DiagnosticLevel::kHelp, span); |
| } |
| |
| /*! \brief A diagnostic context for recording errors against a source file. |
| * TODO(jroesch): convert source map and improve in follow up PR, the parser |
| * assumes a single global file for now. |
| */ |
| struct DiagnosticContext { |
| /*! \brief The source to report against. */ |
| Source source; |
| |
| /*! \brief The set of diagnostics to report. */ |
| std::vector<Diagnostic> diagnostics; |
| |
| explicit DiagnosticContext(const Source& source) : source(source) {} |
| |
| /*! \brief Emit a diagnostic. */ |
| void Emit(const Diagnostic& diagnostic) { diagnostics.push_back(diagnostic); } |
| |
| /*! \brief Emit a diagnostic. */ |
| void EmitFatal(const Diagnostic& diagnostic) { |
| diagnostics.push_back(diagnostic); |
| Render(std::cout); |
| } |
| |
| // TODO(jroesch): eventually modularize the rendering interface to provide control of how to |
| // format errors. |
| void Render(std::ostream& ostream) { |
| for (auto diagnostic : diagnostics) { |
| source.ReportAt(ostream, diagnostic.span, diagnostic.message); |
| } |
| |
| if (diagnostics.size()) { |
| LOG(FATAL) << "DiagnosticError: one or more error diagnostics were " |
| << "emitted, please check diagnostic render for output."; |
| } |
| } |
| }; |
| |
| } // namespace parser |
| } // namespace tvm |
| #endif // TVM_PARSER_DIAGNOSTIC_H_ |