typecheck for some expressions

This commit is contained in:
ProgramSnail 2024-02-16 00:47:40 +03:00
parent 070b08dba4
commit 61fa3a19a0
3 changed files with 78 additions and 52 deletions

View file

@ -446,7 +446,7 @@ public:
return TypeCheckResult(); return TypeCheckResult();
} }
explicit TypeCheckResult(std::optional<TypeProxy> type) : type_(type) {} explicit TypeCheckResult(nodes::TypeProxy type) : type_(type) {}
// //
@ -478,7 +478,7 @@ private:
TypeCheckResult() = default; TypeCheckResult() = default;
private: private:
std::optional<TypeProxy> type_; nodes::MaybeTypeProxy type_;
}; };
} // namespace nodes } // namespace nodes

View file

@ -186,8 +186,8 @@ private:
class ContextHolder { class ContextHolder {
public: public:
ContextHolder(State &state, const nodes::Node &node, ContextHolder(State &state, const nodes::Node &node,
error_handling::ErrorLog &error_log) error_handling::ErrorLog &error_log, nodes::MaybeTypeProxy* context_exit_type)
: state(state) { : state_(state), context_exit_type_(context_exit_type) {
state.enter_context(node, error_log); state.enter_context(node, error_log);
} }
@ -197,10 +197,17 @@ public:
ContextHolder &operator=(const ContextHolder &) = delete; ContextHolder &operator=(const ContextHolder &) = delete;
ContextHolder &operator=(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: private:
State &state; State &state_;
nodes::MaybeTypeProxy* context_exit_type_;
}; };
nodes::TypeCheckResult type_same_to_expected( nodes::TypeCheckResult type_same_to_expected(

View file

@ -10,6 +10,8 @@
// IN PROGRESS // IN PROGRESS
// TODO: typecheck pass in all functions
namespace type_check { namespace type_check {
nodes::TypeCheckResult nodes::TypeCheckResult
@ -80,7 +82,6 @@ type_check_expression(const nodes::Expression &expression,
// --- flow control // --- flow control
// TODO
nodes::TypeCheckResult type_check_match(const nodes::Match &expression, nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
SourcesManager &sources_manager, SourcesManager &sources_manager,
State &state, State &state,
@ -98,6 +99,9 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
std::optional<nodes::TypeCheckResult> expression_result; std::optional<nodes::TypeCheckResult> 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) { for (size_t i = 0; i < expression.cases_size(); ++i) {
const nodes::Match::Case *current_case = expression.get_case(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) .expect_builtin(builtin::types::Type::BOOL, sources_manager)
.pass(value_result.is_invalid() ? nodes::MaybeTypeProxy{} .pass(value_result.is_invalid() ? nodes::MaybeTypeProxy{}
: expression_result.value().get())); : expression_result.value().get()));
// TODO: work with case // TODO: use type modifiers ??
// TODO: use type modifiers
// ... ?? x ... // ... ?? x ...
if (current_case->get_condition().has_value()) { if (current_case->get_condition().has_value()) {
@ -121,6 +124,7 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
// ... -> x // ... -> x
if (current_case->get_expression().has_value()) { if (current_case->get_expression().has_value()) {
at_least_one_case_with_expression = true;
nodes::TypeCheckResult case_result = type_check_expression( nodes::TypeCheckResult case_result = type_check_expression(
*current_case->get_condition().value(), sources_manager, state, *current_case->get_condition().value(), sources_manager, state,
Arguments{}.expect(expression_result.has_value() 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); expression_result = std::move(case_result);
} }
} else { } 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()) { if (!expression_result.has_value()) {
expression_result = nodes::TypeCheckResult{ expression_result = nodes::TypeCheckResult{
sources_manager.get_type_storage()->primitive_type( sources_manager.get_type_storage()->primitive_type(
@ -145,7 +157,7 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
expression_result.value().get()), expression_result.value().get()),
arguments.get_expected(), expression, arguments.get_expected(), expression,
*sources_manager.get_error_log()); *sources_manager.get_error_log());
} // IN PROGRESS }
nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression, nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression,
SourcesManager &sources_manager, SourcesManager &sources_manager,
@ -186,11 +198,6 @@ nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression,
expression_result = nodes::TypeCheckResult::construct_invalid_result(); 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( return type_same_to_expected(sources_manager.get_type_storage()->add_array_of(
expression_result.value().get()), expression_result.value().get()),
arguments.get_expected(), expression, arguments.get_expected(), expression,
@ -203,8 +210,6 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression,
const Arguments &arguments) { const Arguments &arguments) {
// TODO: ranges ?? // TODO: ranges ??
// std::optional<nodes::TypeCheckResult> condition_result;
std::optional<nodes::TypeCheckResult> interval_result; std::optional<nodes::TypeCheckResult> interval_result;
std::optional<nodes::TypeCheckResult> variable_result; std::optional<nodes::TypeCheckResult> variable_result;
@ -216,7 +221,7 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression,
case nodes::Loop::LOOP: // infinity loop, no params case nodes::Loop::LOOP: // infinity loop, no params
break; break;
case nodes::Loop::WHILE: case nodes::Loop::WHILE:
/*condition_result = */ type_check_expression( type_check_expression(
*expression.get_condition().value(), sources_manager, state, *expression.get_condition().value(), sources_manager, state,
Arguments{}.expect_builtin(builtin::types::Type::BOOL, Arguments{}.expect_builtin(builtin::types::Type::BOOL,
sources_manager)); sources_manager));
@ -226,17 +231,6 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression,
// return condition_result.value(); // 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; break;
case nodes::Loop::FOR: case nodes::Loop::FOR:
// TODO: expect range ?? // TODO: expect range ??
@ -296,7 +290,7 @@ nodes::TypeCheckResult type_check_array(const nodes::Container &expression,
*expression.get_expression(i), *expression.get_expression(i),
"Elements in array should have same type", "Elements in array should have same type",
error_handling::ErrorType::TYPE_CHECK)); 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()), last_expression_result.value().get()),
arguments.get_expected(), expression, arguments.get_expected(), expression,
*sources_manager.get_error_log()); *sources_manager.get_error_log());
} // IN PROGRESS }
// TODO
nodes::TypeCheckResult type_check_block(const nodes::Container &expression, nodes::TypeCheckResult type_check_block(const nodes::Container &expression,
SourcesManager &sources_manager, SourcesManager &sources_manager,
State &state, State &state,
const Arguments &arguments) { const Arguments &arguments) {
ContextHolder context_holder(state, expression, nodes::MaybeTypeProxy context_exit_type;
*sources_manager.get_error_log());
} // 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, nodes::TypeCheckResult type_check_container(const nodes::Container &expression,
SourcesManager &sources_manager, SourcesManager &sources_manager,
@ -333,11 +348,9 @@ nodes::TypeCheckResult type_check_container(const nodes::Container &expression,
case nodes::Container::ARRAY: case nodes::Container::ARRAY:
return type_check_array(expression, sources_manager, state, arguments); return type_check_array(expression, sources_manager, state, arguments);
case nodes::Container::BLOCK: case nodes::Container::BLOCK:
return type_check_block(expression, sources_manager, state, return type_check_block(expression, sources_manager, state, arguments);
arguments); // TODO: check that expression brought
// type are same, -> brought_type
} }
} // IN PROGRESS }
// --- modifiers // --- modifiers
@ -379,31 +392,33 @@ nodes::TypeCheckResult type_check_return(const nodes::Return &expression,
arguments.get_expected(), expression, *sources_manager.get_error_log()); arguments.get_expected(), expression, *sources_manager.get_error_log());
} }
// TODO
nodes::TypeCheckResult nodes::TypeCheckResult
type_check_name_definition(const nodes::NameDefinition &expression, type_check_name_definition(const nodes::NameDefinition &expression,
SourcesManager &sources_manager, State &state, SourcesManager &sources_manager, State &state,
const Arguments &arguments) { const Arguments &arguments) {
if (!arguments.get_expected().has_value()) { if (!arguments.get_passed().has_value()) {
sources_manager.get_error_log()->add_error( sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage( error_handling::ErrorLog::ErrorMessage(
expression, "Can't deduce type of new variable from context", expression, "Can't deduce type of new variable from context",
error_handling::ErrorType::TYPE_CHECK)); error_handling::ErrorType::TYPE_CHECK));
} }
// defined name modifier should be -> (or contain -> ??) // assigned type shold be one of <-, <>, -- (can't be ->)
// TODO: deal with ...|...|... modifiers const auto variable_type = arguments.get_passed().value();
const auto expected_type = arguments.get_expected().value(); if (nodes::utils::modifier_contains_OUT(
if (!expected_type.get()->is_modifier( variable_type.get()
nodes::Modifier::OUT)) { // TODO: utils::modifier_contains_OUT ->get_modifier())) { // TODO: utils::modifier_contains_OUT
sources_manager.get_error_log()->add_error( sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage( 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)); error_handling::ErrorType::TYPE_CHECK));
} }
// TODO: remove modifier ?? // variable accessible by reference by default ??
if (!state.insert_variable(*expression.get_name()->get(), expected_type, 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())) { expression.get_modifier())) {
sources_manager.get_error_log()->add_error( sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage( error_handling::ErrorLog::ErrorMessage(
@ -411,8 +426,12 @@ type_check_name_definition(const nodes::NameDefinition &expression,
error_handling::ErrorType::TYPE_CHECK)); error_handling::ErrorType::TYPE_CHECK));
} }
return nodes::TypeCheckResult{expected_type}; // Return BOOL as any := / =: expression
} // IN PROGRESS 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, nodes::TypeCheckResult type_check_array_access(const nodes::Access &expression,
SourcesManager &sources_manager, SourcesManager &sources_manager,