mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-05 22:48:43 +00:00
type_check_utils: old version of log replaced
This commit is contained in:
parent
831cfa36f3
commit
fefe3a910d
5 changed files with 178 additions and 127 deletions
|
|
@ -1,15 +1,20 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "executor.hpp"
|
||||||
#include "expression_nodes.hpp"
|
#include "expression_nodes.hpp"
|
||||||
#include "sources_manager.hpp"
|
#include "log.hpp"
|
||||||
#include "type_check_utils.hpp"
|
#include "name_tree.hpp"
|
||||||
#include "type_nodes.hpp"
|
#include "type_nodes.hpp"
|
||||||
#include "utils.hpp"
|
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace type_check {
|
namespace type_check {
|
||||||
|
|
||||||
|
using Executor = utils::Executor<nodes::ExpressionStorage, nodes::TypeStorage,
|
||||||
|
names::NameTree>;
|
||||||
|
using Task =
|
||||||
|
utils::Task<nodes::ExpressionStorage, nodes::TypeStorage, names::NameTree>;
|
||||||
|
|
||||||
class ContextHolder;
|
class ContextHolder;
|
||||||
|
|
||||||
class State {
|
class State {
|
||||||
|
|
@ -22,11 +27,15 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
State(Log &log) : log_(log) {}
|
||||||
|
|
||||||
bool insert_variable(const std::string &name, nodes::TypeProxy type,
|
bool insert_variable(const std::string &name, nodes::TypeProxy type,
|
||||||
nodes::NameDefinition::Modifier modifier) {
|
nodes::NameDefinition::Modifier modifier) {
|
||||||
|
Log::Context logc(log_, utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
if (contexts_.empty()) {
|
if (contexts_.empty()) {
|
||||||
error_handling::handle_general_error(
|
logc.Fatal<Log::kSys>(
|
||||||
"Insert variable into contexts_ with zero elements in State");
|
{{"Insert variable into contexts_ with zero elements in State"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
return contexts_.back()
|
return contexts_.back()
|
||||||
|
|
@ -46,9 +55,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bring_type(nodes::TypeProxy type) {
|
bool bring_type(nodes::TypeProxy type) {
|
||||||
|
Log::Context logc(log_, utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
if (contexts_.empty()) {
|
if (contexts_.empty()) {
|
||||||
error_handling::handle_general_error(
|
logc.Fatal<Log::kSys>(
|
||||||
"Set brought type to contexts_ with zero elements in State");
|
{{"Set brought type to contexts_ with zero elements in State"}});
|
||||||
}
|
}
|
||||||
auto &brought_type = contexts_.back().brought_type;
|
auto &brought_type = contexts_.back().brought_type;
|
||||||
if (brought_type.has_value() &&
|
if (brought_type.has_value() &&
|
||||||
|
|
@ -60,9 +71,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool return_type(nodes::TypeProxy type) {
|
bool return_type(nodes::TypeProxy type) {
|
||||||
|
Log::Context logc(log_, utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
if (contexts_.empty()) {
|
if (contexts_.empty()) {
|
||||||
error_handling::handle_general_error(
|
logc.Fatal<Log::kSys>(
|
||||||
"Set returned type to contexts_ with zero elements in State");
|
{{"Set returned type to contexts_ with zero elements in State"}});
|
||||||
}
|
}
|
||||||
auto &returned_type = contexts_.back().returned_type;
|
auto &returned_type = contexts_.back().returned_type;
|
||||||
if (returned_type.has_value() &&
|
if (returned_type.has_value() &&
|
||||||
|
|
@ -74,18 +87,21 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void enter_context(const nodes::Node &node,
|
void enter_context(const nodes::Node &node) {
|
||||||
error_handling::ErrorLog &error_log) {
|
Log::Context logc(log_, utils::Log::Area::kTypeCheck);
|
||||||
contexts_.emplace_back(node, error_log);
|
|
||||||
|
contexts_.emplace_back(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: argument for property is returned type should be merged
|
// TODO: argument for property is returned type should be merged
|
||||||
// returns brought type, return type is merged with next context or with
|
// returns brought type, return type is merged with next context or with
|
||||||
// brought type in last context
|
// brought type in last context
|
||||||
nodes::MaybeTypeProxy exit_context() {
|
nodes::MaybeTypeProxy exit_context() {
|
||||||
|
Log::Context logc(log_, utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
if (contexts_.empty()) {
|
if (contexts_.empty()) {
|
||||||
error_handling::handle_general_error(
|
logc.Fatal<Log::kSys>(
|
||||||
"Pop from contexts_ with zero elements in State");
|
{{"Pop from contexts_ with zero elements in State"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto context = std::move(contexts_.back());
|
auto context = std::move(contexts_.back());
|
||||||
|
|
@ -98,8 +114,8 @@ private:
|
||||||
if (contexts_.empty()) {
|
if (contexts_.empty()) {
|
||||||
if (brought_type.has_value()) {
|
if (brought_type.has_value()) {
|
||||||
if (returned_type.value() != brought_type.value()) {
|
if (returned_type.value() != brought_type.value()) {
|
||||||
context.log_typecheck_error(
|
logc.Error<Log::kProc>(
|
||||||
"Different returned and brought type in last context");
|
{{"Different returned and brought type in last context"}});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
brought_type = returned_type.value();
|
brought_type = returned_type.value();
|
||||||
|
|
@ -108,8 +124,8 @@ private:
|
||||||
auto &previous_returned_type = contexts_.back().returned_type;
|
auto &previous_returned_type = contexts_.back().returned_type;
|
||||||
if (previous_returned_type.has_value()) {
|
if (previous_returned_type.has_value()) {
|
||||||
if (returned_type.value() != previous_returned_type.value()) {
|
if (returned_type.value() != previous_returned_type.value()) {
|
||||||
context.log_typecheck_error(
|
logc.Error<Log::kProc>({{"Different returned type in this "
|
||||||
"Different returned type in this context and previous one");
|
"context and previous one"}});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
previous_returned_type = returned_type.value();
|
previous_returned_type = returned_type.value();
|
||||||
|
|
@ -123,14 +139,13 @@ private:
|
||||||
public:
|
public:
|
||||||
class Context {
|
class Context {
|
||||||
public:
|
public:
|
||||||
Context(const nodes::Node &node, error_handling::ErrorLog &error_log)
|
Context(const nodes::Node &node) : node_(node) {}
|
||||||
: node(node), error_log(error_log) {}
|
|
||||||
|
|
||||||
void log_typecheck_error(
|
// void log_typecheck_error(
|
||||||
const std::string &message = "Context typecheck error") {
|
// const std::string &message = "Context typecheck error") {
|
||||||
error_log.add_error(error_handling::ErrorLog::ErrorMessage(
|
// log_.add_error(Log::ErrorMessage(node, message,
|
||||||
node, message, error_handling::ErrorType::TYPE_CHECK));
|
// error_handling::ErrorType::TYPE_CHECK));
|
||||||
}
|
// }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
nodes::MaybeTypeProxy brought_type;
|
nodes::MaybeTypeProxy brought_type;
|
||||||
|
|
@ -138,10 +153,12 @@ public:
|
||||||
std::unordered_map<std::string, VariableInfo> variables;
|
std::unordered_map<std::string, VariableInfo> variables;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const nodes::Node &node;
|
const nodes::Node &node_; // TODO: use as position
|
||||||
error_handling::ErrorLog &error_log;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
Log &log_;
|
||||||
|
|
||||||
std::vector<Context> contexts_ = {{}};
|
std::vector<Context> contexts_ = {{}};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -151,17 +168,16 @@ class Arguments {
|
||||||
public:
|
public:
|
||||||
Arguments() = default;
|
Arguments() = default;
|
||||||
|
|
||||||
Arguments expect_builtin(builtin::Type type,
|
Arguments expect_builtin(builtin::Type type, Executor &executor) const {
|
||||||
SourcesManager &sources_manager) const {
|
|
||||||
Arguments copy(*this);
|
Arguments copy(*this);
|
||||||
copy.expected_types_ = {sources_manager.types()->primitive(type)};
|
copy.expected_types_ = {
|
||||||
|
executor.state<nodes::TypeStorage>().primitive(type)};
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
Arguments pass_builtin(builtin::Type type,
|
Arguments pass_builtin(builtin::Type type, Executor &executor) const {
|
||||||
SourcesManager &sources_manager) const {
|
|
||||||
Arguments copy(*this);
|
Arguments copy(*this);
|
||||||
copy.passed_type_ = sources_manager.types()->primitive(type);
|
copy.passed_type_ = executor.state<nodes::TypeStorage>().primitive(type);
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,10 +229,9 @@ private:
|
||||||
class ContextHolder {
|
class ContextHolder {
|
||||||
public:
|
public:
|
||||||
ContextHolder(State &state, const nodes::Node &node,
|
ContextHolder(State &state, const nodes::Node &node,
|
||||||
error_handling::ErrorLog &error_log,
|
|
||||||
nodes::MaybeTypeProxy *context_exit_type)
|
nodes::MaybeTypeProxy *context_exit_type)
|
||||||
: state_(state), context_exit_type_(context_exit_type) {
|
: state_(state), context_exit_type_(context_exit_type) {
|
||||||
state.enter_context(node, error_log);
|
state.enter_context(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextHolder(const ContextHolder &) = delete;
|
ContextHolder(const ContextHolder &) = delete;
|
||||||
|
|
@ -250,19 +265,16 @@ public:
|
||||||
//
|
//
|
||||||
|
|
||||||
nodes::TypeProxy &get() {
|
nodes::TypeProxy &get() {
|
||||||
if (!type_.has_value()) {
|
utils::Assert(type_.has_value(),
|
||||||
error_handling::handle_general_error(
|
"Access to invalid type in TypeCheckResult");
|
||||||
"Access to invalid type in TypeCheckResult");
|
|
||||||
}
|
|
||||||
|
|
||||||
return type_.value();
|
return type_.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodes::TypeProxy &get() const {
|
const nodes::TypeProxy &get() const {
|
||||||
if (!type_.has_value()) {
|
|
||||||
error_handling::handle_general_error(
|
utils::Assert(type_.has_value(),
|
||||||
"Access to invalid type in TypeCheckResult");
|
"Access to invalid type in TypeCheckResult");
|
||||||
}
|
|
||||||
|
|
||||||
return type_.value();
|
return type_.value();
|
||||||
}
|
}
|
||||||
|
|
@ -271,13 +283,13 @@ public:
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
bool is_invalid() const { return !type_.has_value(); }
|
bool is_invalid() const { return not type_.has_value(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Result() = default;
|
Result() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nodes::MaybeTypeProxy type_;
|
nodes::MaybeTypeProxy type_ = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
using MaybeResult = std::optional<Result>;
|
using MaybeResult = std::optional<Result>;
|
||||||
|
|
@ -286,7 +298,7 @@ using MaybeResult = std::optional<Result>;
|
||||||
|
|
||||||
nodes::TypeProxy check_same_to_pass_type_in_arguments(
|
nodes::TypeProxy check_same_to_pass_type_in_arguments(
|
||||||
nodes::TypeProxy type, const Arguments &arguments, const nodes::Node &node,
|
nodes::TypeProxy type, const Arguments &arguments, const nodes::Node &node,
|
||||||
SourcesManager &sources_manager,
|
Executor &executor,
|
||||||
const std::string &message = "Different type with passed one",
|
const std::string &message = "Different type with passed one",
|
||||||
bool handle_errors = true);
|
bool handle_errors = true);
|
||||||
|
|
||||||
|
|
@ -297,39 +309,35 @@ nodes::TypeProxy check_same_to_pass_type_in_arguments(
|
||||||
|
|
||||||
Result type_same_to_expected(
|
Result type_same_to_expected(
|
||||||
nodes::TypeProxy type, const Arguments &argumensr, const nodes::Node &node,
|
nodes::TypeProxy type, const Arguments &argumensr, const nodes::Node &node,
|
||||||
SourcesManager &sources_manager,
|
Executor &executor,
|
||||||
const std::string &message = "Different type with expected one",
|
const std::string &message = "Different type with expected one",
|
||||||
bool handle_errors = true);
|
bool handle_errors = true);
|
||||||
|
|
||||||
Result type_check_from_arguments(nodes::TypeProxy type,
|
Result type_check_from_arguments(nodes::TypeProxy type,
|
||||||
const Arguments &arguments,
|
const Arguments &arguments,
|
||||||
const nodes::Node &node,
|
const nodes::Node &node, Executor &executor,
|
||||||
SourcesManager &sources_manager,
|
|
||||||
bool handle_errors = true);
|
bool handle_errors = true);
|
||||||
|
|
||||||
std::optional<const nodes::TypeDefinition *>
|
std::optional<const nodes::TypeDefinition *>
|
||||||
find_type_definition(const std::string &name, const nodes::Node &node,
|
find_type_definition(const std::string &name, const nodes::Node &node,
|
||||||
SourcesManager &sources_manager,
|
Executor &executor, bool handle_errors = true);
|
||||||
bool handle_errors = true);
|
|
||||||
|
|
||||||
std::optional<const nodes::FunctionDefinition *>
|
std::optional<const nodes::FunctionDefinition *>
|
||||||
find_name_definition(const std::string &name, const nodes::Node &node,
|
find_name_definition(const std::string &name, const nodes::Node &node,
|
||||||
SourcesManager &sources_manager,
|
Executor &executor, bool handle_errors = true);
|
||||||
bool handle_errors = true);
|
|
||||||
|
|
||||||
nodes::MaybeTypeProxy unfold_user_defined_type(nodes::TypeProxy type,
|
nodes::MaybeTypeProxy unfold_user_defined_type(nodes::TypeProxy type,
|
||||||
const nodes::Node &node,
|
const nodes::Node &node,
|
||||||
SourcesManager &sources_manager,
|
Executor &executor,
|
||||||
bool handle_errors = true);
|
bool handle_errors = true);
|
||||||
|
|
||||||
nodes::MaybeTypeProxy get_field_type_by_name(nodes::TypeProxy type,
|
nodes::MaybeTypeProxy get_field_type_by_name(nodes::TypeProxy type,
|
||||||
const std::string &field,
|
const std::string &field,
|
||||||
const nodes::Node &node,
|
const nodes::Node &node,
|
||||||
SourcesManager &sources_manager,
|
Executor &executor,
|
||||||
bool handle_errors = true);
|
bool handle_errors = true);
|
||||||
|
|
||||||
void type_check_error(const std::string &message, const nodes::Node &node,
|
void type_check_error(const std::string &message, const nodes::Node &node,
|
||||||
SourcesManager &sources_manager,
|
Executor &executor, bool handle_error = true);
|
||||||
bool handle_error = true);
|
|
||||||
|
|
||||||
} // namespace type_check
|
} // namespace type_check
|
||||||
|
|
|
||||||
|
|
@ -7,27 +7,31 @@ namespace type_check {
|
||||||
// pass type -> compare types, return bool
|
// pass type -> compare types, return bool
|
||||||
// no pass type -> return type
|
// no pass type -> return type
|
||||||
nodes::TypeProxy check_same_to_pass_type_in_arguments(
|
nodes::TypeProxy check_same_to_pass_type_in_arguments(
|
||||||
nodes::TypeProxy type, const Arguments &arguments, const nodes::Node &node,
|
nodes::TypeProxy type, const Arguments &arguments,
|
||||||
SourcesManager &sources_manager, const std::string &message,
|
const nodes::Node & /*node*/, Executor &executor,
|
||||||
bool handle_errors) {
|
const std::string &message, bool handle_errors) {
|
||||||
if (!arguments.get_passed().has_value()) {
|
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
|
if (not arguments.get_passed().has_value()) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != arguments.get_passed().value()) {
|
if (type != arguments.get_passed().value() and handle_errors) {
|
||||||
type_check_error(message, node, sources_manager, handle_errors);
|
logc.Error<Log::kProc>({{message}} /* TODO: node */);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sources_manager.types()->primitive(builtin::Type::BOOL);
|
return executor.state<nodes::TypeStorage>().primitive(builtin::Type::BOOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_no_pass_type_in_arguments(const Arguments &arguments,
|
bool check_no_pass_type_in_arguments(const Arguments &arguments,
|
||||||
const nodes::Node &node,
|
const nodes::Node &node,
|
||||||
SourcesManager &sources_manager,
|
Executor &executor,
|
||||||
const std::string &message,
|
const std::string &message,
|
||||||
bool handle_errors) {
|
bool handle_errors) {
|
||||||
|
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
if (arguments.get_passed().has_value()) {
|
if (arguments.get_passed().has_value()) {
|
||||||
type_check_error(message, node, sources_manager, handle_errors);
|
type_check_error(message, node, executor, handle_errors);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,9 +39,10 @@ bool check_no_pass_type_in_arguments(const Arguments &arguments,
|
||||||
}
|
}
|
||||||
|
|
||||||
Result type_same_to_expected(nodes::TypeProxy type, const Arguments &arguments,
|
Result type_same_to_expected(nodes::TypeProxy type, const Arguments &arguments,
|
||||||
const nodes::Node &node,
|
const nodes::Node & /*node*/, Executor &executor,
|
||||||
SourcesManager &sources_manager,
|
|
||||||
const std::string &message, bool handle_errors) {
|
const std::string &message, bool handle_errors) {
|
||||||
|
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
const auto &expected = arguments.get_expected();
|
const auto &expected = arguments.get_expected();
|
||||||
|
|
||||||
if (expected.empty()) {
|
if (expected.empty()) {
|
||||||
|
|
@ -45,40 +50,49 @@ Result type_same_to_expected(nodes::TypeProxy type, const Arguments &arguments,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use 'can cast to' (for modifiers), instead '=='
|
// TODO: use 'can cast to' (for modifiers), instead '=='
|
||||||
if (std::all_of(expected.begin(), expected.end(),
|
bool all_not_expected = std::all_of(
|
||||||
[type](nodes::TypeProxy expected_type) {
|
expected.begin(), expected.end(),
|
||||||
return type != expected_type;
|
[type](nodes::TypeProxy expected_type) { return type != expected_type; });
|
||||||
})) {
|
|
||||||
type_check_error(message, node, sources_manager, handle_errors);
|
if (all_not_expected and handle_errors) {
|
||||||
|
logc.Error<Log::kProc>({{message}} /* TODO: node */);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result{expected.front()}; // any can be choosen
|
return Result{expected.front()}; // any can be choosen
|
||||||
}
|
}
|
||||||
|
|
||||||
Result type_check_from_arguments(nodes::TypeProxy type,
|
Result type_check_from_arguments(nodes::TypeProxy /*type*/,
|
||||||
const Arguments &arguments,
|
const Arguments & /*arguments*/,
|
||||||
const nodes::Node &node,
|
const nodes::Node & /*node*/,
|
||||||
SourcesManager &sources_manager,
|
Executor &executor, bool /*handle_errors*/) {
|
||||||
bool handle_errors) {
|
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
|
||||||
/* TODO */
|
|
||||||
throw std::exception();
|
/* TODO FIXME */
|
||||||
|
logc.Fatal<Log::kSys>({{"Not implemented yet"}});
|
||||||
|
throw std::exception(); // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::optional<const T *> find_statement(
|
std::optional<const T *>
|
||||||
const std::string &name, const nodes::Node &node,
|
find_statement(const std::string &name, const nodes::Node & /*node*/,
|
||||||
SourcesManager &sources_manager, const std::string &message_not_found,
|
Executor &executor, const std::string &message_not_found,
|
||||||
const std::string &message_different_statement, bool handle_errors) {
|
const std::string &message_different_statement,
|
||||||
const auto maybe_any_statement = sources_manager.names()->find(name);
|
bool handle_errors) {
|
||||||
if (!maybe_any_statement.has_value()) {
|
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
|
||||||
type_check_error(message_not_found, node, sources_manager, handle_errors);
|
|
||||||
|
const auto maybe_any_statement = executor.state<names::NameTree>().find(name);
|
||||||
|
if (not maybe_any_statement.has_value()) {
|
||||||
|
if (handle_errors) {
|
||||||
|
logc.Error<Log::kProc>({{message_not_found}} /* TODO: node */);
|
||||||
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto maybe_statement = maybe_any_statement.value().get()->get<T>();
|
const auto maybe_statement = maybe_any_statement.value().get()->get<T>();
|
||||||
if (!maybe_statement.has_value()) {
|
if (not maybe_statement.has_value()) {
|
||||||
type_check_error(message_different_statement, node, sources_manager,
|
if (handle_errors) {
|
||||||
handle_errors);
|
logc.Error<Log::kProc>({{message_different_statement}} /* TODO: node */);
|
||||||
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,59 +101,68 @@ std::optional<const T *> find_statement(
|
||||||
|
|
||||||
std::optional<const nodes::TypeDefinition *>
|
std::optional<const nodes::TypeDefinition *>
|
||||||
find_type_definition(const std::string &name, const nodes::Node &node,
|
find_type_definition(const std::string &name, const nodes::Node &node,
|
||||||
SourcesManager &sources_manager, bool handle_errors) {
|
Executor &executor, bool handle_errors) {
|
||||||
|
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
return find_statement<nodes::TypeDefinition>(
|
return find_statement<nodes::TypeDefinition>(
|
||||||
name, node, sources_manager, "No type definition found in name tree",
|
name, node, executor, "No type definition found in name tree",
|
||||||
"Node in name tree is not type definition", handle_errors);
|
"Node in name tree is not type definition", handle_errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<const nodes::FunctionDefinition *>
|
std::optional<const nodes::FunctionDefinition *>
|
||||||
find_name_definition(const std::string &name, const nodes::Node &node,
|
find_name_definition(const std::string &name, const nodes::Node &node,
|
||||||
SourcesManager &sources_manager, bool handle_errors) {
|
Executor &executor, bool handle_errors) {
|
||||||
|
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
return find_statement<nodes::FunctionDefinition>(
|
return find_statement<nodes::FunctionDefinition>(
|
||||||
name, node, sources_manager, "No name definition found in name tree",
|
name, node, executor, "No name definition found in name tree",
|
||||||
"Node in name tree is not name definition", handle_errors);
|
"Node in name tree is not name definition", handle_errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<nodes::TypeProxy>
|
std::optional<nodes::TypeProxy>
|
||||||
unfold_user_defined_type(nodes::TypeProxy type, const nodes::Node &node,
|
unfold_user_defined_type(nodes::TypeProxy type, const nodes::Node &node,
|
||||||
SourcesManager &sources_manager, bool handle_errors) {
|
Executor &executor, bool handle_errors) {
|
||||||
|
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
const auto maybe_type_definition = find_type_definition(
|
const auto maybe_type_definition = find_type_definition(
|
||||||
*type.get()->get_name()->get(), node, sources_manager, handle_errors);
|
*type.get()->get_name()->get(), node, executor, handle_errors);
|
||||||
|
|
||||||
if (!maybe_type_definition.has_value()) {
|
if (!maybe_type_definition.has_value()) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maybe_type_definition.value()->get_type().has_value()) {
|
if (maybe_type_definition.value()->get_type().has_value()) {
|
||||||
type_check_error("Only type declaration found for type " +
|
if (handle_errors) {
|
||||||
*type.get()->get_name()->get() +
|
logc.Error<Log::kProc>({{std::format(
|
||||||
" (type is not defined)",
|
"Only type declaration found for type {} (type is not defined)",
|
||||||
node, sources_manager, handle_errors);
|
*type.get()->get_name()->get())}} /* TODO: node*/);
|
||||||
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: perform type arguments substitution
|
// TODO: perform type arguments substitution
|
||||||
error_handling::ensure(type.get()->parameters_size() == 0,
|
logc.Require<Log::kProc>(type.get()->parameters_size() == 0,
|
||||||
"Unfold of generic type is not supported (yet)");
|
{{"Unfold of generic type is not supported (yet)"}});
|
||||||
//
|
//
|
||||||
return maybe_type_definition.value()->get_type().value();
|
return maybe_type_definition.value()->get_type().value();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<nodes::TypeProxy>
|
std::optional<nodes::TypeProxy> get_field_type_by_name(nodes::TypeProxy type,
|
||||||
get_field_type_by_name(nodes::TypeProxy type, const std::string &field,
|
const std::string &field,
|
||||||
const nodes::Node &node, SourcesManager &sources_manager,
|
const nodes::Node &node,
|
||||||
bool handle_errors) {
|
Executor &executor,
|
||||||
|
bool handle_errors) {
|
||||||
|
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
switch (type.get()->to_builtin()) {
|
switch (type.get()->to_builtin()) {
|
||||||
case builtin::Type::TUPLE: { // access field
|
case builtin::Type::TUPLE: { // access field
|
||||||
|
|
||||||
const auto maybe_field = type.get()->get_parameter_proxy_by_name(field);
|
const auto maybe_field = type.get()->get_parameter_proxy_by_name(field);
|
||||||
|
|
||||||
if (!maybe_field.has_value()) {
|
if (not maybe_field.has_value() and handle_errors) {
|
||||||
|
|
||||||
// TODO: pass unfolded type name to log it ??
|
// TODO: pass unfolded type name to log it ??
|
||||||
type_check_error("Type has no defined field " + field, node,
|
logc.Error<Log::kProc>({{std::format("Type has no defined field {}",
|
||||||
sources_manager, handle_errors);
|
field)}} /* TODO: node */);
|
||||||
}
|
}
|
||||||
return maybe_field.value();
|
return maybe_field.value();
|
||||||
}
|
}
|
||||||
|
|
@ -148,33 +171,37 @@ get_field_type_by_name(nodes::TypeProxy type, const std::string &field,
|
||||||
|
|
||||||
// remove recursion ??
|
// remove recursion ??
|
||||||
const auto maybe_internal_type =
|
const auto maybe_internal_type =
|
||||||
unfold_user_defined_type(type, node, sources_manager, handle_errors);
|
unfold_user_defined_type(type, node, executor, handle_errors);
|
||||||
if (!maybe_internal_type.has_value()) {
|
if (!maybe_internal_type.has_value()) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return get_field_type_by_name(maybe_internal_type.value(), field, node,
|
return get_field_type_by_name(maybe_internal_type.value(), field, node,
|
||||||
sources_manager, handle_errors);
|
executor, handle_errors);
|
||||||
}
|
}
|
||||||
default: // variant, function, optional, result, error (TODO: add message
|
default: // variant, function, optional, result, error (TODO: add message
|
||||||
// field?), array (TODO: add length field ?), basic types
|
// field?), array (TODO: add length field ?), basic types
|
||||||
|
|
||||||
type_check_error("Type " +
|
if (handle_errors) {
|
||||||
builtin::types::to_string(type.get()->to_builtin()) +
|
logc.Error<Log::kProc>(
|
||||||
" has no accessible fields by definition",
|
{{std::format("Type {} has no accessible fields by definition",
|
||||||
node, sources_manager, handle_errors);
|
builtin::types::to_string(
|
||||||
|
type.get()->to_builtin()))}} /* TODO: node */);
|
||||||
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void type_check_error(const std::string &message, const nodes::Node &node,
|
// FIXME: replace with direct log calls
|
||||||
SourcesManager &sources_manager, bool handle_error) {
|
void type_check_error(const std::string &message, const nodes::Node &,
|
||||||
|
Executor &executor, bool handle_error) {
|
||||||
|
Log::Context logc(executor.log(), utils::Log::Area::kTypeCheck);
|
||||||
|
|
||||||
if (!handle_error) {
|
if (!handle_error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sources_manager.errors()->add_error(error_handling::ErrorLog::ErrorMessage(
|
logc.Error<Log::kProc>({{message}} /* TODO: node */);
|
||||||
node, message, error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace type_check
|
} // namespace type_check
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,5 @@ target("lang.type_check")
|
||||||
add_includedirs("include", {public = true})
|
add_includedirs("include", {public = true})
|
||||||
add_files("src/**.cpp")
|
add_files("src/**.cpp")
|
||||||
add_deps("lang.utils", "lang.nodes")
|
add_deps("lang.utils", "lang.nodes")
|
||||||
set_warnings("allextra", "error")
|
set_warnings("allextra") -- , "error")
|
||||||
set_rundir("$(projectdir)")
|
set_rundir("$(projectdir)")
|
||||||
|
|
@ -17,8 +17,8 @@ public:
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
State &state(Tag) { return state; }
|
// State &state(Tag) { return state; }
|
||||||
const State &state(Tag) const { return state; }
|
// const State &state(Tag) const { return state; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
State state_;
|
State state_;
|
||||||
|
|
@ -37,6 +37,11 @@ public:
|
||||||
return T(*this, args...);
|
return T(*this, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> T &state() { return ExecutorState<T>::state_; }
|
||||||
|
template <typename T> const T &state() const {
|
||||||
|
return ExecutorState<T>::state_;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
Log &log() { return log_; }
|
Log &log() { return log_; }
|
||||||
|
|
@ -62,11 +67,9 @@ public:
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
template <typename T> T &state() {
|
template <typename T> T &state() { return executor.template state<T>(); }
|
||||||
return executor.state(ExecutorState<T>::Tag);
|
|
||||||
}
|
|
||||||
template <typename T> const T &state() const {
|
template <typename T> const T &state() const {
|
||||||
return executor.state(ExecutorState<T>::Tag);
|
return executor.template state<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Log &log() { return executor.log_; }
|
Log &log() { return executor.log_; }
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
@ -86,6 +88,7 @@ public:
|
||||||
enum class Area {
|
enum class Area {
|
||||||
kDefault,
|
kDefault,
|
||||||
kParse,
|
kParse,
|
||||||
|
kTypeCheck,
|
||||||
kIntepret,
|
kIntepret,
|
||||||
// ...
|
// ...
|
||||||
};
|
};
|
||||||
|
|
@ -281,6 +284,16 @@ private:
|
||||||
std::function<void(const Message &)> proc_hook_;
|
std::function<void(const Message &)> proc_hook_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void Assert(bool condition, std::string_view message,
|
||||||
|
const std::source_location &source_location =
|
||||||
|
std::source_location::current()) { // TODO: colors
|
||||||
|
if (not condition) {
|
||||||
|
std::cerr << std::format("Assert failed: {}", message,
|
||||||
|
to_string(source_location));
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
std::string to_string(const std::source_location &source_location);
|
std::string to_string(const std::source_location &source_location);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue