blob: 085d1c4ea8fb6a485407ec1eb5da28a5dccc5301 [file] [log] [blame]
/*
* 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_