mirror of
https://codeberg.org/ProgramSnail/lang_2023.git
synced 2025-12-05 22:48:42 +00:00
type_check_visitor returned / brought values check, branches check
This commit is contained in:
parent
a9d4d3a104
commit
f6b50b16ae
3 changed files with 63 additions and 50 deletions
|
|
@ -163,6 +163,15 @@ private:
|
|||
info::definition::AnyType* defined_type,
|
||||
bool is_method);
|
||||
|
||||
void ResetReturnedAndBroughtTypes() {
|
||||
if (returned_type_.has_value()) {
|
||||
all_branches_returned_value_ = false;
|
||||
}
|
||||
if (brought_type_.has_value()) {
|
||||
all_branches_brought_value_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
bool HandleBuiltinFunctionCall(FunctionCallExpression* node);
|
||||
|
|
@ -177,8 +186,13 @@ private:
|
|||
|
||||
std::unordered_set<utils::IdType> type_namespaces_;
|
||||
utils::IdType current_type_;
|
||||
|
||||
std::optional<utils::IdType> returned_type_;
|
||||
bool all_branches_returned_value_ = true;
|
||||
|
||||
std::optional<utils::IdType> brought_type_;
|
||||
bool all_branches_brought_value_ = true;
|
||||
|
||||
std::optional<utils::IsConstModifier> is_const_definition_;
|
||||
|
||||
bool is_in_statement_ = false;
|
||||
|
|
|
|||
|
|
@ -258,8 +258,13 @@ void TypeCheckVisitor::Visit(FunctionDefinitionStatement* node) {
|
|||
utils::IdType returned_type = current_type_;
|
||||
|
||||
returned_type_ = std::nullopt;
|
||||
all_branches_returned_value_ = true;
|
||||
Visitor::Visit(node->value);
|
||||
|
||||
if (!all_branches_returned_value_) {
|
||||
error_handling::HandleTypecheckError("Not all branches return value", node->base);
|
||||
}
|
||||
|
||||
if (!returned_type_.has_value()) {
|
||||
returned_type_ = current_type_;
|
||||
}
|
||||
|
|
@ -479,6 +484,8 @@ void TypeCheckVisitor::Visit(Match* node) { // TODO: move value to match
|
|||
// TODO: several matches with one statement typecheck <- check proposed solution
|
||||
std::optional<Expression*> nearest_statement;
|
||||
for (ssize_t i = (ssize_t)node->matches.size() - 1; i >= 0; --i) { // TODO: internal contexts ??
|
||||
ResetReturnedAndBroughtTypes();
|
||||
|
||||
current_type_ = value_type;
|
||||
|
||||
context_manager_.EnterContext();
|
||||
|
|
@ -530,23 +537,27 @@ void TypeCheckVisitor::Visit(Condition* node) {
|
|||
utils::IdType type;
|
||||
|
||||
for (size_t i = 0; i < node->conditions.size(); ++i) {
|
||||
Visitor::Visit(node->conditions[i]);
|
||||
if (!context_manager_.EqualValues(context_manager_.AddValue(info::type::InternalType::Bool, utils::ValueType::Tmp), current_type_)) {
|
||||
error_handling::HandleTypecheckError("Condition statement condition is not bool expression", node->base);
|
||||
}
|
||||
ResetReturnedAndBroughtTypes();
|
||||
|
||||
Visitor::Visit(node->statements[i]);
|
||||
Visitor::Visit(node->conditions[i]);
|
||||
if (!context_manager_.EqualValues(context_manager_.AddValue(info::type::InternalType::Bool, utils::ValueType::Tmp), current_type_)) {
|
||||
error_handling::HandleTypecheckError("Condition statement condition is not bool expression", node->base);
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
type = current_type_;
|
||||
} else {
|
||||
if (!context_manager_.EqualValues(type, current_type_)) {
|
||||
error_handling::HandleTypecheckError("Condition statement cases have different types", node->base);
|
||||
}
|
||||
Visitor::Visit(node->statements[i]);
|
||||
|
||||
if (i == 0) {
|
||||
type = current_type_;
|
||||
} else {
|
||||
if (!context_manager_.EqualValues(type, current_type_)) {
|
||||
error_handling::HandleTypecheckError("Condition statement cases have different types", node->base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node->statements.size() > node->conditions.size()) {
|
||||
ResetReturnedAndBroughtTypes();
|
||||
|
||||
Visitor::Visit(node->statements[node->conditions.size()]);
|
||||
|
||||
if (!context_manager_.EqualValues(type, current_type_)) {
|
||||
|
|
@ -646,56 +657,27 @@ void TypeCheckVisitor::Visit(LoopLoop* node) {
|
|||
|
||||
// Statements, expressions, blocks, etc. -----------------
|
||||
|
||||
// TODO: check, that last statement in function definition has return type
|
||||
void TypeCheckVisitor::Visit(Block* node) {
|
||||
// TODO: types can be different in statement
|
||||
std::optional<utils::IdType> brought_type;
|
||||
std::optional<utils::IdType> returned_type = returned_type_;
|
||||
|
||||
all_branches_brought_value_ = true;
|
||||
|
||||
context_manager_.EnterContext();
|
||||
for (auto& statement : node->statements) {
|
||||
brought_type_ = std::nullopt;
|
||||
returned_type_ = std::nullopt;
|
||||
|
||||
Visitor::Visit(statement);
|
||||
|
||||
if (brought_type_.has_value()) {
|
||||
if (!brought_type.has_value()) {
|
||||
brought_type = brought_type_.value();
|
||||
} else {
|
||||
if (!context_manager_.EqualValues(brought_type.value(), brought_type_.value())) {
|
||||
error_handling::HandleTypecheckError("Different brought types in block", node->base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (returned_type_.has_value()) {
|
||||
if (!returned_type.has_value()) {
|
||||
returned_type = returned_type_.value();
|
||||
} else {
|
||||
if (!context_manager_.EqualValues(returned_type.value(), returned_type_.value())) {
|
||||
error_handling::HandleTypecheckError("Different returned types in block", node->base);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
context_manager_.EnterContext();
|
||||
context_manager_.ExitContext();
|
||||
|
||||
if (brought_type.has_value()
|
||||
&& !context_manager_.EqualValues(brought_type.value(),
|
||||
context_manager_.AddValue(info::type::InternalType::Unit,
|
||||
utils::ValueType::Tmp))
|
||||
&& !brought_type_.has_value()) {
|
||||
error_handling::HandleTypecheckError("Different brought types in block (no return at end)", node->base);
|
||||
if (!all_branches_brought_value_) {
|
||||
error_handling::HandleTypecheckError("Different brought types in block", node->base);
|
||||
}
|
||||
|
||||
if (brought_type.has_value()) {
|
||||
current_type_ = brought_type.value();
|
||||
if (brought_type_.has_value()) {
|
||||
current_type_ = brought_type_.value();
|
||||
} else {
|
||||
current_type_ = context_manager_.AddValue(info::type::InternalType::Unit, utils::ValueType::Tmp);
|
||||
}
|
||||
|
||||
returned_type_ = returned_type;
|
||||
brought_type_ = std::nullopt;
|
||||
|
||||
node->base.type_ = current_type_;
|
||||
|
|
@ -894,9 +876,23 @@ void TypeCheckVisitor::Visit(VariantExpression* node) {
|
|||
void TypeCheckVisitor::Visit(ReturnExpression* node) {
|
||||
Visitor::Visit(node->expression);
|
||||
if (node->is_from_definition) {
|
||||
returned_type_ = current_type_;
|
||||
if (returned_type_.has_value()) {
|
||||
if (!context_manager_.EqualValues(returned_type_.value(), current_type_)) {
|
||||
error_handling::HandleTypecheckError("Different returned types", node->base);
|
||||
}
|
||||
} else {
|
||||
returned_type_ = current_type_;
|
||||
}
|
||||
all_branches_returned_value_ = true;
|
||||
} else {
|
||||
brought_type_ = current_type_;
|
||||
if (brought_type_.has_value()) {
|
||||
if (!context_manager_.EqualValues(brought_type_.value(), current_type_)) {
|
||||
error_handling::HandleTypecheckError("Different brought types", node->base);
|
||||
}
|
||||
} else {
|
||||
brought_type_ = current_type_;
|
||||
}
|
||||
all_branches_brought_value_ = true;
|
||||
}
|
||||
|
||||
current_type_ = context_manager_.AddValue(info::type::InternalType::Unit, utils::ValueType::Tmp);
|
||||
|
|
|
|||
|
|
@ -142,5 +142,8 @@ def func : s = {
|
|||
|
||||
exec main {
|
||||
for i in (,0 ,1 ,2 ,3) do func: "abacaba"
|
||||
; print: ({ bring read: })
|
||||
; print: ({
|
||||
if true then bring read: else ()
|
||||
bring "nothing"
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue