From 8a84cfff70dcfe9972c97c7b4dd8d9beea60fe7a Mon Sep 17 00:00:00 2001 From: ProgramSnail Date: Sat, 20 May 2023 20:18:49 +0300 Subject: [PATCH] constructors on heap, consuming match, move modifier in reference expression, .bring. keyword to return from block, some fixes --- include/execute_visitor.hpp | 3 +- include/interpreter_tree.hpp | 6 +++ include/type_check_visitor.hpp | 1 + lang-parser | 2 +- src/build_visitor.cpp | 8 ++++ src/execute_visitor.cpp | 42 ++++++++++++++++----- src/print_visitor.cpp | 13 ++++++- src/type_check_visitor.cpp | 65 +++++++++++++++++++++++++-------- src/typed_print_visitor.cpp | 14 ++++++- tests/default_constructors.lang | 3 +- tests/match.lang | 3 +- tests/test_code.lang | 2 +- 12 files changed, 128 insertions(+), 34 deletions(-) diff --git a/include/execute_visitor.hpp b/include/execute_visitor.hpp index 53dd7db..7efe385 100644 --- a/include/execute_visitor.hpp +++ b/include/execute_visitor.hpp @@ -174,7 +174,8 @@ private: utils::IdType current_value_; std::optional active_loop_control_expression_; - std::optional returned_value_; // TODO: work outside block ?? + std::optional returned_value_; + std::optional brought_value_; std::optional is_const_definition_; bool case_matched_; }; diff --git a/include/interpreter_tree.hpp b/include/interpreter_tree.hpp index 2635490..eee663c 100644 --- a/include/interpreter_tree.hpp +++ b/include/interpreter_tree.hpp @@ -420,6 +420,8 @@ struct Match { Expression value; std::vector matches; + + bool is_consuming_value = false; }; struct Condition { @@ -545,6 +547,8 @@ struct ReturnExpression { BaseNode base; Expression expression; + + bool is_from_definition = false; // from definition or from current block }; struct TypeConstructorParameter { @@ -560,6 +564,8 @@ struct TypeConstructor { std::unique_ptr constructor; std::vector parameters; + + bool is_allocated_on_heap = false; }; struct LambdaFunction { diff --git a/include/type_check_visitor.hpp b/include/type_check_visitor.hpp index c5bd669..7096543 100644 --- a/include/type_check_visitor.hpp +++ b/include/type_check_visitor.hpp @@ -178,6 +178,7 @@ private: std::unordered_set type_namespaces_; utils::IdType current_type_; std::optional returned_type_; + std::optional brought_type_; std::optional is_const_definition_; bool is_in_statement_ = false; diff --git a/lang-parser b/lang-parser index 630eced..ed33952 160000 --- a/lang-parser +++ b/lang-parser @@ -1 +1 @@ -Subproject commit 630eced5368dca21af5eb2b6bea7f90651ce5e30 +Subproject commit ed339526706e0e9289a112fa2cec6ecfdcb362ab diff --git a/src/build_visitor.cpp b/src/build_visitor.cpp index 239ba67..323646b 100644 --- a/src/build_visitor.cpp +++ b/src/build_visitor.cpp @@ -551,6 +551,8 @@ void BuildVisitor::Visit(Match* node) { auto parse_node = current_node_; + node->is_consuming_value = (parse_node.NthChild(1).GetValue() == "<-"); + current_node_ = parse_node.ChildByFieldName("value"); Visit(node->value); @@ -924,6 +926,8 @@ void BuildVisitor::Visit(ReferenceExpression* node) { node->references[i] = utils::ReferenceModifier::Reference; } else if (reference == "~") { node->references[i] = utils::ReferenceModifier::Dereference; + } else if (reference == "@") { + node->references[i] = utils::ReferenceModifier::UniqueReference; // TODO: rename to move ?? } } } @@ -1042,6 +1046,8 @@ void BuildVisitor::Visit(ReturnExpression* node) { auto parse_node = current_node_; + node->is_from_definition = (parse_node.NthChild(0).GetValue() == "return"); // "return" to return from definition and "bring" to return from block + current_node_ = parse_node.ChildByFieldName("expression"); Visit(node->expression); @@ -1077,6 +1083,8 @@ void BuildVisitor::Visit(TypeConstructor* node) { auto parse_node = current_node_; + node->is_allocated_on_heap = (parse_node.NthChild(1).GetValue() == "@"); + current_node_ = parse_node.ChildByFieldName("constructor"); node->constructor = std::make_unique(); Visit(node->constructor.get()); diff --git a/src/execute_visitor.cpp b/src/execute_visitor.cpp index 5498c20..111005d 100644 --- a/src/execute_visitor.cpp +++ b/src/execute_visitor.cpp @@ -49,7 +49,16 @@ void ExecuteVisitor::Visit(FunctionDeclaration*) {} // no value void ExecuteVisitor::Visit(FunctionDefinitionStatement* node) { // visited on function call // Visit(node->definition.get()); context_manager_.EnterContext(); + + returned_value_ = std::nullopt; Visitor::Visit(node->value); + + if (returned_value_.has_value()) { + current_value_ = returned_value_.value(); + } // else returned type = current_type_ + + returned_value_ = std::nullopt; + context_manager_.ExitContext(); } @@ -308,20 +317,27 @@ void ExecuteVisitor::Visit(Block* node) { context_manager_.EnterContext(); for (auto& statement : node->statements) { - returned_value_ = std::nullopt; + brought_value_ = std::nullopt; Visitor::Visit(statement); if (returned_value_.has_value()) { - current_value_ = returned_value_.value(); - returned_value_ = std::nullopt; // TODO: ?? ("return" exits only from one block) - return; + brought_value_ = std::nullopt; + break; + } + if (brought_value_.has_value()) { + break; } } context_manager_.ExitContext(); - current_value_ = context_manager_.AddValue( - info::value::InternalValue(info::value::Unit()), - utils::ValueType::Tmp); + if (brought_value_.has_value()) { + current_value_ = brought_value_.value(); + brought_value_ = std::nullopt; + } else { + current_value_ = context_manager_.AddValue( + info::value::InternalValue(info::value::Unit()), + utils::ValueType::Tmp); + } } void ExecuteVisitor::Visit(ScopedStatement* node) { @@ -332,7 +348,7 @@ void ExecuteVisitor::Visit(LoopControlExpression& node) { active_loop_control_expression_ = node; current_value_ = context_manager_.AddValue(info::value::InternalValue(info::value::Unit()), - utils::ValueType::Tmp); // ?? + utils::ValueType::Tmp); } // Operators @@ -563,7 +579,15 @@ void ExecuteVisitor::Visit(VariantExpression* node) { void ExecuteVisitor::Visit(ReturnExpression* node) { Visitor::Visit(node->expression); - returned_value_ = current_value_; + if (node->is_from_definition) { + returned_value_ = current_value_; + } else { + brought_value_ = current_value_; + } + + current_value_ = context_manager_.AddValue( + info::value::InternalValue(info::value::Unit()), + utils::ValueType::Tmp); } diff --git a/src/print_visitor.cpp b/src/print_visitor.cpp index 3482545..17ec189 100644 --- a/src/print_visitor.cpp +++ b/src/print_visitor.cpp @@ -282,7 +282,11 @@ void PrintVisitor::Visit(MatchCase* node) { } void PrintVisitor::Visit(Match* node) { - out_ << "[Match] ("; + out_ << "[Match"; + if (node->is_consuming_value) { + out_ << " <- "; + } + out_ << "] ("; Visitor::Visit(node->value); out_ << ") [with] (\n"; for (auto& match_case : node->matches) { @@ -476,7 +480,12 @@ void PrintVisitor::Visit(VariantExpression* node) { } void PrintVisitor::Visit(ReturnExpression* node) { - out_ << "[Return] ("; + if (node->is_from_definition) { + out_ << "[Return] ("; + } else { + out_ << "[Bring] ("; + } + Visitor::Visit(node->expression); out_ << ")\n"; } diff --git a/src/type_check_visitor.cpp b/src/type_check_visitor.cpp index 6a7f90d..b6ad075 100644 --- a/src/type_check_visitor.cpp +++ b/src/type_check_visitor.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -254,12 +255,18 @@ void TypeCheckVisitor::Visit(FunctionDefinitionStatement* node) { } Visitor::Visit(declaration->type->types.back()); - utils::IdType return_type = current_type_; + utils::IdType returned_type = current_type_; + returned_type_ = std::nullopt; Visitor::Visit(node->value); - if (!context_manager_.EqualValues(return_type, current_type_)) { + + if (!returned_type_.has_value()) { + returned_type_ = current_type_; + } + if (!context_manager_.EqualValues(returned_type, returned_type_.value())) { error_handling::HandleTypecheckError("Wrong function return type", node->base); } + returned_type_ = std::nullopt; context_manager_.ExitContext(); @@ -639,35 +646,57 @@ 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 - utils::IdType type; - - bool is_type_found = false; + std::optional brought_type; + std::optional returned_type = returned_type_; context_manager_.EnterContext(); for (auto& statement : node->statements) { + brought_type_ = std::nullopt; returned_type_ = std::nullopt; + Visitor::Visit(statement); - if (returned_type_.has_value()) { - if (!is_type_found) { - type = returned_type_.value(); - is_type_found = true; + + if (brought_type_.has_value()) { + if (!brought_type.has_value()) { + brought_type = brought_type_.value(); } else { - if (!context_manager_.EqualValues(type, returned_type_.value())) { - error_handling::HandleTypecheckError("Different return types in block", node->base); + 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); } } - // returned_type_ = std::nullopt; // not needed } } context_manager_.EnterContext(); - if (!is_type_found) { - type = context_manager_.AddValue(info::type::InternalType::Unit, utils::ValueType::Tmp); + 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); } - current_type_ = type; + 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_; } @@ -864,7 +893,11 @@ void TypeCheckVisitor::Visit(VariantExpression* node) { void TypeCheckVisitor::Visit(ReturnExpression* node) { Visitor::Visit(node->expression); - returned_type_ = current_type_; + if (node->is_from_definition) { + returned_type_ = current_type_; + } else { + brought_type_ = current_type_; + } current_type_ = context_manager_.AddValue(info::type::InternalType::Unit, utils::ValueType::Tmp); diff --git a/src/typed_print_visitor.cpp b/src/typed_print_visitor.cpp index 7234403..4286127 100644 --- a/src/typed_print_visitor.cpp +++ b/src/typed_print_visitor.cpp @@ -385,7 +385,13 @@ void TypedPrintVisitor::Visit(MatchCase* node) { } void TypedPrintVisitor::Visit(Match* node) { - out_ << "[Match : "; + out_ << "[Match"; + + if (node->is_consuming_value) { + out_ << " <-"; + } + + out_ << " : "; if (node->base.type_.has_value()) { out_ << context_manager_.GetAnyValue(node->base.type_.value())->GetTypeName(); @@ -657,7 +663,11 @@ void TypedPrintVisitor::Visit(VariantExpression* node) { } void TypedPrintVisitor::Visit(ReturnExpression* node) { - out_ << "[Return : "; + if (node->is_from_definition) { + out_ << "[Return : "; + } else { + out_ << "[Bring : "; + } if (node->base.type_.has_value()) { out_ << context_manager_.GetAnyValue(node->base.type_.value())->GetTypeName(); diff --git a/tests/default_constructors.lang b/tests/default_constructors.lang index 51a19c6..bfed145 100644 --- a/tests/default_constructors.lang +++ b/tests/default_constructors.lang @@ -1,8 +1,9 @@ namespace Employee { decl gen_employee : Unit -> Employee def gen_employee = { + var x = $@Complex & 11.3 & 15.87 // construct on heap return - $Employee + $Employee // construct on stack & name = "John" & role = ($Manager diff --git a/tests/match.lang b/tests/match.lang index a882ef3..0541c72 100644 --- a/tests/match.lang +++ b/tests/match.lang @@ -1,6 +1,7 @@ decl fruit_cost : Fruit -> Int def fruit_cost : fruit = { - return (match fruit with + var fruit_copy = fruit + return (match <- fruit_copy with // consuming match | $Banana -> 11 | $Apple | $Orange -> 7) } diff --git a/tests/test_code.lang b/tests/test_code.lang index 6d743b1..ee2a19b 100644 --- a/tests/test_code.lang +++ b/tests/test_code.lang @@ -142,5 +142,5 @@ def func : s = { exec main { for i in (,0 ,1 ,2 ,3) do func: "abacaba" - ; print: ({ return read: }) + ; print: ({ bring read: }) }