type_check_utils: old version of log replaced

This commit is contained in:
programsnail 2024-07-28 20:19:42 +03:00
parent 831cfa36f3
commit fefe3a910d
5 changed files with 178 additions and 127 deletions

View file

@ -1,15 +1,20 @@
#pragma once #pragma once
#include "executor.hpp"
#include "expression_nodes.hpp" #include "expression_nodes.hpp"
#include "sources_manager.hpp" #include "log.hpp"
#include "type_check_utils.hpp" #include "name_tree.hpp"
#include "type_nodes.hpp" #include "type_nodes.hpp"
#include "utils.hpp"
#include <optional> #include <optional>
namespace type_check { namespace type_check {
using Executor = utils::Executor<nodes::ExpressionStorage, nodes::TypeStorage,
names::NameTree>;
using Task =
utils::Task<nodes::ExpressionStorage, nodes::TypeStorage, names::NameTree>;
class ContextHolder; class ContextHolder;
class State { class State {
@ -22,11 +27,15 @@ public:
}; };
public: public:
State(Log &log) : log_(log) {}
bool insert_variable(const std::string &name, nodes::TypeProxy type, bool insert_variable(const std::string &name, nodes::TypeProxy type,
nodes::NameDefinition::Modifier modifier) { nodes::NameDefinition::Modifier modifier) {
Log::Context logc(log_, utils::Log::Area::kTypeCheck);
if (contexts_.empty()) { if (contexts_.empty()) {
error_handling::handle_general_error( logc.Fatal<Log::kSys>(
"Insert variable into contexts_ with zero elements in State"); {{"Insert variable into contexts_ with zero elements in State"}});
} }
return contexts_.back() return contexts_.back()
@ -46,9 +55,11 @@ public:
} }
bool bring_type(nodes::TypeProxy type) { bool bring_type(nodes::TypeProxy type) {
Log::Context logc(log_, utils::Log::Area::kTypeCheck);
if (contexts_.empty()) { if (contexts_.empty()) {
error_handling::handle_general_error( logc.Fatal<Log::kSys>(
"Set brought type to contexts_ with zero elements in State"); {{"Set brought type to contexts_ with zero elements in State"}});
} }
auto &brought_type = contexts_.back().brought_type; auto &brought_type = contexts_.back().brought_type;
if (brought_type.has_value() && if (brought_type.has_value() &&
@ -60,9 +71,11 @@ public:
} }
bool return_type(nodes::TypeProxy type) { bool return_type(nodes::TypeProxy type) {
Log::Context logc(log_, utils::Log::Area::kTypeCheck);
if (contexts_.empty()) { if (contexts_.empty()) {
error_handling::handle_general_error( logc.Fatal<Log::kSys>(
"Set returned type to contexts_ with zero elements in State"); {{"Set returned type to contexts_ with zero elements in State"}});
} }
auto &returned_type = contexts_.back().returned_type; auto &returned_type = contexts_.back().returned_type;
if (returned_type.has_value() && if (returned_type.has_value() &&
@ -74,18 +87,21 @@ public:
} }
private: private:
void enter_context(const nodes::Node &node, void enter_context(const nodes::Node &node) {
error_handling::ErrorLog &error_log) { Log::Context logc(log_, utils::Log::Area::kTypeCheck);
contexts_.emplace_back(node, error_log);
contexts_.emplace_back(node);
} }
// TODO: argument for property is returned type should be merged // TODO: argument for property is returned type should be merged
// returns brought type, return type is merged with next context or with // returns brought type, return type is merged with next context or with
// brought type in last context // brought type in last context
nodes::MaybeTypeProxy exit_context() { nodes::MaybeTypeProxy exit_context() {
Log::Context logc(log_, utils::Log::Area::kTypeCheck);
if (contexts_.empty()) { if (contexts_.empty()) {
error_handling::handle_general_error( logc.Fatal<Log::kSys>(
"Pop from contexts_ with zero elements in State"); {{"Pop from contexts_ with zero elements in State"}});
} }
auto context = std::move(contexts_.back()); auto context = std::move(contexts_.back());
@ -98,8 +114,8 @@ private:
if (contexts_.empty()) { if (contexts_.empty()) {
if (brought_type.has_value()) { if (brought_type.has_value()) {
if (returned_type.value() != brought_type.value()) { if (returned_type.value() != brought_type.value()) {
context.log_typecheck_error( logc.Error<Log::kProc>(
"Different returned and brought type in last context"); {{"Different returned and brought type in last context"}});
} }
} else { } else {
brought_type = returned_type.value(); brought_type = returned_type.value();
@ -108,8 +124,8 @@ private:
auto &previous_returned_type = contexts_.back().returned_type; auto &previous_returned_type = contexts_.back().returned_type;
if (previous_returned_type.has_value()) { if (previous_returned_type.has_value()) {
if (returned_type.value() != previous_returned_type.value()) { if (returned_type.value() != previous_returned_type.value()) {
context.log_typecheck_error( logc.Error<Log::kProc>({{"Different returned type in this "
"Different returned type in this context and previous one"); "context and previous one"}});
} }
} else { } else {
previous_returned_type = returned_type.value(); previous_returned_type = returned_type.value();
@ -123,14 +139,13 @@ private:
public: public:
class Context { class Context {
public: public:
Context(const nodes::Node &node, error_handling::ErrorLog &error_log) Context(const nodes::Node &node) : node_(node) {}
: node(node), error_log(error_log) {}
void log_typecheck_error( // void log_typecheck_error(
const std::string &message = "Context typecheck error") { // const std::string &message = "Context typecheck error") {
error_log.add_error(error_handling::ErrorLog::ErrorMessage( // log_.add_error(Log::ErrorMessage(node, message,
node, message, error_handling::ErrorType::TYPE_CHECK)); // error_handling::ErrorType::TYPE_CHECK));
} // }
public: public:
nodes::MaybeTypeProxy brought_type; nodes::MaybeTypeProxy brought_type;
@ -138,10 +153,12 @@ public:
std::unordered_map<std::string, VariableInfo> variables; std::unordered_map<std::string, VariableInfo> variables;
private: private:
const nodes::Node &node; const nodes::Node &node_; // TODO: use as position
error_handling::ErrorLog &error_log;
}; };
private:
Log &log_;
std::vector<Context> contexts_ = {{}}; std::vector<Context> contexts_ = {{}};
}; };
@ -151,17 +168,16 @@ class Arguments {
public: public:
Arguments() = default; Arguments() = default;
Arguments expect_builtin(builtin::Type type, Arguments expect_builtin(builtin::Type type, Executor &executor) const {
SourcesManager &sources_manager) const {
Arguments copy(*this); Arguments copy(*this);
copy.expected_types_ = {sources_manager.types()->primitive(type)}; copy.expected_types_ = {
executor.state<nodes::TypeStorage>().primitive(type)};
return copy; return copy;
} }
Arguments pass_builtin(builtin::Type type, Arguments pass_builtin(builtin::Type type, Executor &executor) const {
SourcesManager &sources_manager) const {
Arguments copy(*this); Arguments copy(*this);
copy.passed_type_ = sources_manager.types()->primitive(type); copy.passed_type_ = executor.state<nodes::TypeStorage>().primitive(type);
return copy; return copy;
} }
@ -213,10 +229,9 @@ private:
class ContextHolder { class ContextHolder {
public: public:
ContextHolder(State &state, const nodes::Node &node, ContextHolder(State &state, const nodes::Node &node,
error_handling::ErrorLog &error_log,
nodes::MaybeTypeProxy *context_exit_type) nodes::MaybeTypeProxy *context_exit_type)
: state_(state), context_exit_type_(context_exit_type) { : state_(state), context_exit_type_(context_exit_type) {
state.enter_context(node, error_log); state.enter_context(node);
} }
ContextHolder(const ContextHolder &) = delete; ContextHolder(const ContextHolder &) = delete;
@ -250,19 +265,16 @@ public:
// //
nodes::TypeProxy &get() { nodes::TypeProxy &get() {
if (!type_.has_value()) { utils::Assert(type_.has_value(),
error_handling::handle_general_error(
"Access to invalid type in TypeCheckResult"); "Access to invalid type in TypeCheckResult");
}
return type_.value(); return type_.value();
} }
const nodes::TypeProxy &get() const { const nodes::TypeProxy &get() const {
if (!type_.has_value()) {
error_handling::handle_general_error( utils::Assert(type_.has_value(),
"Access to invalid type in TypeCheckResult"); "Access to invalid type in TypeCheckResult");
}
return type_.value(); return type_.value();
} }
@ -271,13 +283,13 @@ public:
// //
bool is_invalid() const { return !type_.has_value(); } bool is_invalid() const { return not type_.has_value(); }
private: private:
Result() = default; Result() = default;
private: private:
nodes::MaybeTypeProxy type_; nodes::MaybeTypeProxy type_ = {};
}; };
using MaybeResult = std::optional<Result>; using MaybeResult = std::optional<Result>;
@ -286,7 +298,7 @@ using MaybeResult = std::optional<Result>;
nodes::TypeProxy check_same_to_pass_type_in_arguments( nodes::TypeProxy check_same_to_pass_type_in_arguments(
nodes::TypeProxy type, const Arguments &arguments, const nodes::Node &node, nodes::TypeProxy type, const Arguments &arguments, const nodes::Node &node,
SourcesManager &sources_manager, Executor &executor,
const std::string &message = "Different type with passed one", const std::string &message = "Different type with passed one",
bool handle_errors = true); bool handle_errors = true);
@ -297,39 +309,35 @@ nodes::TypeProxy check_same_to_pass_type_in_arguments(
Result type_same_to_expected( Result type_same_to_expected(
nodes::TypeProxy type, const Arguments &argumensr, const nodes::Node &node, nodes::TypeProxy type, const Arguments &argumensr, const nodes::Node &node,
SourcesManager &sources_manager, Executor &executor,
const std::string &message = "Different type with expected one", const std::string &message = "Different type with expected one",
bool handle_errors = true); bool handle_errors = true);
Result type_check_from_arguments(nodes::TypeProxy type, Result type_check_from_arguments(nodes::TypeProxy type,
const Arguments &arguments, const Arguments &arguments,
const nodes::Node &node, const nodes::Node &node, Executor &executor,
SourcesManager &sources_manager,
bool handle_errors = true); bool handle_errors = true);
std::optional<const nodes::TypeDefinition *> std::optional<const nodes::TypeDefinition *>
find_type_definition(const std::string &name, const nodes::Node &node, find_type_definition(const std::string &name, const nodes::Node &node,
SourcesManager &sources_manager, Executor &executor, bool handle_errors = true);
bool handle_errors = true);
std::optional<const nodes::FunctionDefinition *> std::optional<const nodes::FunctionDefinition *>
find_name_definition(const std::string &name, const nodes::Node &node, find_name_definition(const std::string &name, const nodes::Node &node,
SourcesManager &sources_manager, Executor &executor, bool handle_errors = true);
bool handle_errors = true);
nodes::MaybeTypeProxy unfold_user_defined_type(nodes::TypeProxy type, nodes::MaybeTypeProxy unfold_user_defined_type(nodes::TypeProxy type,
const nodes::Node &node, const nodes::Node &node,
SourcesManager &sources_manager, Executor &executor,
bool handle_errors = true); bool handle_errors = true);
nodes::MaybeTypeProxy get_field_type_by_name(nodes::TypeProxy type, nodes::MaybeTypeProxy get_field_type_by_name(nodes::TypeProxy type,
const std::string &field, const std::string &field,
const nodes::Node &node, const nodes::Node &node,
SourcesManager &sources_manager, Executor &executor,
bool handle_errors = true); bool handle_errors = true);
void type_check_error(const std::string &message, const nodes::Node &node, void type_check_error(const std::string &message, const nodes::Node &node,
SourcesManager &sources_manager, Executor &executor, bool handle_error = true);
bool handle_error = true);
} // namespace type_check } // namespace type_check

View file

@ -7,27 +7,31 @@ namespace type_check {
// pass type -> compare types, return bool // pass type -> compare types, return bool
// no pass type -> return type // no pass type -> return type
nodes::TypeProxy check_same_to_pass_type_in_arguments( nodes::TypeProxy check_same_to_pass_type_in_arguments(
nodes::TypeProxy type, const Arguments &arguments, const nodes::Node &node, nodes::TypeProxy type, const Arguments &arguments,
SourcesManager &sources_manager, const std::string &message, const nodes::Node & /*node*/, Executor &executor,
bool handle_errors) { const std::string &message, bool handle_errors) {
if (!arguments.get_passed().has_value()) { Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
if (not arguments.get_passed().has_value()) {
return type; return type;
} }
if (type != arguments.get_passed().value()) { if (type != arguments.get_passed().value() and handle_errors) {
type_check_error(message, node, sources_manager, handle_errors); logc.Error<Log::kProc>({{message}} /* TODO: node */);
} }
return sources_manager.types()->primitive(builtin::Type::BOOL); return executor.state<nodes::TypeStorage>().primitive(builtin::Type::BOOL);
} }
bool check_no_pass_type_in_arguments(const Arguments &arguments, bool check_no_pass_type_in_arguments(const Arguments &arguments,
const nodes::Node &node, const nodes::Node &node,
SourcesManager &sources_manager, Executor &executor,
const std::string &message, const std::string &message,
bool handle_errors) { bool handle_errors) {
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
if (arguments.get_passed().has_value()) { if (arguments.get_passed().has_value()) {
type_check_error(message, node, sources_manager, handle_errors); type_check_error(message, node, executor, handle_errors);
return false; return false;
} }
@ -35,9 +39,10 @@ bool check_no_pass_type_in_arguments(const Arguments &arguments,
} }
Result type_same_to_expected(nodes::TypeProxy type, const Arguments &arguments, Result type_same_to_expected(nodes::TypeProxy type, const Arguments &arguments,
const nodes::Node &node, const nodes::Node & /*node*/, Executor &executor,
SourcesManager &sources_manager,
const std::string &message, bool handle_errors) { const std::string &message, bool handle_errors) {
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
const auto &expected = arguments.get_expected(); const auto &expected = arguments.get_expected();
if (expected.empty()) { if (expected.empty()) {
@ -45,40 +50,49 @@ Result type_same_to_expected(nodes::TypeProxy type, const Arguments &arguments,
} }
// TODO: use 'can cast to' (for modifiers), instead '==' // TODO: use 'can cast to' (for modifiers), instead '=='
if (std::all_of(expected.begin(), expected.end(), bool all_not_expected = std::all_of(
[type](nodes::TypeProxy expected_type) { expected.begin(), expected.end(),
return type != expected_type; [type](nodes::TypeProxy expected_type) { return type != expected_type; });
})) {
type_check_error(message, node, sources_manager, handle_errors); if (all_not_expected and handle_errors) {
logc.Error<Log::kProc>({{message}} /* TODO: node */);
} }
return Result{expected.front()}; // any can be choosen return Result{expected.front()}; // any can be choosen
} }
Result type_check_from_arguments(nodes::TypeProxy type, Result type_check_from_arguments(nodes::TypeProxy /*type*/,
const Arguments &arguments, const Arguments & /*arguments*/,
const nodes::Node &node, const nodes::Node & /*node*/,
SourcesManager &sources_manager, Executor &executor, bool /*handle_errors*/) {
bool handle_errors) { Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
/* TODO */
throw std::exception(); /* TODO FIXME */
logc.Fatal<Log::kSys>({{"Not implemented yet"}});
throw std::exception(); // unreachable
} }
template <typename T> template <typename T>
std::optional<const T *> find_statement( std::optional<const T *>
const std::string &name, const nodes::Node &node, find_statement(const std::string &name, const nodes::Node & /*node*/,
SourcesManager &sources_manager, const std::string &message_not_found, Executor &executor, const std::string &message_not_found,
const std::string &message_different_statement, bool handle_errors) { const std::string &message_different_statement,
const auto maybe_any_statement = sources_manager.names()->find(name); bool handle_errors) {
if (!maybe_any_statement.has_value()) { Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
type_check_error(message_not_found, node, sources_manager, handle_errors);
const auto maybe_any_statement = executor.state<names::NameTree>().find(name);
if (not maybe_any_statement.has_value()) {
if (handle_errors) {
logc.Error<Log::kProc>({{message_not_found}} /* TODO: node */);
}
return std::nullopt; return std::nullopt;
} }
const auto maybe_statement = maybe_any_statement.value().get()->get<T>(); const auto maybe_statement = maybe_any_statement.value().get()->get<T>();
if (!maybe_statement.has_value()) { if (not maybe_statement.has_value()) {
type_check_error(message_different_statement, node, sources_manager, if (handle_errors) {
handle_errors); logc.Error<Log::kProc>({{message_different_statement}} /* TODO: node */);
}
return std::nullopt; return std::nullopt;
} }
@ -87,59 +101,68 @@ std::optional<const T *> find_statement(
std::optional<const nodes::TypeDefinition *> std::optional<const nodes::TypeDefinition *>
find_type_definition(const std::string &name, const nodes::Node &node, find_type_definition(const std::string &name, const nodes::Node &node,
SourcesManager &sources_manager, bool handle_errors) { Executor &executor, bool handle_errors) {
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
return find_statement<nodes::TypeDefinition>( return find_statement<nodes::TypeDefinition>(
name, node, sources_manager, "No type definition found in name tree", name, node, executor, "No type definition found in name tree",
"Node in name tree is not type definition", handle_errors); "Node in name tree is not type definition", handle_errors);
} }
std::optional<const nodes::FunctionDefinition *> std::optional<const nodes::FunctionDefinition *>
find_name_definition(const std::string &name, const nodes::Node &node, find_name_definition(const std::string &name, const nodes::Node &node,
SourcesManager &sources_manager, bool handle_errors) { Executor &executor, bool handle_errors) {
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
return find_statement<nodes::FunctionDefinition>( return find_statement<nodes::FunctionDefinition>(
name, node, sources_manager, "No name definition found in name tree", name, node, executor, "No name definition found in name tree",
"Node in name tree is not name definition", handle_errors); "Node in name tree is not name definition", handle_errors);
} }
std::optional<nodes::TypeProxy> std::optional<nodes::TypeProxy>
unfold_user_defined_type(nodes::TypeProxy type, const nodes::Node &node, unfold_user_defined_type(nodes::TypeProxy type, const nodes::Node &node,
SourcesManager &sources_manager, bool handle_errors) { Executor &executor, bool handle_errors) {
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
const auto maybe_type_definition = find_type_definition( const auto maybe_type_definition = find_type_definition(
*type.get()->get_name()->get(), node, sources_manager, handle_errors); *type.get()->get_name()->get(), node, executor, handle_errors);
if (!maybe_type_definition.has_value()) { if (!maybe_type_definition.has_value()) {
return std::nullopt; return std::nullopt;
} }
if (maybe_type_definition.value()->get_type().has_value()) { if (maybe_type_definition.value()->get_type().has_value()) {
type_check_error("Only type declaration found for type " + if (handle_errors) {
*type.get()->get_name()->get() + logc.Error<Log::kProc>({{std::format(
" (type is not defined)", "Only type declaration found for type {} (type is not defined)",
node, sources_manager, handle_errors); *type.get()->get_name()->get())}} /* TODO: node*/);
}
return std::nullopt; return std::nullopt;
} }
// TODO: perform type arguments substitution // TODO: perform type arguments substitution
error_handling::ensure(type.get()->parameters_size() == 0, logc.Require<Log::kProc>(type.get()->parameters_size() == 0,
"Unfold of generic type is not supported (yet)"); {{"Unfold of generic type is not supported (yet)"}});
// //
return maybe_type_definition.value()->get_type().value(); return maybe_type_definition.value()->get_type().value();
} }
std::optional<nodes::TypeProxy> std::optional<nodes::TypeProxy> get_field_type_by_name(nodes::TypeProxy type,
get_field_type_by_name(nodes::TypeProxy type, const std::string &field, const std::string &field,
const nodes::Node &node, SourcesManager &sources_manager, const nodes::Node &node,
Executor &executor,
bool handle_errors) { bool handle_errors) {
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
switch (type.get()->to_builtin()) { switch (type.get()->to_builtin()) {
case builtin::Type::TUPLE: { // access field case builtin::Type::TUPLE: { // access field
const auto maybe_field = type.get()->get_parameter_proxy_by_name(field); const auto maybe_field = type.get()->get_parameter_proxy_by_name(field);
if (!maybe_field.has_value()) { if (not maybe_field.has_value() and handle_errors) {
// TODO: pass unfolded type name to log it ?? // TODO: pass unfolded type name to log it ??
type_check_error("Type has no defined field " + field, node, logc.Error<Log::kProc>({{std::format("Type has no defined field {}",
sources_manager, handle_errors); field)}} /* TODO: node */);
} }
return maybe_field.value(); return maybe_field.value();
} }
@ -148,33 +171,37 @@ get_field_type_by_name(nodes::TypeProxy type, const std::string &field,
// remove recursion ?? // remove recursion ??
const auto maybe_internal_type = const auto maybe_internal_type =
unfold_user_defined_type(type, node, sources_manager, handle_errors); unfold_user_defined_type(type, node, executor, handle_errors);
if (!maybe_internal_type.has_value()) { if (!maybe_internal_type.has_value()) {
return std::nullopt; return std::nullopt;
} }
return get_field_type_by_name(maybe_internal_type.value(), field, node, return get_field_type_by_name(maybe_internal_type.value(), field, node,
sources_manager, handle_errors); executor, handle_errors);
} }
default: // variant, function, optional, result, error (TODO: add message default: // variant, function, optional, result, error (TODO: add message
// field?), array (TODO: add length field ?), basic types // field?), array (TODO: add length field ?), basic types
type_check_error("Type " + if (handle_errors) {
builtin::types::to_string(type.get()->to_builtin()) + logc.Error<Log::kProc>(
" has no accessible fields by definition", {{std::format("Type {} has no accessible fields by definition",
node, sources_manager, handle_errors); builtin::types::to_string(
type.get()->to_builtin()))}} /* TODO: node */);
}
return std::nullopt; return std::nullopt;
} }
} }
void type_check_error(const std::string &message, const nodes::Node &node, // FIXME: replace with direct log calls
SourcesManager &sources_manager, bool handle_error) { void type_check_error(const std::string &message, const nodes::Node &,
Executor &executor, bool handle_error) {
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
if (!handle_error) { if (!handle_error) {
return; return;
} }
sources_manager.errors()->add_error(error_handling::ErrorLog::ErrorMessage( logc.Error<Log::kProc>({{message}} /* TODO: node */);
node, message, error_handling::ErrorType::TYPE_CHECK));
} }
} // namespace type_check } // namespace type_check

View file

@ -8,5 +8,5 @@ target("lang.type_check")
add_includedirs("include", {public = true}) add_includedirs("include", {public = true})
add_files("src/**.cpp") add_files("src/**.cpp")
add_deps("lang.utils", "lang.nodes") add_deps("lang.utils", "lang.nodes")
set_warnings("allextra", "error") set_warnings("allextra") -- , "error")
set_rundir("$(projectdir)") set_rundir("$(projectdir)")

View file

@ -17,8 +17,8 @@ public:
// //
State &state(Tag) { return state; } // State &state(Tag) { return state; }
const State &state(Tag) const { return state; } // const State &state(Tag) const { return state; }
protected: protected:
State state_; State state_;
@ -37,6 +37,11 @@ public:
return T(*this, args...); return T(*this, args...);
} }
template <typename T> T &state() { return ExecutorState<T>::state_; }
template <typename T> const T &state() const {
return ExecutorState<T>::state_;
}
// //
Log &log() { return log_; } Log &log() { return log_; }
@ -62,11 +67,9 @@ public:
// //
template <typename T> T &state() { template <typename T> T &state() { return executor.template state<T>(); }
return executor.state(ExecutorState<T>::Tag);
}
template <typename T> const T &state() const { template <typename T> const T &state() const {
return executor.state(ExecutorState<T>::Tag); return executor.template state<T>();
} }
Log &log() { return executor.log_; } Log &log() { return executor.log_; }

View file

@ -1,3 +1,5 @@
#pragma once
#include <format> #include <format>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
@ -86,6 +88,7 @@ public:
enum class Area { enum class Area {
kDefault, kDefault,
kParse, kParse,
kTypeCheck,
kIntepret, kIntepret,
// ... // ...
}; };
@ -281,6 +284,16 @@ private:
std::function<void(const Message &)> proc_hook_; std::function<void(const Message &)> proc_hook_;
}; };
inline void Assert(bool condition, std::string_view message,
const std::source_location &source_location =
std::source_location::current()) { // TODO: colors
if (not condition) {
std::cerr << std::format("Assert failed: {}", message,
to_string(source_location));
throw std::exception();
}
}
// //
std::string to_string(const std::source_location &source_location); std::string to_string(const std::source_location &source_location);