mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-05 22:48:43 +00:00
type check error function
This commit is contained in:
parent
61fa3a19a0
commit
1a9408c2f6
4 changed files with 83 additions and 84 deletions
|
|
@ -186,7 +186,8 @@ private:
|
|||
class ContextHolder {
|
||||
public:
|
||||
ContextHolder(State &state, const nodes::Node &node,
|
||||
error_handling::ErrorLog &error_log, nodes::MaybeTypeProxy* context_exit_type)
|
||||
error_handling::ErrorLog &error_log,
|
||||
nodes::MaybeTypeProxy *context_exit_type)
|
||||
: state_(state), context_exit_type_(context_exit_type) {
|
||||
state.enter_context(node, error_log);
|
||||
}
|
||||
|
|
@ -198,16 +199,16 @@ public:
|
|||
ContextHolder &operator=(ContextHolder &&) = delete;
|
||||
|
||||
~ContextHolder() {
|
||||
if (context_exit_type_) {
|
||||
*context_exit_type_ = state_.exit_context();
|
||||
} else {
|
||||
state_.exit_context();
|
||||
}
|
||||
if (context_exit_type_) {
|
||||
*context_exit_type_ = state_.exit_context();
|
||||
} else {
|
||||
state_.exit_context();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
State &state_;
|
||||
nodes::MaybeTypeProxy* context_exit_type_;
|
||||
nodes::MaybeTypeProxy *context_exit_type_;
|
||||
};
|
||||
|
||||
nodes::TypeCheckResult type_same_to_expected(
|
||||
|
|
@ -225,4 +226,7 @@ find_name_definition_handle_errors(const std::string &name,
|
|||
const nodes::Node &node,
|
||||
SourcesManager &sources_manager);
|
||||
|
||||
void type_check_error(const std::string &message, const nodes::Node &node,
|
||||
SourcesManager &sources_manager);
|
||||
|
||||
} // namespace type_check
|
||||
|
|
|
|||
|
|
@ -11,3 +11,19 @@ inline void handle_general_error(const std::string &message) {
|
|||
}
|
||||
|
||||
} // namespace error_handling
|
||||
|
||||
namespace utils {
|
||||
|
||||
// in std from c++23
|
||||
[[noreturn]] inline void unreachable() {
|
||||
// Uses compiler specific extensions if possible.
|
||||
// Even if no extension is used, undefined behavior is still raised by
|
||||
// an empty function body and the noreturn attribute.
|
||||
#if defined(_MSC_VER) && !defined(__clang__) // MSVC
|
||||
__assume(false);
|
||||
#else // GCC, Clang
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
// IN PROGRESS
|
||||
|
||||
// TODO: typecheck pass in all functions
|
||||
// TODO: assign types in nodes
|
||||
|
||||
namespace type_check {
|
||||
|
||||
|
|
@ -78,6 +79,8 @@ type_check_expression(const nodes::Expression &expression,
|
|||
sources_manager.get_type_storage()->primitive_type(
|
||||
builtin::types::Type::UNIT));
|
||||
}
|
||||
|
||||
utils::unreachable();
|
||||
}
|
||||
|
||||
// --- flow control
|
||||
|
|
@ -91,10 +94,7 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
|
|||
|
||||
// x :=/=: ...
|
||||
if (value_result.is_invalid()) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression, "Match value is invalid",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("Match value is invalid", expression, sources_manager);
|
||||
}
|
||||
|
||||
std::optional<nodes::TypeCheckResult> expression_result;
|
||||
|
|
@ -139,11 +139,11 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
|
|||
}
|
||||
}
|
||||
|
||||
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));
|
||||
if (at_least_one_case_with_expression &&
|
||||
at_least_one_case_without_expression) {
|
||||
type_check_error(
|
||||
"All cases should be with or without expression at the same time",
|
||||
expression, sources_manager);
|
||||
expression_result = nodes::TypeCheckResult::construct_invalid_result();
|
||||
}
|
||||
|
||||
|
|
@ -191,10 +191,8 @@ nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression,
|
|||
}
|
||||
|
||||
if (!expression_result.has_value()) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression, "There should be at least one case in if statement",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("There should be at least one case in if statement",
|
||||
expression, sources_manager);
|
||||
expression_result = nodes::TypeCheckResult::construct_invalid_result();
|
||||
}
|
||||
|
||||
|
|
@ -221,10 +219,10 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression,
|
|||
case nodes::Loop::LOOP: // infinity loop, no params
|
||||
break;
|
||||
case nodes::Loop::WHILE:
|
||||
type_check_expression(
|
||||
*expression.get_condition().value(), sources_manager, state,
|
||||
Arguments{}.expect_builtin(builtin::types::Type::BOOL,
|
||||
sources_manager));
|
||||
type_check_expression(*expression.get_condition().value(), sources_manager,
|
||||
state,
|
||||
Arguments{}.expect_builtin(builtin::types::Type::BOOL,
|
||||
sources_manager));
|
||||
|
||||
// --- type check is independent from loop itself ---
|
||||
// if (condition_result.value().is_invalid()) {
|
||||
|
|
@ -285,21 +283,16 @@ nodes::TypeCheckResult type_check_array(const nodes::Container &expression,
|
|||
last_expression_result = expression_result;
|
||||
} else {
|
||||
if (last_expression_result.value().get() != expression_result.get()) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
*expression.get_expression(i),
|
||||
"Elements in array should have same type",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
// return nodes::TypeCheckResult::construct_invalid_result(); // max possible checks, so no return
|
||||
type_check_error("Elements in array should have same type",
|
||||
*expression.get_expression(i), sources_manager);
|
||||
// return nodes::TypeCheckResult::construct_invalid_result(); // max
|
||||
// possible checks, so no return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!last_expression_result.has_value()) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression, "Array with zero elements",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("Array with zero elements", expression, sources_manager);
|
||||
return nodes::TypeCheckResult::construct_invalid_result();
|
||||
}
|
||||
|
||||
|
|
@ -316,9 +309,9 @@ nodes::TypeCheckResult type_check_block(const nodes::Container &expression,
|
|||
nodes::MaybeTypeProxy context_exit_type;
|
||||
|
||||
{
|
||||
ContextHolder context_holder(state, expression,
|
||||
*sources_manager.get_error_log(),
|
||||
&context_exit_type); // TODO: is brought type returned
|
||||
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
|
||||
|
|
@ -368,19 +361,15 @@ nodes::TypeCheckResult type_check_return(const nodes::Return &expression,
|
|||
switch (expression.get_type()) {
|
||||
case nodes::Return::BRING:
|
||||
if (state.bring_type(returned_result.get())) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression, "Different brought type to current one",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("Different brought type to current one", expression,
|
||||
sources_manager);
|
||||
return nodes::TypeCheckResult::construct_invalid_result();
|
||||
}
|
||||
break;
|
||||
case nodes::Return::RETURN:
|
||||
if (!state.return_type(returned_result.get())) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression, "Different returned type to current one",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("Different returned type to current one", expression,
|
||||
sources_manager);
|
||||
return nodes::TypeCheckResult::construct_invalid_result();
|
||||
}
|
||||
break;
|
||||
|
|
@ -397,10 +386,8 @@ type_check_name_definition(const nodes::NameDefinition &expression,
|
|||
SourcesManager &sources_manager, State &state,
|
||||
const Arguments &arguments) {
|
||||
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));
|
||||
type_check_error("Can't deduce type of new variable from context",
|
||||
expression, sources_manager);
|
||||
}
|
||||
|
||||
// assigned type shold be one of <-, <>, -- (can't be ->)
|
||||
|
|
@ -408,10 +395,8 @@ type_check_name_definition(const nodes::NameDefinition &expression,
|
|||
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, "Variabla cant be asignet from out (->) value",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("Variable can't be assigned from out (->) value",
|
||||
expression, sources_manager);
|
||||
}
|
||||
|
||||
// variable accessible by reference by default ??
|
||||
|
|
@ -420,10 +405,8 @@ type_check_name_definition(const nodes::NameDefinition &expression,
|
|||
|
||||
if (!state.insert_variable(*expression.get_name()->get(), variable_type,
|
||||
expression.get_modifier())) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression, "Variable is already defined in this context",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("Variable is already defined in this context", expression,
|
||||
sources_manager);
|
||||
}
|
||||
|
||||
// Return BOOL as any := / =: expression
|
||||
|
|
@ -535,10 +518,8 @@ type_check_modifier_expression(const nodes::ModifierExpression &expression,
|
|||
modified_result.set(modified_result.get().get()->get_parameter_proxy(0));
|
||||
break;
|
||||
default:
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression, "Can unwrap only Optional or Result",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("Can unwrap only Optional or Result", expression,
|
||||
sources_manager);
|
||||
return nodes::TypeCheckResult::construct_invalid_result();
|
||||
}
|
||||
} else {
|
||||
|
|
@ -572,11 +553,9 @@ type_check_constructor(const nodes::Constructor &expression,
|
|||
const nodes::TypeDefinition *type_definition = maybe_type_definition.value();
|
||||
|
||||
if (!type_definition->get_type().has_value()) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression,
|
||||
"Type defenition for constructor type not found (declaration only)",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error(
|
||||
"Type defenition for constructor type not found (declaration only)",
|
||||
expression, sources_manager);
|
||||
return nodes::TypeCheckResult::construct_invalid_result();
|
||||
}
|
||||
|
||||
|
|
@ -592,16 +571,13 @@ type_check_constructor(const nodes::Constructor &expression,
|
|||
// TODO: work with different parametric types: tuple, variant, ...
|
||||
|
||||
if (type.get()->parameters_size() != expression.arguments_size()) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression,
|
||||
"Constructor arguments count is " +
|
||||
std::string{expression.arguments_size() <
|
||||
type.get()->parameters_size()
|
||||
? "less"
|
||||
: "more"} +
|
||||
" then type fields count",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("Constructor arguments count is " +
|
||||
std::string{expression.arguments_size() <
|
||||
type.get()->parameters_size()
|
||||
? "less"
|
||||
: "more"} +
|
||||
" then type fields count",
|
||||
expression, sources_manager);
|
||||
return nodes::TypeCheckResult::construct_invalid_result();
|
||||
}
|
||||
|
||||
|
|
@ -627,18 +603,14 @@ nodes::TypeCheckResult type_check_lambda(const nodes::Lambda &expression,
|
|||
State &state,
|
||||
const Arguments &arguments) {
|
||||
if (!arguments.get_expected().has_value()) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression, "Can't deduce type of lambda function from context",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("Can't deduce type of lambda function from context",
|
||||
expression, sources_manager);
|
||||
}
|
||||
|
||||
const auto expected_type = arguments.get_expected().value();
|
||||
if (!expected_type.get()->is_builtin(builtin::types::Type::FUNCTION)) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
expression, "Type of lambda function should be function",
|
||||
error_handling::ErrorType::TYPE_CHECK));
|
||||
type_check_error("Type of lambda function should be function", expression,
|
||||
sources_manager);
|
||||
}
|
||||
|
||||
// TODO: define vars
|
||||
|
|
|
|||
|
|
@ -65,4 +65,11 @@ find_name_definition_handle_errors(const std::string &name,
|
|||
"Node in name tree is not name definition");
|
||||
}
|
||||
|
||||
void type_check_error(const std::string &message, const nodes::Node &node,
|
||||
SourcesManager &sources_manager) {
|
||||
sources_manager.get_error_log()->add_error(
|
||||
error_handling::ErrorLog::ErrorMessage(
|
||||
node, message, error_handling::ErrorType::TYPE_CHECK));
|
||||
}
|
||||
|
||||
} // namespace type_check
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue