diff --git a/include/basic_type_check.hpp b/include/basic_type_check.hpp index 5ddd838..27867de 100644 --- a/include/basic_type_check.hpp +++ b/include/basic_type_check.hpp @@ -2,6 +2,7 @@ #include "basic_nodes.hpp" #include "sources_manager.hpp" +#include "type_check_utils.hpp" namespace type_check { @@ -9,6 +10,6 @@ namespace type_check { nodes::TypeCheckResult type_check_literal(const nodes::Literal &literal, SourcesManager &sources_manager, - nodes::MaybeTypeProxy expected_type); + const Arguments& arguments); } // namespace type_check diff --git a/include/builtin_types.hpp b/include/builtin_types.hpp index 854a222..fb8f454 100644 --- a/include/builtin_types.hpp +++ b/include/builtin_types.hpp @@ -21,6 +21,8 @@ const static std::string OPTIONAL_IDENTIFIER = "Optional"; const static std::string RESULT_IDENTIFIER = "Result"; +const static std::string ERROR_IDENTIFIER = "Error"; + // -- basic types const static std::string FLOAT_IDENTIFIER = "Float"; @@ -56,6 +58,7 @@ enum class Type { ARRAY, OPTIONAL, RESULT, + ERROR, // -- basic types FLOAT, DOUBLE, @@ -86,6 +89,8 @@ inline std::string to_string(Type type) { return OPTIONAL_IDENTIFIER; case Type::RESULT: return RESULT_IDENTIFIER; + case Type::ERROR: + return ERROR_IDENTIFIER; // -- basic types case Type::FLOAT: return FLOAT_IDENTIFIER; @@ -127,6 +132,7 @@ inline Type to_type(const std::string &str) { builtin_types[ARRAY_IDENTIFIER] = Type::ARRAY; builtin_types[OPTIONAL_IDENTIFIER] = Type::OPTIONAL; builtin_types[RESULT_IDENTIFIER] = Type::RESULT; + builtin_types[ERROR_IDENTIFIER] = Type::ERROR; // -- basic types builtin_types[FLOAT_IDENTIFIER] = Type::FLOAT; @@ -172,6 +178,7 @@ inline std::optional get_parameters_count(Type type) { case Type::ARRAY: case Type::OPTIONAL: case Type::RESULT: + case Type::ERROR: return 1; // -- basic types case Type::FLOAT: diff --git a/include/nodes/type_nodes.hpp b/include/nodes/type_nodes.hpp index 64c3380..560efd8 100644 --- a/include/nodes/type_nodes.hpp +++ b/include/nodes/type_nodes.hpp @@ -40,6 +40,7 @@ private: }; using MaybeTypeProxy = std::optional; +using TypeProxies = std::vector; class Type { public: diff --git a/include/type_check_utils.hpp b/include/type_check_utils.hpp index b83b563..b9dfb75 100644 --- a/include/type_check_utils.hpp +++ b/include/type_check_utils.hpp @@ -147,8 +147,9 @@ public: Arguments expect_builtin(builtin::types::Type type, SourcesManager &sources_manager) const { Arguments copy(*this); - copy.expected_type_ = - sources_manager.get_type_storage()->primitive_type(type); + copy.expected_types_ = { + sources_manager.get_type_storage()->primitive_type(type)}; + return copy; } Arguments pass_builtin(builtin::types::Type type, @@ -159,9 +160,15 @@ public: return copy; } + Arguments expect(nodes::TypeProxies types) const { + Arguments copy(*this); + copy.expected_types_ = types; + return copy; + } + Arguments expect(nodes::MaybeTypeProxy type) const { Arguments copy(*this); - copy.expected_type_ = type; + copy.expected_types_ = (type.has_value() ? nodes::TypeProxies{type.value()} : nodes::TypeProxies{}); return copy; } @@ -171,7 +178,19 @@ public: return copy; } - nodes::MaybeTypeProxy get_expected() const { return expected_type_; }; + Arguments without_expect() const { + Arguments copy(*this); + copy.expected_types_ = {}; + return copy; + } + + Arguments without_pass() const { + Arguments copy(*this); + copy.passed_type_ = {}; + return copy; + } + + nodes::TypeProxies get_expected() const { return expected_types_; }; nodes::MaybeTypeProxy get_passed() const { return passed_type_; }; @@ -179,8 +198,8 @@ public: // TODO: arguments builder ?? private: - nodes::MaybeTypeProxy expected_type_ = {}; - nodes::MaybeTypeProxy passed_type_ = {}; + nodes::TypeProxies expected_types_; + nodes::MaybeTypeProxy passed_type_; }; class ContextHolder { @@ -211,11 +230,25 @@ private: nodes::MaybeTypeProxy *context_exit_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 = "Different type with passed one"); + +// bool check_no_pass_type_in_arguments( +// const Arguments &arguments, const nodes::Node &node, +// SourcesManager &sources_manager, +// const std::string &message = "Type can't be passed to this node"); + nodes::TypeCheckResult type_same_to_expected( - nodes::TypeProxy type, nodes::MaybeTypeProxy expected_type, - const nodes::Node &node, error_handling::ErrorLog &error_log, + nodes::TypeProxy type, const Arguments& argumensr, + const nodes::Node &node, SourcesManager &sources_manager, const std::string &message = "Different type with expected one"); +nodes::TypeCheckResult type_check_from_arguments( + nodes::TypeProxy type, const Arguments& arguments, + const nodes::Node &node, SourcesManager &sources_manager); + std::optional find_type_definition_handle_errors(const std::string &name, const nodes::Node &node, @@ -229,8 +262,4 @@ find_name_definition_handle_errors(const std::string &name, void type_check_error(const std::string &message, const nodes::Node &node, SourcesManager &sources_manager); -bool check_no_pass_type_in_arguments(const Arguments &arguments, - const nodes::Node &node, - SourcesManager &sources_manager); - } // namespace type_check diff --git a/src/basic_type_check.cpp b/src/basic_type_check.cpp index 5bd0190..a0a536d 100644 --- a/src/basic_type_check.cpp +++ b/src/basic_type_check.cpp @@ -51,13 +51,9 @@ nodes::TypeProxy get_literal_type(const nodes::Literal &literal, nodes::TypeCheckResult type_check_literal(const nodes::Literal &literal, SourcesManager &sources_manager, - nodes::MaybeTypeProxy expected_type) { + const Arguments &arguments) { auto const type = get_literal_type(literal, sources_manager); - if (expected_type.has_value() && type != expected_type.value()) { - return nodes::TypeCheckResult::construct_invalid_result(); - // nodes::TypeCheckResult::fail_with(type, expected_type, literal); // TODO: create error ?? - } - return nodes::TypeCheckResult(type); + return type_same_to_expected(type, arguments, literal, sources_manager); } } // namespace type_check diff --git a/src/expression_type_check.cpp b/src/expression_type_check.cpp index 61f19f4..b87fe19 100644 --- a/src/expression_type_check.cpp +++ b/src/expression_type_check.cpp @@ -68,7 +68,7 @@ type_check_expression(const nodes::Expression &expression, case 12: // Literal // TODO return type_check_literal(*expression.get().value(), - sources_manager, arguments.get_expected()); + sources_manager, arguments); // --- empty lines case 13: // Extra return nodes::TypeCheckResult( @@ -153,10 +153,10 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression, builtin::types::Type::UNIT)}; } - return type_same_to_expected(sources_manager.get_type_storage()->add_array_of( - expression_result.value().get()), - arguments.get_expected(), expression, - *sources_manager.get_error_log()); + return type_check_from_arguments( + sources_manager.get_type_storage()->add_array_of( + expression_result.value().get()), + arguments, expression, sources_manager); } nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression, @@ -196,10 +196,10 @@ nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression, expression_result = nodes::TypeCheckResult::construct_invalid_result(); } - return type_same_to_expected(sources_manager.get_type_storage()->add_array_of( - expression_result.value().get()), - arguments.get_expected(), expression, - *sources_manager.get_error_log()); + return type_check_from_arguments( + sources_manager.get_type_storage()->add_array_of( + expression_result.value().get()), + arguments, expression, sources_manager); } nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression, @@ -261,9 +261,9 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression, // TODO: modifier checks ??, modifiers ?? - return type_same_to_expected( + return type_check_from_arguments( sources_manager.get_type_storage()->add_array_of(expression_result.get()), - arguments.get_expected(), expression, *sources_manager.get_error_log()); + arguments, expression, sources_manager); } // IN PROGRESS // --- containers @@ -296,10 +296,10 @@ nodes::TypeCheckResult type_check_array(const nodes::Container &expression, return nodes::TypeCheckResult::construct_invalid_result(); } - return type_same_to_expected(sources_manager.get_type_storage()->add_array_of( - last_expression_result.value().get()), - arguments.get_expected(), expression, - *sources_manager.get_error_log()); + return type_check_from_arguments( + sources_manager.get_type_storage()->add_array_of( + last_expression_result.value().get()), + arguments, expression, sources_manager); } nodes::TypeCheckResult type_check_block(const nodes::Container &expression, @@ -327,10 +327,10 @@ nodes::TypeCheckResult type_check_block(const nodes::Container &expression, 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()); + return type_check_from_arguments( + sources_manager.get_type_storage()->add_array_of( + block_brought_type.get()), + arguments, expression, sources_manager); } nodes::TypeCheckResult type_check_container(const nodes::Container &expression, @@ -375,10 +375,10 @@ nodes::TypeCheckResult type_check_return(const nodes::Return &expression, break; } - return type_same_to_expected( + return type_check_from_arguments( sources_manager.get_type_storage()->primitive_type( builtin::types::Type::UNIT), - arguments.get_expected(), expression, *sources_manager.get_error_log()); + arguments, expression, sources_manager); } nodes::TypeCheckResult @@ -410,10 +410,10 @@ type_check_name_definition(const nodes::NameDefinition &expression, } // Return BOOL as any := / =: expression - return type_same_to_expected( + return type_check_from_arguments( sources_manager.get_type_storage()->primitive_type( builtin::types::Type::BOOL), - arguments.get_expected(), expression, *sources_manager.get_error_log()); + arguments, expression, sources_manager); } nodes::TypeCheckResult type_check_array_access(const nodes::Access &expression, @@ -439,9 +439,9 @@ nodes::TypeCheckResult type_check_array_access(const nodes::Access &expression, // TODO: modifier checks ?? - return type_same_to_expected(value_result.get().get()->get_parameter_proxy(0), - arguments.get_expected(), expression, - *sources_manager.get_error_log()); + return type_check_from_arguments( + value_result.get().get()->get_parameter_proxy(0), arguments, expression, + sources_manager); } nodes::TypeCheckResult type_check_tuple_access(const nodes::Access &expression, @@ -464,9 +464,9 @@ nodes::TypeCheckResult type_check_tuple_access(const nodes::Access &expression, // TODO: modifier checks ?? - return type_same_to_expected( - value_result.get().get()->get_parameter_proxy(index), - arguments.get_expected(), expression, *sources_manager.get_error_log()); + return type_check_from_arguments( + value_result.get().get()->get_parameter_proxy(index), arguments, + expression, sources_manager); } nodes::TypeCheckResult type_check_access(const nodes::Access &expression, @@ -487,10 +487,10 @@ nodes::TypeCheckResult type_check_loop_control(const nodes::LoopControl &expression, SourcesManager &sources_manager, State &, const Arguments &arguments) { - return type_same_to_expected( + return type_check_from_arguments( sources_manager.get_type_storage()->primitive_type( builtin::types::Type::UNIT), - arguments.get_expected(), expression, *sources_manager.get_error_log()); + arguments, expression, sources_manager); } nodes::TypeCheckResult @@ -528,8 +528,8 @@ type_check_modifier_expression(const nodes::ModifierExpression &expression, modified_result.get(), expression.get_modifier())); } - return type_same_to_expected(modified_result.get(), arguments.get_expected(), - expression, *sources_manager.get_error_log()); + return type_check_from_arguments(modified_result.get(), arguments, expression, + sources_manager); } // IN PROGRESS // --- other @@ -628,9 +628,8 @@ type_check_name_expression(const nodes::NameExpression &expression, // TODO: invert modifier ?? // TODO: generic types should be deduced from arguments - return type_same_to_expected(returned->get_type_proxy().value(), - arguments.get_expected(), expression, - *sources_manager.get_error_log()); + return type_check_from_arguments(returned->get_type_proxy().value(), + arguments, expression, sources_manager); } // checks for universal call syntax ?? @@ -680,41 +679,67 @@ type_check_constructor(const nodes::Constructor &expression, // TODO: work with generics (type_definition->arguments, ...) - // for tuple - for (size_t i = 0; i < expression.arguments_size(); - ++i) { // TODO: deduce order by annotations - const auto annotation = expression.get_argument_annotation(i); - const auto expected_annotation = - type.get()->get_parameter(i)->get_annotation(); + const auto builtin_type = type.get()->to_builtin(); - if (annotation.has_value() != expected_annotation.has_value()) { + switch (builtin_type) { + case builtin::types::Type::TUPLE: + // for tuple + for (size_t i = 0; i < expression.arguments_size(); + ++i) { // TODO: deduce order by annotations + const auto annotation = expression.get_argument_annotation(i); + const auto expected_annotation = + type.get()->get_parameter(i)->get_annotation(); - type_check_error( - "Wrong type constructor argument annotation: should be " + - std::string{expected_annotation.has_value() - ? *expected_annotation.value() - : "[none]"}, - *expression.get_argument_value(i), sources_manager); + if (annotation.has_value() != expected_annotation.has_value()) { + + type_check_error( + "Wrong type constructor argument annotation: should be " + + std::string{expected_annotation.has_value() + ? *expected_annotation.value() + : "[none]"}, + *expression.get_argument_value(i), sources_manager); + } + + if (annotation.has_value() && + *annotation.value() != *expected_annotation.value()) { + type_check_error( + "Wrong function argument type annotation: " + *annotation.value() + + " instead of " + *expected_annotation.value(), + *expression.get_argument_value(i), sources_manager); + } + + type_check_expression( + *expression.get_argument_value(i), sources_manager, state, + Arguments{}.expect(type.get()->get_parameter_proxy(i))); + // TODO: do something with argument type ?? } - - if (annotation.has_value() && - *annotation.value() != *expected_annotation.value()) { - type_check_error( - "Wrong function argument type annotation: " + *annotation.value() + - " instead of " + *expected_annotation.value(), - *expression.get_argument_value(i), sources_manager); - } - - type_check_expression( - *expression.get_argument_value(i), sources_manager, state, - Arguments{}.expect(type.get()->get_parameter_proxy(i))); - // TODO: do something with argument type ?? + break; + case builtin::types::Type::VARIANT: + // TODO: expect one of types + break; + case builtin::types::Type::OPTIONAL: + // TODO: expect type (generic) or NULL + break; + case builtin::types::Type::RESULT: + // TODO: expect ERROR or type (generic) + break; + case builtin::types::Type::ERROR: + // TODO: expect type (generic) + break; + case builtin::types::Type::FUNCTION: + // TODO: built from one value (function) + break; + case builtin::types::Type::NONE: + // TODO: built from one value + break; + default: // array, basic types + type_check_error("Type can't be constructed", expression, sources_manager); + break; } // TODO: deduce generic parts in type - return type_same_to_expected(expression.get_type_proxy(), - arguments.get_expected(), expression, - *sources_manager.get_error_log()); + return type_check_from_arguments(expression.get_type_proxy(), arguments, + expression, sources_manager); // TODO: add <- modifiier to type ?? } // IN PROGRESS @@ -724,12 +749,19 @@ nodes::TypeCheckResult type_check_lambda(const nodes::Lambda &expression, SourcesManager &sources_manager, State &state, const Arguments &arguments) { - if (!arguments.get_expected().has_value()) { - type_check_error("Can't deduce type of lambda function from context", + if (arguments.get_expected().empty()) { + type_check_error("Can't deduce type of lambda function from context: no " + "one type expected", expression, sources_manager); } - const auto expected_type = arguments.get_expected().value(); + if (arguments.get_expected().size() != 1) { + type_check_error("Can't deduce type of lambda function from context; too " + "much possible types", + expression, sources_manager); + } + + const auto expected_type = arguments.get_expected().front(); if (!expected_type.get()->is_builtin(builtin::types::Type::FUNCTION)) { type_check_error("Type of lambda function should be function", expression, sources_manager); @@ -742,7 +774,10 @@ nodes::TypeCheckResult type_check_lambda(const nodes::Lambda &expression, // auto returned_type = type_check_expression( // *expression.get_expression(), sources_manager, state, Arguments{}); - return nodes::TypeCheckResult{expected_type}; // TODO: same to expected ?? + // TODO: needed ?? (only passed type check required ??) + return type_check_from_arguments( + expected_type, arguments, expression, + sources_manager); // TODO: same to expected ?? } // IN PROGRESS } // namespace type_check diff --git a/src/type_check_utils.cpp b/src/type_check_utils.cpp index 0f8d5bb..95d3db3 100644 --- a/src/type_check_utils.cpp +++ b/src/type_check_utils.cpp @@ -1,24 +1,54 @@ #include "type_check_utils.hpp" +#include namespace type_check { -nodes::TypeCheckResult type_same_to_expected( - nodes::TypeProxy type, nodes::MaybeTypeProxy expected_type, - const nodes::Node &node, error_handling::ErrorLog &error_log, - const std::string &message) { - if (!expected_type.has_value()) { +// 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) { + if (!arguments.get_passed().has_value()) { + return type; + } + + if (type != arguments.get_passed().value()) { + type_check_error(message, node, sources_manager); + } + + return sources_manager.get_type_storage()->primitive_type( + builtin::types::Type::BOOL); +} + +bool check_no_pass_type_in_arguments(const Arguments &arguments, + const nodes::Node &node, + SourcesManager &sources_manager, + const std::string &message) { + if (arguments.get_passed().has_value()) { + type_check_error(message, node, sources_manager); + return false; + } + + return true; +} + +nodes::TypeCheckResult +type_same_to_expected(nodes::TypeProxy type, + const Arguments& arguments, + const nodes::Node &node, SourcesManager &sources_manager, + const std::string &message) { + const auto& expected = arguments.get_expected(); + + if (expected.empty()) { return nodes::TypeCheckResult{type}; } - if (type != expected_type.value()) { - error_log.add_error(error_handling::ErrorLog::ErrorMessage( - node, message, error_handling::ErrorType::TYPE_CHECK)); - - return nodes::TypeCheckResult::construct_invalid_result(); - } // TODO: use 'can cast to' (for modifiers), instead '==' - return nodes::TypeCheckResult{ - expected_type.value()}; // TODO: retern type or expected type ?? + if (std::all_of(expected.begin(), expected.end(), [type](nodes::TypeProxy expected_type) { return type != expected_type; })) { + type_check_error(message, node, sources_manager); + } + + return nodes::TypeCheckResult{expected.front()}; // any can be choosen } template @@ -72,15 +102,4 @@ void type_check_error(const std::string &message, const nodes::Node &node, node, message, error_handling::ErrorType::TYPE_CHECK)); } -bool check_no_pass_type_in_arguments(const Arguments &arguments, - const nodes::Node &node, - SourcesManager &sources_manager) { - if (arguments.get_passed().has_value()) { - type_check_error("Type can't be passed to this node", node, - sources_manager); - return false; - } - return true; -} - } // namespace type_check