#include #include // for clangd #include "../include/execute_visitor.hpp" #include "../include/builtin_functions.hpp" // TODO namespace interpreter { // Sources ----------------- void ExecuteVisitor::Visit(SourceFile* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.SourceFile", &node->base); } // Namespaces, partitions ----------------- void ExecuteVisitor::Visit(NamespaceSources* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.NamespaceSources", &node->base); } void ExecuteVisitor::Visit(Namespace* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.Namespace", &node->base); } // Definitions ----------------- void ExecuteVisitor::Visit(ImportStatement* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.ImportStatement", &node->base); } void ExecuteVisitor::Visit(AliasDefinitionStatement* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.AliasDefinitionStatement", &node->base); } void ExecuteVisitor::Visit(VariableDefinitionStatement* node) { Visitor::Visit(node->value); is_const_definition_ = node->modifier; Visitor::Visit(node->name); // current_type_ passed from value is_const_definition_ = std::nullopt; } void ExecuteVisitor::Visit(FunctionDeclaration* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.FunctionDeclaration", &node->base); } void ExecuteVisitor::Visit(FunctionDefinitionStatement* node) { // visited on function call context_manager_.EnterContext(); try { Visitor::Visit(node->value); } catch (utils::ValueReturnedMarker&) {} // TODO: sometimes return references, choose by declaration current_value_ = context_manager_.ToTemporaryValue(current_value_); context_manager_.ExitContext(); } void ExecuteVisitor::Visit(TypeDefinitionStatement* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.TypeDefinitionStatement", &node->base); } void ExecuteVisitor::Visit(AbstractTypeDefinitionStatement* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.AbstractTypeDefinitionStatement", &node->base); } void ExecuteVisitor::Visit(TypeclassDefinitionStatement* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.TypeclassDefinitionStatement", &node->base); } void ExecuteVisitor::Visit(PartitionStatement* node) { Visitor::Visit(node->value); } // Flow control ----------------- void ExecuteVisitor::Visit(TypeConstructorPatternParameter* node) { // handled in TypeConstructorPattern error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.TypeConstructorPatternParameter", &node->base); } // TODO: check void ExecuteVisitor::Visit(TypeConstructorPattern* node) { if (!node->constructor->constructor_id_.has_value()) { // checked in typeckeck visitor ?? error_handling::HandleRuntimeError("Type constructor pattern constructor name not found", node->base); } utils::IdType constructor_id = node->constructor->constructor_id_.value(); // only one has value inside auto maybe_variant_value_info = context_manager_.GetValue(current_value_); auto maybe_tuple_value_info = context_manager_.GetValue(current_value_); if (maybe_variant_value_info.has_value()) { info::value::VariantValue* variant_value_info = maybe_variant_value_info.value(); if (constructor_id != variant_value_info->current_constructor) { case_matched_ = false; return; } // extract named parameters ?? for (size_t i = 0; i < node->parameters.size(); ++i) { // not visit if case not matched inside ?? current_value_ = variant_value_info->value.fields[i].second; Visitor::Visit(node->parameters[i].value); } } else if (maybe_tuple_value_info.has_value()) { info::value::TupleValue* tuple_value_info = maybe_tuple_value_info.value(); // extract named parameters ?? for (size_t i = 0; i < node->parameters.size(); ++i) { // not visit if case not matched inside ?? current_value_ = tuple_value_info->fields[i].second; Visitor::Visit(node->parameters[i].value); } } else { error_handling::HandleRuntimeError("Wrong value type for type constructor pattern (not variant or tuple)", node->base); } } void ExecuteVisitor::Visit(MatchCase* node) { // handeled in Match error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.MatchCase", &node->base); } void ExecuteVisitor::Visit(Match* node) { context_manager_.EnterContext(); Visitor::Visit(node->value); utils::IdType value = current_value_; bool case_choosen = false; bool statement_visited = false; for (auto& match_case : node->matches) { if (case_choosen) { if (match_case.statement.has_value()) { Visitor::Visit(match_case.statement.value()); statement_visited = true; break; } } else { current_value_ = value; case_matched_ = true; context_manager_.EnterContext(); Visitor::Visit(node->value); if (case_matched_ && (match_case.condition.has_value() ? HandleCondition(match_case.condition.value(), match_case.base) : true)) { case_choosen = true; if (match_case.statement.has_value()) { Visitor::Visit(match_case.statement.value()); statement_visited = true; break; } } else { context_manager_.ExitContext(); } } } if (case_choosen) { context_manager_.ExitContext(); } if (!statement_visited) { error_handling::HandleRuntimeError("Value match option not found", node->base); } context_manager_.ExitContext(); } void ExecuteVisitor::Visit(Condition* node) { bool branch_visited = false; for (size_t i = 0; i < node->conditions.size(); ++i) { if (HandleCondition(node->conditions[i], node->base)) { context_manager_.EnterContext(); Visitor::Visit(node->statements[i]); context_manager_.ExitContext(); if (node->statements.size() == node->conditions.size()) { current_value_ = context_manager_.AddValue( // optional with "reference" to value info::value::OptionalValue(current_value_, context_manager_.GetValueManager()), context_manager_.GetValueType(current_value_)); } branch_visited = true; break; } } if (!branch_visited) { if (node->statements.size() > node->conditions.size()) { context_manager_.EnterContext(); Visitor::Visit(node->statements[node->conditions.size()]); context_manager_.ExitContext(); } else { current_value_ = context_manager_.AddValue( // optional with "reference" to value info::value::OptionalValue(std::nullopt, context_manager_.GetValueManager()), context_manager_.GetValueType(current_value_)); } } } void ExecuteVisitor::Visit(DoWhileLoop* node) { std::vector result; do { context_manager_.EnterContext(); Visitor::Visit(node->statement); if (active_loop_control_expression_.has_value()) { if (active_loop_control_expression_.value() == LoopControlExpression::Break) { active_loop_control_expression_ = std::nullopt; break; } active_loop_control_expression_ = std::nullopt; continue; } result.push_back(context_manager_.ToTemporaryValue(current_value_)); context_manager_.ExitContext(); } while(HandleCondition(node->condition, node->base)); current_value_ = context_manager_.AddValue( info::value::ArrayValue(std::move(result), false, context_manager_.GetValueManager()), utils::ValueType::Tmp); } void ExecuteVisitor::Visit(WhileLoop* node) { std::vector result; while(HandleCondition(node->condition, node->base)) { context_manager_.EnterContext(); Visitor::Visit(node->statement); if (active_loop_control_expression_.has_value()) { if (active_loop_control_expression_.value() == LoopControlExpression::Break) { active_loop_control_expression_ = std::nullopt; break; } active_loop_control_expression_ = std::nullopt; continue; } result.push_back(context_manager_.ToTemporaryValue(current_value_)); context_manager_.ExitContext(); } current_value_ = context_manager_.AddValue( info::value::ArrayValue(std::move(result), false, context_manager_.GetValueManager()), utils::ValueType::Tmp); } // TODO: extend to different interval types (not only array) // TODO: assign to variable, instead of making new ?? void ExecuteVisitor::Visit(ForLoop* node) { std::vector result; Visitor::Visit(node->interval); info::value::ArrayValue* interval = ExtractValue(current_value_, node->base); for (auto& value : interval->elements) { // TODO: reference to element context_manager_.EnterContext(); current_value_ = value; is_const_definition_ = node->variable_modifier; Visitor::Visit(node->variable); is_const_definition_ = std::nullopt; Visitor::Visit(node->statement); if (active_loop_control_expression_.has_value()) { if (active_loop_control_expression_.value() == LoopControlExpression::Break) { active_loop_control_expression_ = std::nullopt; break; } active_loop_control_expression_ = std::nullopt; continue; } result.push_back(context_manager_.ToTemporaryValue(current_value_)); context_manager_.ExitContext(); } current_value_ = context_manager_.AddValue( info::value::ArrayValue(std::move(result), false, context_manager_.GetValueManager()), utils::ValueType::Tmp); } void ExecuteVisitor::Visit(LoopLoop* node) { std::vector result; while(true) { context_manager_.EnterContext(); Visitor::Visit(node->statement); if (active_loop_control_expression_.has_value()) { if (active_loop_control_expression_.value() == LoopControlExpression::Break) { active_loop_control_expression_ = std::nullopt; break; } active_loop_control_expression_ = std::nullopt; continue; } result.push_back(context_manager_.ToTemporaryValue(current_value_)); context_manager_.ExitContext(); } current_value_ = context_manager_.AddValue( info::value::ArrayValue(std::move(result), false, context_manager_.GetValueManager()), utils::ValueType::Tmp); } // Statements, expressions, blocks, etc. ----------------- void ExecuteVisitor::Visit(Block* node) { context_manager_.EnterContext(); bool value_brought = false; for (auto& statement : node->statements) { try { Visitor::Visit(statement); } catch (utils::ValueBroughtMarker&) { // current_value_ passed from ReturnExpression value_brought = true; break; } } context_manager_.ExitContext(); if (!value_brought) { current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } } void ExecuteVisitor::Visit(ScopedStatement* node) { Visitor::Visit(node->statement); // current_value_ passed from statement } void ExecuteVisitor::Visit(LoopControlExpression& node) { active_loop_control_expression_ = node; current_value_ = context_manager_.AddValue(info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } // Operators void ExecuteVisitor::Visit(ReferenceExpression* node) { // TODO: check, that there is no references to "Tmp"?? Visit(node->expression.get()); utils::ValueType value_type = context_manager_.GetValueType(current_value_); current_value_ = context_manager_.AddValue( // "reference" to type (save const / var) info::value::ReferenceToValue({node->reference}, current_value_, context_manager_.GetValueManager()), value_type); } // TODO: extend to other types // TODO: string should be array void ExecuteVisitor::Visit(AccessExpression* node) { Visit(node->name.get()); utils::IdType array_value = current_value_; utils::ValueType value_type = context_manager_.GetValueType(array_value); Visitor::Visit(node->id); int64_t index = *ExtractInternalValue(current_value_, node->base); // TODO: size_t if (index < 0) { error_handling::HandleRuntimeError("Access index is negative", node->base); } if (node->is_string_access_) { std::string* string_value_info = ExtractInternalValue(current_value_, node->base); if (index >= (int64_t)string_value_info->size()) { error_handling::HandleRuntimeError("Access index is out of range (string)", node->base); } current_value_ = context_manager_.ToModifiedValue((*string_value_info)[index], utils::ValueType::Tmp); } else { info::value::ArrayValue* array_value_info = ExtractValue(current_value_, node->base); if (index >= (int64_t)array_value_info->elements.size()) { error_handling::HandleRuntimeError("Access index is out of range (array)", node->base); } current_value_ = context_manager_.ToModifiedValue(array_value_info->elements[index], value_type); } } // Other Expressions // TODO: refactor, separate to several functions void ExecuteVisitor::Visit(FunctionCallExpression* node) { context_manager_.EnterContext(); if (node->prefix.has_value()) { if (std::holds_alternative>(node->prefix.value())) { Visitor::Visit(*std::get>(node->prefix.value())); if (context_manager_.GetValueType(current_value_) == utils::ValueType::Tmp) { // temporary value can't be modified inside context_manager_.ToModifiedValue(current_value_, utils::ValueType::Const); } if (!context_manager_.DefineVariable(utils::ClassInternalVarName, current_value_)) { error_handling::HandleRuntimeError("Variable redefinition (mathod caller var)", node->base); } } else if (std::holds_alternative>(node->prefix.value())) { TypeExpression& prefix = *std::get>(node->prefix.value()); // TODO: abstract types, local abstract types, abstract types, ... as path entities for (auto& path_type : prefix.path) { CollectTypeContext(path_type); } CollectTypeContext(prefix.type); } else { error_handling::HandleInternalError("Unexpected prefix type", "ExecuteVisitor.FunctionCallExpression", &node->base); } } else { if (node->is_method_of_first_argument_) { Visitor::Visit(node->arguments[0]); if (context_manager_.GetValueType(current_value_) == utils::ValueType::Tmp) { // temporary value can't be modified inside context_manager_.ToModifiedValue(current_value_, utils::ValueType::Const); } if (!context_manager_.DefineVariable(utils::ClassInternalVarName, current_value_)) { error_handling::HandleRuntimeError("Variable redefinition (mathod caller var)", node->base); } } } FunctionDeclaration* function_declaration = nullptr; FunctionDefinitionStatement* function_definition = nullptr; if (node->function_id_.has_value()) { auto maybe_function_declaration_info = global_info_.GetFunctionInfo(node->function_id_.value()).declaration; if (!maybe_function_declaration_info.has_value()) { error_handling::HandleRuntimeError("Function declaration not found (for namespace function)", node->base); } function_declaration = maybe_function_declaration_info.value().node; auto maybe_function_definition_info = global_info_.GetFunctionInfo(node->function_id_.value()).definition; if (!maybe_function_definition_info.has_value()) { if (HandleBuiltinFunctionCall(node)) { context_manager_.ExitContext(); return; } error_handling::HandleRuntimeError("Function definition not found (by graph_id_)", node->base); } function_definition = maybe_function_definition_info.value().node; } else if (node->graph_id_.has_value()) { error_handling::DebugPrint(typeclass_graph_.GetVertex(node->graph_id_.value()).name); utils::IdType defined_type_graph_id; // try to find defined or basic type if (typeclass_graph_.GetVertex(node->graph_id_.value()).type_id.has_value() || (node->abstract_type_name_.has_value() && info::type::ToInternalType(node->abstract_type_name_.value()).has_value())) { defined_type_graph_id = node->graph_id_.value(); } else { auto maybe_defined_type_graph_id = context_manager_.FindLocalType(node->abstract_type_name_.value()); if (!maybe_defined_type_graph_id.has_value()) { error_handling::HandleRuntimeError("Function's defined / basic abstract type not found (by abstract_type_name_ and in typeclass graph)", node->base); } defined_type_graph_id = maybe_defined_type_graph_id.value(); } std::optional maybe_function_definition; auto maybe_function_graph_info = typeclass_graph_.GetFunctionInfo(node->name, node->defined_type_graph_id.value()); if (!maybe_function_graph_info.has_value()) { error_handling::HandleRuntimeError("Function info not found (by graph_id_)", node->base); } function_declaration = maybe_function_graph_info.value()->declaration; maybe_function_definition = maybe_function_graph_info.value()->definition; if (!maybe_function_definition.has_value()) { if (typeclass_graph_.GetVertex(node->graph_id_.value()).modifier == info::TypeclassGraph::Modifier::Type) { auto maybe_internal_type = info::type::ToInternalType(typeclass_graph_.GetVertex(node->graph_id_.value()).name); if (maybe_internal_type.has_value()) { if (HandleBuiltinTypeFunctionCall(node, maybe_internal_type.value())) { context_manager_.ExitContext(); return; // TODO: return from end of function } error_handling::HandleRuntimeError("Type function definition not found (builtin type)", node->base); } error_handling::HandleRuntimeError("Type function definition not found (by graph_id_)", node->base); } // if (!node->abstract_type_name_.has_value()) { // error_handling::HandleInternalError("Typeclass function's abstract_type_name_ has no value", // "ExecuteVisitor.FunctionCallExpression", // &node->base); // } auto maybe_type_id = typeclass_graph_.GetVertex(defined_type_graph_id).type_id; if (!maybe_type_id.has_value()) { error_handling::HandleInternalError("Function's abstract type type_id not found", "ExecuteVisitor.FunctionCallExpression", &node->base); } auto maybe_type_info = global_info_.GetTypeInfo(maybe_type_id.value()); if (!maybe_type_info.has_value()) { error_handling::HandleRuntimeError("Function's abstract type replacement defined type is not AnyType", node->base); } maybe_function_graph_info = typeclass_graph_.GetFunctionInfo(node->name, maybe_type_info.value()->type.node->graph_id_); if (!maybe_function_graph_info.has_value()) { error_handling::HandleRuntimeError("Function info not found (by abstract type graph_id_)", node->base); } maybe_function_definition = maybe_function_graph_info.value()->definition; } if (!maybe_function_definition.has_value()) { error_handling::HandleRuntimeError("Function definition not found (by graph_id_)", node->base); } function_definition = maybe_function_definition.value(); auto dependency_graph_ids = typeclass_graph_.GetDependenciesSet(node->graph_id_.value()); dependency_graph_ids.insert(node->graph_id_.value()); // TODO: ?? for (auto& dependency_graph_id : dependency_graph_ids) { context_manager_.DefineLocalType(typeclass_graph_.GetVertex(dependency_graph_id).name, defined_type_graph_id); } } // handle choosen type typclasses // handle parameters for (size_t i = 0; i < node->parameters.size(); ++i) { utils::IdType graph_id = 0; if (node->parameters[i]->type_id_.has_value()) { graph_id = GraphIdByTypeId(node->parameters[i]->type_id_.value()); } else { auto maybe_parameter_graph_id = context_manager_.FindLocalType(node->parameters[i]->type.type); if (!maybe_parameter_graph_id.has_value()) { error_handling::HandleInternalError("Parameter type not found", "ExecuteVisitor.FunctionCallExpression", &node->base); } graph_id = maybe_parameter_graph_id.value(); } if (!context_manager_.DefineLocalType(function_declaration->parameters[i]->type, graph_id)) { error_handling::HandleRuntimeError("Type redefinition (function argument)", node->base); } } size_t index_shift = (node->is_method_of_first_argument_ ? 1 : 0); // handle arguments for (size_t i = index_shift; i < node->arguments.size(); ++i) { Visitor::Visit(node->arguments[i]); // function arguments can't be changed inside function current_value_ = context_manager_.ToModifiedValue(current_value_, utils::ValueType::Const); if (!context_manager_.DefineVariable(function_definition->definition->arguments[i - index_shift], current_value_)) { error_handling::HandleRuntimeError("Variable redefinition (function argument)", node->base); } } context_manager_.ChangeHidingOfCurrentContextTo(true); Visit(function_definition); context_manager_.ExitContext(); } void ExecuteVisitor::Visit(TupleExpression* node) { std::vector, utils::IdType>> fields; fields.reserve(node->expressions.size()); for (auto& expression : node->expressions) { Visitor::Visit(expression); fields.push_back({std::nullopt, context_manager_.ToTemporaryValue(current_value_)}); } current_value_ = context_manager_.AddValue( info::value::TupleValue(std::move(fields), context_manager_.GetValueManager()), utils::ValueType::Tmp); } // TODO: handle tuples separately ?? void ExecuteVisitor::Visit(VariantExpression* node) { for (size_t i = 0; i < node->expressions.size(); ++i) { Visitor::Visit(node->expressions[i]); current_value_ = context_manager_.ToTemporaryValue(current_value_); info::value::OptionalValue* expression_value = ExtractValue(current_value_, node->base); if (expression_value->value.has_value()) { std::vector, utils::IdType>> fields {{std::nullopt, expression_value->value.value()}}; // TODO: any type instead tuple in variant type ?? info::value::TupleValue variant_tuple = info::value::TupleValue(std::move(fields), context_manager_.GetValueManager()); current_value_ = context_manager_.AddValue( info::value::VariantValue(std::move(variant_tuple), i), utils::ValueType::Tmp); current_value_ = context_manager_.AddValue( info::value::OptionalValue(current_value_, context_manager_.GetValueManager()), utils::ValueType::Tmp); return; } } current_value_ = context_manager_.AddValue( info::value::OptionalValue(std::nullopt, context_manager_.GetValueManager()), utils::ValueType::Tmp); } void ExecuteVisitor::Visit(ReturnExpression* node) { Visitor::Visit(node->expression); if (node->is_from_definition) { throw utils::ValueReturnedMarker(); } throw utils::ValueBroughtMarker(); } void ExecuteVisitor::Visit(TypeConstructorParameter* node) { // handled in TypeConstructor error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.TypeConstructorParameter", &node->base); } void ExecuteVisitor::Visit(TypeConstructor* node) { std::vector, utils::IdType>> fields; if (!node->constructor->constructor_id_.has_value()) { error_handling::HandleRuntimeError("Type constructor name not found", node->base); } utils::IdType constructor_id = node->constructor->constructor_id_.value(); info::definition::Constructor constructor_info = global_info_.GetConstructorInfo(constructor_id); fields.reserve(node->parameters.size()); for (auto& parameter : node->parameters) { Visitor::Visit(parameter.value); fields.push_back( { parameter.name.has_value() ? std::optional(parameter.name.value()) : std::nullopt, context_manager_.ToTemporaryValue(current_value_) }); } if (constructor_info.order.has_value()) { // => variant current_value_ = context_manager_.AddValue( info::value::VariantValue( info::value::TupleValue(std::move(fields), context_manager_.GetValueManager()), constructor_info.order.value()), utils::ValueType::Tmp); } else { // => tuple current_value_ = context_manager_.AddValue( info::value::TupleValue(std::move(fields), context_manager_.GetValueManager()), utils::ValueType::Tmp); } } // TODO void ExecuteVisitor::Visit(LambdaFunction* node) { error_handling::HandleInternalError("Lambda function are not implemented yet", "ExecuteVisitor.LambdaFunction", &node->base); } void ExecuteVisitor::Visit(ArrayExpression* node) { std::vector elements; elements.reserve(node->elements.size()); for (auto& element : node->elements) { Visitor::Visit(element); elements.push_back(context_manager_.ToTemporaryValue(current_value_)); } current_value_ = context_manager_.AddValue( info::value::ArrayValue(std::move(elements), true, context_manager_.GetValueManager()), // maybe size not fixed?? utils::ValueType::Tmp); } // Name void ExecuteVisitor::Visit(NameExpression* node) { // TODO: check if (node->names.empty()) { error_handling::HandleInternalError("Names array is empty", "ExecuteVisitor.NameExpression", &node->base); } std::optional maybe_variable_value = context_manager_.FindVariable(node->names[0]); if (!maybe_variable_value.has_value()) { error_handling::HandleRuntimeError("Variable not found", node->base); } current_value_ = maybe_variable_value.value(); if (node->names.size() > 1) { utils::ValueType variable_value_type = context_manager_.GetValueType(current_value_); for (size_t i = 1; i < node->names.size(); ++i) { std::optional maybe_field_value = context_manager_.GetAnyValue(current_value_)->GetFieldValue(node->names[i]); if (!maybe_field_value.has_value()) { error_handling::HandleRuntimeError("Variable field not found", node->base); } current_value_ = maybe_field_value.value(); } current_value_ = context_manager_.ToModifiedValue(current_value_, variable_value_type); } } void ExecuteVisitor::Visit(TupleName* node) { utils::IdType value = current_value_; std::optional maybe_tuple_value = context_manager_.GetValue(value); if (maybe_tuple_value.has_value()) { error_handling::HandleRuntimeError("Mismatched value types in tuple variable definition", node->base); } if (maybe_tuple_value.value()->fields.size() != node->names.size()) { error_handling::HandleRuntimeError("Mismatched field count in tuple variable definition", node->base); } for (size_t i = 0; i < node->names.size(); ++i) { current_value_ = maybe_tuple_value.value()->fields[i].second; Visitor::Visit(node->names[i]); } current_value_ = value; } // TODO // TODO: make variant of TupleValue void ExecuteVisitor::Visit(VariantName* node) { utils::IdType value = current_value_; auto value_type = context_manager_.GetValueType(value); std::optional maybe_variant_value = context_manager_.GetValue(value); if (!maybe_variant_value.has_value()) { error_handling::HandleRuntimeError("Mismatched value types in variant variable definition", node->base); } for (size_t i = 0; i < node->names.size(); ++i) { if (i == maybe_variant_value.value()->current_constructor) { if (maybe_variant_value.value()->value.fields.empty()) { current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else { current_value_ = context_manager_.AddValue( maybe_variant_value.value()->value, value_type); } current_value_ = context_manager_.AddValue( // make optional value "reference" info::value::OptionalValue(current_value_, context_manager_.GetValueManager()), value_type); } else { current_value_ = context_manager_.AddValue( info::value::OptionalValue(std::nullopt, context_manager_.GetValueManager()), utils::ValueType::Tmp); } Visitor::Visit(node->names[i]); } current_value_ = value; } // TODO: move, etc. void ExecuteVisitor::Visit(AnnotatedName* node) { if (!is_const_definition_.has_value()) { error_handling::HandleInternalError("No value in is_const_definition_", "TypeCheckVisitor.AnnotatedName", &node->base); } auto value_type = context_manager_.GetValueType(current_value_); if (value_type == utils::ValueType::Tmp) { // consume temporary value context_manager_.ModifiyValue(current_value_, IsConstModifierToValueType(is_const_definition_.value())); } else { // make value copy current_value_ = context_manager_.ToModifiedValueCopy(current_value_, IsConstModifierToValueType(is_const_definition_.value())); } if (!context_manager_.DefineVariable(node->name, current_value_)) { error_handling::HandleRuntimeError("Variable name already present in context", node->base); } } // Type, typeclass, etc. ----------------- // Type void ExecuteVisitor::Visit(FunctionType* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.FunctionType", &node->base); } void ExecuteVisitor::Visit(TupleType* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.TupleType", &node->base); } void ExecuteVisitor::Visit(VariantType* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.VariantType", &node->base); } void ExecuteVisitor::Visit(TypeExpression* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.TypeExpression", &node->base); } void ExecuteVisitor::Visit(ExtendedScopedAnyType* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.ExtendedScopedAnyType", &node->base); } // Typeclass void ExecuteVisitor::Visit(ParametrizedTypeclass* node) { error_handling::HandleInternalError("Should be unreachable", "TypeCheckVisitor.ParametrizedTypeclass", &node->base); } // Typeclass & Type ----------------- void ExecuteVisitor::Visit(ParametrizedType*) {} // no value // Identifiers, constants, etc. ----------------- void ExecuteVisitor::Visit(FloatNumberLiteral* node) { current_value_ = context_manager_.AddValue( info::value::InternalValue(node->value), utils::ValueType::Tmp); } void ExecuteVisitor::Visit(NumberLiteral* node) { current_value_ = context_manager_.AddValue( info::value::InternalValue(node->value), utils::ValueType::Tmp); } void ExecuteVisitor::Visit(StringLiteral* node) { current_value_ = context_manager_.AddValue( info::value::InternalValue(node->value), utils::ValueType::Tmp); } void ExecuteVisitor::Visit(CharLiteral* node) { current_value_ = context_manager_.AddValue( info::value::InternalValue(node->value), utils::ValueType::Tmp); } void ExecuteVisitor::Visit(UnitLiteral*) { current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } void ExecuteVisitor::Visit(BoolLiteral* node) { current_value_ = context_manager_.AddValue( info::value::InternalValue(node->value), utils::ValueType::Tmp); } // bool ExecuteVisitor::HandleCondition(Expression& node, const BaseNode& base_node) { Visitor::Visit(node); return *ExtractInternalValue(current_value_, base_node); } // TODO: handle abstract types, handle local abstract types, etc. // partially done (check needed) void ExecuteVisitor::CollectTypeContext(const ParametrizedType& type) { utils::IdType type_id = 0; if (!type.type_id_.has_value()) { // abstract types have no parameters return; } else { type_id = type.type_id_.has_value(); } auto maybe_type_info = global_info_.GetTypeInfo(type_id); if (!maybe_type_info.has_value()) { error_handling::HandleInternalError("CollectTypeContext implemented only for AnyType", "ExecuteVisitor.CollectTYpeContext", std::nullopt); } info::definition::AnyType& type_info = *maybe_type_info.value(); // check, that has value ?? for (size_t i = 0; i < type.parameters.size(); ++i) { if (type.parameters[i]->type_id_.has_value()) { context_manager_.DefineLocalType(type_info.parameters[i].type, GraphIdByTypeId(type.parameters[i]->type_id_.value())); } } } void ExecuteVisitor::CheckPattern(Pattern& node, const BaseNode& base_node) { utils::IdType value = current_value_; switch (node.index()) { case 0: // always copy, because case can not match value value = context_manager_.ToModifiedValueCopy(value, utils::ValueType::Const); if (!context_manager_.DefineVariable(*std::get>(node), value)) { error_handling::HandleRuntimeError("Can't redifine variable", base_node); } break; case 1: Visitor::Visit(*std::get>(node)); if (!context_manager_.EqualValues(current_value_, value)) { case_matched_ = false; } break; case 2: Visit(std::get>(node).get()); break; default: // error break; } } // bool ExecuteVisitor::HandleBuiltinFunctionCall(FunctionCallExpression* node) { if (node->name == "print") { Visitor::Visit(node->arguments[0]); info::builtin::Print(*ExtractInternalValue(current_value_, node->base)); current_value_ = context_manager_.AddValue(info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else if (node->name == "scan") { current_value_ = context_manager_.AddValue(info::value::InternalValue(info::builtin::Read()), utils::ValueType::Tmp); } else if (node->name == "random") { // TODO: different types, better random, seed, etc. current_value_ = context_manager_.AddValue(info::value::InternalValue(rand()), utils::ValueType::Tmp); } else { return false; } return true; } bool ExecuteVisitor::HandleBuiltinTypeFunctionCall(FunctionCallExpression* node, info::type::InternalType type) { const std::string& name = node->name; if (utils::IsBuiltinFunction(name)) { std::vector arguments; arguments.reserve(node->arguments.size()); if (node->prefix.has_value() && std::holds_alternative>(node->prefix.value())) { Visitor::Visit(*std::get>(node->prefix.value())); arguments.push_back(ExtractValue(current_value_, node->base)); } for (auto& argument : node->arguments) { Visitor::Visit(argument); arguments.push_back(ExtractValue(current_value_, node->base)); } switch (type) { case info::type::InternalType::Float: if (name == "show") { current_value_ = context_manager_.AddValue( info::value::InternalValue(std::to_string(*arguments[0]->GetValue().value())), utils::ValueType::Tmp); } else if (name == "<") { current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() < *arguments[1]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "==") { current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() == *arguments[1]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "zero") { current_value_ = context_manager_.AddValue( info::value::InternalValue(0.0), utils::ValueType::Tmp); } else if (name == "one") { current_value_ = context_manager_.AddValue( info::value::InternalValue(1.0), utils::ValueType::Tmp); } else if (name == "=") { *arguments[0]->GetValue().value() = *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else if (name == "+=") { *arguments[0]->GetValue().value() += *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else if (name == "-=") { *arguments[0]->GetValue().value() -= *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else if (name == "*=") { *arguments[0]->GetValue().value() *= *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else if (name == "/=") { *arguments[0]->GetValue().value() /= *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else { return false; } break; case info::type::InternalType::Int: if (name == "show") { current_value_ = context_manager_.AddValue( info::value::InternalValue(std::to_string(*arguments[0]->GetValue().value())), utils::ValueType::Tmp); } else if (name == "<") { current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() < *arguments[1]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "==") { current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() == *arguments[1]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "div") { current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() / *arguments[1]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "mod") { // TODO: better implementation of mod (read "%" specification) current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() % *arguments[1]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "zero") { current_value_ = context_manager_.AddValue( info::value::InternalValue(0), utils::ValueType::Tmp); } else if (name == "one") { current_value_ = context_manager_.AddValue( info::value::InternalValue(1), utils::ValueType::Tmp); } else if (name == "=") { *arguments[0]->GetValue().value() = *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else if (name == "+=") { *arguments[0]->GetValue().value() += *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else if (name == "-=") { *arguments[0]->GetValue().value() -= *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else if (name == "*=") { *arguments[0]->GetValue().value() *= *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else { return false; } break; case info::type::InternalType::String: if (name == "show") { // do not copy ?? current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "<") { current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() < *arguments[1]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "==") { current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() == *arguments[1]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "size") { current_value_ = context_manager_.AddValue( info::value::InternalValue(static_cast(arguments[0]->GetValue().value()->size())), utils::ValueType::Tmp); } else if (name == "at") { current_value_ = context_manager_.AddValue( info::value::InternalValue((*arguments[0]->GetValue().value())[*arguments[1]->GetValue().value()]), utils::ValueType::Tmp); } else if (name == "=") { *arguments[0]->GetValue().value() = *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else { return false; } break; case info::type::InternalType::Char: if (name == "show") { current_value_ = context_manager_.AddValue( info::value::InternalValue(std::string{*arguments[0]->GetValue().value()}), utils::ValueType::Tmp); } else if (name == "<") { current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() < *arguments[1]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "==") { current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() == *arguments[1]->GetValue().value()), utils::ValueType::Tmp); } else if (name == "=") { *arguments[0]->GetValue().value() = *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else { return false; } break; case info::type::InternalType::Bool: if (name == "show") { current_value_ = context_manager_.AddValue( info::value::InternalValue(*arguments[0]->GetValue().value() ? "true" : "false"), utils::ValueType::Tmp); } else if (name == "=") { *arguments[0]->GetValue().value() = *arguments[1]->GetValue().value(); current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else { return false; } break; case info::type::InternalType::Unit: if (name == "show") { current_value_ = context_manager_.AddValue( info::value::InternalValue("()"), utils::ValueType::Tmp); } else if (name == "=") { current_value_ = context_manager_.AddValue( info::value::InternalValue(info::value::Unit()), utils::ValueType::Tmp); } else { return false; } break; default: error_handling::HandleInternalError("Unknown basic type", "ExecuteVisitor.HandleBuiltinTypeFunctionCall", &node->base); break; } return true; } return false; } } // namespace interpreter