utils functions, expect, ensure, error handling refactoring (string -> string_view), std::source_location

This commit is contained in:
ProgramSnail 2024-03-11 00:33:53 +03:00
parent 5afbaf06ae
commit d6a3ce1946
7 changed files with 149 additions and 29 deletions

1
.ignore Normal file
View file

@ -0,0 +1 @@
deps/

View file

@ -8,58 +8,64 @@
namespace error_handling { namespace error_handling {
inline void print_position(std::ostream &out, inline void handle_internal_error(
std::pair<size_t, size_t> start_position, std::string_view message, const nodes::Node &node,
std::pair<size_t, size_t> end_position) { const std::source_location &location = std::source_location::current()) {
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) {
std::cerr << "\x1b[1;31mInternal Error:\x1b[0m " << message << " at "; std::cerr << "\x1b[1;31mInternal Error:\x1b[0m " << message << " at ";
print_position(std::cerr, node.get_start_position(), node.get_end_position()); print_position(std::cerr, node.get_start_position(), node.get_end_position());
std::cerr << ".\n"; std::cerr << ".\n";
print_source_location(std::cerr, location);
exit(1); exit(1);
} }
inline void handle_internal_error(const std::string &message, inline void handle_internal_error(
parser::ParseTree::Node node) { 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 "; std::cerr << "\x1b[1;31mInternal Error:\x1b[0m " << message << " at ";
print_position(std::cerr, node.get_start_point(), node.get_end_point()); print_position(std::cerr, node.get_start_point(), node.get_end_point());
std::cerr << ".\n"; std::cerr << ".\n";
print_source_location(std::cerr, location);
exit(1); exit(1);
} }
inline void handle_parsing_error(const std::string &message, inline void handle_parsing_error(
parser::ParseTree::Node parse_node) { 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 "; std::cerr << "\x1b[1;31mParsing Error:\x1b[0m " << message << " at ";
print_position(std::cerr, parse_node.get_start_point(), print_position(std::cerr, parse_node.get_start_point(),
parse_node.get_end_point()); parse_node.get_end_point());
std::cerr << ".\n"; std::cerr << ".\n";
print_source_location(std::cerr, location);
exit(1); exit(1);
} }
inline void handle_typecheck_error(const std::string &message, inline void handle_typecheck_error(
nodes::Node node) { 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 "; std::cerr << "\x1b[1;31mTypecheck Error:\x1b[0m " << message << " at ";
print_position(std::cerr, node.get_start_position(), node.get_end_position()); print_position(std::cerr, node.get_start_position(), node.get_end_position());
std::cerr << ".\n"; std::cerr << ".\n";
print_source_location(std::cerr, location);
exit(1); 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 "; std::cerr << "\x1b[1;31mRuntime Error:\x1b[0m " << message << " at ";
print_position(std::cerr, node.get_start_position(), node.get_end_position()); print_position(std::cerr, node.get_start_position(), node.get_end_position());
std::cerr << ".\n"; std::cerr << ".\n";
print_source_location(std::cerr, location);
exit(1); 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 "; std::cerr << "\x1b[1;31mNames Error:\x1b[0m " << message << " at ";
print_position(std::cerr, node.get_start_position(), node.get_end_position()); print_position(std::cerr, node.get_start_position(), node.get_end_position());
std::cerr << ".\n"; std::cerr << ".\n";
print_source_location(std::cerr, location);
exit(1); exit(1);
} }

View file

@ -1,10 +1,13 @@
#pragma once #pragma once
#include "utils.hpp" #include "utils.hpp"
#include <optional> #include <optional>
#include <ranges>
#include <string> #include <string>
#include <utility> #include <utility>
#include <variant> #include <variant>
#include <vector>
namespace nodes { namespace nodes {
@ -222,6 +225,8 @@ private:
class Identifier : public Node { class Identifier : public Node {
public: public:
static constexpr char NAME_DELIMITER = '.';
enum IdentifierType { enum IdentifierType {
SIMPLE_NAME, SIMPLE_NAME,
SIMPLE_TYPE, 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) { 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<Identifier> git_fragments() const {
std::vector<Identifier> 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<Identifier, Identifier> split_first() { std::pair<Identifier, Identifier> split_first() {
const auto pos = value_.find('.'); const auto pos = value_.find(NAME_DELIMITER);
if (pos == std::string::npos) { if (pos == std::string::npos) {
return {Identifier(*this, type_, ""), *this}; 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
} }
// //

View file

@ -4,6 +4,7 @@
#include "builtin_types.hpp" #include "builtin_types.hpp"
#include "utils.hpp" #include "utils.hpp"
#include <algorithm>
#include <iterator> #include <iterator>
#include <memory> #include <memory>
#include <optional> #include <optional>
@ -75,13 +76,40 @@ public:
size_t parameters_size() const { return parameters_.size(); } 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 { 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<TypeProxy>
get_parameter_proxy_by_name(const std::string &name) const {
const auto it = std::find_if(
parameters_.begin(), parameters_.end(), [&name](const auto &parameter) {
return parameter.get()->has_annotation() &&
*parameter.get()->get_annotation().value() == name;
});
if (it != parameters_.end()) {
return *it;
}
return std::nullopt;
}
std::optional<const Type *>
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<const Type *>{};
}
std::optional<Type *> 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<Type *>{};
}
// //
@ -93,6 +121,8 @@ public:
// //
bool has_annotation() const { return annotation_.has_value(); }
std::optional<std::string *> get_annotation() { std::optional<std::string *> get_annotation() {
if (annotation_.has_value()) { if (annotation_.has_value()) {
return &annotation_.value(); return &annotation_.value();

View file

@ -1,15 +1,55 @@
#pragma once #pragma once
#include <iostream> #include <iostream>
#include <source_location>
#include <string> #include <string>
namespace error_handling { namespace error_handling {
inline void handle_general_error(const std::string &message) { inline void print_position(std::ostream &out,
std::pair<size_t, size_t> start_position,
std::pair<size_t, size_t> 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"; std::cerr << "\x1b[1;31mGeneral Error:\x1b[0m " << message << ".\n";
exit(1); 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 error_handling
namespace utils { namespace utils {

View file

@ -381,6 +381,7 @@ nodes::TypeCheckResult type_check_return(const nodes::Return &expression,
arguments, expression, sources_manager); arguments, expression, sources_manager);
} }
// TODO: warning if name is same to package prefix, function prefix, etc. ??
nodes::TypeCheckResult nodes::TypeCheckResult
type_check_name_definition(const nodes::NameDefinition &expression, type_check_name_definition(const nodes::NameDefinition &expression,
SourcesManager &sources_manager, State &state, SourcesManager &sources_manager, State &state,
@ -541,13 +542,17 @@ type_check_name_expression(const nodes::NameExpression &expression,
const Arguments &arguments) { const Arguments &arguments) {
// TODO: constraints ?? // 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 passed type --- TODO --- (additional argument)
// TODO: deal with given ->(out) Args (type not expected, but passed into) // TODO: deal with given ->(out) Args (type not expected, but passed into)
// TODO: check, if there is variable with this name // TODO: check, if there is variable with this name
// TODO: check var + fields // TODO: check var + fields
const auto maybe_function_definition = find_name_definition_handle_errors( 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()) { if (!maybe_function_definition.has_value()) {
return nodes::TypeCheckResult::construct_invalid_result(); return nodes::TypeCheckResult::construct_invalid_result();
} }

View file

@ -7,7 +7,7 @@ namespace printers {
// TODO: better printing format for builtin types // TODO: better printing format for builtin types
void print_type(const nodes::Type &type, printers::Printer &printer) { 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); print_annotation(*type.get_annotation().value(), printer);
printer.space(); printer.space();
} }