From 512d011f72ecb57e2dbb84a91f052f7b29b2097e Mon Sep 17 00:00:00 2001 From: ProgramSnail Date: Thu, 4 Jan 2024 14:30:57 +0300 Subject: [PATCH] api improvements, part of expression type checks --- include/nodes/expression_nodes.hpp | 2 + include/nodes/type_nodes.hpp | 14 +++++- include/type_check_utils.hpp | 13 +++-- src/expression_type_check.cpp | 76 ++++++++++++++++++++++++++++-- 4 files changed, 96 insertions(+), 9 deletions(-) diff --git a/include/nodes/expression_nodes.hpp b/include/nodes/expression_nodes.hpp index df02bcd..3001b35 100644 --- a/include/nodes/expression_nodes.hpp +++ b/include/nodes/expression_nodes.hpp @@ -473,6 +473,8 @@ public: const Type *get_type() const { return constructor_type_.get(); } + TypeProxy get_type_proxy() const { return constructor_type_; } + size_t arguments_size() const { return arguments_.size(); } Expression *get_argument_value(size_t id) { diff --git a/include/nodes/type_nodes.hpp b/include/nodes/type_nodes.hpp index 8e7b9df..9d4cb0b 100644 --- a/include/nodes/type_nodes.hpp +++ b/include/nodes/type_nodes.hpp @@ -86,6 +86,8 @@ public: void set_modifier(Modifier modifier) { modifier_ = modifier; } + bool is_modifier(Modifier modifier) const { return modifier_ == modifier; } + // std::optional get_annotation() { @@ -102,6 +104,12 @@ public: return std::nullopt; } + bool is_no_annotation() const { return !annotation_.has_value(); } + + bool is_annotation(const std::string &annotation) const { + return annotation_.has_value() && annotation_.value() == annotation; + } + void set_annotation(std::string &&annotation) { annotation_ = std::move(annotation); } @@ -176,7 +184,7 @@ public: bool operator>=(const Type &other) const { return !operator<(other); } // is parameters count check necessary ?? - builtin::types::Type to_builtin() { + builtin::types::Type to_builtin() const { auto builtin_type = builtin::types::to_type(*name_.get()); auto builtin_type_parameters_count = @@ -191,7 +199,9 @@ public: return builtin_type; } - bool is_builtin(builtin::types::Type type) { return to_builtin() == type; } + bool is_builtin(builtin::types::Type type) const { + return to_builtin() == type; + } private: Identifier name_; diff --git a/include/type_check_utils.hpp b/include/type_check_utils.hpp index 32a4919..b49df23 100644 --- a/include/type_check_utils.hpp +++ b/include/type_check_utils.hpp @@ -16,16 +16,18 @@ class State { friend ContextHolder; public: - bool insert_variable(const std::string &name, nodes::TypeProxy type) { + bool insert_variable(const std::string &name, nodes::TypeProxy type, + nodes::NameDefinition::Modifier modifier) { 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; + return contexts_.back().variables.insert({name, {type, modifier}}).second; } - nodes::MaybeTypeProxy find_variable(const std::string &name) { + std::optional> + 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()) { @@ -70,6 +72,7 @@ private: contexts_.emplace_back(node, error_log); } + // 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() { @@ -125,7 +128,9 @@ public: public: nodes::MaybeTypeProxy brought_type; nodes::MaybeTypeProxy returned_type; - std::unordered_map variables; + std::unordered_map> + variables; private: const nodes::Node &node; diff --git a/src/expression_type_check.cpp b/src/expression_type_check.cpp index d8cc2b1..97599df 100644 --- a/src/expression_type_check.cpp +++ b/src/expression_type_check.cpp @@ -111,6 +111,8 @@ nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression, SourcesManager &sources_manager, State &state, const Arguments &arguments) { + // TODO: extract functiona argument names + // typecheck in statements ?? } // IN PROGRESS nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression, @@ -128,7 +130,6 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression, nodes::TypeCheckResult expression_result = type_check_expression( *expression.get_expression(), sources_manager, state, {}); - // detect maximum amount of errors switch (expression.get_type()) { case nodes::Loop::LOOP: // infinity loop, no params break; @@ -229,6 +230,9 @@ nodes::TypeCheckResult type_check_block(const nodes::Container &expression, SourcesManager &sources_manager, State &state, const Arguments &arguments) { + ContextHolder context_holder(state, expression, + *sources_manager.get_error_log()); + } // IN PROGRESS nodes::TypeCheckResult type_check_container(const nodes::Container &expression, @@ -289,7 +293,36 @@ nodes::TypeCheckResult type_check_return(const nodes::Return &expression, nodes::TypeCheckResult type_check_name_definition(const nodes::NameDefinition &expression, SourcesManager &sources_manager, State &state, - const Arguments &arguments) {} // IN PROGRESS + const Arguments &arguments) { + if (!arguments.expected_type.has_value()) { + sources_manager.get_error_log()->add_error( + error_handling::ErrorLog::ErrorMessage( + expression, "Can't deduce type of new variable from context", + error_handling::ErrorType::TYPE_CHECK)); + } + + // defined name modifier should be -> (or contain -> ??) + // TODO: deal with ...|...|... modifiers + const auto &expected_type = arguments.expected_type.value(); + if (!expected_type.get()->is_modifier( + nodes::Modifier::OUT)) { // TODO: utils::modifier_contains_OUT + sources_manager.get_error_log()->add_error( + error_handling::ErrorLog::ErrorMessage( + expression, "Type of lambda function should be function", + error_handling::ErrorType::TYPE_CHECK)); + } + + // TODO: remove modifier ?? + if (!state.insert_variable(*expression.get_name()->get(), expected_type, + expression.get_modifier())) { + sources_manager.get_error_log()->add_error( + error_handling::ErrorLog::ErrorMessage( + expression, "Variable is already defined in this context", + error_handling::ErrorType::TYPE_CHECK)); + } + + return nodes::TypeCheckResult{expected_type}; +} // IN PROGRESS nodes::TypeCheckResult type_check_array_access(const nodes::Access &expression, SourcesManager &sources_manager, @@ -421,13 +454,50 @@ type_check_name_expression(const nodes::NameExpression &expression, nodes::TypeCheckResult type_check_constructor(const nodes::Constructor &expression, SourcesManager &sources_manager, State &state, - const Arguments &arguments) {} // IN PROGRESS + const Arguments &arguments) { + // TODO: find definition + for (size_t i = 0; i < expression.arguments_size(); ++i) { + const auto annotation = expression.get_argument_annotation(i); + auto argument_type = type_check_expression( + *expression.get_argument_value(i), sources_manager, state, + /* TODO: type from definition by annotation */); + } + // TODO: expect types of arguments by type definition + return type_same_to_expected(expression.get_type_proxy(), + arguments.expected_type, expression, + *sources_manager.get_error_log()); + // TODO: add <- modifiier to type ?? + +} // IN PROGRESS // TODO nodes::TypeCheckResult type_check_lambda(const nodes::Lambda &expression, SourcesManager &sources_manager, State &state, const Arguments &arguments) { + if (!arguments.expected_type.has_value()) { + sources_manager.get_error_log()->add_error( + error_handling::ErrorLog::ErrorMessage( + expression, "Can't deduce type of lambda function from context", + error_handling::ErrorType::TYPE_CHECK)); + } + + const auto &expected_type = arguments.expected_type.value(); + if (!expected_type.get()->is_builtin(builtin::types::Type::FUNCTION)) { + sources_manager.get_error_log()->add_error( + error_handling::ErrorLog::ErrorMessage( + expression, "Type of lambda function should be function", + error_handling::ErrorType::TYPE_CHECK)); + } + + // TODO: define vars + // TODO: expect returned type as type of internal expression + // TODO: merge returned and brought type + // TODO: add context + // auto returned_type = type_check_expression( + // *expression.get_expression(), sources_manager, state, Arguments{}); + + return nodes::TypeCheckResult{expected_type}; } // IN PROGRESS } // namespace type_check