mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-06 15:08:48 +00:00
part of constuctor typecheck (constructors for different types)
This commit is contained in:
parent
005fb6aaf3
commit
d7f1b6c377
3 changed files with 217 additions and 59 deletions
|
|
@ -177,9 +177,10 @@ inline std::optional<size_t> get_parameters_count(Type type) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
case Type::ARRAY:
|
case Type::ARRAY:
|
||||||
case Type::OPTIONAL:
|
case Type::OPTIONAL:
|
||||||
case Type::RESULT:
|
|
||||||
case Type::ERROR:
|
case Type::ERROR:
|
||||||
return 1;
|
return 1;
|
||||||
|
case Type::RESULT: // RESULT[T E] = T | Error[E]
|
||||||
|
return 2;
|
||||||
// -- basic types
|
// -- basic types
|
||||||
case Type::FLOAT:
|
case Type::FLOAT:
|
||||||
case Type::DOUBLE:
|
case Type::DOUBLE:
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,21 @@ public:
|
||||||
std::move(parameters)));
|
std::move(parameters)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypeProxy add_error_of(TypeProxy type, Node node = Node()) {
|
||||||
|
if (type.type_storage_ != this) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"TypeStorage: Can't add error of type from another type "
|
||||||
|
"storage");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<nodes::TypeProxy> parameters;
|
||||||
|
parameters.push_back(type);
|
||||||
|
|
||||||
|
return add_type(Type(Identifier(node, Identifier::SIMPLE_TYPE,
|
||||||
|
builtin::types::ERROR_IDENTIFIER),
|
||||||
|
std::move(parameters)));
|
||||||
|
}
|
||||||
|
|
||||||
nodes::TypeProxy add_container_of(std::vector<TypeProxy> &¶meters,
|
nodes::TypeProxy add_container_of(std::vector<TypeProxy> &¶meters,
|
||||||
builtin::types::Type container,
|
builtin::types::Type container,
|
||||||
Node node = Node()) {
|
Node node = Node()) {
|
||||||
|
|
|
||||||
|
|
@ -541,7 +541,8 @@ type_check_name_expression(const nodes::NameExpression &expression,
|
||||||
const Arguments &arguments) {
|
const Arguments &arguments) {
|
||||||
// TODO: constraints ??
|
// TODO: constraints ??
|
||||||
|
|
||||||
// TODO: deal with passed type
|
// --- TODO --- deal with passed type --- TODO --- (additional argument)
|
||||||
|
// 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
|
||||||
const auto maybe_function_definition = find_name_definition_handle_errors(
|
const auto maybe_function_definition = find_name_definition_handle_errors(
|
||||||
|
|
@ -665,13 +666,9 @@ type_check_constructor(const nodes::Constructor &expression,
|
||||||
|
|
||||||
// TODO: work with different parametric types: tuple, variant, ...
|
// TODO: work with different parametric types: tuple, variant, ...
|
||||||
|
|
||||||
if (expression.arguments_size() !=
|
if (expression.arguments_size() == 0) {
|
||||||
type.get()->parameters_size()) { // other, when there is passed type
|
type_check_error("Number of type constructor arguments should be > 0",
|
||||||
type_check_error(
|
expression, sources_manager);
|
||||||
"Number of type constructor arguments is different from expected (" +
|
|
||||||
std::to_string(expression.arguments_size()) + " instead of " +
|
|
||||||
std::to_string(type.get()->parameters_size()) + ")",
|
|
||||||
expression, sources_manager);
|
|
||||||
return nodes::TypeCheckResult::construct_invalid_result();
|
return nodes::TypeCheckResult::construct_invalid_result();
|
||||||
// TODO: try return correct type (constructor's type), when possible (not
|
// TODO: try return correct type (constructor's type), when possible (not
|
||||||
// generic)
|
// generic)
|
||||||
|
|
@ -681,60 +678,205 @@ type_check_constructor(const nodes::Constructor &expression,
|
||||||
|
|
||||||
const auto builtin_type = type.get()->to_builtin();
|
const auto builtin_type = type.get()->to_builtin();
|
||||||
|
|
||||||
switch (builtin_type) {
|
{ // check arguments size, ets.
|
||||||
case builtin::types::Type::TUPLE:
|
switch (builtin_type) {
|
||||||
// for tuple
|
case builtin::types::Type::TUPLE:
|
||||||
for (size_t i = 0; i < expression.arguments_size();
|
if (expression.arguments_size() != type.get()->parameters_size()) {
|
||||||
++i) { // TODO: deduce order by annotations
|
|
||||||
const auto annotation = expression.get_argument_annotation(i);
|
|
||||||
const auto expected_annotation =
|
|
||||||
type.get()->get_parameter(i)->get_annotation();
|
|
||||||
|
|
||||||
if (annotation.has_value() != expected_annotation.has_value()) {
|
|
||||||
|
|
||||||
type_check_error(
|
type_check_error(
|
||||||
"Wrong type constructor argument annotation: should be " +
|
"Number of type constructor arguments is different from expected "
|
||||||
std::string{expected_annotation.has_value()
|
"(" +
|
||||||
? *expected_annotation.value()
|
std::to_string(expression.arguments_size()) + " instead of " +
|
||||||
: "[none]"},
|
std::to_string(type.get()->parameters_size()) + ")",
|
||||||
*expression.get_argument_value(i), sources_manager);
|
expression, sources_manager);
|
||||||
|
return nodes::TypeCheckResult::construct_invalid_result();
|
||||||
|
// TODO: try return correct type (constructor's type), when possible
|
||||||
|
// (not generic)
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
if (annotation.has_value() &&
|
case builtin::types::Type::VARIANT:
|
||||||
*annotation.value() != *expected_annotation.value()) {
|
case builtin::types::Type::OPTIONAL:
|
||||||
type_check_error(
|
case builtin::types::Type::RESULT:
|
||||||
"Wrong function argument type annotation: " + *annotation.value() +
|
case builtin::types::Type::ERROR:
|
||||||
" instead of " + *expected_annotation.value(),
|
case builtin::types::Type::FUNCTION:
|
||||||
*expression.get_argument_value(i), sources_manager);
|
case builtin::types::Type::NONE:
|
||||||
|
if (expression.arguments_size() != 1) { // TODO: better to_string
|
||||||
|
type_check_error("Number of type constructor arguments should be = 1 "
|
||||||
|
"(builtin type " +
|
||||||
|
std::to_string(uint(builtin_type)) + ")",
|
||||||
|
expression, sources_manager);
|
||||||
|
return nodes::TypeCheckResult::construct_invalid_result();
|
||||||
|
// TODO: try return correct type (constructor's type), when possible
|
||||||
|
// (not generic)
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
type_check_expression(
|
default: // array, basic types
|
||||||
*expression.get_argument_value(i), sources_manager, state,
|
break;
|
||||||
Arguments{}.expect(type.get()->get_parameter_proxy(i)));
|
}
|
||||||
// TODO: do something with argument type ??
|
|
||||||
|
if (get_parameters_count(builtin_type).has_value() &&
|
||||||
|
type.get()->parameters_size() !=
|
||||||
|
get_parameters_count(builtin_type).value()) {
|
||||||
|
type_check_error("Wrong amount of parametars for builtin type",
|
||||||
|
expression, sources_manager);
|
||||||
|
|
||||||
|
return nodes::TypeCheckResult::construct_invalid_result();
|
||||||
|
// TODO: try return correct type (constructor's type), when possible (not
|
||||||
|
// generic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<size_t> chosen_variant_option; // for VARIANT
|
||||||
|
|
||||||
|
{ // check annotations
|
||||||
|
const auto check_same_annotation =
|
||||||
|
[&expression, &sources_manager](
|
||||||
|
size_t i, std::optional<const std::string *> expected_annotation,
|
||||||
|
bool log_errors) {
|
||||||
|
bool is_same = true;
|
||||||
|
|
||||||
|
const auto annotation = expression.get_argument_annotation(i);
|
||||||
|
|
||||||
|
if (annotation.has_value() != expected_annotation.has_value()) {
|
||||||
|
if (log_errors) {
|
||||||
|
type_check_error(
|
||||||
|
"Wrong type constructor argument annotation: should be " +
|
||||||
|
std::string{expected_annotation.has_value()
|
||||||
|
? *expected_annotation.value()
|
||||||
|
: "[none]"},
|
||||||
|
*expression.get_argument_value(i), sources_manager);
|
||||||
|
}
|
||||||
|
is_same = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (annotation.has_value() &&
|
||||||
|
*annotation.value() != *expected_annotation.value()) {
|
||||||
|
if (log_errors) {
|
||||||
|
type_check_error("Wrong function argument type annotation: " +
|
||||||
|
*annotation.value() + " instead of " +
|
||||||
|
*expected_annotation.value(),
|
||||||
|
*expression.get_argument_value(i),
|
||||||
|
sources_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
is_same = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_same;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto check_no_annotation =
|
||||||
|
[&expression, &sources_manager](size_t i, bool log_errors) {
|
||||||
|
if (expression.get_argument_annotation(i).has_value()) {
|
||||||
|
if (log_errors) {
|
||||||
|
type_check_error(
|
||||||
|
"Type constructor argument annotation not expected there",
|
||||||
|
*expression.get_argument_value(i), sources_manager);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (builtin_type) {
|
||||||
|
case builtin::types::Type::TUPLE:
|
||||||
|
for (size_t i = 0; i < expression.arguments_size(); ++i) {
|
||||||
|
check_same_annotation(i, type.get()->get_parameter(i)->get_annotation(),
|
||||||
|
true /*log errors*/);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case builtin::types::Type::VARIANT:
|
||||||
|
// more then one same annotation ??
|
||||||
|
for (size_t i = 0; i < type.get()->parameters_size(); ++i) {
|
||||||
|
if (check_same_annotation(
|
||||||
|
0, type.get()->get_parameter(i)->get_annotation(),
|
||||||
|
false /*do not log errors*/)) {
|
||||||
|
chosen_variant_option = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chosen_variant_option.has_value() &&
|
||||||
|
!check_no_annotation(0, false /*do not log errors*/)) {
|
||||||
|
type_check_error("Wrong type constructor argument annotation in "
|
||||||
|
"constructor of variant type",
|
||||||
|
*expression.get_argument_value(0), sources_manager);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case builtin::types::Type::ERROR: // no anotations ??
|
||||||
|
check_same_annotation(0, type.get()->get_parameter(0)->get_annotation(),
|
||||||
|
true /*log errors*/);
|
||||||
|
break;
|
||||||
|
case builtin::types::Type::OPTIONAL:
|
||||||
|
case builtin::types::Type::RESULT:
|
||||||
|
case builtin::types::Type::FUNCTION:
|
||||||
|
case builtin::types::Type::NONE:
|
||||||
|
check_no_annotation(0, true /*log errors*/);
|
||||||
|
break;
|
||||||
|
default: // array, basic types
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // type check arguments
|
||||||
|
switch (builtin_type) {
|
||||||
|
case builtin::types::Type::TUPLE:
|
||||||
|
for (size_t i = 0; i < expression.arguments_size(); ++i) {
|
||||||
|
type_check_expression(
|
||||||
|
*expression.get_argument_value(i), sources_manager, state,
|
||||||
|
Arguments{}.expect(type.get()->get_parameter_proxy(i)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case builtin::types::Type::VARIANT:
|
||||||
|
if (chosen_variant_option.has_value()) {
|
||||||
|
type_check_expression(
|
||||||
|
*expression.get_argument_value(0), sources_manager, state,
|
||||||
|
Arguments{}.expect(type.get()->get_parameter_proxy(
|
||||||
|
chosen_variant_option.value())));
|
||||||
|
} else { // TODO: error, if there is more then one possible variant in
|
||||||
|
// answer
|
||||||
|
nodes::TypeProxies possible_options;
|
||||||
|
for (size_t i = 0; i < type.get()->parameters_size(); ++i) {
|
||||||
|
possible_options.push_back(type.get()->get_parameter_proxy(i));
|
||||||
|
}
|
||||||
|
type_check_expression(*expression.get_argument_value(0),
|
||||||
|
sources_manager, state,
|
||||||
|
Arguments{}.expect(possible_options));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case builtin::types::Type::OPTIONAL:
|
||||||
|
// first parameter or NULL
|
||||||
|
type_check_expression(
|
||||||
|
*expression.get_argument_value(0), sources_manager, state,
|
||||||
|
Arguments{}.expect(
|
||||||
|
{type.get()->get_parameter_proxy(0),
|
||||||
|
sources_manager.get_type_storage()->primitive_type(
|
||||||
|
builtin::types::Type::NULL_OPTION)}));
|
||||||
|
break;
|
||||||
|
case builtin::types::Type::RESULT:
|
||||||
|
// first parameter or ERROR[second parameter]
|
||||||
|
type_check_expression(
|
||||||
|
*expression.get_argument_value(0), sources_manager, state,
|
||||||
|
Arguments{}.expect({type.get()->get_parameter_proxy(0),
|
||||||
|
sources_manager.get_type_storage()->add_error_of(
|
||||||
|
type.get()->get_parameter_proxy(1))}));
|
||||||
|
break;
|
||||||
|
case builtin::types::Type::ERROR:
|
||||||
|
// first parameter
|
||||||
|
type_check_expression(
|
||||||
|
*expression.get_argument_value(0), sources_manager, state,
|
||||||
|
Arguments{}.expect(type.get()->get_parameter_proxy(0)));
|
||||||
|
break;
|
||||||
|
case builtin::types::Type::FUNCTION:
|
||||||
|
case builtin::types::Type::NONE:
|
||||||
|
// type itself
|
||||||
|
type_check_expression(*expression.get_argument_value(0), sources_manager,
|
||||||
|
state, Arguments{}.expect(type));
|
||||||
|
break;
|
||||||
|
default: // array, basic types
|
||||||
|
type_check_error("Type can't be constructed", expression,
|
||||||
|
sources_manager);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case builtin::types::Type::VARIANT:
|
|
||||||
// TODO: expect one of types
|
|
||||||
break;
|
|
||||||
case builtin::types::Type::OPTIONAL:
|
|
||||||
// TODO: expect type (generic) or NULL
|
|
||||||
break;
|
|
||||||
case builtin::types::Type::RESULT:
|
|
||||||
// TODO: expect ERROR or type (generic)
|
|
||||||
break;
|
|
||||||
case builtin::types::Type::ERROR:
|
|
||||||
// TODO: expect type (generic)
|
|
||||||
break;
|
|
||||||
case builtin::types::Type::FUNCTION:
|
|
||||||
// TODO: built from one value (function)
|
|
||||||
break;
|
|
||||||
case builtin::types::Type::NONE:
|
|
||||||
// TODO: built from one value
|
|
||||||
break;
|
|
||||||
default: // array, basic types
|
|
||||||
type_check_error("Type can't be constructed", expression, sources_manager);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: deduce generic parts in type
|
// TODO: deduce generic parts in type
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue