mirror of
https://codeberg.org/ProgramSnail/lang_2023.git
synced 2025-12-07 15:38:47 +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,
|
info::definition::AnyType* defined_type,
|
||||||
bool is_method);
|
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);
|
bool HandleBuiltinFunctionCall(FunctionCallExpression* node);
|
||||||
|
|
@ -177,8 +186,13 @@ private:
|
||||||
|
|
||||||
std::unordered_set<utils::IdType> type_namespaces_;
|
std::unordered_set<utils::IdType> type_namespaces_;
|
||||||
utils::IdType current_type_;
|
utils::IdType current_type_;
|
||||||
|
|
||||||
std::optional<utils::IdType> returned_type_;
|
std::optional<utils::IdType> returned_type_;
|
||||||
|
bool all_branches_returned_value_ = true;
|
||||||
|
|
||||||
std::optional<utils::IdType> brought_type_;
|
std::optional<utils::IdType> brought_type_;
|
||||||
|
bool all_branches_brought_value_ = true;
|
||||||
|
|
||||||
std::optional<utils::IsConstModifier> is_const_definition_;
|
std::optional<utils::IsConstModifier> is_const_definition_;
|
||||||
|
|
||||||
bool is_in_statement_ = false;
|
bool is_in_statement_ = false;
|
||||||
|
|
|
||||||
|
|
@ -258,8 +258,13 @@ void TypeCheckVisitor::Visit(FunctionDefinitionStatement* node) {
|
||||||
utils::IdType returned_type = current_type_;
|
utils::IdType returned_type = current_type_;
|
||||||
|
|
||||||
returned_type_ = std::nullopt;
|
returned_type_ = std::nullopt;
|
||||||
|
all_branches_returned_value_ = true;
|
||||||
Visitor::Visit(node->value);
|
Visitor::Visit(node->value);
|
||||||
|
|
||||||
|
if (!all_branches_returned_value_) {
|
||||||
|
error_handling::HandleTypecheckError("Not all branches return value", node->base);
|
||||||
|
}
|
||||||
|
|
||||||
if (!returned_type_.has_value()) {
|
if (!returned_type_.has_value()) {
|
||||||
returned_type_ = current_type_;
|
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
|
// TODO: several matches with one statement typecheck <- check proposed solution
|
||||||
std::optional<Expression*> nearest_statement;
|
std::optional<Expression*> nearest_statement;
|
||||||
for (ssize_t i = (ssize_t)node->matches.size() - 1; i >= 0; --i) { // TODO: internal contexts ??
|
for (ssize_t i = (ssize_t)node->matches.size() - 1; i >= 0; --i) { // TODO: internal contexts ??
|
||||||
|
ResetReturnedAndBroughtTypes();
|
||||||
|
|
||||||
current_type_ = value_type;
|
current_type_ = value_type;
|
||||||
|
|
||||||
context_manager_.EnterContext();
|
context_manager_.EnterContext();
|
||||||
|
|
@ -530,23 +537,27 @@ void TypeCheckVisitor::Visit(Condition* node) {
|
||||||
utils::IdType type;
|
utils::IdType type;
|
||||||
|
|
||||||
for (size_t i = 0; i < node->conditions.size(); ++i) {
|
for (size_t i = 0; i < node->conditions.size(); ++i) {
|
||||||
Visitor::Visit(node->conditions[i]);
|
ResetReturnedAndBroughtTypes();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
Visitor::Visit(node->statements[i]);
|
||||||
type = current_type_;
|
|
||||||
} else {
|
if (i == 0) {
|
||||||
if (!context_manager_.EqualValues(type, current_type_)) {
|
type = current_type_;
|
||||||
error_handling::HandleTypecheckError("Condition statement cases have different types", node->base);
|
} 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()) {
|
if (node->statements.size() > node->conditions.size()) {
|
||||||
|
ResetReturnedAndBroughtTypes();
|
||||||
|
|
||||||
Visitor::Visit(node->statements[node->conditions.size()]);
|
Visitor::Visit(node->statements[node->conditions.size()]);
|
||||||
|
|
||||||
if (!context_manager_.EqualValues(type, current_type_)) {
|
if (!context_manager_.EqualValues(type, current_type_)) {
|
||||||
|
|
@ -646,56 +657,27 @@ void TypeCheckVisitor::Visit(LoopLoop* node) {
|
||||||
|
|
||||||
// Statements, expressions, blocks, etc. -----------------
|
// Statements, expressions, blocks, etc. -----------------
|
||||||
|
|
||||||
// TODO: check, that last statement in function definition has return type
|
|
||||||
void TypeCheckVisitor::Visit(Block* node) {
|
void TypeCheckVisitor::Visit(Block* node) {
|
||||||
// TODO: types can be different in statement
|
// 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();
|
context_manager_.EnterContext();
|
||||||
for (auto& statement : node->statements) {
|
for (auto& statement : node->statements) {
|
||||||
brought_type_ = std::nullopt;
|
|
||||||
returned_type_ = std::nullopt;
|
|
||||||
|
|
||||||
Visitor::Visit(statement);
|
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()
|
if (!all_branches_brought_value_) {
|
||||||
&& !context_manager_.EqualValues(brought_type.value(),
|
error_handling::HandleTypecheckError("Different brought types in block", node->base);
|
||||||
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 (brought_type.has_value()) {
|
if (brought_type_.has_value()) {
|
||||||
current_type_ = brought_type.value();
|
current_type_ = brought_type_.value();
|
||||||
} else {
|
} else {
|
||||||
current_type_ = context_manager_.AddValue(info::type::InternalType::Unit, utils::ValueType::Tmp);
|
current_type_ = context_manager_.AddValue(info::type::InternalType::Unit, utils::ValueType::Tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
returned_type_ = returned_type;
|
|
||||||
brought_type_ = std::nullopt;
|
brought_type_ = std::nullopt;
|
||||||
|
|
||||||
node->base.type_ = current_type_;
|
node->base.type_ = current_type_;
|
||||||
|
|
@ -894,9 +876,23 @@ void TypeCheckVisitor::Visit(VariantExpression* node) {
|
||||||
void TypeCheckVisitor::Visit(ReturnExpression* node) {
|
void TypeCheckVisitor::Visit(ReturnExpression* node) {
|
||||||
Visitor::Visit(node->expression);
|
Visitor::Visit(node->expression);
|
||||||
if (node->is_from_definition) {
|
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 {
|
} 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);
|
current_type_ = context_manager_.AddValue(info::type::InternalType::Unit, utils::ValueType::Tmp);
|
||||||
|
|
|
||||||
|
|
@ -142,5 +142,8 @@ def func : s = {
|
||||||
|
|
||||||
exec main {
|
exec main {
|
||||||
for i in (,0 ,1 ,2 ,3) do func: "abacaba"
|
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