Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/openvic-simulation/core/Typedefs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <array>
#include <string_view>
#include <type_traits> // IWYU pragma: keep
#include <utility>

#if defined(__GNUC__)
Expand Down Expand Up @@ -61,6 +62,9 @@
#endif
#endif // OV_LIFETIME_BOUND

#define OV_MOV(...) static_cast<std::remove_reference_t<decltype(__VA_ARGS__)>&&>(__VA_ARGS__)
#define OV_FWD(...) static_cast<decltype(__VA_ARGS__)>(__VA_ARGS__)

namespace OpenVic {
template<std::size_t... Idxs>
constexpr auto substring_as_array(std::string_view str, std::index_sequence<Idxs...>) {
Expand Down
12 changes: 3 additions & 9 deletions src/openvic-simulation/core/memory/Formatting.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,9 @@

namespace OpenVic::memory {
namespace fmt {
template<typename T, class RawAllocator = foonathan::memory::default_allocator>
using basic_memory_buffer = ::fmt::basic_memory_buffer<
T,
::fmt::inline_buffer_size,
foonathan::memory::std_allocator<
T,
OpenVic::memory::tracker<RawAllocator>
>
>;
template<typename T, size_t SIZE = ::fmt::inline_buffer_size, class RawAllocator = foonathan::memory::default_allocator>
using basic_memory_buffer =
::fmt::basic_memory_buffer<T, SIZE, foonathan::memory::std_allocator<T, OpenVic::memory::tracker<RawAllocator>>>;

inline static memory::string vformat(::fmt::string_view fmt, ::fmt::format_args args) {
memory::fmt::basic_memory_buffer<char> buf {};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#include "DiagnosticBag.hpp"

#include <fmt/base.h>

#include <range/v3/algorithm/sort.hpp>

#include <spdlog/common.h>
#include <spdlog/logger.h>

#include "openvic-simulation/core/Typedefs.hpp"
#include "openvic-simulation/core/memory/Formatting.hpp"
#include "openvic-simulation/core/memory/Vector.hpp"
#include "openvic-simulation/definition/dataloader/diagnostic/DiagnosticItem.hpp"
#include "openvic-simulation/definition/dataloader/diagnostic/DiagnosticLevel.hpp"

using namespace OpenVic::dataloader;

DiagnosticBag::DiagnosticBag(ovdl::v2script::Parser const* parser) : _parser(parser) {}

DiagnosticItem& DiagnosticBag::fatal(ovdl::v2script::ast::Node const* node) {
return report(DiagnosticLevel::FATAL, node);
}

DiagnosticItem& DiagnosticBag::error(ovdl::v2script::ast::Node const* node) {
return report(DiagnosticLevel::ERROR, node);
}

DiagnosticItem& DiagnosticBag::warning(ovdl::v2script::ast::Node const* node) {
return report(DiagnosticLevel::WARN, node);
}

DiagnosticItem& DiagnosticBag::info(ovdl::v2script::ast::Node const* node) {
return report(DiagnosticLevel::INFO, node);
}

DiagnosticItem& DiagnosticBag::hint(ovdl::v2script::ast::Node const* node) {
return report(DiagnosticLevel::HINT, node);
}

DiagnosticItem& DiagnosticBag::suggestion(ovdl::v2script::ast::Node const* node) {
return report(DiagnosticLevel::SUGGEST, node);
}

DiagnosticItem& DiagnosticBag::report(DiagnosticLevel level, ovdl::v2script::ast::Node const* node) {
return report({ *this, node }).with_level(level);
}

DiagnosticItem& DiagnosticBag::report(DiagnosticItem&& item) {
DiagnosticItem& report = *_diagnostics.emplace(std::move(item));
report._bag = this;
switch (report.level()) {
case DiagnosticLevel::FATAL: _fatal_error = true; [[fallthrough]];
case DiagnosticLevel::ERROR: _error_count++; break;
case DiagnosticLevel::WARN: _warning_count++; break;
default: break;
}
return report;
}

void DiagnosticBag::clear() {
_diagnostics.clear();
}

void DiagnosticBag::sort() {
if (parser() == nullptr) {
_diagnostics.sort([](DiagnosticItem const& a, DiagnosticItem const& b) -> bool {
if (a.is_primary() != b.is_primary()) {
return a.is_primary();
}

if (a.level() != b.level() && a.level() > DiagnosticLevel::WARN && b.level() > DiagnosticLevel::WARN) {
return a.level() > b.level();
}

return true;
});
}

_diagnostics.sort([](DiagnosticItem const& a, DiagnosticItem const& b) -> bool {
if (a.is_primary() != b.is_primary()) {
return a.is_primary();
}

if (a.level() != b.level() && a.level() > DiagnosticLevel::WARN && b.level() > DiagnosticLevel::WARN) {
return a.level() > b.level();
}

if (a.location().start_line != b.location().start_line) {
return a.location().start_line < b.location().start_line;
}

return a.location().start_column < b.location().start_column;
});
}

DiagnosticBag DiagnosticBag::as_sorted() const {
DiagnosticBag sorted(*this);
sorted.sort();
return sorted;
}

template<bool IsParserNullptr>
void DiagnosticBag::log_to_impl(spdlog::logger* logger) const {
for (DiagnosticItem const& item : _diagnostics) {
if (item.is_secondary()) {
continue;
}

spdlog::level::level_enum log_level;
switch (item.level()) {
case DiagnosticLevel::NONE: continue;
case DiagnosticLevel::FATAL:
case DiagnosticLevel::ERROR: log_level = spdlog::level::err; break;
case DiagnosticLevel::WARN: log_level = spdlog::level::warn; break;
case DiagnosticLevel::INFO:
case DiagnosticLevel::HINT:
case DiagnosticLevel::SUGGEST: log_level = spdlog::level::info; break;
}

if (item.related_items().empty()) {
if constexpr (IsParserNullptr) {
logger->log(log_level, item.message());
} else {
logger->log(
log_level,
"{}:{}:{}: {}",
item.filepath(),
item.location().start_line,
item.location().start_column,
item.message()
);
}
} else {
memory::fmt::basic_memory_buffer<char, 250> buf;
auto out = fmt::appender(buf);

DiagnosticItem const* last = item.related_items().back();
for (DiagnosticItem const* sec : item.related_items()) {
switch (sec->level()) {
case DiagnosticLevel::NONE: break;
case DiagnosticLevel::FATAL: out = fmt::detail::write<char>(out, "fatal: "); break;
case DiagnosticLevel::ERROR: out = fmt::detail::write<char>(out, "error: "); break;
case DiagnosticLevel::WARN: out = fmt::detail::write<char>(out, "warning: "); break;
case DiagnosticLevel::INFO: out = fmt::detail::write<char>(out, "info: "); break;
case DiagnosticLevel::HINT: out = fmt::detail::write<char>(out, "hint: "); break;
case DiagnosticLevel::SUGGEST: out = fmt::detail::write<char>(out, "suggestion: "); break;
}
if constexpr (IsParserNullptr) {
out = fmt::detail::write<char>(out, sec->message());
} else {
out = fmt::detail::write<char>(out, sec->filepath());
out = fmt::detail::write<char>(out, ':');
out = fmt::detail::write<char>(out, sec->filepath());
out = fmt::detail::write<char>(out, ':');
out = fmt::detail::write<char>(out, sec->filepath());
out = fmt::detail::write<char>(out, ": ");
out = fmt::detail::write<char>(out, sec->message());
}
if (last != sec) {
out = fmt::detail::write<char>(out, "\n\t");
}
}

std::string_view sv { buf.data(), buf.size() };
if constexpr (IsParserNullptr) {
logger->log(log_level, "{}\n\t{}", item.message(), sv);
} else {
logger->log(
log_level,
"{}:{}:{}: {}\n\t{}",
item.filepath(),
item.location().start_line,
item.location().start_column,
item.message(),
sv
);
}
}
}
}

void DiagnosticBag::log_to(spdlog::logger* logger) const {
if (parser() == nullptr) {
log_to_impl<true>(logger);
return;
}

log_to_impl<false>(logger);
}

ovdl::v2script::Parser const* DiagnosticBag::parser() const {
return _parser;
}

OpenVic::memory::colony<DiagnosticItem> const& DiagnosticBag::diagnostics() const& {
return _diagnostics;
}

OpenVic::memory::colony<DiagnosticItem> DiagnosticBag::diagnostics() && {
return OV_MOV(_diagnostics);
}

size_t DiagnosticBag::error_count() const {
return _error_count;
}

size_t DiagnosticBag::warning_count() const {
return _warning_count;
}

bool DiagnosticBag::has_fatal_error() const {
return _fatal_error;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#pragma once

#include <utility>

#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
#include <openvic-dataloader/v2script/Parser.hpp>

#include <range/v3/view/filter.hpp>

#include "openvic-simulation/core/Typedefs.hpp"
#include "openvic-simulation/core/memory/Colony.hpp"
#include "openvic-simulation/definition/dataloader/diagnostic/DiagnosticCode.hpp"
#include "openvic-simulation/definition/dataloader/diagnostic/DiagnosticItem.hpp"
#include "openvic-simulation/definition/dataloader/diagnostic/DiagnosticLevel.hpp"

namespace spdlog {
class logger;
}

namespace OpenVic::dataloader {
class DiagnosticBag {
public:
friend class DiagnosticItem;

DiagnosticBag(ovdl::v2script::Parser const* parser);

DiagnosticItem& fatal(ovdl::v2script::ast::Node const* node) OV_LIFETIME_BOUND;
DiagnosticItem& error(ovdl::v2script::ast::Node const* node) OV_LIFETIME_BOUND;
DiagnosticItem& warning(ovdl::v2script::ast::Node const* node) OV_LIFETIME_BOUND;
DiagnosticItem& info(ovdl::v2script::ast::Node const* node) OV_LIFETIME_BOUND;
DiagnosticItem& hint(ovdl::v2script::ast::Node const* node) OV_LIFETIME_BOUND;
DiagnosticItem& suggestion(ovdl::v2script::ast::Node const* node) OV_LIFETIME_BOUND;
DiagnosticItem& report(DiagnosticLevel level, ovdl::v2script::ast::Node const* node) OV_LIFETIME_BOUND;

void clear();
void sort();

DiagnosticBag as_sorted() const;

void log_to(spdlog::logger* logger) const;

ovdl::v2script::Parser const* parser() const;

memory::colony<DiagnosticItem> const& diagnostics() const & OV_LIFETIME_BOUND;
memory::colony<DiagnosticItem> diagnostics() &&;

size_t error_count() const;
size_t warning_count() const;
bool has_fatal_error() const;

template<typename Predicate>
auto filter(Predicate&& predicate) const OV_LIFETIME_BOUND {
return _diagnostics | ranges::views::filter(std::forward<Predicate>(predicate));
}

auto errors() const OV_LIFETIME_BOUND {
return filter([](DiagnosticItem const& d) {
return d.level() <= DiagnosticLevel::ERROR;
});
}

auto warnings() const OV_LIFETIME_BOUND {
return filter([](DiagnosticItem const& d) {
return d.level() == DiagnosticLevel::WARN;
});
}

auto of_level(DiagnosticLevel level) const OV_LIFETIME_BOUND {
return filter([level](DiagnosticItem const& d) {
return d.level() == level;
});
}

auto of_code(diagnostic_code_t code) const OV_LIFETIME_BOUND {
return filter([code](DiagnosticItem const& d) {
return d.diagnostic_code() == code;
});
}

private:
memory::colony<DiagnosticItem> _diagnostics;
ovdl::v2script::Parser const* _parser;
size_t _error_count = 0;
size_t _warning_count = 0;
bool _fatal_error = false;

DiagnosticItem& report(DiagnosticItem&& item) OV_LIFETIME_BOUND;

template<bool IsParserNullptr>
void log_to_impl(spdlog::logger* logger) const;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "DiagnosticCode.hpp"

#include <fmt/base.h>
#include <fmt/format.h>

#include <type_safe/strong_typedef.hpp>

using namespace OpenVic::dataloader;

fmt::format_context::iterator fmt::formatter<diagnostic_code_t>::format(
diagnostic_code_t value, fmt::format_context& ctx
) const {
if (!_specs.dynamic()) {
return fmt::detail::write<char>(ctx.out(), type_safe::get(value), _specs, ctx.locale());
}
auto specs = fmt::format_specs(_specs);
fmt::detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, _specs.width_ref, ctx);
fmt::detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision, _specs.precision_ref, ctx);
return fmt::detail::write<char>(ctx.out(), type_safe::get(value), specs, ctx.locale());
}
Loading
Loading