utils to typecheck name expression, ccls config

This commit is contained in:
ProgramSnail 2024-04-07 21:45:59 +03:00
parent f688dd99a2
commit c969dac7cc
3 changed files with 100 additions and 14 deletions

1
.gitignore vendored
View file

@ -19,3 +19,4 @@ cmake-build-debug
.idea
.cache
.ccls-cache

View file

@ -17,8 +17,8 @@ class State {
public:
struct VariableInfo {
nodes::TypeProxy type;
nodes::NameDefinition::Modifier modifier;
nodes::TypeProxy type;
nodes::NameDefinition::Modifier modifier;
};
public:
@ -29,11 +29,12 @@ public:
"Insert variable into contexts_ with zero elements in State");
}
return contexts_.back().variables.insert({name, VariableInfo{type, modifier}}).second;
return contexts_.back()
.variables.insert({name, VariableInfo{type, modifier}})
.second;
}
std::optional<VariableInfo>
find_variable(const std::string &name) {
std::optional<VariableInfo> find_variable(const std::string &name) {
for (ssize_t i = contexts_.size(); i >= 0; --i) {
auto iter = contexts_[i].variables.find(name);
if (iter != contexts_[i].variables.end()) {
@ -134,8 +135,7 @@ public:
public:
nodes::MaybeTypeProxy brought_type;
nodes::MaybeTypeProxy returned_type;
std::unordered_map<std::string, VariableInfo>
variables;
std::unordered_map<std::string, VariableInfo> variables;
private:
const nodes::Node &node;
@ -266,6 +266,15 @@ find_name_definition_handle_errors(const std::string &name,
const nodes::Node &node,
SourcesManager &sources_manager);
std::optional<nodes::TypeProxy>
unfold_user_defined_type_handle_errors(nodes::TypeProxy type,
const nodes::Node &node,
SourcesManager &sources_manager);
std::optional<nodes::TypeProxy> get_field_type_by_name_handle_errors(
nodes::TypeProxy type, const std::string &field, const nodes::Node &node,
SourcesManager &sources_manager);
void type_check_error(const std::string &message, const nodes::Node &node,
SourcesManager &sources_manager);

View file

@ -1,4 +1,5 @@
#include "type_check_utils.hpp"
#include "builtin_types.hpp"
#include <algorithm>
namespace type_check {
@ -32,19 +33,22 @@ bool check_no_pass_type_in_arguments(const Arguments &arguments,
return true;
}
nodes::TypeCheckResult
type_same_to_expected(nodes::TypeProxy type,
const Arguments& arguments,
const nodes::Node &node, SourcesManager &sources_manager,
const std::string &message) {
const auto& expected = arguments.get_expected();
nodes::TypeCheckResult type_same_to_expected(nodes::TypeProxy type,
const Arguments &arguments,
const nodes::Node &node,
SourcesManager &sources_manager,
const std::string &message) {
const auto &expected = arguments.get_expected();
if (expected.empty()) {
return nodes::TypeCheckResult{type};
}
// TODO: use 'can cast to' (for modifiers), instead '=='
if (std::all_of(expected.begin(), expected.end(), [type](nodes::TypeProxy expected_type) { return type != expected_type; })) {
if (std::all_of(expected.begin(), expected.end(),
[type](nodes::TypeProxy expected_type) {
return type != expected_type;
})) {
type_check_error(message, node, sources_manager);
}
@ -95,6 +99,78 @@ find_name_definition_handle_errors(const std::string &name,
"Node in name tree is not name definition");
}
std::optional<nodes::TypeProxy>
unfold_user_defined_type_handle_errors(nodes::TypeProxy type,
const nodes::Node &node,
SourcesManager &sources_manager) {
const auto maybe_type_definition = find_type_definition_handle_errors(
*type.get()->get_name()->get(), node, sources_manager);
if (!maybe_type_definition.has_value()) {
return std::nullopt;
}
if (maybe_type_definition.value()->get_type().has_value()) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
node,
"Only type declaration found for type " +
*type.get()->get_name()->get() + " (type is not defined)",
error_handling::ErrorType::TYPE_CHECK));
return std::nullopt;
}
// TODO: perform type arguments substitution
error_handling::ensure(type.get()->parameters_size() == 0,
"Unfold of generic type is not supported (yet)");
//
return maybe_type_definition.value()->get_type().value();
}
std::optional<nodes::TypeProxy> get_field_type_by_name_handle_errors(
nodes::TypeProxy type, const std::string &field, const nodes::Node &node,
SourcesManager &sources_manager) {
switch (type.get()->to_builtin()) {
case builtin::types::Type::TUPLE: { // access field
const auto maybe_field = type.get()->get_parameter_proxy_by_name(field);
if (!maybe_field.has_value()) {
// TODO: pass unfolded type name to log it ??
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
node, "Type has no defined field " + field,
error_handling::ErrorType::TYPE_CHECK));
}
return maybe_field.value();
}
case builtin::types::Type::NONE: { // user defined type, trying to unfold, and
// then repeat access
// remove recursion ??
const auto maybe_internal_type =
unfold_user_defined_type_handle_errors(type, node, sources_manager);
if (!maybe_internal_type.has_value()) {
return std::nullopt;
}
return get_field_type_by_name_handle_errors(maybe_internal_type.value(),
field, node, sources_manager);
}
default: // variant, function, optional, result, error (TODO: add message
// field?), array (TODO: add length field ?), basic types
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
node,
"Type " + builtin::types::to_string(type.get()->to_builtin()) +
" has no accessible fields by definition",
error_handling::ErrorType::TYPE_CHECK));
return std::nullopt;
}
}
void type_check_error(const std::string &message, const nodes::Node &node,
SourcesManager &sources_manager) {
sources_manager.get_error_log()->add_error(