diff --git a/include/expression_type_check.hpp b/include/expression_type_check.hpp index 1bec090..e36e580 100644 --- a/include/expression_type_check.hpp +++ b/include/expression_type_check.hpp @@ -2,6 +2,7 @@ #include "expression_nodes.hpp" #include "sources_manager.hpp" +#include "type_check_utils.hpp" #include "type_nodes.hpp" #include "utils.hpp" @@ -11,159 +12,77 @@ namespace type_check { -// TODO: make context stack o top of RAII -class State { -public: - bool insert_variable(const std::string &name, nodes::TypeProxy type) { - if (contexts_.empty()) { - error_handling::handle_general_error( - "Insert variable into contexts_ with zero elements in State"); - } - - return contexts_.back().variables.insert({name, type}).second; - } - - nodes::MaybeTypeProxy find_variable(const std::string &name) { - for (ssize_t i = contexts_.size(); i >= 0; --i) { - auto iter = contexts_[i].variables.find(name); - if (iter != contexts_[i].variables.end()) { - return iter->second; - } - } - - return std::nullopt; - } - - void enter_context(const nodes::Node& node) { contexts_.emplace_back(node); } - - // returns brought type, return type is merged with next context or with - // brought type in last context - nodes::MaybeTypeProxy exit_context() { - if (contexts_.empty()) { - error_handling::handle_general_error( - "Pop from contexts_ with zero elements in State"); - } - - const auto brought_type = contexts_.back().brought_type; - const auto returned_type = contexts_.back().returned_type; - contexts_.pop_back(); - - if (contexts_.empty()) { - // TODO: merge returned and brought types - } else { - // TODO: merge to previous - } - - return brought_type; - } - - bool bring_type(nodes::TypeProxy type) { - if (contexts_.empty()) { - error_handling::handle_general_error( - "Set brought type to contexts_ with zero elements in State"); - } - auto &brought_type = contexts_.back().brought_type; - if (brought_type.has_value() &&) { - // TODO - return false; - } - brought_type = type; - return true; - } - - bool return_type(nodes::TypeProxy type) { - if (contexts_.empty()) { - error_handling::handle_general_error( - "Set returned type to contexts_ with zero elements in State"); - } - auto &returned_type = contexts_.back().returned_type; - if (returned_type.has_value() &&) { - // TODO - return false; - } - returned_type = type; - return true; - } - -public: - class Context { - public: - Context(const nodes::Node& node) : node(node) {} - - public: - nodes::MaybeTypeProxy brought_type; - nodes::MaybeTypeProxy returned_type; - std::unordered_map variables; - const nodes::Node& node; - }; - -private: - std::vector contexts_ = {{}}; -}; - -class Arguments { -public: - nodes::MaybeTypeProxy expected_type = {}; -}; - nodes::TypeCheckResult type_check_expression(const nodes::Expression &expression, - SourcesManager &sources_manager, State &state, const Arguments& arguments = {}); + SourcesManager &sources_manager, State &state, + const Arguments &arguments = {}); // --- flow control nodes::TypeCheckResult type_check_match(const nodes::Match &expression, SourcesManager &sources_manager, - State &state, const Arguments& arguments = {}); + State &state, + const Arguments &arguments = {}); nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression, SourcesManager &sources_manager, - State &state, const Arguments& arguments = {}); + State &state, + const Arguments &arguments = {}); nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression, SourcesManager &sources_manager, - State &state, const Arguments& arguments = {}); + State &state, + const Arguments &arguments = {}); // --- containers nodes::TypeCheckResult type_check_container(const nodes::Container &expression, SourcesManager &sources_manager, - State &state, const Arguments& arguments = {}); + State &state, + const Arguments &arguments = {}); // --- modifiers nodes::TypeCheckResult type_check_return(const nodes::Return &expression, SourcesManager &sources_manager, - State &state, const Arguments& arguments = {}); + State &state, + const Arguments &arguments = {}); nodes::TypeCheckResult type_check_name_definition(const nodes::NameDefinition &expression, - SourcesManager &sources_manager, State &state, const Arguments& arguments = {}); + SourcesManager &sources_manager, State &state, + const Arguments &arguments = {}); nodes::TypeCheckResult type_check_access(const nodes::Access &expression, SourcesManager &sources_manager, - State &state, const Arguments& arguments = {}); + State &state, + const Arguments &arguments = {}); nodes::TypeCheckResult type_check_loop_control(const nodes::LoopControl &expression, - SourcesManager &sources_manager, State &state, const Arguments& arguments = {}); + SourcesManager &sources_manager, State &state, + const Arguments &arguments = {}); nodes::TypeCheckResult type_check_modifier_expression(const nodes::ModifierExpression &expression, - SourcesManager &sources_manager, State &state, const Arguments& arguments = {}); + SourcesManager &sources_manager, State &state, + const Arguments &arguments = {}); // --- other nodes::TypeCheckResult type_check_name_expression(const nodes::NameExpression &expression, - SourcesManager &sources_manager, State &state, const Arguments& arguments = {}); + SourcesManager &sources_manager, State &state, + const Arguments &arguments = {}); nodes::TypeCheckResult type_check_constructor(const nodes::Constructor &expression, - SourcesManager &sources_manager, State &state, const Arguments& arguments = {}); + SourcesManager &sources_manager, State &state, + const Arguments &arguments = {}); nodes::TypeCheckResult type_check_lambda(const nodes::Lambda &expression, SourcesManager &sources_manager, - State &state, const Arguments& arguments = {}); + State &state, + const Arguments &arguments = {}); } // namespace type_check diff --git a/include/nodes/type_nodes.hpp b/include/nodes/type_nodes.hpp index dbc82cb..1c546e5 100644 --- a/include/nodes/type_nodes.hpp +++ b/include/nodes/type_nodes.hpp @@ -135,7 +135,7 @@ public: } for (size_t i = 0; i < parameters_.size(); ++i) { - if (*parameters_[i].get() != *other.parameters_[i].get()) { + if (parameters_[i] != other.parameters_[i]) { return false; } } @@ -161,7 +161,7 @@ public: } for (size_t i = 0; i < parameters_.size(); ++i) { - if (*parameters_[i].get() != *other.parameters_[i].get()) { + if (parameters_[i] != other.parameters_[i]) { return false; } } diff --git a/include/type_check_utils.hpp b/include/type_check_utils.hpp new file mode 100644 index 0000000..d802a56 --- /dev/null +++ b/include/type_check_utils.hpp @@ -0,0 +1,130 @@ +#pragma once + +#include "expression_nodes.hpp" +#include "sources_manager.hpp" +#include "type_check_utils.hpp" +#include "type_nodes.hpp" +#include "utils.hpp" + +#include + +namespace type_check { + +class ContextHolder; + +class State { + friend ContextHolder; + +public: + bool insert_variable(const std::string &name, nodes::TypeProxy type) { + if (contexts_.empty()) { + error_handling::handle_general_error( + "Insert variable into contexts_ with zero elements in State"); + } + + return contexts_.back().variables.insert({name, type}).second; + } + + nodes::MaybeTypeProxy find_variable(const std::string &name) { + for (ssize_t i = contexts_.size(); i >= 0; --i) { + auto iter = contexts_[i].variables.find(name); + if (iter != contexts_[i].variables.end()) { + return iter->second; + } + } + + return std::nullopt; + } + + bool bring_type(nodes::TypeProxy type) { + if (contexts_.empty()) { + error_handling::handle_general_error( + "Set brought type to contexts_ with zero elements in State"); + } + auto &brought_type = contexts_.back().brought_type; + if (brought_type.has_value() &&) { + // TODO + return false; + } + brought_type = type; + return true; + } + + bool return_type(nodes::TypeProxy type) { + if (contexts_.empty()) { + error_handling::handle_general_error( + "Set returned type to contexts_ with zero elements in State"); + } + auto &returned_type = contexts_.back().returned_type; + if (returned_type.has_value() &&) { + // TODO + return false; + } + returned_type = type; + return true; + } + +private: + void enter_context(const nodes::Node &node) { contexts_.emplace_back(node); } + + // returns brought type, return type is merged with next context or with + // brought type in last context + nodes::MaybeTypeProxy exit_context() { + if (contexts_.empty()) { + error_handling::handle_general_error( + "Pop from contexts_ with zero elements in State"); + } + + const auto brought_type = contexts_.back().brought_type; + const auto returned_type = contexts_.back().returned_type; + contexts_.pop_back(); + + if (contexts_.empty()) { + // TODO: merge returned and brought types + } else { + // TODO: merge to previous + } + + return brought_type; + } + +public: + class Context { + public: + Context(const nodes::Node &node) : node(node) {} + + public: + nodes::MaybeTypeProxy brought_type; + nodes::MaybeTypeProxy returned_type; + std::unordered_map variables; + const nodes::Node &node; + }; + +private: + std::vector contexts_ = {{}}; +}; + +class Arguments { +public: + nodes::MaybeTypeProxy expected_type = {}; +}; + +class ContextHolder { +public: + ContextHolder(State &state, const nodes::Node &node) : state(state) { + state.enter_context(node); + } + + ContextHolder(const ContextHolder &) = delete; + ContextHolder(ContextHolder &&) = delete; + + ContextHolder &operator=(const ContextHolder &) = delete; + ContextHolder &operator=(ContextHolder &&) = delete; + + ~ContextHolder() { state.exit_context(); } + +private: + State &state; +}; + +} // namespace type_check diff --git a/src/expression_type_check.cpp b/src/expression_type_check.cpp index ef76fcf..4cfd69d 100644 --- a/src/expression_type_check.cpp +++ b/src/expression_type_check.cpp @@ -194,8 +194,7 @@ nodes::TypeCheckResult type_check_array(const nodes::Container &expression, if (!last_expression_result.has_value()) { last_expression_result = expression_result; } else { - if (*last_expression_result.value().get().get() != - *expression_result.get().get()) { + if (last_expression_result.value().get() != expression_result.get()) { sources_manager.get_error_log()->add_error( error_handling::ErrorLog::ErrorMessage( *expression.get_expression(i),