From aa4e9fa721be9e483c890cbc4bb8fe496f5ff15a Mon Sep 17 00:00:00 2001 From: ProgramSnail Date: Fri, 14 Apr 2023 14:37:46 +0300 Subject: [PATCH] type graph class --- include/find_symbols_visitor.hpp | 4 - include/global_info.hpp | 52 ++- include/type_check_visitor.hpp | 115 ++++++ include/type_graph.hpp | 239 +++++++++++ src/print_visitor.cpp | 1 - src/type_check_visitor.cpp | 684 +++++++++++++++++++++++++++++++ 6 files changed, 1073 insertions(+), 22 deletions(-) create mode 100644 include/type_check_visitor.hpp create mode 100644 include/type_graph.hpp create mode 100644 src/type_check_visitor.cpp diff --git a/include/find_symbols_visitor.hpp b/include/find_symbols_visitor.hpp index 2b3f891..1e859e8 100644 --- a/include/find_symbols_visitor.hpp +++ b/include/find_symbols_visitor.hpp @@ -7,10 +7,6 @@ #include "visitor.hpp" #include "global_info.hpp" -// TODO: -// add/remove global variables -// - namespace interpreter { class FindSymbolsVisitor : public Visitor { diff --git a/include/global_info.hpp b/include/global_info.hpp index a3dbc2a..65cb34e 100644 --- a/include/global_info.hpp +++ b/include/global_info.hpp @@ -12,7 +12,7 @@ namespace info { class GlobalInfo { public: GlobalInfo() { - namespace_stack.push_back(&global_namespace_); + namespace_stack_.push_back(&global_namespace_); } void AddImport(ImportInfo&& import_info, const std::optional& name = std::nullopt) { @@ -23,62 +23,80 @@ public: } } - void AddEnterNamespace(const std::string& type, + void AddEnterNamespace(const std::string& name, const std::optional& modifier = std::nullopt, const std::optional& variable = std::nullopt) { - NamespaceInfo* namespace_info = &namespace_stack.back()->namespaces[type].emplace_back(); - namespace_stack.push_back(namespace_info); + NamespaceInfo* namespace_info = &namespace_stack_.back()->namespaces[name].emplace_back(); + namespace_stack_.push_back(namespace_info); namespace_info->modifier = modifier; namespace_info->variable = variable; - namespace_info->type_name = type; + namespace_info->type_name = name; + } + + void EnterNamespace(const std::string& name) { // TODO: enter sibling namespace, etc. + auto& namespace_parts = namespace_stack_.back()->namespaces[name]; + for (auto& part : namespace_parts) { + if (part.variable == std::nullopt) { + namespace_stack_.push_back(&part); + } + } + } + + void ExitAllNameNamespaces(const std::string& name) { + while(namespace_stack_.size() > 1 && namespace_stack_.back()->type_name == name) { + namespace_stack_.pop_back(); + } } void ExitNamespace() { - if (namespace_stack.size() <= 1) { + if (namespace_stack_.size() <= 1) { // error return; } - namespace_stack.pop_back(); + namespace_stack_.pop_back(); } void ToGlobalNamespace() { - namespace_stack.clear(); - namespace_stack.push_back(&global_namespace_); + namespace_stack_.clear(); + namespace_stack_.push_back(&global_namespace_); } void AddFunctionDeclaration(const std::string& name, FunctionDeclarationInfo&& function_declaration_info) { - FunctionInfo* function_info = &namespace_stack.back()->functions[name]; + FunctionInfo* function_info = &namespace_stack_.back()->functions[name]; function_info->declaration = std::move(function_declaration_info); } void AddFunctionDefinition(const std::string& name, FunctionDefinitionInfo&& function_definition_info) { - FunctionInfo* function_info = &namespace_stack.back()->functions[name]; + FunctionInfo* function_info = &namespace_stack_.back()->functions[name]; function_info->definition = std::move(function_definition_info); } void AddType(const std::string& type, TypeInfo&& type_info) { - namespace_stack.back()->types[type] = std::move(type_info); + namespace_stack_.back()->types[type] = std::move(type_info); } void AddTypeclass(const std::string& typeclass, TypeclassInfo&& typeclass_info) { - namespace_stack.back()->typeclasses[typeclass] = std::move(typeclass_info); + namespace_stack_.back()->typeclasses[typeclass] = std::move(typeclass_info); } - // FindFunction - // FindType + void FindFunction(const std::vector& path) { + // TODO + } - // FindVar ?? + void FindType(const std::vector& path) { + // TODO + } private: - std::vector namespace_stack; + std::vector namespace_stack_; NamespaceInfo global_namespace_; std::vector imports_; diff --git a/include/type_check_visitor.hpp b/include/type_check_visitor.hpp new file mode 100644 index 0000000..3d49dfd --- /dev/null +++ b/include/type_check_visitor.hpp @@ -0,0 +1,115 @@ +#pragma once + +// for clangd +#include "visitor.hpp" +#include "global_info.hpp" + +namespace interpreter { + +class TypeCheckVisitor : public Visitor { +public: + explicit TypeCheckVisitor(info::GlobalInfo& global_info) : global_info_(global_info) {} + +private: + // Sources ----------------- + + void Visit(SourceFile* node) override; + void Visit(Sources* node) override; + + // Namespaces, partitions ----------------- + + void Visit(Partition* node) override; + void Visit(Namespace* node) override; + + // Definitions ----------------- + + void Visit(ImportStatement* node) override; + void Visit(AliasDefinitionStatement* node) override; + void Visit(VariableDefinitionStatement* node) override; + void Visit(FunctionDeclaration* node) override; + void Visit(FunctionDefinitionStatement* node) override; + void Visit(TypeDefinitionStatement* node) override; + void Visit(AbstractTypeDefinitionStatement* node) override; + void Visit(TypeclassDefinitionStatement* node) override; + + // Definition parts + + void Visit(FunctionDefinition* node) override; + void Visit(TypeDefinition* node) override; + void Visit(AnyAnnotatedType* node) override; + + // Flow control ----------------- + + void Visit(MatchCase* node) override; + void Visit(Match* node) override; + void Visit(Condition* node) override; + void Visit(DoWhileLoop* node) override; + void Visit(WhileLoop* node) override; + void Visit(ForLoop* node) override; + void Visit(LoopLoop* node) override; + + // Statements, expressions, blocks, etc. ----------------- + + void Visit(Block* node) override; + + void Visit(ScopedStatement* node) override; + + // Operators + + void Visit(BinaryOperatorExpression* node) override; + void Visit(UnaryOperatorExpression* node) override; + void Visit(ReferenceExpression* node) override; + + // Simple Expressions + + void Visit(FunctionCallExpression* node) override; + + void Visit(TupleExpression* node) override; + void Visit(VariantExpression* node) override; + void Visit(ReturnExpression* node) override; + void Visit(TypeConstructor* node) override; + void Visit(LambdaFunction* node) override; + void Visit(ArrayExpression* node) override; + + void Visit(LoopControlExpression& node) override; // enum + + // Name + + void Visit(NameExpression* node) override; + void Visit(TupleName* node) override; + void Visit(VariantName* node) override; + void Visit(AnnotatedName* node) override; + + // Type, typeclass, etc. ----------------- + + // Type + + void Visit(FunctionType* node) override; + void Visit(TupleType* node) override; + void Visit(VariantType* node) override; + void Visit(ParametrizedType* node) override; + void Visit(TypeExpression* node) override; + + void Visit(ExtendedScopedAnyType* node) override; + + // Typeclass + + void Visit(ParametrizedTypeclass* node) override; + void Visit(TypeclassExpression* node) override; + + // Identifiers, constants, etc. ----------------- + + void Visit(ExtendedName* node) override; + + void Visit(std::string* node) override; // std::string + + void Visit(FloatNumberLiteral* node) override; + void Visit(NumberLiteral* node) override; + void Visit(StringLiteral* node) override; + void Visit(CharLiteral* node) override; + +private: + info::GlobalInfo& global_info_; +}; + +} // namespace interpreter diff --git a/include/type_graph.hpp b/include/type_graph.hpp new file mode 100644 index 0000000..cf49a13 --- /dev/null +++ b/include/type_graph.hpp @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include + +// TODO: optimize recalc + +class TypeGraph { +public: + size_t AddVertex(const std::vector& path, + const std::vector& methods = {}, + const std::vector& typeclasses = {}) { + is_calculated_ = false; + + Vertex vertex; + vertex.path = path; + + for (auto& method : methods) { + vertex.new_requirements.methods.insert(GetHash(method)); + } + + for (auto& typeclass : typeclasses) { + vertex.new_requirements.typeclasses.insert(GetHash(typeclass)); + } + + verticles_.push_back(vertex); + edges_.emplace_back(); + back_edges_.emplace_back(); + + verticle_ids_[vertex.path] = verticles_.size() - 1; + return verticles_.size() - 1; + } + + size_t FindVertex(const std::vector& path) { + return verticle_ids_[path]; + } + + std::vector VertexMethods(size_t id) { + if (!is_calculated_) { + // error + return {}; + } + + size_t cluster_id = verticles_[id].cluster.value(); + + std::vector methods; + + methods.reserve(cluster_requirements_[cluster_id].methods.size()); + + for (auto& method : cluster_requirements_[cluster_id].methods) { + methods.push_back(std::move(GetString(method))); + } + + return methods; + } + + std::vector VertexTypeclasses(size_t id) { + if (!is_calculated_) { + // error + return {}; + } + + size_t cluster_id = verticles_[id].cluster.value(); + + std::vector typeclasses; + + typeclasses.reserve(cluster_requirements_[cluster_id].typeclasses.size()); + + for (auto& typeclass : cluster_requirements_[cluster_id].typeclasses) { + typeclasses.push_back(std::move(GetString(typeclass))); + } + + return typeclasses; + } + + void AddTypeclass(size_t id, const std::string& method) { + is_calculated_ = false; + + verticles_[id].new_requirements.methods.insert(GetHash(method)); + } + + void AddMethod(size_t id, const std::string& typeclass) { + is_calculated_ = false; + + verticles_[id].new_requirements.typeclasses.insert(GetHash(typeclass)); + } + + void AddEdge(size_t from, size_t to) { + is_calculated_ = false; + + edges_[from].push_back(to); + back_edges_[to].push_back(from); + } + + void Calculate() { + if (is_calculated_) { + return; + } + + auto clusters = FindClusters(); + + std::vector cluster_requirements(clusters.size()); + std::vector> cluster_edges(clusters.size()); + + for (size_t i = 0; i < clusters.size(); ++i) { + for (auto& vertex_id : clusters[i]) { + for (auto& method : verticles_[vertex_id].new_requirements.methods) { + cluster_requirements[i].methods.insert(method); + } + verticles_[vertex_id].new_requirements.methods.clear(); + + for (auto& typeclass : verticles_[vertex_id].new_requirements.typeclasses) { + cluster_requirements[i].typeclasses.insert(typeclass); + } + verticles_[vertex_id].new_requirements.methods.clear(); + + for (auto& edge : edges_[vertex_id]) { + cluster_edges[i].insert(edge); + } + } + } + + // TODO: check, that clusters are top sorted + for (size_t i = 0; i < clusters.size(); ++i) { + for (auto& edge : cluster_edges[i]) { + for (auto& method : cluster_requirements[edge].methods) { + cluster_requirements[i].methods.insert(method); + } + + for (auto& typeclass : cluster_requirements[edge].typeclasses) { + cluster_requirements[i].typeclasses.insert(typeclass); + } + } + } + + for (size_t i = 0; i < clusters.size(); ++i) { + for (auto& vertex_id : clusters[i]) { + verticles_[vertex_id].cluster = i; + } + } + + clusters_ = std::move(clusters); + cluster_requirements_ = std::move(cluster_requirements); + + is_calculated_ = true; + } + + + +private: + struct RequirementsData { + std::unordered_set methods; + std::unordered_set typeclasses; + }; + + struct Vertex { + std::vector path; + RequirementsData new_requirements; + std::optional cluster; + }; + + std::vector> FindClusters() { + std::vector> clusters; + + auto sorted_verticles = TopSort(); + + std::vector marks(sorted_verticles.size(), 0); + for (size_t i = 0; i < sorted_verticles.size(); ++i) { + if (marks[i] == 0) { + clusters.emplace_back(); + VisitDfs(i, clusters[i], marks, back_edges_, clusters.size()); + } + } + + return clusters; + } + + void VisitDfs(size_t id, + std::vector& verticles, + std::vector& marks, + const std::vector>& edges, + size_t mark) { + if (marks[id] != 0) { + return; + } + + marks[id] = mark; + verticles.push_back(id); + + for (size_t i = 0; i < edges[id].size(); ++i) { + VisitDfs(id, verticles, marks, edges, mark); + } + } + + std::vector TopSort() { + std::vector sorted_verticles; + std::vector marks(verticles_.size(), 0); + + for (size_t i = 0; i < marks.size(); ++i) { + VisitDfs(i, sorted_verticles, marks, edges_, 1); + } + + return sorted_verticles; + } + + size_t GetHash(const std::string& str) { + size_t hash = 0; + auto str_position = string_to_hash_.find(str); + + if (str_position == string_to_hash_.end()) { + hash = hash_to_string_.size(); + string_to_hash_[str] = hash; + hash_to_string_.push_back(str); + } else { + hash = str_position->second; + } + + return hash; + } + + std::string GetString(size_t hash) { + return hash_to_string_[hash]; + } + +private: + std::unordered_map, size_t> verticle_ids_; + std::vector> edges_; + std::vector> back_edges_; + std::vector verticles_; + + std::vector> clusters_; + std::vector cluster_requirements_; + + std::vector hash_to_string_; + std::unordered_map string_to_hash_; + + bool is_calculated_ = false; +}; diff --git a/src/print_visitor.cpp b/src/print_visitor.cpp index 23757e6..f7081d2 100644 --- a/src/print_visitor.cpp +++ b/src/print_visitor.cpp @@ -1,6 +1,5 @@ // for clangd #include "../include/print_visitor.hpp" -#include namespace interpreter { diff --git a/src/type_check_visitor.cpp b/src/type_check_visitor.cpp new file mode 100644 index 0000000..52c98c3 --- /dev/null +++ b/src/type_check_visitor.cpp @@ -0,0 +1,684 @@ +#include "../include/type_check_visitor.hpp" + +// TODO + +namespace interpreter { + +// Sources ----------------- + +void TypeCheckVisitor::Visit(SourceFile* node) { + out_ << "[SourceFile] (\n\n"; + for (auto& statement : node->statements) { + if (std::holds_alternative(statement)) { + Visit(&std::get(statement)); + } else if (std::holds_alternative(statement)) { + Visitor::Visit(std::get(statement)); + } else { + // error + } + } + out_ << "\n)\n"; +} + +void TypeCheckVisitor::Visit(Sources* node) { + out_ << "[Sources](\n"; + for (auto& statement : node->statements) { + Visitor::Visit(statement); + } + out_ << ")\n"; +} + +// Namespaces, partitions ----------------- + +void TypeCheckVisitor::Visit(Partition* node) { + out_ << "[Partition] "; + switch (node->name) { + case Partition::Test: + out_ << "TEST"; + break; + case Partition::Interface: + out_ << "INTERFACE"; + break; + case Partition::Core: + out_ << "CORE"; + break; + case Partition::Lib: + out_ << "LIB"; + break; + case Partition::Module: + out_ << "MODULE"; + break; + case Partition::Exe: + out_ << "EXE"; + break; + } + out_ << " {\n"; + Visit(node->scope.get()); + out_ << "}\n"; +} + +void TypeCheckVisitor::Visit(Namespace* node) { + out_ << "[Namespace] "; + if (node->name.has_value()) { + if (node->modifier.has_value()) { + switch (node->modifier.value()) { + case Namespace::Const: + out_ << "const "; + break; + case Namespace::Var: + out_ << "var "; + break; + } + } else { + // error + } + Visit(&node->name.value()); + } + Visit(&node->type); + out_ << "{\n"; + Visit(node->scope.get()); + out_ << "}\n"; +} + +// Definitions ----------------- + +void TypeCheckVisitor::Visit(ImportStatement* node) { + if (node->name.has_value()) { + out_ << "[Use " << node->name.value() << "] = "; + } + out_ << "[Import " << node->module_name << "]"; + if (!node->symbols.empty()) { + out_ << " (\n"; + for (auto& symbol : node->symbols) { + Visit(&symbol); + out_ << '\n'; + } + out_ << ')'; + } + out_ << '\n'; +} + +void TypeCheckVisitor::Visit(AliasDefinitionStatement* node) { + out_ << "[Alias "; + switch (node->modifier) { + case AliasDefinitionStatement::Alias: + out_ << "alias"; + break; + case AliasDefinitionStatement::Type: + out_ << "type"; + break; + case AliasDefinitionStatement::Let: + out_ << "let"; + break; + } + out_ << ' '; + Visit(&node->type); + out_ << "] = ("; + Visit(node->value.get()); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(VariableDefinitionStatement* node) { + out_ << "[Variable "; + switch (node->modifier) { + case VariableDefinitionStatement::Const: + out_ << "const"; + break; + case VariableDefinitionStatement::Var: + out_ << "var"; + break; + } + out_ << ' '; + Visitor::Visit(node->name); + out_ << "] = ("; + Visitor::Visit(node->value); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(FunctionDeclaration* node) { + out_ << "[FunctionDeclaration "; + Visit(&node->name); + out_ << "] ("; + for (auto& parameter : node->parameters) { + Visit(parameter.get()); + } + out_ << ") : ("; + Visit(node->type.get()); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(FunctionDefinitionStatement* node) { + out_ << "[Function] ("; + Visit(node->definition.get()); + out_ << ") = ("; + Visitor::Visit(node->value); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(TypeDefinitionStatement* node) { + out_ << "[Type "; + switch (node->modifier) { + case TypeDefinitionStatement::Struct: + out_ << "struct"; + break; + case TypeDefinitionStatement::Class: + out_ << "class"; + break; + } + out_ << "] ("; + Visit(node->definition.get()); + out_ << ") = ("; + Visitor::Visit(node->value); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(AbstractTypeDefinitionStatement* node) { + out_ << "[AbstractType "; + switch (node->modifier) { + case AbstractTypeDefinitionStatement::Basic: + out_ << "basic"; + break; + case AbstractTypeDefinitionStatement::Abstract: + out_ << "abstract"; + break; + } + out_ << "] ("; + Visit(node->type.get()); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(TypeclassDefinitionStatement* node) { + out_ << "[Typeclass] ("; + Visit(node->definition.get()); + if (!node->requirements.empty()) { + out_ << ") : (\n"; + } + for (auto& requirement : node->requirements) { + out_ << "& "; + Visit(requirement.get()); + out_ << "\n"; + } + out_ << ")\n"; +} + +// Definition parts + +void TypeCheckVisitor::Visit(FunctionDefinition* node) { + out_ << "[FunctionDefinition "; + switch (node->modifier) { + case FunctionDefinition::Operator: + out_ << "operator"; + break; + case FunctionDefinition::Function: + out_ << "function"; + break; + } + out_ << ' '; + Visit(&node->name); + out_ << "]"; + if (!node->parameters.empty()) { + out_ << " ("; + for (auto& parameter : node->parameters) { + Visit(parameter.get()); + } + out_ << ')'; + } + if (!node->arguments.empty()) { + out_ << " : ("; + for (auto& argument : node->arguments) { + Visit(&argument); + } + out_ << ')'; + } + out_ << ' '; +} + +void TypeCheckVisitor::Visit(TypeDefinition* node) { + out_ << "[TypeDefinition] ("; + Visit(node->type.get()); + out_ << ')'; + if (!node->parameters.empty()) { + out_ << '('; + for (auto& parameter : node->parameters) { + Visit(parameter.get()); + } + out_ << ')'; + } + out_ << ' '; +} + +void TypeCheckVisitor::Visit(AnyAnnotatedType* node) { + out_ << "[Annotated (Abstract) Type "; + Visit(&node->type); + out_ << ']'; + if (!node->typeclasses.empty() > 0) { + out_ << " ("; + for (auto& typeclass : node->typeclasses) { + Visitor::Visit(typeclass); + } + out_ << ')'; + } + out_ << ' '; +} + +// Flow control ----------------- + +void TypeCheckVisitor::Visit(MatchCase* node) { + out_ << "[MatchCase | "; + Visitor::Visit(node->value); + if (node->condition.has_value()) { + out_ << " ? "; + Visitor::Visit(node->condition.value()); + } + if (node->statement.has_value()) { + out_ << " -> "; + Visitor::Visit(node->statement.value()); + } + out_ << "]\n"; +} + +void TypeCheckVisitor::Visit(Match* node) { + out_ << "[Match] ("; + Visitor::Visit(node->value); + out_ << ") [with] (\n"; + for (auto& match_case : node->matches) { + Visit(&match_case); + } + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(Condition* node) { + out_ << "[If] ("; + Visitor::Visit(node->conditions[0]); + out_ << ") [then] (\n"; + Visitor::Visit(node->statements[0]); + out_ << ')'; + for (size_t i = 1; i < node->conditions.size(); ++i) { + out_ << " [elif] ("; + Visitor::Visit(node->conditions[i]); + out_ << ") [then] (\n"; + Visitor::Visit(node->statements[i]); + out_ << ')'; + } + if (node->statements.size() > node->conditions.size()) { + out_ << " [else] (\n"; + Visitor::Visit(node->statements[node->conditions.size()]); + out_ << ')'; + } + out_ << '\n'; +} + +void TypeCheckVisitor::Visit(DoWhileLoop* node) { + out_ << "[Do] (\n"; + Visitor::Visit(node->statement); + out_ << ") [while] ("; + Visitor::Visit(node->condition); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(WhileLoop* node) { + out_ << "[While] ("; + Visitor::Visit(node->statement); + out_ << ") [do] (\n"; + Visitor::Visit(node->condition); + out_ << ")\n"; +} +void TypeCheckVisitor::Visit(ForLoop* node) { + out_ << "[For] ("; + Visitor::Visit(node->variable); + out_ << ") [in] ("; + Visitor::Visit(node->interval); + out_ << ") [do] (\n"; + Visitor::Visit(node->statement); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(LoopLoop* node) { + out_ << "[Loop] (\n"; + Visitor::Visit(node->statement); + out_ << ")\n"; +} + +// Statements, expressions, blocks, etc. ----------------- + +void TypeCheckVisitor::Visit(Block* node) { + out_ << "[Block] {\n"; + for (auto& statement : node->statements) { + Visitor::Visit(statement); + } + out_ << "}\n"; +} + +void TypeCheckVisitor::Visit(ScopedStatement* node) { + out_ << "[Scoped] ( "; + Visitor::Visit(node->statement); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(LoopControlExpression& node) { // enum + switch (node) { + case LoopControlExpression::Break: + out_ << "[Break]\n"; + break; + case LoopControlExpression::Continue: + out_ << "[Continue]\n"; + break; + } +} + +// Operators + +void TypeCheckVisitor::Visit(BinaryOperatorExpression* node) { + out_ << "[BinaryOperator] ("; + Visitor::Visit(node->left_expression); + out_ << ") ["; + Visit(&node->operator_name); + out_ << "] ("; + Visitor::Visit(node->right_expression); + out_ << ')'; +} + +void TypeCheckVisitor::Visit(UnaryOperatorExpression* node) { + out_ << "[UnaryOperator "; + Visit(&node->operator_name); + out_ << "] ("; + Visitor::Visit(node->expression); + out_ << ')'; +} + +void TypeCheckVisitor::Visit(ReferenceExpression* node) { + out_ << "[ReferenceExpression "; + for (auto& reference : node->references) { + switch (reference) { + case ReferenceType::Reference: + out_ << '~'; + break; + case ReferenceType::UniqueReference: + out_ << '@'; + break; + } + } + out_ << "] ("; + Visit(node->expression.get()); + out_ << ')'; +} + +// Other Expressions + +void TypeCheckVisitor::Visit(FunctionCallExpression* node) { + out_ << "[FunctionCall "; + Visit(node->name.get()); + out_ << "] ("; + for (auto& argument : node->arguments) { + Visitor::Visit(argument); + out_ << ", "; + } + out_ << ")"; +} + +void TypeCheckVisitor::Visit(TupleExpression* node) { + out_ << "[TupleExpression] ("; + for (auto& expression : node->expressions) { + out_ << "&"; + Visitor::Visit(expression); + } + out_ << ")"; +} + +void TypeCheckVisitor::Visit(VariantExpression* node) { + out_ << "[VariantExpression] ("; + for (auto& expression : node->expressions) { + out_ << "|"; + Visitor::Visit(expression); + } + out_ << ")"; +} + +void TypeCheckVisitor::Visit(ReturnExpression* node) { + out_ << "[Return] ("; + Visitor::Visit(node->expression); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(TypeConstructor* node) { + out_ << "[TypeConstructor "; + Visit(node->type.get()); + out_ << "]\n("; + + bool is_first = true; + for (auto& parameter : node->parameters) { + if (!is_first) { + out_ << ")\n"; + is_first = false; + } + out_ << '('; + Visit(&std::get<0>(parameter)); + switch (std::get<1>(parameter)) { + case TypeConstructor::Assign: + out_ << " = "; + break; + case TypeConstructor::Move: + out_ << " <- "; + break; + } + Visitor::Visit(std::get<2>(parameter)); + } + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(LambdaFunction* node) { + out_ << "[LambdaFunction] ("; + for (auto& parameter : node->parameters) { + Visit(parameter.get()); + } + if (!node->parameters.empty()) { + out_ << ") : ("; + } + for (auto& argument : node->arguments) { + Visit(&argument); + } + out_ << ") -> (\n"; + Visitor::Visit(node->expression); + out_ << ")\n"; +} + +void TypeCheckVisitor::Visit(ArrayExpression* node) { + out_ << "[ArrayExpression] (["; + for (auto& element : node->elements) { + Visitor::Visit(element); + out_ << ';'; + } + out_ << "])"; +} + +// Name + +void TypeCheckVisitor::Visit(NameExpression* node) { + out_ << "[NameExpression] ("; + for (auto& variable_namespace : node->namespaces) { + Visitor::Visit(variable_namespace); + out_ << '.'; + } + for (size_t i = 0; i < node->expressions.size(); ++i) { + Visitor::Visit(node->expressions[i]); + if (i + 1 < node->expressions.size()) { + out_ << '.'; + } + } + out_ << ')'; +} + +void TypeCheckVisitor::Visit(TupleName* node) { + out_ << "[TupleName] ("; + for (auto& name : node->names) { + out_ << "& "; + Visitor::Visit(name); + } + out_ << ')'; +} + +void TypeCheckVisitor::Visit(VariantName* node) { + out_ << "[VariantName] ("; + for (auto& name : node->names) { + out_ << "| "; + Visitor::Visit(name); + } + out_ << ')'; +} + +void TypeCheckVisitor::Visit(AnnotatedName* node) { + out_ << "[AnnotatedName "; + Visit(&node->name); + out_ << ']'; + if (node->type.has_value()) { + out_ << " : ("; + Visitor::Visit(node->type.value()); + out_ << ')'; + } +} + +// Type, typeclass, etc. ----------------- + +// Type + +void TypeCheckVisitor::Visit(FunctionType* node) { + out_ << "[FunctionType] ("; + bool is_first = true; + for (auto& type : node->types) { + if (!is_first) { + out_ << " -> "; + } + is_first = false; + Visitor::Visit(type); + } + out_ << ')'; +} + +void TypeCheckVisitor::Visit(TupleType* node) { + out_ << "[TupleType "; + if (node->type.has_value()) { + Visit(&node->type.value()); + } + out_ << "] ("; + for (auto& entity : node->entities) { + out_ << "& "; + if (entity.first.has_value()) { + Visit(&entity.first.value()); + out_ << " : "; + } + Visit(entity.second.get()); + } + out_ << ')'; +} + +void TypeCheckVisitor::Visit(VariantType* node) { + out_ << "[VariantType "; + if (node->type.has_value()) { + Visit(&node->type.value()); + } + out_ << "] ("; + for (auto& constructor : node->constructors) { + out_ << "| "; + if (std::holds_alternative(constructor)) { + Visit(&std::get(constructor)); + } else if (std::holds_alternative>(constructor)) { + Visit(std::get>(constructor).get()); + } else { + // error + } + } + out_ << ')'; +} + +void TypeCheckVisitor::Visit(ParametrizedType* node) { + out_ << "[ParametrizedType] ("; + Visit(node->type_expression.get()); + for (auto& parameter : node->parameters) { + out_ << ' '; + Visitor::Visit(parameter); + } + out_ << ')'; +} + +void TypeCheckVisitor::Visit(TypeExpression* node) { + out_ << "[TypeExpression "; + + if (node->array_size.has_value()) { + out_ << "[array size: " << node->array_size.value() << ']'; + } + + out_ << "] ("; + for (auto& type_namespace : node->namespaces) { + Visitor::Visit(type_namespace); + out_ << '.'; + } + Visit(&node->type); + out_ << ')'; +} + +void TypeCheckVisitor::Visit(ExtendedScopedAnyType* node) { + out_ << "[ExtendedScopedAnyType "; + for (auto& reference : node->references) { + switch (reference) { + case ReferenceType::Reference: + out_ << '~'; + break; + case ReferenceType::UniqueReference: + out_ << '@'; + break; + } + } + out_ << "] ("; + Visitor::Visit(node->type); + out_ << ')'; +} + +// Typeclass + +void TypeCheckVisitor::Visit(ParametrizedTypeclass* node) { + out_ << "[ParametrizedTypeclass] ("; + Visit(node->typeclass_expression.get()); + for (auto& paramater : node->parameters) { + out_ << ' '; + Visitor::Visit(paramater); + } + out_ << ')'; +} + +void TypeCheckVisitor::Visit(TypeclassExpression* node) { + out_ << "[TypeclassExpression] ("; + for (auto& typeclass_namespace : node->namespaces) { + Visitor::Visit(typeclass_namespace); + out_ << '.'; + } + Visit(&node->typeclass); + out_ << ')'; +} + +// Identifiers, constants, etc. ----------------- + +void TypeCheckVisitor::Visit(ExtendedName* node) { + out_ << "[ExtendedName " << node->name << "] "; +} + +void TypeCheckVisitor::Visit(std::string* node) { // std::string + out_ << "[Identifier " << *node << "] "; +} + +void TypeCheckVisitor::Visit(FloatNumberLiteral* node) { + out_ << "[FloatNumber " << node->value << "] "; +} + +void TypeCheckVisitor::Visit(NumberLiteral* node) { + out_ << "[Number " << node->value << "] "; +} + +void TypeCheckVisitor::Visit(StringLiteral* node) { + out_ << "[String " << node->value << "] "; +} + +void TypeCheckVisitor::Visit(CharLiteral* node) { + out_ << "[Char " << node->value << "] "; +} + +} // namespace interpreter