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

View file

@ -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(

View file

@ -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<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) {
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<nodes::TypeCheckResult> condition_result;
std::optional<nodes::TypeCheckResult> interval_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
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,