From 361a267054317d547b28f0df4c7e6921f478b8d4 Mon Sep 17 00:00:00 2001 From: ProgramSnail Date: Sun, 15 Sep 2024 15:02:25 +0300 Subject: [PATCH] func name fix, move name expr and constructor type checks to separated files --- lang/nodes/include/statement_nodes.hpp | 3 +- .../constructor_expression_type_check.hpp | 17 + .../include/expression_type_check.hpp | 20 +- .../include/name_expression_type_check.hpp | 18 + lang/type_check/include/type_check_utils.hpp | 2 +- .../src/constructor_expression_type_check.cpp | 5 + lang/type_check/src/expression_type_check.cpp | 570 ++++-------------- .../src/name_expression_type_check.cpp | 174 ++++++ 8 files changed, 325 insertions(+), 484 deletions(-) create mode 100644 lang/type_check/include/constructor_expression_type_check.hpp create mode 100644 lang/type_check/include/name_expression_type_check.hpp create mode 100644 lang/type_check/src/constructor_expression_type_check.cpp create mode 100644 lang/type_check/src/name_expression_type_check.cpp diff --git a/lang/nodes/include/statement_nodes.hpp b/lang/nodes/include/statement_nodes.hpp index 2bb883a..2678e13 100644 --- a/lang/nodes/include/statement_nodes.hpp +++ b/lang/nodes/include/statement_nodes.hpp @@ -168,13 +168,14 @@ struct FunctionDefinition { // +public: SymbolDocs docs; std::vector constraints; Modifier return_modifier; bool is_method; Identifier name; Identifier full_name; - std::vector args; + std::vector args; // including returned values bool are_annotations_same_to_names; // needed for easier prinitng process std::optional expr; }; // refactor ?? diff --git a/lang/type_check/include/constructor_expression_type_check.hpp b/lang/type_check/include/constructor_expression_type_check.hpp new file mode 100644 index 0000000..5efedeb --- /dev/null +++ b/lang/type_check/include/constructor_expression_type_check.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "type_check_utils.hpp" + +// IN PROGRESS + +namespace type_check { + +template <> +struct CheckTask + : public CheckTaskBase { + using CheckTaskBase::CheckTaskBase; + + Result operator()(const nodes::Constructor &expr, const Args &args) override; +}; + +} // namespace type_check diff --git a/lang/type_check/include/expression_type_check.hpp b/lang/type_check/include/expression_type_check.hpp index dcd3e08..d8c4bb9 100644 --- a/lang/type_check/include/expression_type_check.hpp +++ b/lang/type_check/include/expression_type_check.hpp @@ -3,6 +3,9 @@ #include "expression_nodes.hpp" #include "type_check_utils.hpp" +#include "constructor_expression_type_check.hpp" +#include "name_expression_type_check.hpp" + // IN PROGRESS namespace type_check { @@ -104,22 +107,9 @@ struct CheckTask // --- other -template <> -struct CheckTask - : public CheckTaskBase { - using CheckTaskBase::CheckTaskBase; +// NameExpression -> other file - Result operator()(const nodes::NameExpression &expr, - const Args &args) override; -}; - -template <> -struct CheckTask - : public CheckTaskBase { - using CheckTaskBase::CheckTaskBase; - - Result operator()(const nodes::Constructor &expr, const Args &args) override; -}; +// Constructor -> other file template <> struct CheckTask : public CheckTaskBase { diff --git a/lang/type_check/include/name_expression_type_check.hpp b/lang/type_check/include/name_expression_type_check.hpp new file mode 100644 index 0000000..c14a74d --- /dev/null +++ b/lang/type_check/include/name_expression_type_check.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "type_check_utils.hpp" + +// IN PROGRESS + +namespace type_check { + +template <> +struct CheckTask + : public CheckTaskBase { + using CheckTaskBase::CheckTaskBase; + + Result operator()(const nodes::NameExpression &expr, + const Args &args) override; +}; + +} // namespace type_check diff --git a/lang/type_check/include/type_check_utils.hpp b/lang/type_check/include/type_check_utils.hpp index 1f975d1..6de7620 100644 --- a/lang/type_check/include/type_check_utils.hpp +++ b/lang/type_check/include/type_check_utils.hpp @@ -358,7 +358,7 @@ nodes::MaybeType FieldTypeByName(nodes::Type type, const std::string &field, const utils::Pos &pos, Executor &executor, bool handle_errors = true); -inline nodes::MaybeType Curry(MaybeResult result) { +inline nodes::MaybeType Bind(MaybeResult result) { return result.has_value() ? result->Get() : nodes::MaybeType{}; } diff --git a/lang/type_check/src/constructor_expression_type_check.cpp b/lang/type_check/src/constructor_expression_type_check.cpp new file mode 100644 index 0000000..ec6e42a --- /dev/null +++ b/lang/type_check/src/constructor_expression_type_check.cpp @@ -0,0 +1,5 @@ +#include "constructor_expression_type_check.hpp" + +#include "expression_type_check.hpp" + +namespace type_check {} // namespace type_check diff --git a/lang/type_check/src/expression_type_check.cpp b/lang/type_check/src/expression_type_check.cpp index 241ecb6..7cfbc70 100644 --- a/lang/type_check/src/expression_type_check.cpp +++ b/lang/type_check/src/expression_type_check.cpp @@ -8,6 +8,7 @@ // TODO: typecheck pass in all functions // TODO: assign types in nodes +// TODO: pass passet type into subexpressions ?? namespace type_check { @@ -85,7 +86,7 @@ Result CheckTask::operator()(const nodes::Match &expr, const auto &expr = current_case.expr.value(); at_least_one_case_with_expression = true; - Result case_result = Run(expr, Args{expr}.Expect(Curry(expr_result))); + Result case_result = Run(expr, Args{expr}.Expect(Bind(expr_result))); if (not expr_result.has_value() and not case_result.is_invalid()) { expr_result = std::move(case_result); @@ -127,7 +128,7 @@ Result CheckTask::operator()(const nodes::Condition &expr, // expression Result case_result = Run(current_case.second, - Args{current_case.second}.Expect(Curry(expr_result))); + Args{current_case.second}.Expect(Bind(expr_result))); if (not expr_result.has_value() and not case_result.is_invalid()) { expr_result = std::move(case_result); @@ -136,7 +137,7 @@ Result CheckTask::operator()(const nodes::Condition &expr, if (expr.else_case.has_value()) { Run(expr.else_case.value(), - Args{expr.else_case.value()}.Expect(Curry(expr_result))); + Args{expr.else_case.value()}.Expect(Bind(expr_result))); } if (!expr_result.has_value()) { @@ -308,17 +309,15 @@ Result CheckTask::operator()(const nodes::Return &expr, current_pos); } -// <------ NOTE: CHECK ENDED THERE - -// TODO: warning if name is same to package prefix, function prefix, etc. ?? Result CheckTask::operator()(const nodes::NameDefinition &expr, const Args &args) { Log::Context logc(executor.log(), Log::Area::kTypeCheck); - const auto current_pos = PosOf(args.current_id); - if (!args.passed().has_value()) { + // + + if (not args.passed().has_value()) { TypeCheckError("Can't deduce type of new variable from context", current_pos); } @@ -326,26 +325,26 @@ CheckTask::operator()(const nodes::NameDefinition &expr, // assigned type shold be one of <-, <>, -- (can't be ->) const auto variable_type = args.passed().value(); if (nodes::utils::modifier_contains_OUT( - variable_type.get() - ->get_modifier())) { // TODO: utils::modifier_contains_OUT + variable_type.get()->get_modifier())) { + // TODO: modifiers are nto fully implemented yet TypeCheckError("Variable can't be assigned from out (->) value", current_pos); } - // variable accessible by reference by default ?? + // variable is accessible by reference by default state().add_modification_of(variable_type, nodes::Modifier::REF); - if (!state().InsertVariable(expr.name.value, variable_type, - expr.kind)) { + // TODO: warning if name is same to package prefix, function prefix, etc. ?? + if (not state().InsertVariable(expr.name.value, variable_type, + expr.kind)) { TypeCheckError("Variable is already defined in this context", current_pos); } - // Return BOOL as any := / =: expression + // Return BOOL (as any := / =: expression) == true return TypeCheckFromArgs(state().primitive(builtin::Type::BOOL), args, current_pos); } -// NOTE: CHECKED Result CheckTask::CheckArrayAccess(const nodes::Access &expr, const Args &args) { Log::Context logc(executor.log(), Log::Area::kTypeCheck); @@ -375,7 +374,6 @@ Result CheckTask::CheckArrayAccess(const nodes::Access &expr, args, current_pos); } -// NOTE: CHECKED Result CheckTask::CheckTupleAccess(const nodes::Access &expr, const Args &args) { Log::Context logc(executor.log(), Log::Area::kTypeCheck); @@ -383,7 +381,7 @@ Result CheckTask::CheckTupleAccess(const nodes::Access &expr, // - // TODO: check expect for parametrized type without parametears + // TODO: check expect for parametrized type without parameters auto value_result = Run(expr.value, Args{expr.value}.ExpectBuiltin(builtin::Type::TUPLE, executor)); @@ -401,7 +399,6 @@ Result CheckTask::CheckTupleAccess(const nodes::Access &expr, args, current_pos); } -// NOTE: CHECKED Result CheckTask::operator()(const nodes::Access &expr, const Args &args) { Log::Context logc(executor.log(), Log::Area::kTypeCheck); @@ -414,7 +411,6 @@ Result CheckTask::operator()(const nodes::Access &expr, } } -// NOTE: CHECKED Result CheckTask::operator()(const nodes::LoopControl &expr, const Args &args) { Log::Context logc(executor.log(), Log::Area::kTypeCheck); @@ -433,25 +429,46 @@ Result CheckTask::operator()( // - // TODO: expext Optional or Result ?? - auto modified_result = Run(expr.expr, {expr.expr}); + // TODO: check expect for parametrized type without parameters + auto given_args = nodes::utils::is_suffix_modifier(expr.modifier) + ? Args{expr.expr}.Expect({ + state().primitive(builtin::Type::OPTIONAL), + state().primitive(builtin::Type::RESULT), + }) + : Args{expr.expr}; + + auto modified_result = Run(expr.expr, given_args); if (modified_result.is_invalid()) { return Result::invalid(); } if (nodes::utils::is_suffix_modifier(expr.modifier)) { // optional, result - - // '?' - open optional / result in -> (execute or not execute pattern - // matching expression) / (value / return) (TODO: alternative for bring) - - // '!' - open optional / result -> value / panic - switch (modified_result.Get().get()->to_builtin()) { - case builtin::Type::OPTIONAL: - case builtin::Type::RESULT: - modified_result.Set(modified_result.Get().get()->get_parameter_proxy(0)); + case builtin::Type::OPTIONAL: { // '?' - open optional / result in -> + // (execute + // or not execute pattern matching expression) + // / (value / return) + + const auto underlying_type = + modified_result.Get().get()->get_parameter_proxy(0); + + // TODO: alternative for bring in future + if (not state().ReturnType(underlying_type)) { + TypeCheckError("Different returned type to current one", current_pos); + } + + modified_result.Set(underlying_type); break; + } + case builtin::Type::RESULT: { // '!' - open optional / result -> value / + // panic + const auto underlying_type = + modified_result.Get().get()->get_parameter_proxy(0); + + modified_result.Set(underlying_type); + break; + } default: TypeCheckError("Can unwrap only Optional or Result", current_pos); return Result::invalid(); @@ -459,440 +476,35 @@ Result CheckTask::operator()( } else { // NOTE: other modifiers applied instead of current one - // TODO: check thatmodification is possible + // TODO: check that modification is possible (not all casts are possible) modified_result.Set(state().add_modification_of( modified_result.Get(), expr.modifier)); } return TypeCheckFromArgs(modified_result.Get(), args, current_pos); -} // IN PROGRESS +} // --- other -// TODO -Result -CheckTask::operator()(const nodes::NameExpression &expr, - const Args &args) { - Log::Context logc(executor.log(), Log::Area::kTypeCheck); - - const auto current_pos = PosOf(args.current_id); - - // TODO: constraints ?? - - const auto name = expr.name; - - { - const auto fragments = name.get_fragments(); - nodes::Identifier current_prefix = fragments.front(); - std::optional maybe_variable; - size_t i = 0; - for (; i < fragments.size(); ++i) { - // go in prefixes and try to find matching var namei - if (i > 0) { - current_prefix.append_after(fragments[i]); - } - - maybe_variable = state().FindVariable(current_prefix.value); - - if (maybe_variable.has_value()) { - break; - } - } - - if (maybe_variable.has_value()) { - auto &type = maybe_variable.value().type; - for (size_t j = i + 1; j < fragments.size(); ++i) { - if (j + 1 == - fragments - .size()) { // then this can be method call - // TODO: try to find method or local function - // if found, search to field (without error handling) - } - - // TODO: fields from several fragments ? (not acceptable fors methods / - // functions) - - // <- in typecheck utils method - // TODO: switch by type types: Variant, Tuple, ... - // Tuple -> try to find field - // Others -> try to open / builtin fields ? - const auto maybe_field_type = - FieldTypeByName(type, fragments[i].value, current_pos, executor); - - if (maybe_field_type.has_value()) { - type = maybe_field_type.value(); - // TODO - continue; - } - - // TODO - - // fields for the names should be found - // last segment can be function name - } - } - } - - // --- TODO --- deal with passed type --- TODO --- (additional argument) - // TODO: deal with given ->(out) Args (type not expected, but passed into) - - // TODO: check, if there is variable with this name - // TODO: check var + fields - const auto maybe_function_definition = - FindNameDefinition(name.value, current_pos, executor); - if (!maybe_function_definition.has_value()) { - return Result::invalid(); - } - const nodes::FunctionDefinition *function_definition = - maybe_function_definition.value(); - - // TODO: count passed type, if needed - // TODO: manage situation with one out type at any position - // TODO + 1 - returned type - somtimes (can be ==) - const auto args_given = expr.args.size(); - const auto args_defined = function_definition->args.size(); - if (args_given + 1 < args_defined || - args_given > args_defined) { // other, when there is passed type - TypeCheckError(std::format("Number of function args is different from " - "expected ({} instead of {}{})", - args_given, args_defined, - args_defined > 0 - ? (" or " + std::to_string(args_defined - 1)) - : ""), - current_pos); - return Result::invalid(); - // TODO: try return correct type (function return type), when possible - } - - // TODO: define types for generic function - - std::vector function_argument_results; - for (size_t i = 0; i < args_given; - ++i) { // TODO: pass types with oud modifier - const nodes::FunctionDefinition::Argument &argument = - function_definition->args.at(i); - - if (!argument.type.has_value()) { - TypeCheckError( - std::format("Function argument type is not defined for argument {}", - i), - current_pos); - continue; - } - - const auto annotation = expr.args.at(i).first; - const auto expected_annotation = argument.annotation; - - if (annotation.has_value() != expected_annotation.has_value()) { - TypeCheckError("Wrong function argument annotation: should be " + - std::string{expected_annotation.has_value() - ? expected_annotation.value() - : "[none]"}, - PosOf(expr.args.at(i).second)); - } - - if (annotation.has_value() && - annotation.value() != expected_annotation.value()) { - TypeCheckError( - std::format( - "Wrong function argument type annotation: {} instead of {}", - annotation.value(), expected_annotation.value()), - PosOf(expr.args.at(i).second)); - } - - function_argument_results.push_back( - Run(expr.args.at(i).second, - Args{expr.args.at(i).second}.Expect(argument.type.value()))); - } - - if (function_definition->args.size() == 0) { - TypeCheckError( - "Function arguments size is zero. Returned type is not defined", - current_pos); - return Result::invalid(); - } - - // TODO: check condition - if (args_given + 1 == args_defined) { - // returned type - const nodes::FunctionDefinition::Argument &returned = - function_definition->args.back(); - - // TODO: invert modifier ?? - if (!returned.type.has_value()) { - TypeCheckError("Function argument type is not defined for returned type", - current_pos); - return Result::invalid(); - } - - // TODO: invert modifier ?? - // TODO: generic types should be deduced from args - return TypeCheckFromArgs(returned.type.value(), args, current_pos); - } - - // checks for universal call syntax ?? - - // TODO: return result -} // IN PROGRESS - -// TODO -Result CheckTask::operator()(const nodes::Constructor &expr, - const Args &args) { - Log::Context logc(executor.log(), Log::Area::kTypeCheck); - - const auto current_pos = PosOf(args.current_id); - - // TODO: constraints ?? - - // TODO: use pass type - const auto maybe_type_definition = FindTypeDefinition( - expr.type.get()->get_name()->value, current_pos, executor); - if (!maybe_type_definition.has_value()) { - return Result::invalid(); - } - const nodes::TypeDefinition *type_definition = maybe_type_definition.value(); - - if (!type_definition->type.has_value()) { - TypeCheckError( - "Type defenition for constructor type not found (declaration only)", - current_pos); - return Result::invalid(); - } - - // TODO: deal with anniotations, recursive annotations - - // TODO: check that is not typeclass ?? - - nodes::Type type = type_definition->type.value(); - - // TODO: work with different parametric types: tuple, variant, ... - - if (expr.args.size() == 0) { - TypeCheckError("Number of type constructor arguments should be > 0", - current_pos); - return Result::invalid(); - // TODO: try return correct type (constructor's type), when possible (not - // generic) - } - - // TODO: work with generics (type_definition->args, ...) - - const auto builtin_type = type.get()->to_builtin(); - - { // check args size, ets. - switch (builtin_type) { - case builtin::Type::TUPLE: - if (expr.args.size() != type.get()->parameters_size()) { - TypeCheckError( - "Number of type constructor arguments is different from expected " - "(" + - std::to_string(expr.args.size()) + " instead of " + - std::to_string(type.get()->parameters_size()) + ")", - current_pos); - return Result::invalid(); - // TODO: try return correct type (constructor's type), when possible - // (not generic) - } - break; - case builtin::Type::VARIANT: - case builtin::Type::OPTIONAL: - case builtin::Type::RESULT: - case builtin::Type::ERROR: - case builtin::Type::FUNCTION: - case builtin::Type::NONE: - if (expr.args.size() != 1) { // TODO: better to_string - TypeCheckError(std::format("Number of type constructor arguments " - "should be = 1 (builtin type {})", - uint(builtin_type)), - current_pos); - return Result::invalid(); - // TODO: try return correct type (constructor's type), when possible - // (not generic) - } - break; - default: // array, basic types - break; - } - - if (builtin::types::get_parameters_count(builtin_type).has_value() && - type.get()->parameters_size() != - builtin::types::get_parameters_count(builtin_type).value()) { - TypeCheckError("Wrong amount of parametars for builtin type", - current_pos); - - return Result::invalid(); - // TODO: try return correct type (constructor's type), when possible (not - // generic) - } - } - - std::optional chosen_variant_option; // for VARIANT - - { // check annotations - const auto check_same_annotation = - [&expr, this](size_t i, - std::optional expected_annotation, - bool log_errors) { - bool is_same = true; - - const auto annotation = expr.args.at(i).first; - - if (annotation.has_value() != expected_annotation.has_value()) { - if (log_errors) { - TypeCheckError( - "Wrong type constructor argument annotation: should be " + - std::string{expected_annotation.has_value() - ? *expected_annotation.value() - : "[none]"}, - PosOf(expr.args.at(i).second)); - } - is_same = false; - } - - if (annotation.has_value() && - annotation.value() != *expected_annotation.value()) { - if (log_errors) { - TypeCheckError("Wrong function argument type annotation: " + - annotation.value() + " instead of " + - *expected_annotation.value(), - PosOf(expr.args.at(i).second)); - } - - is_same = false; - } - - return is_same; - }; - - const auto check_no_annotation = [&expr, this](size_t i, bool log_errors) { - if (expr.args.at(i).first.has_value()) { - if (log_errors) { - TypeCheckError( - "Type constructor argument annotation not expected there", - PosOf(expr.args.at(i).second)); - } - return false; - } - return true; - }; - - switch (builtin_type) { - case builtin::Type::TUPLE: - for (size_t i = 0; i < expr.args.size(); ++i) { - check_same_annotation(i, type.get()->get_parameter(i)->get_annotation(), - true /*log errors*/); - } - break; - case builtin::Type::VARIANT: - // more then one same annotation ?? - for (size_t i = 0; i < type.get()->parameters_size(); ++i) { - if (check_same_annotation( - 0, type.get()->get_parameter(i)->get_annotation(), - false /*do not log errors*/)) { - chosen_variant_option = i; - break; - } - } - - if (!chosen_variant_option.has_value() && - !check_no_annotation(0, false /*do not log errors*/)) { - TypeCheckError("Wrong type constructor argument annotation in " - "constructor of variant type", - PosOf(expr.args.front().second)); - } - break; - case builtin::Type::ERROR: // no anotations ?? - check_same_annotation(0, type.get()->get_parameter(0)->get_annotation(), - true /*log errors*/); - break; - case builtin::Type::OPTIONAL: - case builtin::Type::RESULT: - case builtin::Type::FUNCTION: - case builtin::Type::NONE: - check_no_annotation(0, true /*log errors*/); - break; - default: // array, basic types - break; - } - } - - { // type check args - switch (builtin_type) { - case builtin::Type::TUPLE: - for (size_t i = 0; i < expr.args.size(); ++i) { - Run(expr.args.at(i).second, Args{expr.args.at(i).second}.Expect( - type.get()->get_parameter_proxy(i))); - } - break; - case builtin::Type::VARIANT: - if (chosen_variant_option.has_value()) { - Run(expr.args.front().second, Args{expr.args.front().second}.Expect( - type.get()->get_parameter_proxy( - chosen_variant_option.value()))); - } else { // TODO: error, if there is more then one possible variant in - // answer - nodes::Types possible_options; - for (size_t i = 0; i < type.get()->parameters_size(); ++i) { - possible_options.push_back(type.get()->get_parameter_proxy(i)); - } - Run(expr.args.front().second, - Args{expr.args.front().second}.Expect(possible_options)); - } - break; - case builtin::Type::OPTIONAL: - // first parameter or NULL - Run(expr.args.front().second, - Args{expr.args.front().second}.Expect( - {type.get()->get_parameter_proxy(0), - state().primitive(builtin::Type::NULL_OPTION)})); - break; - case builtin::Type::RESULT: - // first parameter or ERROR[second parameter] - Run(expr.args.front().second, - Args{expr.args.front().second}.Expect( - {type.get()->get_parameter_proxy(0), - state().add_error_of( - type.get()->get_parameter_proxy(1))})); - break; - case builtin::Type::ERROR: - // first parameter - Run(expr.args.front().second, Args{expr.args.front().second}.Expect( - type.get()->get_parameter_proxy(0))); - break; - case builtin::Type::FUNCTION: - case builtin::Type::NONE: - // type itself - Run(expr.args.front().second, - Args{expr.args.front().second}.Expect(type)); - break; - default: // array, basic types - TypeCheckError("Type can't be constructed", current_pos); - break; - } - } - - // TODO: deduce generic parts in type - return TypeCheckFromArgs(expr.type, args, current_pos); - // TODO: add <- modifiier to type ?? - -} // IN PROGRESS +// <------ NOTE: CHECK ENDED THERE // TODO Result CheckTask::operator()(const nodes::Lambda &expr, const Args &args) { Log::Context logc(executor.log(), Log::Area::kTypeCheck); - const auto current_pos = PosOf(args.current_id); + // + + // TODO: maybe expected type is not always required (type deduction) ?? if (args.expected().empty()) { TypeCheckError("Can't deduce type of lambda function from context: no " - "one type expected", + "type is expected", current_pos); } - if (args.expected().size() != - 1) { // TODO: check if only one function argument - TypeCheckError("Can't deduce type of lambda function from context; too " + if (args.expected().size() > 1) { // TODO: check if only one function argument + TypeCheckError("Can't deduce type of lambda function from context: too " "much possible types", current_pos); } @@ -902,37 +514,61 @@ Result CheckTask::operator()(const nodes::Lambda &expr, TypeCheckError("Type of lambda function should be function", current_pos); } + // ---- maybe use new type and then unify instead ?? --- + // TODO: deal with return type (+1 sometimes), etc - const auto args_given = expr.args.size(); - const auto args_defined = expected_type.get()->parameters_size(); - if (args_given != args_defined) { - TypeCheckError(std::format("Number of function arguments is different from " - "expected ({} istead of {}{})", - args_given, args_defined, - args_defined > 0 - ? (" or " + std::to_string(args_defined - 1)) - : ""), - current_pos); - } + // const auto args_given = expr.args.size(); + // const auto args_defined = expected_type.get()->parameters_size(); + // if (args_given != args_defined) { + // TypeCheckError(std::format("Number of function arguments is different + // from " + // "expected ({} istead of {}{})", + // args_given, args_defined, + // args_defined > 0 + // ? (" or " + std::to_string(args_defined - + // 1)) : ""), + // current_pos); + // } // TODO: set another context (for expression typecheck and vars) + nodes::MaybeType context_exit_type; - for (size_t i = 0; i < args_given; ++i) { - if (!state().InsertVariable( - expr.args.at(i).value, expected_type.get()->get_parameter_proxy(i), - nodes::NameDefinition::Kind::LET)) { - // TODO: which modifier ?? - TypeCheckError("Variable is already defined in this context", - current_pos); + { + ContextHolder context_holder( + state(), current_pos, &context_exit_type); + + for (size_t i = 0; i < expr.args.size(); ++i) { + if (not state().InsertVariable(expr.args.at(i).value, + state().add_generic_type(), + nodes::NameDefinition::Kind::LET)) { + // TODO: choose LET / CONST + TypeCheckError("Variable is already defined in this context", + current_pos); + } } + + // TODO: replace with defined args ?? + // for (size_t i = 0; i < args_given; ++i) { + // if (not state().InsertVariable( + // expr.args.at(i).value, + // expected_type.get()->get_parameter_proxy(i), + // nodes::NameDefinition::Kind::LET)) { + // // TODO: choose LET / CONST + // TypeCheckError("Variable is already defined in this context", + // current_pos); + // } + // } + + // TODO: run args exprs + // TODO: run lambda expr itself, get returned type } // TODO: out type is can be not last - if (args_given + 1 == args_defined) { - Run(expr.expr, - Args{expr.expr}.Expect( - expected_type.get()->get_parameter_proxy(args_defined - 1))); - } + // if (args_given + 1 == args_defined) { + // Run(expr.expr, + // Args{expr.expr}.Expect( + // expected_type.get()->get_parameter_proxy(args_defined - 1))); + // } // TODO: needed ?? (only passed type check required ??) return TypeCheckFromArgs(expected_type, args, current_pos); diff --git a/lang/type_check/src/name_expression_type_check.cpp b/lang/type_check/src/name_expression_type_check.cpp new file mode 100644 index 0000000..e28ed98 --- /dev/null +++ b/lang/type_check/src/name_expression_type_check.cpp @@ -0,0 +1,174 @@ +#include "name_expression_type_check.hpp" + +#include "expression_type_check.hpp" + +namespace type_check { + +// TODO: add constraints evaluation +Result +CheckTask::operator()(const nodes::NameExpression &expr, + const Args &args) { + Log::Context logc(executor.log(), Log::Area::kTypeCheck); + const auto current_pos = PosOf(args.current_id); + + // + + const auto name = expr.name; + + { // find variable name equal to expression name prefix + const auto fragments = name.get_fragments(); + nodes::Identifier current_prefix = fragments.front(); + std::optional maybe_variable; + size_t i = 0; + for (; i < fragments.size(); ++i) { + // go in prefixes and try to find matching var namei + if (i > 0) { + current_prefix.append_after(fragments[i]); + } + + maybe_variable = state().FindVariable(current_prefix.value); + + if (maybe_variable.has_value()) { + // possible variable name found + break; + } + } + + // + + if (maybe_variable.has_value()) { + auto &type = maybe_variable.value().type; + for (size_t j = i + 1; j < fragments.size(); ++i) { + if (j + 1 == fragments.size()) { + // then this can be method call + // TODO: try to find method or local function + // if found, search to field (without error handling) + } + + // TODO: fields from several fragments ? (not acceptable fors methods / + // functions) + + // <- in typecheck utils method + // TODO: switch by type types: Variant, Tuple, ... + // Tuple -> try to find field + // Others -> try to open / builtin fields ? + const auto maybe_field_type = + FieldTypeByName(type, fragments[i].value, current_pos, executor); + + if (maybe_field_type.has_value()) { + type = maybe_field_type.value(); + // TODO + continue; + } + + // TODO + + // fields for the names should be found + // last segment can be function name + } + } + } + + // --- TODO --- deal with passed type --- TODO --- (additional argument) + // TODO: deal with given ->(out) Args (type not expected, but passed into) + + // TODO: check, if there is variable with this name + // TODO: check var + fields + const auto maybe_function_definition = + FindNameDefinition(name.value, current_pos, executor); + if (!maybe_function_definition.has_value()) { + return Result::invalid(); + } + const nodes::FunctionDefinition *function_definition = + maybe_function_definition.value(); + + // TODO: count passed type, if needed + // TODO: manage situation with one out type at any position + // TODO + 1 - returned type - somtimes (can be ==) + const auto args_given = expr.args.size(); + const auto args_defined = function_definition->args.size(); + if (args_given + 1 < args_defined || + args_given > args_defined) { // other, when there is passed type + TypeCheckError(std::format("Number of function args is different from " + "expected ({} instead of {}{})", + args_given, args_defined, + args_defined > 0 + ? (" or " + std::to_string(args_defined - 1)) + : ""), + current_pos); + return Result::invalid(); + // TODO: try return correct type (function return type), when possible + } + + // TODO: define types for generic function + + std::vector function_argument_results; + for (size_t i = 0; i < args_given; + ++i) { // TODO: pass types with oud modifier + const nodes::FunctionDefinition::Argument &argument = + function_definition->args.at(i); + + if (!argument.type.has_value()) { + TypeCheckError( + std::format("Function argument type is not defined for argument {}", + i), + current_pos); + continue; + } + + const auto annotation = expr.args.at(i).first; + const auto expected_annotation = argument.annotation; + + if (annotation.has_value() != expected_annotation.has_value()) { + TypeCheckError("Wrong function argument annotation: should be " + + std::string{expected_annotation.has_value() + ? expected_annotation.value() + : "[none]"}, + PosOf(expr.args.at(i).second)); + } + + if (annotation.has_value() && + annotation.value() != expected_annotation.value()) { + TypeCheckError( + std::format( + "Wrong function argument type annotation: {} instead of {}", + annotation.value(), expected_annotation.value()), + PosOf(expr.args.at(i).second)); + } + + function_argument_results.push_back( + Run(expr.args.at(i).second, + Args{expr.args.at(i).second}.Expect(argument.type.value()))); + } + + if (function_definition->args.size() == 0) { + TypeCheckError( + "Function arguments size is zero. Returned type is not defined", + current_pos); + return Result::invalid(); + } + + // TODO: check condition + if (args_given + 1 == args_defined) { + // returned type + const nodes::FunctionDefinition::Argument &returned = + function_definition->args.back(); + + // TODO: invert modifier ?? + if (!returned.type.has_value()) { + TypeCheckError("Function argument type is not defined for returned type", + current_pos); + return Result::invalid(); + } + + // TODO: invert modifier ?? + // TODO: generic types should be deduced from args + return TypeCheckFromArgs(returned.type.value(), args, current_pos); + } + + // checks for universal call syntax ?? + + // TODO: return result +} // IN PROGRESS + +} // namespace type_check