diff --git a/lang/type_check/include/type_check_utils.hpp b/lang/type_check/include/type_check_utils.hpp index c3d076f..b2f22dd 100644 --- a/lang/type_check/include/type_check_utils.hpp +++ b/lang/type_check/include/type_check_utils.hpp @@ -1,15 +1,20 @@ #pragma once +#include "executor.hpp" #include "expression_nodes.hpp" -#include "sources_manager.hpp" -#include "type_check_utils.hpp" +#include "log.hpp" +#include "name_tree.hpp" #include "type_nodes.hpp" -#include "utils.hpp" #include namespace type_check { +using Executor = utils::Executor; +using Task = + utils::Task; + class ContextHolder; class State { @@ -22,11 +27,15 @@ public: }; public: + State(Log &log) : log_(log) {} + bool insert_variable(const std::string &name, nodes::TypeProxy type, nodes::NameDefinition::Modifier modifier) { + Log::Context logc(log_, utils::Log::Area::kTypeCheck); + if (contexts_.empty()) { - error_handling::handle_general_error( - "Insert variable into contexts_ with zero elements in State"); + logc.Fatal( + {{"Insert variable into contexts_ with zero elements in State"}}); } return contexts_.back() @@ -46,9 +55,11 @@ public: } bool bring_type(nodes::TypeProxy type) { + Log::Context logc(log_, utils::Log::Area::kTypeCheck); + if (contexts_.empty()) { - error_handling::handle_general_error( - "Set brought type to contexts_ with zero elements in State"); + logc.Fatal( + {{"Set brought type to contexts_ with zero elements in State"}}); } auto &brought_type = contexts_.back().brought_type; if (brought_type.has_value() && @@ -60,9 +71,11 @@ public: } bool return_type(nodes::TypeProxy type) { + Log::Context logc(log_, utils::Log::Area::kTypeCheck); + if (contexts_.empty()) { - error_handling::handle_general_error( - "Set returned type to contexts_ with zero elements in State"); + logc.Fatal( + {{"Set returned type to contexts_ with zero elements in State"}}); } auto &returned_type = contexts_.back().returned_type; if (returned_type.has_value() && @@ -74,18 +87,21 @@ public: } private: - void enter_context(const nodes::Node &node, - error_handling::ErrorLog &error_log) { - contexts_.emplace_back(node, error_log); + void enter_context(const nodes::Node &node) { + Log::Context logc(log_, utils::Log::Area::kTypeCheck); + + contexts_.emplace_back(node); } // TODO: argument for property is returned type should be merged // returns brought type, return type is merged with next context or with // brought type in last context nodes::MaybeTypeProxy exit_context() { + Log::Context logc(log_, utils::Log::Area::kTypeCheck); + if (contexts_.empty()) { - error_handling::handle_general_error( - "Pop from contexts_ with zero elements in State"); + logc.Fatal( + {{"Pop from contexts_ with zero elements in State"}}); } auto context = std::move(contexts_.back()); @@ -98,8 +114,8 @@ private: if (contexts_.empty()) { if (brought_type.has_value()) { if (returned_type.value() != brought_type.value()) { - context.log_typecheck_error( - "Different returned and brought type in last context"); + logc.Error( + {{"Different returned and brought type in last context"}}); } } else { brought_type = returned_type.value(); @@ -108,8 +124,8 @@ private: auto &previous_returned_type = contexts_.back().returned_type; if (previous_returned_type.has_value()) { if (returned_type.value() != previous_returned_type.value()) { - context.log_typecheck_error( - "Different returned type in this context and previous one"); + logc.Error({{"Different returned type in this " + "context and previous one"}}); } } else { previous_returned_type = returned_type.value(); @@ -123,14 +139,13 @@ private: public: class Context { public: - Context(const nodes::Node &node, error_handling::ErrorLog &error_log) - : node(node), error_log(error_log) {} + Context(const nodes::Node &node) : node_(node) {} - void log_typecheck_error( - const std::string &message = "Context typecheck error") { - error_log.add_error(error_handling::ErrorLog::ErrorMessage( - node, message, error_handling::ErrorType::TYPE_CHECK)); - } + // void log_typecheck_error( + // const std::string &message = "Context typecheck error") { + // log_.add_error(Log::ErrorMessage(node, message, + // error_handling::ErrorType::TYPE_CHECK)); + // } public: nodes::MaybeTypeProxy brought_type; @@ -138,10 +153,12 @@ public: std::unordered_map variables; private: - const nodes::Node &node; - error_handling::ErrorLog &error_log; + const nodes::Node &node_; // TODO: use as position }; +private: + Log &log_; + std::vector contexts_ = {{}}; }; @@ -151,17 +168,16 @@ class Arguments { public: Arguments() = default; - Arguments expect_builtin(builtin::Type type, - SourcesManager &sources_manager) const { + Arguments expect_builtin(builtin::Type type, Executor &executor) const { Arguments copy(*this); - copy.expected_types_ = {sources_manager.types()->primitive(type)}; + copy.expected_types_ = { + executor.state().primitive(type)}; return copy; } - Arguments pass_builtin(builtin::Type type, - SourcesManager &sources_manager) const { + Arguments pass_builtin(builtin::Type type, Executor &executor) const { Arguments copy(*this); - copy.passed_type_ = sources_manager.types()->primitive(type); + copy.passed_type_ = executor.state().primitive(type); return copy; } @@ -213,10 +229,9 @@ private: class ContextHolder { public: ContextHolder(State &state, const nodes::Node &node, - error_handling::ErrorLog &error_log, nodes::MaybeTypeProxy *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; @@ -250,19 +265,16 @@ public: // nodes::TypeProxy &get() { - if (!type_.has_value()) { - error_handling::handle_general_error( - "Access to invalid type in TypeCheckResult"); - } + utils::Assert(type_.has_value(), + "Access to invalid type in TypeCheckResult"); return type_.value(); } const nodes::TypeProxy &get() const { - if (!type_.has_value()) { - error_handling::handle_general_error( - "Access to invalid type in TypeCheckResult"); - } + + utils::Assert(type_.has_value(), + "Access to invalid type in TypeCheckResult"); 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: Result() = default; private: - nodes::MaybeTypeProxy type_; + nodes::MaybeTypeProxy type_ = {}; }; using MaybeResult = std::optional; @@ -286,7 +298,7 @@ using MaybeResult = std::optional; nodes::TypeProxy check_same_to_pass_type_in_arguments( nodes::TypeProxy type, const Arguments &arguments, const nodes::Node &node, - SourcesManager &sources_manager, + Executor &executor, const std::string &message = "Different type with passed one", bool handle_errors = true); @@ -297,39 +309,35 @@ nodes::TypeProxy check_same_to_pass_type_in_arguments( Result type_same_to_expected( nodes::TypeProxy type, const Arguments &argumensr, const nodes::Node &node, - SourcesManager &sources_manager, + Executor &executor, const std::string &message = "Different type with expected one", bool handle_errors = true); Result type_check_from_arguments(nodes::TypeProxy type, const Arguments &arguments, - const nodes::Node &node, - SourcesManager &sources_manager, + const nodes::Node &node, Executor &executor, bool handle_errors = true); std::optional find_type_definition(const std::string &name, const nodes::Node &node, - SourcesManager &sources_manager, - bool handle_errors = true); + Executor &executor, bool handle_errors = true); std::optional find_name_definition(const std::string &name, const nodes::Node &node, - SourcesManager &sources_manager, - bool handle_errors = true); + Executor &executor, bool handle_errors = true); nodes::MaybeTypeProxy unfold_user_defined_type(nodes::TypeProxy type, const nodes::Node &node, - SourcesManager &sources_manager, + Executor &executor, bool handle_errors = true); nodes::MaybeTypeProxy get_field_type_by_name(nodes::TypeProxy type, const std::string &field, const nodes::Node &node, - SourcesManager &sources_manager, + Executor &executor, bool handle_errors = true); void type_check_error(const std::string &message, const nodes::Node &node, - SourcesManager &sources_manager, - bool handle_error = true); + Executor &executor, bool handle_error = true); } // namespace type_check diff --git a/lang/type_check/src/type_check_utils.cpp b/lang/type_check/src/type_check_utils.cpp index 5c355bc..546d707 100644 --- a/lang/type_check/src/type_check_utils.cpp +++ b/lang/type_check/src/type_check_utils.cpp @@ -7,27 +7,31 @@ namespace type_check { // pass type -> compare types, return bool // no pass type -> return type nodes::TypeProxy check_same_to_pass_type_in_arguments( - nodes::TypeProxy type, const Arguments &arguments, const nodes::Node &node, - SourcesManager &sources_manager, const std::string &message, - bool handle_errors) { - if (!arguments.get_passed().has_value()) { + nodes::TypeProxy type, const Arguments &arguments, + const nodes::Node & /*node*/, Executor &executor, + const std::string &message, bool handle_errors) { + Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck); + + if (not arguments.get_passed().has_value()) { return type; } - if (type != arguments.get_passed().value()) { - type_check_error(message, node, sources_manager, handle_errors); + if (type != arguments.get_passed().value() and handle_errors) { + logc.Error({{message}} /* TODO: node */); } - return sources_manager.types()->primitive(builtin::Type::BOOL); + return executor.state().primitive(builtin::Type::BOOL); } bool check_no_pass_type_in_arguments(const Arguments &arguments, const nodes::Node &node, - SourcesManager &sources_manager, + Executor &executor, const std::string &message, bool handle_errors) { + Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck); + 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; } @@ -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, - const nodes::Node &node, - SourcesManager &sources_manager, + const nodes::Node & /*node*/, Executor &executor, const std::string &message, bool handle_errors) { + Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck); + const auto &expected = arguments.get_expected(); 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 '==' - if (std::all_of(expected.begin(), expected.end(), - [type](nodes::TypeProxy expected_type) { - return type != expected_type; - })) { - type_check_error(message, node, sources_manager, handle_errors); + bool all_not_expected = std::all_of( + expected.begin(), expected.end(), + [type](nodes::TypeProxy expected_type) { return type != expected_type; }); + + if (all_not_expected and handle_errors) { + logc.Error({{message}} /* TODO: node */); } return Result{expected.front()}; // any can be choosen } -Result type_check_from_arguments(nodes::TypeProxy type, - const Arguments &arguments, - const nodes::Node &node, - SourcesManager &sources_manager, - bool handle_errors) { - /* TODO */ - throw std::exception(); +Result type_check_from_arguments(nodes::TypeProxy /*type*/, + const Arguments & /*arguments*/, + const nodes::Node & /*node*/, + Executor &executor, bool /*handle_errors*/) { + Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck); + + /* TODO FIXME */ + logc.Fatal({{"Not implemented yet"}}); + throw std::exception(); // unreachable } template -std::optional find_statement( - const std::string &name, const nodes::Node &node, - SourcesManager &sources_manager, const std::string &message_not_found, - const std::string &message_different_statement, bool handle_errors) { - const auto maybe_any_statement = sources_manager.names()->find(name); - if (!maybe_any_statement.has_value()) { - type_check_error(message_not_found, node, sources_manager, handle_errors); +std::optional +find_statement(const std::string &name, const nodes::Node & /*node*/, + Executor &executor, const std::string &message_not_found, + const std::string &message_different_statement, + bool handle_errors) { + Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck); + + const auto maybe_any_statement = executor.state().find(name); + if (not maybe_any_statement.has_value()) { + if (handle_errors) { + logc.Error({{message_not_found}} /* TODO: node */); + } return std::nullopt; } const auto maybe_statement = maybe_any_statement.value().get()->get(); - if (!maybe_statement.has_value()) { - type_check_error(message_different_statement, node, sources_manager, - handle_errors); + if (not maybe_statement.has_value()) { + if (handle_errors) { + logc.Error({{message_different_statement}} /* TODO: node */); + } return std::nullopt; } @@ -87,59 +101,68 @@ std::optional find_statement( std::optional 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( - 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); } std::optional 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( - 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); } std::optional 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( - *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()) { return std::nullopt; } if (maybe_type_definition.value()->get_type().has_value()) { - type_check_error("Only type declaration found for type " + - *type.get()->get_name()->get() + - " (type is not defined)", - node, sources_manager, handle_errors); + if (handle_errors) { + logc.Error({{std::format( + "Only type declaration found for type {} (type is not defined)", + *type.get()->get_name()->get())}} /* TODO: node*/); + } return std::nullopt; } // TODO: perform type arguments substitution - error_handling::ensure(type.get()->parameters_size() == 0, - "Unfold of generic type is not supported (yet)"); + logc.Require(type.get()->parameters_size() == 0, + {{"Unfold of generic type is not supported (yet)"}}); // return maybe_type_definition.value()->get_type().value(); } -std::optional -get_field_type_by_name(nodes::TypeProxy type, const std::string &field, - const nodes::Node &node, SourcesManager &sources_manager, - bool handle_errors) { +std::optional get_field_type_by_name(nodes::TypeProxy type, + const std::string &field, + const nodes::Node &node, + Executor &executor, + bool handle_errors) { + Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck); + switch (type.get()->to_builtin()) { case builtin::Type::TUPLE: { // access 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 ?? - type_check_error("Type has no defined field " + field, node, - sources_manager, handle_errors); + logc.Error({{std::format("Type has no defined field {}", + field)}} /* TODO: node */); } return maybe_field.value(); } @@ -148,33 +171,37 @@ get_field_type_by_name(nodes::TypeProxy type, const std::string &field, // remove recursion ?? 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()) { return std::nullopt; } 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 // field?), array (TODO: add length field ?), basic types - type_check_error("Type " + - builtin::types::to_string(type.get()->to_builtin()) + - " has no accessible fields by definition", - node, sources_manager, handle_errors); + if (handle_errors) { + logc.Error( + {{std::format("Type {} has no accessible fields by definition", + builtin::types::to_string( + type.get()->to_builtin()))}} /* TODO: node */); + } return std::nullopt; } } -void type_check_error(const std::string &message, const nodes::Node &node, - SourcesManager &sources_manager, bool handle_error) { +// FIXME: replace with direct log calls +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) { return; } - sources_manager.errors()->add_error(error_handling::ErrorLog::ErrorMessage( - node, message, error_handling::ErrorType::TYPE_CHECK)); + logc.Error({{message}} /* TODO: node */); } } // namespace type_check diff --git a/lang/type_check/_xmake.lua b/lang/type_check/xmake.lua similarity index 86% rename from lang/type_check/_xmake.lua rename to lang/type_check/xmake.lua index 18790de..08e52b8 100644 --- a/lang/type_check/_xmake.lua +++ b/lang/type_check/xmake.lua @@ -8,5 +8,5 @@ target("lang.type_check") add_includedirs("include", {public = true}) add_files("src/**.cpp") add_deps("lang.utils", "lang.nodes") - set_warnings("allextra", "error") + set_warnings("allextra") -- , "error") set_rundir("$(projectdir)") diff --git a/lang/utils/include/executor.hpp b/lang/utils/include/executor.hpp index d9fbc5c..1cbaa73 100644 --- a/lang/utils/include/executor.hpp +++ b/lang/utils/include/executor.hpp @@ -17,8 +17,8 @@ public: // - State &state(Tag) { return state; } - const State &state(Tag) const { return state; } + // State &state(Tag) { return state; } + // const State &state(Tag) const { return state; } protected: State state_; @@ -37,6 +37,11 @@ public: return T(*this, args...); } + template T &state() { return ExecutorState::state_; } + template const T &state() const { + return ExecutorState::state_; + } + // Log &log() { return log_; } @@ -62,11 +67,9 @@ public: // - template T &state() { - return executor.state(ExecutorState::Tag); - } + template T &state() { return executor.template state(); } template const T &state() const { - return executor.state(ExecutorState::Tag); + return executor.template state(); } Log &log() { return executor.log_; } diff --git a/lang/utils/include/log.hpp b/lang/utils/include/log.hpp index 8e3ef2d..e9a41e3 100644 --- a/lang/utils/include/log.hpp +++ b/lang/utils/include/log.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include #include @@ -86,6 +88,7 @@ public: enum class Area { kDefault, kParse, + kTypeCheck, kIntepret, // ... }; @@ -281,6 +284,16 @@ private: std::function 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);