mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-06 06:58:46 +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
|
.idea
|
||||||
.cache
|
.cache
|
||||||
|
.ccls-cache
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,12 @@ public:
|
||||||
"Insert variable into contexts_ with zero elements in State");
|
"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>
|
std::optional<VariableInfo> find_variable(const std::string &name) {
|
||||||
find_variable(const std::string &name) {
|
|
||||||
for (ssize_t i = contexts_.size(); i >= 0; --i) {
|
for (ssize_t i = contexts_.size(); i >= 0; --i) {
|
||||||
auto iter = contexts_[i].variables.find(name);
|
auto iter = contexts_[i].variables.find(name);
|
||||||
if (iter != contexts_[i].variables.end()) {
|
if (iter != contexts_[i].variables.end()) {
|
||||||
|
|
@ -134,8 +135,7 @@ public:
|
||||||
public:
|
public:
|
||||||
nodes::MaybeTypeProxy brought_type;
|
nodes::MaybeTypeProxy brought_type;
|
||||||
nodes::MaybeTypeProxy returned_type;
|
nodes::MaybeTypeProxy returned_type;
|
||||||
std::unordered_map<std::string, VariableInfo>
|
std::unordered_map<std::string, VariableInfo> variables;
|
||||||
variables;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const nodes::Node &node;
|
const nodes::Node &node;
|
||||||
|
|
@ -266,6 +266,15 @@ find_name_definition_handle_errors(const std::string &name,
|
||||||
const nodes::Node &node,
|
const nodes::Node &node,
|
||||||
SourcesManager &sources_manager);
|
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,
|
void type_check_error(const std::string &message, const nodes::Node &node,
|
||||||
SourcesManager &sources_manager);
|
SourcesManager &sources_manager);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "type_check_utils.hpp"
|
#include "type_check_utils.hpp"
|
||||||
|
#include "builtin_types.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace type_check {
|
namespace type_check {
|
||||||
|
|
@ -32,10 +33,10 @@ bool check_no_pass_type_in_arguments(const Arguments &arguments,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes::TypeCheckResult
|
nodes::TypeCheckResult type_same_to_expected(nodes::TypeProxy type,
|
||||||
type_same_to_expected(nodes::TypeProxy type,
|
|
||||||
const Arguments &arguments,
|
const Arguments &arguments,
|
||||||
const nodes::Node &node, SourcesManager &sources_manager,
|
const nodes::Node &node,
|
||||||
|
SourcesManager &sources_manager,
|
||||||
const std::string &message) {
|
const std::string &message) {
|
||||||
const auto &expected = arguments.get_expected();
|
const auto &expected = arguments.get_expected();
|
||||||
|
|
||||||
|
|
@ -44,7 +45,10 @@ type_same_to_expected(nodes::TypeProxy type,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use 'can cast to' (for modifiers), instead '=='
|
// 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);
|
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");
|
"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,
|
void type_check_error(const std::string &message, const nodes::Node &node,
|
||||||
SourcesManager &sources_manager) {
|
SourcesManager &sources_manager) {
|
||||||
sources_manager.get_error_log()->add_error(
|
sources_manager.get_error_log()->add_error(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue