diff --git a/include/nodes/type_nodes.hpp b/include/nodes/type_nodes.hpp index d4c0a33..64c3380 100644 --- a/include/nodes/type_nodes.hpp +++ b/include/nodes/type_nodes.hpp @@ -446,7 +446,7 @@ public: return TypeCheckResult(); } - explicit TypeCheckResult(std::optional type) : type_(type) {} + explicit TypeCheckResult(nodes::TypeProxy type) : type_(type) {} // @@ -478,7 +478,7 @@ private: TypeCheckResult() = default; private: - std::optional type_; + nodes::MaybeTypeProxy type_; }; } // namespace nodes diff --git a/include/type_check_utils.hpp b/include/type_check_utils.hpp index a4b5b24..5472c6b 100644 --- a/include/type_check_utils.hpp +++ b/include/type_check_utils.hpp @@ -186,8 +186,8 @@ private: class ContextHolder { public: ContextHolder(State &state, const nodes::Node &node, - error_handling::ErrorLog &error_log) - : state(state) { + error_handling::ErrorLog &error_log, nodes::MaybeTypeProxy* context_exit_type) + : state_(state), context_exit_type_(context_exit_type) { state.enter_context(node, error_log); } @@ -197,10 +197,17 @@ public: ContextHolder &operator=(const ContextHolder &) = delete; ContextHolder &operator=(ContextHolder &&) = delete; - ~ContextHolder() { state.exit_context(); } + ~ContextHolder() { + if (context_exit_type_) { + *context_exit_type_ = state_.exit_context(); + } else { + state_.exit_context(); + } + } private: - State &state; + State &state_; + nodes::MaybeTypeProxy* context_exit_type_; }; nodes::TypeCheckResult type_same_to_expected( diff --git a/src/expression_type_check.cpp b/src/expression_type_check.cpp index dc8baf5..f81b316 100644 --- a/src/expression_type_check.cpp +++ b/src/expression_type_check.cpp @@ -10,6 +10,8 @@ // IN PROGRESS +// TODO: typecheck pass in all functions + namespace type_check { nodes::TypeCheckResult @@ -80,7 +82,6 @@ type_check_expression(const nodes::Expression &expression, // --- flow control -// TODO nodes::TypeCheckResult type_check_match(const nodes::Match &expression, SourcesManager &sources_manager, State &state, @@ -98,6 +99,9 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression, std::optional expression_result; + bool at_least_one_case_with_expression = false; + bool at_least_one_case_without_expression = false; + for (size_t i = 0; i < expression.cases_size(); ++i) { const nodes::Match::Case *current_case = expression.get_case(i); @@ -108,8 +112,7 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression, .expect_builtin(builtin::types::Type::BOOL, sources_manager) .pass(value_result.is_invalid() ? nodes::MaybeTypeProxy{} : expression_result.value().get())); - // TODO: work with case - // TODO: use type modifiers + // TODO: use type modifiers ?? // ... ?? x ... if (current_case->get_condition().has_value()) { @@ -121,6 +124,7 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression, // ... -> x if (current_case->get_expression().has_value()) { + at_least_one_case_with_expression = true; nodes::TypeCheckResult case_result = type_check_expression( *current_case->get_condition().value(), sources_manager, state, Arguments{}.expect(expression_result.has_value() @@ -131,10 +135,18 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression, expression_result = std::move(case_result); } } else { - // TODO: if there is expression_result, it should be returned in all cases + at_least_one_case_without_expression = true; } } + if (at_least_one_case_with_expression && at_least_one_case_without_expression) { + sources_manager.get_error_log()->add_error( + error_handling::ErrorLog::ErrorMessage( + expression, "all cases should be with or without expression at the same time", + error_handling::ErrorType::TYPE_CHECK)); + expression_result = nodes::TypeCheckResult::construct_invalid_result(); + } + if (!expression_result.has_value()) { expression_result = nodes::TypeCheckResult{ sources_manager.get_type_storage()->primitive_type( @@ -145,7 +157,7 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression, expression_result.value().get()), arguments.get_expected(), expression, *sources_manager.get_error_log()); -} // IN PROGRESS +} nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression, SourcesManager &sources_manager, @@ -186,11 +198,6 @@ nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression, expression_result = nodes::TypeCheckResult::construct_invalid_result(); } - // ?????????????????????????? - // TODO: extract function argument names - // typecheck in statements ?? - // ?????????????????????????? - return type_same_to_expected(sources_manager.get_type_storage()->add_array_of( expression_result.value().get()), arguments.get_expected(), expression, @@ -203,8 +210,6 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression, const Arguments &arguments) { // TODO: ranges ?? - // std::optional condition_result; - std::optional interval_result; std::optional variable_result; @@ -216,7 +221,7 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression, case nodes::Loop::LOOP: // infinity loop, no params break; case nodes::Loop::WHILE: - /*condition_result = */ type_check_expression( + type_check_expression( *expression.get_condition().value(), sources_manager, state, Arguments{}.expect_builtin(builtin::types::Type::BOOL, sources_manager)); @@ -226,17 +231,6 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression, // return condition_result.value(); // } - // --- done in expect --- - // if (!condition_result.value().get().get()->is_builtin( - // builtin::types::Type::BOOL)) { - // sources_manager.get_error_log()->add_error( - // error_handling::ErrorLog::ErrorMessage( - // *expression.get_condition().value(), - // "While loop condition should have type Bool", - // error_handling::ErrorType::TYPE_CHECK)); - // return nodes::TypeCheckResult::construct_invalid_result(); - // } - break; case nodes::Loop::FOR: // TODO: expect range ?? @@ -296,7 +290,7 @@ nodes::TypeCheckResult type_check_array(const nodes::Container &expression, *expression.get_expression(i), "Elements in array should have same type", error_handling::ErrorType::TYPE_CHECK)); - return nodes::TypeCheckResult::construct_invalid_result(); + // return nodes::TypeCheckResult::construct_invalid_result(); // max possible checks, so no return } } } @@ -313,17 +307,38 @@ nodes::TypeCheckResult type_check_array(const nodes::Container &expression, last_expression_result.value().get()), arguments.get_expected(), expression, *sources_manager.get_error_log()); -} // IN PROGRESS +} -// TODO 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()); + nodes::MaybeTypeProxy context_exit_type; -} // IN PROGRESS + { + ContextHolder context_holder(state, expression, + *sources_manager.get_error_log(), + &context_exit_type); // TODO: is brought type returned + + for (size_t i = 0; i < expression.expressions_size(); ++i) { + // result types in block are discarded + type_check_expression(*expression.get_expression(i), sources_manager, + state, Arguments{}); + } + } + + nodes::TypeCheckResult block_brought_type = + context_exit_type.has_value() + ? nodes::TypeCheckResult(context_exit_type.value()) + : nodes::TypeCheckResult( + sources_manager.get_type_storage()->primitive_type( + builtin::types::Type::UNIT)); + + return type_same_to_expected(sources_manager.get_type_storage()->add_array_of( + block_brought_type.get()), + arguments.get_expected(), expression, + *sources_manager.get_error_log()); +} nodes::TypeCheckResult type_check_container(const nodes::Container &expression, SourcesManager &sources_manager, @@ -333,11 +348,9 @@ nodes::TypeCheckResult type_check_container(const nodes::Container &expression, case nodes::Container::ARRAY: return type_check_array(expression, sources_manager, state, arguments); case nodes::Container::BLOCK: - return type_check_block(expression, sources_manager, state, - arguments); // TODO: check that expression brought - // type are same, -> brought_type + return type_check_block(expression, sources_manager, state, arguments); } -} // IN PROGRESS +} // --- modifiers @@ -379,31 +392,33 @@ nodes::TypeCheckResult type_check_return(const nodes::Return &expression, arguments.get_expected(), expression, *sources_manager.get_error_log()); } -// TODO nodes::TypeCheckResult type_check_name_definition(const nodes::NameDefinition &expression, SourcesManager &sources_manager, State &state, const Arguments &arguments) { - if (!arguments.get_expected().has_value()) { + if (!arguments.get_passed().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.get_expected().value(); - if (!expected_type.get()->is_modifier( - nodes::Modifier::OUT)) { // TODO: utils::modifier_contains_OUT + // assigned type shold be one of <-, <>, -- (can't be ->) + const auto variable_type = arguments.get_passed().value(); + if (nodes::utils::modifier_contains_OUT( + variable_type.get() + ->get_modifier())) { // TODO: utils::modifier_contains_OUT sources_manager.get_error_log()->add_error( error_handling::ErrorLog::ErrorMessage( - expression, "Type of lambda function should be function", + expression, "Variabla cant be asignet from out (->) value", error_handling::ErrorType::TYPE_CHECK)); } - // TODO: remove modifier ?? - if (!state.insert_variable(*expression.get_name()->get(), expected_type, + // variable accessible by reference by default ?? + sources_manager.get_type_storage()->add_modification_of(variable_type, + nodes::Modifier::REF); + + if (!state.insert_variable(*expression.get_name()->get(), variable_type, expression.get_modifier())) { sources_manager.get_error_log()->add_error( error_handling::ErrorLog::ErrorMessage( @@ -411,8 +426,12 @@ type_check_name_definition(const nodes::NameDefinition &expression, error_handling::ErrorType::TYPE_CHECK)); } - return nodes::TypeCheckResult{expected_type}; -} // IN PROGRESS + // Return BOOL as any := / =: expression + return type_same_to_expected( + sources_manager.get_type_storage()->primitive_type( + builtin::types::Type::BOOL), + arguments.get_expected(), expression, *sources_manager.get_error_log()); +} nodes::TypeCheckResult type_check_array_access(const nodes::Access &expression, SourcesManager &sources_manager,