diff --git a/.ignore b/.ignore new file mode 100644 index 0000000..6912fef --- /dev/null +++ b/.ignore @@ -0,0 +1 @@ +deps/ diff --git a/include/error_handling.hpp b/include/error_handling.hpp index c91947b..690844f 100644 --- a/include/error_handling.hpp +++ b/include/error_handling.hpp @@ -8,58 +8,64 @@ namespace error_handling { -inline void print_position(std::ostream &out, - std::pair start_position, - std::pair end_position) { - out << '[' << start_position.first + 1 << ", " << start_position.second + 1 - << "] - [" << end_position.first + 1 << ", " << end_position.second + 1 - << ']'; -} - -inline void handle_internal_error(const std::string &message, - const nodes::Node &node) { +inline void handle_internal_error( + std::string_view message, const nodes::Node &node, + const std::source_location &location = std::source_location::current()) { std::cerr << "\x1b[1;31mInternal Error:\x1b[0m " << message << " at "; print_position(std::cerr, node.get_start_position(), node.get_end_position()); std::cerr << ".\n"; + print_source_location(std::cerr, location); exit(1); } -inline void handle_internal_error(const std::string &message, - parser::ParseTree::Node node) { +inline void handle_internal_error( + std::string_view message, parser::ParseTree::Node node, + const std::source_location &location = std::source_location::current()) { std::cerr << "\x1b[1;31mInternal Error:\x1b[0m " << message << " at "; print_position(std::cerr, node.get_start_point(), node.get_end_point()); std::cerr << ".\n"; + print_source_location(std::cerr, location); exit(1); } -inline void handle_parsing_error(const std::string &message, - parser::ParseTree::Node parse_node) { +inline void handle_parsing_error( + std::string_view message, parser::ParseTree::Node parse_node, + const std::source_location &location = std::source_location::current()) { std::cerr << "\x1b[1;31mParsing Error:\x1b[0m " << message << " at "; print_position(std::cerr, parse_node.get_start_point(), parse_node.get_end_point()); std::cerr << ".\n"; + print_source_location(std::cerr, location); exit(1); } -inline void handle_typecheck_error(const std::string &message, - nodes::Node node) { +inline void handle_typecheck_error( + std::string_view message, nodes::Node node, + const std::source_location &location = std::source_location::current()) { std::cerr << "\x1b[1;31mTypecheck Error:\x1b[0m " << message << " at "; print_position(std::cerr, node.get_start_position(), node.get_end_position()); std::cerr << ".\n"; + print_source_location(std::cerr, location); exit(1); } -inline void handle_runtime_error(const std::string &message, nodes::Node node) { +inline void handle_runtime_error( + std::string_view message, nodes::Node node, + const std::source_location &location = std::source_location::current()) { std::cerr << "\x1b[1;31mRuntime Error:\x1b[0m " << message << " at "; print_position(std::cerr, node.get_start_position(), node.get_end_position()); std::cerr << ".\n"; + print_source_location(std::cerr, location); exit(1); } -inline void handle_names_error(const std::string &message, nodes::Node node) { +inline void handle_names_error( + std::string_view message, nodes::Node node, + const std::source_location &location = std::source_location::current()) { std::cerr << "\x1b[1;31mNames Error:\x1b[0m " << message << " at "; print_position(std::cerr, node.get_start_position(), node.get_end_position()); std::cerr << ".\n"; + print_source_location(std::cerr, location); exit(1); } diff --git a/include/nodes/basic_nodes.hpp b/include/nodes/basic_nodes.hpp index f52e70b..69dd4a6 100644 --- a/include/nodes/basic_nodes.hpp +++ b/include/nodes/basic_nodes.hpp @@ -1,10 +1,13 @@ #pragma once #include "utils.hpp" + #include +#include #include #include #include +#include namespace nodes { @@ -222,6 +225,8 @@ private: class Identifier : public Node { public: + static constexpr char NAME_DELIMITER = '.'; + enum IdentifierType { SIMPLE_NAME, SIMPLE_TYPE, @@ -251,18 +256,51 @@ public: // - void append_before(const std::string &name) { value_ = name + "." + value_; } + void append_before(const std::string &name) { + value_ = name + NAME_DELIMITER + value_; + } + + void append_before( + const Identifier &identifier, + std::source_location location = std::source_location::current()) { + error_handling::expect(identifier.type_ == type_, + "different Identifier types on append_before", + location); + value_ = *identifier.get() + NAME_DELIMITER + value_; + } void append_after(const std::string &name) { - value_ += "." + name; + value_ += NAME_DELIMITER + name; + } + + void append_after( + const Identifier &identifier, + std::source_location location = std::source_location::current()) { + error_handling::expect(identifier.type_ == type_, + "different Identifier types on append_after", + location); + value_ += NAME_DELIMITER + *identifier.get(); + } + + std::vector git_fragments() const { + std::vector fragments; + for (auto &&fragment_name : + std::ranges::views::split(value_, NAME_DELIMITER)) { + fragments.emplace_back( + *this, type_, + std::string(fragment_name.begin(), fragment_name.end())); + } + return fragments; } std::pair split_first() { - const auto pos = value_.find('.'); + const auto pos = value_.find(NAME_DELIMITER); if (pos == std::string::npos) { return {Identifier(*this, type_, ""), *this}; } - return {Identifier(*this, type_, value_.substr(0, pos)), Identifier(*this, type_, value_.substr(pos + 1))}; // '.' is leaved out + return { + Identifier(*this, type_, value_.substr(0, pos)), + Identifier(*this, type_, value_.substr(pos + 1))}; // '.' is leaved out } // diff --git a/include/nodes/type_nodes.hpp b/include/nodes/type_nodes.hpp index 27f90ff..9fc3390 100644 --- a/include/nodes/type_nodes.hpp +++ b/include/nodes/type_nodes.hpp @@ -4,6 +4,7 @@ #include "builtin_types.hpp" #include "utils.hpp" +#include #include #include #include @@ -28,7 +29,7 @@ public: bool operator==(const TypeProxy &other) const; - bool operator!=(const TypeProxy&) const = default; + bool operator!=(const TypeProxy &) const = default; private: TypeProxy(TypeStorage &type_storage, size_t id) @@ -75,13 +76,40 @@ public: size_t parameters_size() const { return parameters_.size(); } - Type *get_parameter(size_t id) { return parameters_.at(id).get(); } + TypeProxy get_parameter_proxy(size_t id) const { return parameters_.at(id); } + + Type *get_parameter(size_t id) { return get_parameter_proxy(id).get(); } const Type *get_parameter(size_t id) const { - return parameters_.at(id).get(); + return get_parameter_proxy(id).get(); } - TypeProxy get_parameter_proxy(size_t id) const { return parameters_.at(id); } + // TODO: cache with map ?? + std::optional + get_parameter_proxy_by_name(const std::string &name) const { + const auto it = std::find_if( + parameters_.begin(), parameters_.end(), [&name](const auto ¶meter) { + return parameter.get()->has_annotation() && + *parameter.get()->get_annotation().value() == name; + }); + + if (it != parameters_.end()) { + return *it; + } + return std::nullopt; + } + + std::optional + get_parameter_by_name(const std::string &name) const { + const auto proxy = get_parameter_proxy_by_name(name); + return proxy.has_value() ? proxy.value().get() + : std::optional{}; + } + + std::optional get_parameter_by_name(const std::string &name) { + auto proxy = get_parameter_proxy_by_name(name); + return proxy.has_value() ? proxy.value().get() : std::optional{}; + } // @@ -93,6 +121,8 @@ public: // + bool has_annotation() const { return annotation_.has_value(); } + std::optional get_annotation() { if (annotation_.has_value()) { return &annotation_.value(); diff --git a/include/utils.hpp b/include/utils.hpp index 5803658..7061251 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -1,15 +1,55 @@ #pragma once #include +#include #include namespace error_handling { -inline void handle_general_error(const std::string &message) { +inline void print_position(std::ostream &out, + std::pair start_position, + std::pair end_position) { + out << '[' << start_position.first + 1 << ", " << start_position.second + 1 + << "] - [" << end_position.first + 1 << ", " << end_position.second + 1 + << ']'; +} + +inline void print_source_location(std::ostream &out, + const std::source_location &location) { + out << "\x1b[1;33mSOURCE LOCATION:\x1b[0m " << location.file_name() << "(" + << location.line() << ":" << location.column() << ") `" + << location.function_name() << "`.\n"; +} + +inline void handle_general_error(std::string_view message) { std::cerr << "\x1b[1;31mGeneral Error:\x1b[0m " << message << ".\n"; exit(1); } +inline void +expect(bool condition, std::string_view failure_message, + const std::source_location &location = std::source_location::current()) { + + if (!condition) { + std::cerr << "\x1b[1;33mExpected condition failed (compiler error):\x1b[0m " + << failure_message << ".\n"; + print_source_location(std::cerr, location); + exit(1); + } +} + +inline void +ensure(bool condition, std::string_view failure_message, + const std::source_location &location = std::source_location::current()) { + + if (!condition) { + std::cerr << "\x1b[1;33mEnsured condition failed (compiler error):\x1b[0m " + << failure_message << ".\n"; + print_source_location(std::cerr, location); + exit(1); + } +} + } // namespace error_handling namespace utils { diff --git a/src/expression_type_check.cpp b/src/expression_type_check.cpp index 20bd5ba..413c8d5 100644 --- a/src/expression_type_check.cpp +++ b/src/expression_type_check.cpp @@ -381,6 +381,7 @@ nodes::TypeCheckResult type_check_return(const nodes::Return &expression, arguments, expression, sources_manager); } +// TODO: warning if name is same to package prefix, function prefix, etc. ?? nodes::TypeCheckResult type_check_name_definition(const nodes::NameDefinition &expression, SourcesManager &sources_manager, State &state, @@ -541,13 +542,17 @@ type_check_name_expression(const nodes::NameExpression &expression, const Arguments &arguments) { // TODO: constraints ?? + const auto name = expression.get_name(); + for (size_t i = 0; i < /*fragments_count*/; ++i) { // go in prefixes and try to find matching var name + } + // --- TODO --- deal with passed type --- TODO --- (additional argument) // TODO: deal with given ->(out) Args (type not expected, but passed into) // TODO: check, if there is variable with this name // TODO: check var + fields const auto maybe_function_definition = find_name_definition_handle_errors( - *expression.get_name()->get(), expression, sources_manager); + *name->get(), expression, sources_manager); if (!maybe_function_definition.has_value()) { return nodes::TypeCheckResult::construct_invalid_result(); } diff --git a/src/printers/type_printers.cpp b/src/printers/type_printers.cpp index 79e5c1c..75b6ad3 100644 --- a/src/printers/type_printers.cpp +++ b/src/printers/type_printers.cpp @@ -7,7 +7,7 @@ namespace printers { // TODO: better printing format for builtin types void print_type(const nodes::Type &type, printers::Printer &printer) { - if (type.get_annotation().has_value()) { + if (type.has_annotation()) { print_annotation(*type.get_annotation().value(), printer); printer.space(); }