mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-05 22:48:43 +00:00
utils to typecheck name expression, ccls config
This commit is contained in:
parent
f688dd99a2
commit
c969dac7cc
3 changed files with 100 additions and 14 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -19,3 +19,4 @@ cmake-build-debug
|
|||
|
||||
.idea
|
||||
.cache
|
||||
.ccls-cache
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue