mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-05 22:48:43 +00:00
type check: migrate to executor and task structure
This commit is contained in:
parent
9ee8d5c849
commit
61ab01b6fd
8 changed files with 410 additions and 371 deletions
|
|
@ -1,13 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "basic_nodes.hpp"
|
#include "basic_nodes.hpp"
|
||||||
#include "sources_manager.hpp"
|
|
||||||
#include "type_check_utils.hpp"
|
#include "type_check_utils.hpp"
|
||||||
|
|
||||||
namespace type_check {
|
namespace type_check {
|
||||||
|
|
||||||
// IN PROGRESS: modifiers ??
|
// IN PROGRESS: modifiers ??
|
||||||
Result check(const nodes::Literal &literal, SourcesManager &sources_manager,
|
|
||||||
State &state, const Arguments &arguments);
|
template <>
|
||||||
|
struct CheckTask<nodes::Literal> : public CheckTaskBase<nodes::Literal> {
|
||||||
|
using CheckTaskBase<nodes::Literal>::CheckTaskBase;
|
||||||
|
|
||||||
|
Result operator()(const nodes::Literal &literal, Arguments &&arguments);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace type_check
|
} // namespace type_check
|
||||||
|
|
|
||||||
|
|
@ -2,84 +2,143 @@
|
||||||
|
|
||||||
#include "expression_nodes.hpp"
|
#include "expression_nodes.hpp"
|
||||||
#include "type_check_utils.hpp"
|
#include "type_check_utils.hpp"
|
||||||
#include "type_nodes.hpp"
|
|
||||||
#include "utils.hpp"
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
// IN PROGRESS
|
// IN PROGRESS
|
||||||
|
|
||||||
namespace type_check {
|
namespace type_check {
|
||||||
|
|
||||||
// TODO: ???
|
template <>
|
||||||
// TODO: add State to Executor and Task
|
struct CheckTask<nodes::Expression> : public CheckTaskBase<nodes::Expression> {
|
||||||
class CheckTask : public Task {
|
using CheckTaskBase<nodes::Expression>::CheckTaskBase;
|
||||||
using Task::Task;
|
|
||||||
|
|
||||||
Result operator()(const nodes::Expression &expr,
|
Result operator()(const nodes::Expression &expr,
|
||||||
const Arguments &arguments); // check
|
const Arguments &args) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
Result check(const nodes::Expression &expression,
|
|
||||||
SourcesManager &sources_manager, State &state,
|
|
||||||
const Arguments &arguments);
|
|
||||||
|
|
||||||
// --- flow control
|
// --- flow control
|
||||||
|
|
||||||
Result check(const nodes::Match &expression, SourcesManager &sources_manager,
|
template <>
|
||||||
State &state, const Arguments &arguments);
|
struct CheckTask<nodes::Match> : public CheckTaskBase<nodes::Match> {
|
||||||
|
using CheckTaskBase<nodes::Match>::CheckTaskBase;
|
||||||
|
|
||||||
Result check(const nodes::Condition &expression,
|
Result operator()(const nodes::Match &expr, const Arguments &args) override;
|
||||||
SourcesManager &sources_manager, State &state,
|
};
|
||||||
const Arguments &arguments);
|
|
||||||
|
|
||||||
Result check(const nodes::Loop &expression, SourcesManager &sources_manager,
|
template <>
|
||||||
State &state, const Arguments &arguments);
|
struct CheckTask<nodes::Condition> : public CheckTaskBase<nodes::Condition> {
|
||||||
|
using CheckTaskBase<nodes::Condition>::CheckTaskBase;
|
||||||
|
|
||||||
|
Result operator()(const nodes::Condition &expr,
|
||||||
|
const Arguments &args) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct CheckTask<nodes::Loop> : public CheckTaskBase<nodes::Loop> {
|
||||||
|
using CheckTaskBase<nodes::Loop>::CheckTaskBase;
|
||||||
|
|
||||||
|
Result operator()(const nodes::Loop &expr, const Arguments &args) override;
|
||||||
|
};
|
||||||
|
|
||||||
// --- containers
|
// --- containers
|
||||||
|
|
||||||
Result check(const nodes::Container &expression,
|
template <>
|
||||||
SourcesManager &sources_manager, State &state,
|
struct CheckTask<nodes::Container> : public CheckTaskBase<nodes::Container> {
|
||||||
const Arguments &arguments);
|
using CheckTaskBase<nodes::Container>::CheckTaskBase;
|
||||||
|
|
||||||
|
Result CheckArray(const nodes::Container &expr, const Arguments &args);
|
||||||
|
|
||||||
|
Result CheckBlock(const nodes::Container &expr, const Arguments &args);
|
||||||
|
|
||||||
|
Result operator()(const nodes::Container &expr,
|
||||||
|
const Arguments &args) override;
|
||||||
|
};
|
||||||
|
|
||||||
// --- modifiers
|
// --- modifiers
|
||||||
|
|
||||||
Result check(const nodes::Return &expression, SourcesManager &sources_manager,
|
template <>
|
||||||
State &state, const Arguments &arguments);
|
struct CheckTask<nodes::Return> : public CheckTaskBase<nodes::Return> {
|
||||||
|
using CheckTaskBase<nodes::Return>::CheckTaskBase;
|
||||||
|
|
||||||
Result check(const nodes::NameDefinition &expression,
|
Result operator()(const nodes::Return &expr, const Arguments &args) override;
|
||||||
SourcesManager &sources_manager, State &state,
|
};
|
||||||
const Arguments &arguments);
|
|
||||||
|
|
||||||
Result check(const nodes::Access &expression, SourcesManager &sources_manager,
|
template <>
|
||||||
State &state, const Arguments &arguments);
|
struct CheckTask<nodes::NameDefinition>
|
||||||
|
: public CheckTaskBase<nodes::NameDefinition> {
|
||||||
|
using CheckTaskBase<nodes::NameDefinition>::CheckTaskBase;
|
||||||
|
|
||||||
Result check(const nodes::LoopControl &expression,
|
Result operator()(const nodes::NameDefinition &expr,
|
||||||
SourcesManager &sources_manager, State &state,
|
const Arguments &args) override;
|
||||||
const Arguments &arguments);
|
};
|
||||||
|
|
||||||
Result check(const nodes::ModifierExpression &expression,
|
template <>
|
||||||
SourcesManager &sources_manager, State &state,
|
struct CheckTask<nodes::Access> : public CheckTaskBase<nodes::Access> {
|
||||||
const Arguments &arguments);
|
using CheckTaskBase<nodes::Access>::CheckTaskBase;
|
||||||
|
|
||||||
|
Result CheckArrayAccess(const nodes::Access &expr, const Arguments &args);
|
||||||
|
|
||||||
|
Result CheckTupleAccess(const nodes::Access &expr, const Arguments &args);
|
||||||
|
|
||||||
|
Result operator()(const nodes::Access &expr, const Arguments &args) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct CheckTask<nodes::LoopControl>
|
||||||
|
: public CheckTaskBase<nodes::LoopControl> {
|
||||||
|
using CheckTaskBase<nodes::LoopControl>::CheckTaskBase;
|
||||||
|
|
||||||
|
Result operator()(const nodes::LoopControl &expr,
|
||||||
|
const Arguments &args) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct CheckTask<nodes::ModifierExpression>
|
||||||
|
: public CheckTaskBase<nodes::ModifierExpression> {
|
||||||
|
using CheckTaskBase<nodes::ModifierExpression>::CheckTaskBase;
|
||||||
|
|
||||||
|
Result operator()(const nodes::ModifierExpression &expr,
|
||||||
|
const Arguments &args) override;
|
||||||
|
};
|
||||||
|
|
||||||
// --- other
|
// --- other
|
||||||
|
|
||||||
Result check(const nodes::NameExpression &expression,
|
template <>
|
||||||
SourcesManager &sources_manager, State &state,
|
struct CheckTask<nodes::NameExpression>
|
||||||
const Arguments &arguments);
|
: public CheckTaskBase<nodes::NameExpression> {
|
||||||
|
using CheckTaskBase<nodes::NameExpression>::CheckTaskBase;
|
||||||
|
|
||||||
Result check(const nodes::Constructor &expression,
|
Result operator()(const nodes::NameExpression &expr,
|
||||||
SourcesManager &sources_manager, State &state,
|
const Arguments &args) override;
|
||||||
const Arguments &arguments);
|
};
|
||||||
|
|
||||||
Result check(const nodes::Lambda &expression, SourcesManager &sources_manager,
|
template <>
|
||||||
State &state, const Arguments &arguments);
|
struct CheckTask<nodes::Constructor>
|
||||||
|
: public CheckTaskBase<nodes::Constructor> {
|
||||||
|
using CheckTaskBase<nodes::Constructor>::CheckTaskBase;
|
||||||
|
|
||||||
Result check(const nodes::Extra &expression, SourcesManager &sources_manager,
|
Result operator()(const nodes::Constructor &expr,
|
||||||
State &state, const Arguments &arguments);
|
const Arguments &args) override;
|
||||||
|
};
|
||||||
|
|
||||||
Result check(const nodes::EmptyLines &expression,
|
template <>
|
||||||
SourcesManager &sources_manager, State &state,
|
struct CheckTask<nodes::Lambda> : public CheckTaskBase<nodes::Lambda> {
|
||||||
const Arguments &arguments);
|
using CheckTaskBase<nodes::Lambda>::CheckTaskBase;
|
||||||
|
|
||||||
|
Result operator()(const nodes::Lambda &expr, const Arguments &args) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct CheckTask<nodes::Extra> : public CheckTaskBase<nodes::Extra> {
|
||||||
|
using CheckTaskBase<nodes::Extra>::CheckTaskBase;
|
||||||
|
|
||||||
|
Result operator()(const nodes::Extra &expr, const Arguments &args) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct CheckTask<nodes::EmptyLines> : public CheckTaskBase<nodes::EmptyLines> {
|
||||||
|
using CheckTaskBase<nodes::EmptyLines>::CheckTaskBase;
|
||||||
|
|
||||||
|
Result operator()(const nodes::EmptyLines &expr,
|
||||||
|
const Arguments &args) override;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace type_check
|
} // namespace type_check
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,6 @@
|
||||||
|
|
||||||
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 {
|
||||||
|
|
@ -164,20 +159,27 @@ private:
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
using Exprs = nodes::ExpressionStorage;
|
||||||
|
using Types = nodes::TypeStorage;
|
||||||
|
using Names = names::NameTree;
|
||||||
|
|
||||||
|
using Executor = utils::Executor<Exprs, Types, Names, State>;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
class Arguments {
|
class Arguments {
|
||||||
public:
|
public:
|
||||||
Arguments() = default;
|
Arguments() = default;
|
||||||
|
|
||||||
Arguments expect_builtin(builtin::Type type, Executor &executor) const {
|
Arguments expect_builtin(builtin::Type type, Executor &executor) const {
|
||||||
Arguments copy(*this);
|
Arguments copy(*this);
|
||||||
copy.expected_types_ = {
|
copy.expected_types_ = {executor.state<Types>().primitive(type)};
|
||||||
executor.state<nodes::TypeStorage>().primitive(type)};
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
Arguments pass_builtin(builtin::Type type, Executor &executor) const {
|
Arguments pass_builtin(builtin::Type type, Executor &executor) const {
|
||||||
Arguments copy(*this);
|
Arguments copy(*this);
|
||||||
copy.passed_type_ = executor.state<nodes::TypeStorage>().primitive(type);
|
copy.passed_type_ = executor.state<Types>().primitive(type);
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -340,4 +342,21 @@ nodes::MaybeTypeProxy get_field_type_by_name(nodes::TypeProxy type,
|
||||||
void type_check_error(const std::string &message, const nodes::Node &node,
|
void type_check_error(const std::string &message, const nodes::Node &node,
|
||||||
Executor &executor, bool handle_error = true);
|
Executor &executor, bool handle_error = true);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
template <typename N> using Task = utils::Task<Executor, Result, Arguments, N>;
|
||||||
|
|
||||||
|
template <typename N> struct CheckTask {
|
||||||
|
static_assert(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename N> struct CheckTaskBase : public Task<N> {
|
||||||
|
using Task<N>::Task;
|
||||||
|
|
||||||
|
template <typename OtherN> Result Run(const OtherN &node, const Arguments &args) {
|
||||||
|
CheckTask<OtherN> task(this->executor);
|
||||||
|
return task(node, args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace type_check
|
} // namespace type_check
|
||||||
|
|
|
||||||
|
|
@ -3,44 +3,44 @@
|
||||||
namespace type_check {
|
namespace type_check {
|
||||||
|
|
||||||
nodes::TypeProxy get_literal_type(const nodes::Literal &literal,
|
nodes::TypeProxy get_literal_type(const nodes::Literal &literal,
|
||||||
SourcesManager &sources_manager) {
|
Executor &executor) {
|
||||||
switch (literal.get_any()->index()) {
|
switch (literal.get_any()->index()) {
|
||||||
case 0: // float
|
case 0: // float
|
||||||
return sources_manager.types()->primitive(builtin::Type::FLOAT);
|
return executor.state<Types>().primitive(builtin::Type::FLOAT);
|
||||||
case 1: // double
|
case 1: // double
|
||||||
return sources_manager.types()->primitive(builtin::Type::DOUBLE);
|
return executor.state<Types>().primitive(builtin::Type::DOUBLE);
|
||||||
case 2: // int32_t
|
case 2: // int32_t
|
||||||
return sources_manager.types()->primitive(builtin::Type::INT);
|
return executor.state<Types>().primitive(builtin::Type::INT);
|
||||||
case 3: // int64_t
|
case 3: // int64_t
|
||||||
return sources_manager.types()->primitive(builtin::Type::LONG);
|
return executor.state<Types>().primitive(builtin::Type::LONG);
|
||||||
case 4: // size_t
|
case 4: // size_t
|
||||||
return sources_manager.types()->primitive(builtin::Type::INDEX);
|
return executor.state<Types>().primitive(builtin::Type::INDEX);
|
||||||
case 5: // std::string
|
case 5: // std::string
|
||||||
return sources_manager.types()->add_array_of(
|
return executor.state<Types>().add_array_of(
|
||||||
sources_manager.types()->primitive(builtin::Type::CHAR));
|
executor.state<Types>().primitive(builtin::Type::CHAR));
|
||||||
case 6: // unicode_string
|
case 6: // unicode_string
|
||||||
return sources_manager.types()->add_array_of(
|
return executor.state<Types>().add_array_of(
|
||||||
sources_manager.types()->primitive(builtin::Type::UNICODE));
|
executor.state<Types>().primitive(builtin::Type::UNICODE));
|
||||||
case 7: // char
|
case 7: // char
|
||||||
return sources_manager.types()->primitive(builtin::Type::CHAR);
|
return executor.state<Types>().primitive(builtin::Type::CHAR);
|
||||||
case 8: // unicode
|
case 8: // unicode
|
||||||
return sources_manager.types()->primitive(builtin::Type::UNICODE);
|
return executor.state<Types>().primitive(builtin::Type::UNICODE);
|
||||||
case 9: // bool
|
case 9: // bool
|
||||||
return sources_manager.types()->primitive(builtin::Type::BOOL);
|
return executor.state<Types>().primitive(builtin::Type::BOOL);
|
||||||
case 10: // unit
|
case 10: // unit
|
||||||
return sources_manager.types()->primitive(builtin::Type::UNIT);
|
return executor.state<Types>().primitive(builtin::Type::UNIT);
|
||||||
case 11: // null
|
case 11: // null
|
||||||
return sources_manager.types()->primitive(builtin::Type::NULL_OPTION);
|
return executor.state<Types>().primitive(builtin::Type::NULL_OPTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
error_handling::handle_general_error("Unreachable");
|
utils::Assert(true, "Unreachable");
|
||||||
exit(1); // unreachable
|
exit(1); // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
Result check(const nodes::Literal &literal, SourcesManager &sources_manager,
|
Result CheckTask<nodes::Literal>::operator()(const nodes::Literal &literal,
|
||||||
State &, const Arguments &arguments) {
|
Arguments &&arguments) {
|
||||||
auto const type = get_literal_type(literal, sources_manager);
|
auto const type = get_literal_type(literal, this->executor);
|
||||||
return type_same_to_expected(type, arguments, literal, sources_manager);
|
return type_same_to_expected(type, arguments, literal, this->executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace type_check
|
} // namespace type_check
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
#include "expression_type_check.hpp"
|
#include "expression_type_check.hpp"
|
||||||
#include "basic_nodes.hpp"
|
#include "basic_nodes.hpp"
|
||||||
#include "basic_type_check.hpp"
|
|
||||||
#include "builtin_types.hpp"
|
#include "builtin_types.hpp"
|
||||||
#include "sources_manager.hpp"
|
|
||||||
#include "type_nodes.hpp"
|
#include "type_nodes.hpp"
|
||||||
#include "utils.hpp"
|
|
||||||
|
|
||||||
// IN PROGRESS
|
// IN PROGRESS
|
||||||
|
|
||||||
|
|
@ -13,26 +10,24 @@
|
||||||
|
|
||||||
namespace type_check {
|
namespace type_check {
|
||||||
|
|
||||||
Result check(const nodes::Expression &expression,
|
Result CheckTask<nodes::Expression>::operator()(const nodes::Expression &expr,
|
||||||
SourcesManager &sources_manager, State &state,
|
const Arguments &arguments) {
|
||||||
const Arguments &arguments) {
|
|
||||||
return std::visit(
|
return std::visit(
|
||||||
[&sources_manager, &state, &arguments](const auto &arg) -> Result {
|
[this, &arguments](const auto &node) -> Result {
|
||||||
return check(arg, sources_manager, state, arguments);
|
return Run(node, arguments);
|
||||||
},
|
},
|
||||||
*expression.get_any());
|
*expr.get_any());
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- flow control
|
// --- flow control
|
||||||
|
|
||||||
Result check(const nodes::Match &expression, SourcesManager &sources_manager,
|
Result CheckTask<nodes::Match>::operator()(const nodes::Match &expr,
|
||||||
State &state, const Arguments &arguments) {
|
const Arguments &args) {
|
||||||
Result value_result =
|
Result value_result = Run(*expr.get_value(), {});
|
||||||
check(*expression.get_value(), sources_manager, state, Arguments{});
|
|
||||||
|
|
||||||
// x :=/=: ...
|
// x :=/=: ...
|
||||||
if (value_result.is_invalid()) {
|
if (value_result.is_invalid()) {
|
||||||
type_check_error("Match value is invalid", expression, sources_manager);
|
type_check_error("Match value is invalid", expr, executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeResult expression_result;
|
MaybeResult expression_result;
|
||||||
|
|
@ -40,32 +35,31 @@ Result check(const nodes::Match &expression, SourcesManager &sources_manager,
|
||||||
bool at_least_one_case_with_expression = false;
|
bool at_least_one_case_with_expression = false;
|
||||||
bool at_least_one_case_without_expression = false;
|
bool at_least_one_case_without_expression = false;
|
||||||
|
|
||||||
for (size_t i = 0; i < expression.cases_size(); ++i) {
|
for (size_t i = 0; i < expr.cases_size(); ++i) {
|
||||||
const nodes::Match::Case *current_case = expression.get_case(i);
|
const nodes::Match::Case *current_case = expr.get_case(i);
|
||||||
|
|
||||||
// :=/=: x ...
|
// :=/=: x ...
|
||||||
check(*current_case->get_value(), sources_manager, state,
|
Run(*current_case->get_value(),
|
||||||
Arguments{}
|
Arguments{}
|
||||||
.expect_builtin(builtin::Type::BOOL, sources_manager)
|
.expect_builtin(builtin::Type::BOOL, executor)
|
||||||
.pass(value_result.is_invalid()
|
.pass(value_result.is_invalid() ? nodes::MaybeTypeProxy{}
|
||||||
? nodes::MaybeTypeProxy{}
|
: expression_result.value().get()));
|
||||||
: expression_result.value().get()));
|
|
||||||
// TODO: use type modifiers ??
|
// TODO: use type modifiers ??
|
||||||
|
|
||||||
// ... ?? x ...
|
// ... ?? x ...
|
||||||
if (current_case->get_condition().has_value()) {
|
if (current_case->get_condition().has_value()) {
|
||||||
check(*current_case->get_condition().value(), sources_manager, state,
|
Run(*current_case->get_condition().value(),
|
||||||
Arguments{}.expect_builtin(builtin::Type::BOOL, sources_manager));
|
Arguments{}.expect_builtin(builtin::Type::BOOL, executor));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... -> x
|
// ... -> x
|
||||||
if (current_case->get_expression().has_value()) {
|
if (current_case->get_expression().has_value()) {
|
||||||
at_least_one_case_with_expression = true;
|
at_least_one_case_with_expression = true;
|
||||||
Result case_result =
|
Result case_result =
|
||||||
check(*current_case->get_condition().value(), sources_manager, state,
|
Run(*current_case->get_condition().value(),
|
||||||
Arguments{}.expect(expression_result.has_value()
|
Arguments{}.expect(expression_result.has_value()
|
||||||
? expression_result.value().get()
|
? expression_result.value().get()
|
||||||
: nodes::MaybeTypeProxy{}));
|
: nodes::MaybeTypeProxy{}));
|
||||||
|
|
||||||
if (!expression_result.has_value() && !case_result.is_invalid()) {
|
if (!expression_result.has_value() && !case_result.is_invalid()) {
|
||||||
expression_result = std::move(case_result);
|
expression_result = std::move(case_result);
|
||||||
|
|
@ -78,76 +72,73 @@ Result check(const nodes::Match &expression, SourcesManager &sources_manager,
|
||||||
if (at_least_one_case_with_expression &&
|
if (at_least_one_case_with_expression &&
|
||||||
at_least_one_case_without_expression) {
|
at_least_one_case_without_expression) {
|
||||||
type_check_error(
|
type_check_error(
|
||||||
"All cases should be with or without expression at the same time",
|
"All cases should be with or without expression at the same time", expr,
|
||||||
expression, sources_manager);
|
executor);
|
||||||
expression_result = Result::invalid();
|
expression_result = Result::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!expression_result.has_value()) {
|
if (!expression_result.has_value()) {
|
||||||
expression_result =
|
expression_result = Result{state<Types>().primitive(builtin::Type::UNIT)};
|
||||||
Result{sources_manager.types()->primitive(builtin::Type::UNIT)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return type_check_from_arguments(
|
return type_check_from_arguments(
|
||||||
sources_manager.types()->add_array_of(expression_result.value().get()),
|
state<Types>().add_array_of(expression_result.value().get()), args, expr,
|
||||||
arguments, expression, sources_manager);
|
executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result check(const nodes::Condition &expression,
|
Result CheckTask<nodes::Condition>::operator()(const nodes::Condition &expr,
|
||||||
SourcesManager &sources_manager, State &state,
|
const Arguments &args) {
|
||||||
const Arguments &arguments) {
|
|
||||||
MaybeResult expression_result;
|
MaybeResult expression_result;
|
||||||
|
|
||||||
for (size_t i = 0; i < expression.cases_size(); ++i) {
|
for (size_t i = 0; i < expr.cases_size(); ++i) {
|
||||||
check(*expression.get_case(i).first, sources_manager, state,
|
Run(*expr.get_case(i).first,
|
||||||
Arguments{}.expect_builtin(builtin::Type::BOOL, sources_manager));
|
Arguments{}.expect_builtin(builtin::Type::BOOL, executor));
|
||||||
|
|
||||||
Result case_result =
|
Result case_result =
|
||||||
check(*expression.get_case(i).first, sources_manager, state,
|
Run(*expr.get_case(i).first,
|
||||||
Arguments{}.expect(expression_result.has_value()
|
Arguments{}.expect(expression_result.has_value()
|
||||||
? expression_result.value().get()
|
? expression_result.value().get()
|
||||||
: nodes::MaybeTypeProxy{}));
|
: nodes::MaybeTypeProxy{}));
|
||||||
|
|
||||||
if (!expression_result.has_value() && !case_result.is_invalid()) {
|
if (!expression_result.has_value() && !case_result.is_invalid()) {
|
||||||
expression_result = std::move(case_result);
|
expression_result = std::move(case_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expression.get_else_case().has_value()) {
|
if (expr.get_else_case().has_value()) {
|
||||||
check(*expression.get_else_case().value(), sources_manager, state,
|
Run(*expr.get_else_case().value(),
|
||||||
Arguments{}.expect(expression_result.has_value()
|
Arguments{}.expect(expression_result.has_value()
|
||||||
? expression_result.value().get()
|
? expression_result.value().get()
|
||||||
: nodes::MaybeTypeProxy{}));
|
: nodes::MaybeTypeProxy{}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!expression_result.has_value()) {
|
if (!expression_result.has_value()) {
|
||||||
type_check_error("There should be at least one case in if statement",
|
type_check_error("There should be at least one case in if statement", expr,
|
||||||
expression, sources_manager);
|
executor);
|
||||||
expression_result = Result::invalid();
|
expression_result = Result::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
return type_check_from_arguments(
|
return type_check_from_arguments(
|
||||||
sources_manager.types()->add_array_of(expression_result.value().get()),
|
state<Types>().add_array_of(expression_result.value().get()), args, expr,
|
||||||
arguments, expression, sources_manager);
|
executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result check(const nodes::Loop &expression, SourcesManager &sources_manager,
|
Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
|
||||||
State &state, const Arguments &arguments) {
|
const Arguments &args) {
|
||||||
// TODO: ranges ??
|
// TODO: ranges ??
|
||||||
|
|
||||||
MaybeResult interval_result;
|
MaybeResult interval_result;
|
||||||
|
|
||||||
MaybeResult variable_result;
|
MaybeResult variable_result;
|
||||||
|
|
||||||
Result expression_result =
|
Result expression_result = Run(*expr.get_expression(), {});
|
||||||
check(*expression.get_expression(), sources_manager, state, Arguments{});
|
|
||||||
|
|
||||||
switch (expression.get_type()) {
|
switch (expr.get_type()) {
|
||||||
case nodes::Loop::LOOP: // infinity loop, no params
|
case nodes::Loop::LOOP: // infinity loop, no params
|
||||||
break;
|
break;
|
||||||
case nodes::Loop::WHILE:
|
case nodes::Loop::WHILE:
|
||||||
check(*expression.get_condition().value(), sources_manager, state,
|
Run(*expr.get_condition().value(),
|
||||||
Arguments{}.expect_builtin(builtin::Type::BOOL, sources_manager));
|
Arguments{}.expect_builtin(builtin::Type::BOOL, executor));
|
||||||
|
|
||||||
// --- type check is independent from loop itself ---
|
// --- type check is independent from loop itself ---
|
||||||
// if (condition_result.value().is_invalid()) {
|
// if (condition_result.value().is_invalid()) {
|
||||||
|
|
@ -157,9 +148,9 @@ Result check(const nodes::Loop &expression, SourcesManager &sources_manager,
|
||||||
break;
|
break;
|
||||||
case nodes::Loop::FOR:
|
case nodes::Loop::FOR:
|
||||||
// TODO: expect range ??
|
// TODO: expect range ??
|
||||||
interval_result = check(
|
interval_result =
|
||||||
*expression.get_interval().value(), sources_manager, state,
|
Run(*expr.get_interval().value(),
|
||||||
Arguments{}.expect_builtin(builtin::Type::ARRAY, sources_manager));
|
Arguments{}.expect_builtin(builtin::Type::ARRAY, executor));
|
||||||
|
|
||||||
if (interval_result.value().is_invalid()) {
|
if (interval_result.value().is_invalid()) {
|
||||||
// --- type check is independent from loop itself ---
|
// --- type check is independent from loop itself ---
|
||||||
|
|
@ -168,9 +159,9 @@ Result check(const nodes::Loop &expression, SourcesManager &sources_manager,
|
||||||
}
|
}
|
||||||
|
|
||||||
variable_result =
|
variable_result =
|
||||||
check(*expression.get_variable().value(), sources_manager, state,
|
Run(*expr.get_variable().value(),
|
||||||
Arguments{}.expect(
|
Arguments{}.expect(
|
||||||
interval_result.value().get().get()->get_parameter_proxy(0)));
|
interval_result.value().get().get()->get_parameter_proxy(0)));
|
||||||
|
|
||||||
// --- type check is independent from loop itself ---
|
// --- type check is independent from loop itself ---
|
||||||
// if (variable_result.value().is_invalid()) {
|
// if (variable_result.value().is_invalid()) {
|
||||||
|
|
@ -186,28 +177,26 @@ Result check(const nodes::Loop &expression, SourcesManager &sources_manager,
|
||||||
// TODO: modifier checks ??, modifiers ??
|
// TODO: modifier checks ??, modifiers ??
|
||||||
|
|
||||||
return type_check_from_arguments(
|
return type_check_from_arguments(
|
||||||
sources_manager.types()->add_array_of(expression_result.get()), arguments,
|
state<Types>().add_array_of(expression_result.get()), args, expr,
|
||||||
expression, sources_manager);
|
executor);
|
||||||
} // IN PROGRESS
|
} // IN PROGRESS
|
||||||
|
|
||||||
// --- containers
|
// --- containers
|
||||||
|
|
||||||
Result type_check_array(const nodes::Container &expression,
|
Result CheckTask<nodes::Container>::CheckArray(const nodes::Container &expr,
|
||||||
SourcesManager &sources_manager, State &state,
|
const Arguments &args) {
|
||||||
const Arguments &arguments) {
|
|
||||||
MaybeResult last_expression_result;
|
MaybeResult last_expression_result;
|
||||||
|
|
||||||
for (size_t i = 0; i < expression.expressions_size(); ++i) {
|
for (size_t i = 0; i < expr.expressions_size(); ++i) {
|
||||||
// elements should have same type, but type is not expected
|
// elements should have same type, but type is not expected
|
||||||
auto expression_result = check(*expression.get_expression(i),
|
auto expression_result = Run(*expr.get_expression(i), {});
|
||||||
sources_manager, state, Arguments{});
|
|
||||||
|
|
||||||
if (!last_expression_result.has_value()) {
|
if (!last_expression_result.has_value()) {
|
||||||
last_expression_result = expression_result;
|
last_expression_result = expression_result;
|
||||||
} else {
|
} else {
|
||||||
if (last_expression_result.value().get() != expression_result.get()) {
|
if (last_expression_result.value().get() != expression_result.get()) {
|
||||||
type_check_error("Elements in array should have same type",
|
type_check_error("Elements in array should have same type",
|
||||||
*expression.get_expression(i), sources_manager);
|
*expr.get_expression(i), executor);
|
||||||
// return TypeCheckResult::construct_invalid_result(); // max
|
// return TypeCheckResult::construct_invalid_result(); // max
|
||||||
// possible checks, so no return
|
// possible checks, so no return
|
||||||
}
|
}
|
||||||
|
|
@ -215,129 +204,121 @@ Result type_check_array(const nodes::Container &expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!last_expression_result.has_value()) {
|
if (!last_expression_result.has_value()) {
|
||||||
type_check_error("Array with zero elements", expression, sources_manager);
|
type_check_error("Array with zero elements", expr, executor);
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
return type_check_from_arguments(sources_manager.types()->add_array_of(
|
return type_check_from_arguments(
|
||||||
last_expression_result.value().get()),
|
state<Types>().add_array_of(last_expression_result.value().get()), args,
|
||||||
arguments, expression, sources_manager);
|
expr, executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result type_check_block(const nodes::Container &expression,
|
Result CheckTask<nodes::Container>::CheckBlock(const nodes::Container &expr,
|
||||||
SourcesManager &sources_manager, State &state,
|
const Arguments &args) {
|
||||||
const Arguments &arguments) {
|
|
||||||
nodes::MaybeTypeProxy context_exit_type;
|
nodes::MaybeTypeProxy context_exit_type;
|
||||||
|
|
||||||
{
|
{
|
||||||
ContextHolder context_holder(
|
ContextHolder context_holder(
|
||||||
state, expression, *sources_manager.errors(),
|
state<State>(), expr,
|
||||||
&context_exit_type); // TODO: is brought type returned
|
&context_exit_type); // TODO: is brought type returned
|
||||||
|
|
||||||
for (size_t i = 0; i < expression.expressions_size(); ++i) {
|
for (size_t i = 0; i < expr.expressions_size(); ++i) {
|
||||||
// result types in block are discarded
|
// result types in block are discarded
|
||||||
check(*expression.get_expression(i), sources_manager, state, Arguments{});
|
Run(*expr.get_expression(i), {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result block_brought_type =
|
Result block_brought_type =
|
||||||
context_exit_type.has_value()
|
context_exit_type.has_value()
|
||||||
? Result(context_exit_type.value())
|
? Result(context_exit_type.value())
|
||||||
: Result(sources_manager.types()->primitive(builtin::Type::UNIT));
|
: Result(state<Types>().primitive(builtin::Type::UNIT));
|
||||||
|
|
||||||
return type_check_from_arguments(
|
return type_check_from_arguments(
|
||||||
sources_manager.types()->add_array_of(block_brought_type.get()),
|
state<Types>().add_array_of(block_brought_type.get()), args, expr,
|
||||||
arguments, expression, sources_manager);
|
executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result check(const nodes::Container &expression,
|
Result CheckTask<nodes::Container>::operator()(const nodes::Container &expr,
|
||||||
SourcesManager &sources_manager, State &state,
|
const Arguments &args) {
|
||||||
const Arguments &arguments) {
|
switch (expr.get_type()) {
|
||||||
switch (expression.get_type()) {
|
|
||||||
case nodes::Container::ARRAY:
|
case nodes::Container::ARRAY:
|
||||||
return type_check_array(expression, sources_manager, state, arguments);
|
return CheckArray(expr, args);
|
||||||
case nodes::Container::BLOCK:
|
case nodes::Container::BLOCK:
|
||||||
return type_check_block(expression, sources_manager, state, arguments);
|
return CheckBlock(expr, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- modifiers
|
// --- modifiers
|
||||||
|
|
||||||
Result check(const nodes::Return &expression, SourcesManager &sources_manager,
|
Result CheckTask<nodes::Return>::operator()(const nodes::Return &expr,
|
||||||
State &state, const Arguments &arguments) {
|
const Arguments &args) {
|
||||||
auto returned_result =
|
auto returned_result = Run(*expr.get_expression(), {});
|
||||||
check(*expression.get_expression(), sources_manager, state, Arguments{});
|
|
||||||
|
|
||||||
if (returned_result.is_invalid()) {
|
if (returned_result.is_invalid()) {
|
||||||
return returned_result;
|
return returned_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (expression.get_type()) {
|
switch (expr.get_type()) {
|
||||||
case nodes::Return::BRING:
|
case nodes::Return::BRING:
|
||||||
if (state.bring_type(returned_result.get())) {
|
if (state<State>().bring_type(returned_result.get())) {
|
||||||
type_check_error("Different brought type to current one", expression,
|
type_check_error("Different brought type to current one", expr, executor);
|
||||||
sources_manager);
|
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case nodes::Return::RETURN:
|
case nodes::Return::RETURN:
|
||||||
if (!state.return_type(returned_result.get())) {
|
if (!state<State>().return_type(returned_result.get())) {
|
||||||
type_check_error("Different returned type to current one", expression,
|
type_check_error("Different returned type to current one", expr,
|
||||||
sources_manager);
|
executor);
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type_check_from_arguments(
|
return type_check_from_arguments(
|
||||||
sources_manager.types()->primitive(builtin::Type::UNIT), arguments,
|
state<Types>().primitive(builtin::Type::UNIT), args, expr, executor);
|
||||||
expression, sources_manager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: warning if name is same to package prefix, function prefix, etc. ??
|
// TODO: warning if name is same to package prefix, function prefix, etc. ??
|
||||||
Result check(const nodes::NameDefinition &expression,
|
Result
|
||||||
SourcesManager &sources_manager, State &state,
|
CheckTask<nodes::NameDefinition>::operator()(const nodes::NameDefinition &expr,
|
||||||
const Arguments &arguments) {
|
const Arguments &args) {
|
||||||
if (!arguments.get_passed().has_value()) {
|
if (!args.get_passed().has_value()) {
|
||||||
type_check_error("Can't deduce type of new variable from context",
|
type_check_error("Can't deduce type of new variable from context", expr,
|
||||||
expression, sources_manager);
|
executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assigned type shold be one of <-, <>, -- (can't be ->)
|
// assigned type shold be one of <-, <>, -- (can't be ->)
|
||||||
const auto variable_type = arguments.get_passed().value();
|
const auto variable_type = args.get_passed().value();
|
||||||
if (nodes::utils::modifier_contains_OUT(
|
if (nodes::utils::modifier_contains_OUT(
|
||||||
variable_type.get()
|
variable_type.get()
|
||||||
->get_modifier())) { // TODO: utils::modifier_contains_OUT
|
->get_modifier())) { // TODO: utils::modifier_contains_OUT
|
||||||
type_check_error("Variable can't be assigned from out (->) value",
|
type_check_error("Variable can't be assigned from out (->) value", expr,
|
||||||
expression, sources_manager);
|
executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// variable accessible by reference by default ??
|
// variable accessible by reference by default ??
|
||||||
sources_manager.types()->add_modification_of(variable_type,
|
state<Types>().add_modification_of(variable_type, nodes::Modifier::REF);
|
||||||
nodes::Modifier::REF);
|
|
||||||
|
|
||||||
if (!state.insert_variable(*expression.get_name()->get(), variable_type,
|
if (!state<State>().insert_variable(*expr.get_name()->get(), variable_type,
|
||||||
expression.get_modifier())) {
|
expr.get_modifier())) {
|
||||||
type_check_error("Variable is already defined in this context", expression,
|
type_check_error("Variable is already defined in this context", expr,
|
||||||
sources_manager);
|
executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return BOOL as any := / =: expression
|
// Return BOOL as any := / =: expression
|
||||||
return type_check_from_arguments(
|
return type_check_from_arguments(
|
||||||
sources_manager.types()->primitive(builtin::Type::BOOL), arguments,
|
state<Types>().primitive(builtin::Type::BOOL), args, expr, executor);
|
||||||
expression, sources_manager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result type_check_array_access(const nodes::Access &expression,
|
Result CheckTask<nodes::Access>::CheckArrayAccess(const nodes::Access &expr,
|
||||||
SourcesManager &sources_manager, State &state,
|
const Arguments &args) {
|
||||||
const Arguments &arguments) {
|
|
||||||
auto index_result =
|
auto index_result =
|
||||||
check(*expression.get_index(), sources_manager, state,
|
Run(*expr.get_index(),
|
||||||
Arguments{}.expect_builtin(builtin::Type::INDEX, sources_manager));
|
Arguments{}.expect_builtin(builtin::Type::INDEX, executor));
|
||||||
|
|
||||||
auto value_result =
|
auto value_result =
|
||||||
check(*expression.get_value(), sources_manager, state,
|
Run(*expr.get_value(),
|
||||||
Arguments{}.expect_builtin(builtin::Type::ARRAY, sources_manager));
|
Arguments{}.expect_builtin(builtin::Type::ARRAY, executor));
|
||||||
|
|
||||||
if (index_result.is_invalid()) {
|
if (index_result.is_invalid()) {
|
||||||
return index_result;
|
return index_result;
|
||||||
|
|
@ -350,22 +331,20 @@ Result type_check_array_access(const nodes::Access &expression,
|
||||||
// TODO: modifier checks ??
|
// TODO: modifier checks ??
|
||||||
|
|
||||||
return type_check_from_arguments(
|
return type_check_from_arguments(
|
||||||
value_result.get().get()->get_parameter_proxy(0), arguments, expression,
|
value_result.get().get()->get_parameter_proxy(0), args, expr, executor);
|
||||||
sources_manager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result type_check_tuple_access(const nodes::Access &expression,
|
Result CheckTask<nodes::Access>::CheckTupleAccess(const nodes::Access &expr,
|
||||||
SourcesManager &sources_manager, State &state,
|
const Arguments &args) {
|
||||||
const Arguments &arguments) {
|
|
||||||
auto value_result =
|
auto value_result =
|
||||||
check(*expression.get_value(), sources_manager, state,
|
Run(*expr.get_value(),
|
||||||
Arguments{}.expect_builtin(builtin::Type::TUPLE, sources_manager));
|
Arguments{}.expect_builtin(builtin::Type::TUPLE, executor));
|
||||||
|
|
||||||
if (value_result.is_invalid()) {
|
if (value_result.is_invalid()) {
|
||||||
return value_result;
|
return value_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t index = *expression.get_index()
|
size_t index = *expr.get_index()
|
||||||
->get<nodes::Literal>()
|
->get<nodes::Literal>()
|
||||||
.value()
|
.value()
|
||||||
->get<size_t>() // Index type
|
->get<size_t>() // Index type
|
||||||
|
|
@ -374,46 +353,40 @@ Result type_check_tuple_access(const nodes::Access &expression,
|
||||||
// TODO: modifier checks ??
|
// TODO: modifier checks ??
|
||||||
|
|
||||||
return type_check_from_arguments(
|
return type_check_from_arguments(
|
||||||
value_result.get().get()->get_parameter_proxy(index), arguments,
|
value_result.get().get()->get_parameter_proxy(index), args, expr,
|
||||||
expression, sources_manager);
|
executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result check(const nodes::Access &expression, SourcesManager &sources_manager,
|
Result CheckTask<nodes::Access>::operator()(const nodes::Access &expr,
|
||||||
State &state, const Arguments &arguments) {
|
const Arguments &args) {
|
||||||
switch (expression.get_type()) {
|
switch (expr.get_type()) {
|
||||||
case nodes::Access::ARRAY:
|
case nodes::Access::ARRAY:
|
||||||
return type_check_array_access(expression, sources_manager, state,
|
return CheckArrayAccess(expr, args);
|
||||||
arguments);
|
|
||||||
case nodes::Access::TUPLE:
|
case nodes::Access::TUPLE:
|
||||||
return type_check_tuple_access(expression, sources_manager, state,
|
return CheckTupleAccess(expr, args);
|
||||||
arguments);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result check(const nodes::LoopControl &expression,
|
Result CheckTask<nodes::LoopControl>::operator()(const nodes::LoopControl &expr,
|
||||||
SourcesManager &sources_manager, State &,
|
const Arguments &args) {
|
||||||
const Arguments &arguments) {
|
|
||||||
return type_check_from_arguments(
|
return type_check_from_arguments(
|
||||||
sources_manager.types()->primitive(builtin::Type::UNIT), arguments,
|
state<Types>().primitive(builtin::Type::UNIT), args, expr, executor);
|
||||||
expression, sources_manager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result check(const nodes::ModifierExpression &expression,
|
Result CheckTask<nodes::ModifierExpression>::operator()(
|
||||||
SourcesManager &sources_manager, State &state,
|
const nodes::ModifierExpression &expr, const Arguments &args) {
|
||||||
const Arguments &arguments) {
|
auto modified_result = Run(*expr.get_expression(), {});
|
||||||
auto modified_result =
|
|
||||||
check(*expression.get_expression(), sources_manager, state, Arguments{});
|
|
||||||
|
|
||||||
if (modified_result.is_invalid()) {
|
if (modified_result.is_invalid()) {
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodes::utils::is_suffix_modifier(
|
if (nodes::utils::is_suffix_modifier(
|
||||||
expression.get_modifier())) { // optional, result
|
expr.get_modifier())) { // optional, result
|
||||||
// '?' - open optional / result in ->
|
// '?' - open optional / result in ->
|
||||||
// (execute or not execute pattern
|
// (execute or not execute pattern
|
||||||
// matching expression) / (value /
|
// matching expression) / (value /
|
||||||
// return) (TODO: alternative for bring)
|
// return) (TODO: alternative for bring)
|
||||||
|
|
||||||
// '!' - open optional / result -> value / panic
|
// '!' - open optional / result -> value / panic
|
||||||
|
|
||||||
|
|
@ -424,29 +397,27 @@ Result check(const nodes::ModifierExpression &expression,
|
||||||
modified_result.set(modified_result.get().get()->get_parameter_proxy(0));
|
modified_result.set(modified_result.get().get()->get_parameter_proxy(0));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
type_check_error("Can unwrap only Optional or Result", expression,
|
type_check_error("Can unwrap only Optional or Result", expr, executor);
|
||||||
sources_manager);
|
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: check that modifier can be applied
|
// TODO: check that modifier can be applied
|
||||||
modified_result.set(sources_manager.types()->add_modification_of(
|
modified_result.set(state<Types>().add_modification_of(
|
||||||
modified_result.get(), expression.get_modifier()));
|
modified_result.get(), expr.get_modifier()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return type_check_from_arguments(modified_result.get(), arguments, expression,
|
return type_check_from_arguments(modified_result.get(), args, expr, executor);
|
||||||
sources_manager);
|
|
||||||
} // IN PROGRESS
|
} // IN PROGRESS
|
||||||
|
|
||||||
// --- other
|
// --- other
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
Result check(const nodes::NameExpression &expression,
|
Result
|
||||||
SourcesManager &sources_manager, State &state,
|
CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
|
||||||
const Arguments &arguments) {
|
const Arguments &args) {
|
||||||
// TODO: constraints ??
|
// TODO: constraints ??
|
||||||
|
|
||||||
const auto name = expression.get_name();
|
const auto name = expr.get_name();
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto fragments = name->get_fragments();
|
const auto fragments = name->get_fragments();
|
||||||
|
|
@ -459,7 +430,7 @@ Result check(const nodes::NameExpression &expression,
|
||||||
current_prefix.append_after(fragments[i]);
|
current_prefix.append_after(fragments[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_variable = state.find_variable(*current_prefix.get());
|
maybe_variable = state<State>().find_variable(*current_prefix.get());
|
||||||
|
|
||||||
if (maybe_variable.has_value()) {
|
if (maybe_variable.has_value()) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -483,8 +454,8 @@ Result check(const nodes::NameExpression &expression,
|
||||||
// TODO: switch by type types: Variant, Tuple, ...
|
// TODO: switch by type types: Variant, Tuple, ...
|
||||||
// Tuple -> try to find field
|
// Tuple -> try to find field
|
||||||
// Others -> try to open / builtin fields ?
|
// Others -> try to open / builtin fields ?
|
||||||
const auto maybe_field_type = get_field_type_by_name(
|
const auto maybe_field_type =
|
||||||
type, *fragments[i].get(), expression, sources_manager);
|
get_field_type_by_name(type, *fragments[i].get(), expr, executor);
|
||||||
|
|
||||||
if (maybe_field_type.has_value()) {
|
if (maybe_field_type.has_value()) {
|
||||||
type = maybe_field_type.value();
|
type = maybe_field_type.value();
|
||||||
|
|
@ -506,7 +477,7 @@ Result check(const nodes::NameExpression &expression,
|
||||||
// TODO: check, if there is variable with this name
|
// TODO: check, if there is variable with this name
|
||||||
// TODO: check var + fields
|
// TODO: check var + fields
|
||||||
const auto maybe_function_definition =
|
const auto maybe_function_definition =
|
||||||
find_name_definition(*name->get(), expression, sources_manager);
|
find_name_definition(*name->get(), expr, executor);
|
||||||
if (!maybe_function_definition.has_value()) {
|
if (!maybe_function_definition.has_value()) {
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
}
|
}
|
||||||
|
|
@ -516,7 +487,7 @@ Result check(const nodes::NameExpression &expression,
|
||||||
// TODO: count passed type, if needed
|
// TODO: count passed type, if needed
|
||||||
// TODO: manage situation with one out type at any position
|
// TODO: manage situation with one out type at any position
|
||||||
// TODO + 1 - returned type - somtimes (can be ==)
|
// TODO + 1 - returned type - somtimes (can be ==)
|
||||||
const auto arguments_given = expression.arguments_size();
|
const auto arguments_given = expr.arguments_size();
|
||||||
const auto arguments_defined = function_definition->arguments_size();
|
const auto arguments_defined = function_definition->arguments_size();
|
||||||
if (arguments_given + 1 < arguments_defined ||
|
if (arguments_given + 1 < arguments_defined ||
|
||||||
arguments_given > arguments_defined) { // other, when there is passed type
|
arguments_given > arguments_defined) { // other, when there is passed type
|
||||||
|
|
@ -528,7 +499,7 @@ Result check(const nodes::NameExpression &expression,
|
||||||
? (" or " + std::to_string(arguments_defined - 1))
|
? (" or " + std::to_string(arguments_defined - 1))
|
||||||
: ""} +
|
: ""} +
|
||||||
")",
|
")",
|
||||||
expression, sources_manager);
|
expr, executor);
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
// TODO: try return correct type (function return type), when possible
|
// TODO: try return correct type (function return type), when possible
|
||||||
}
|
}
|
||||||
|
|
@ -544,11 +515,11 @@ Result check(const nodes::NameExpression &expression,
|
||||||
if (!argument->get_type().has_value()) {
|
if (!argument->get_type().has_value()) {
|
||||||
type_check_error("Function argument type is not defined for argument " +
|
type_check_error("Function argument type is not defined for argument " +
|
||||||
std::to_string(i),
|
std::to_string(i),
|
||||||
expression, sources_manager);
|
expr, executor);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto annotation = expression.get_argument_annotation(i);
|
const auto annotation = expr.get_argument_annotation(i);
|
||||||
const auto expected_annotation = argument->get_annotation();
|
const auto expected_annotation = argument->get_annotation();
|
||||||
|
|
||||||
if (annotation.has_value() != expected_annotation.has_value()) {
|
if (annotation.has_value() != expected_annotation.has_value()) {
|
||||||
|
|
@ -556,7 +527,7 @@ Result check(const nodes::NameExpression &expression,
|
||||||
std::string{expected_annotation.has_value()
|
std::string{expected_annotation.has_value()
|
||||||
? *expected_annotation.value()
|
? *expected_annotation.value()
|
||||||
: "[none]"},
|
: "[none]"},
|
||||||
*expression.get_argument_value(i), sources_manager);
|
*expr.get_argument_value(i), executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (annotation.has_value() &&
|
if (annotation.has_value() &&
|
||||||
|
|
@ -564,18 +535,18 @@ Result check(const nodes::NameExpression &expression,
|
||||||
type_check_error(
|
type_check_error(
|
||||||
"Wrong function argument type annotation: " + *annotation.value() +
|
"Wrong function argument type annotation: " + *annotation.value() +
|
||||||
" instead of " + *expected_annotation.value(),
|
" instead of " + *expected_annotation.value(),
|
||||||
*expression.get_argument_value(i), sources_manager);
|
*expr.get_argument_value(i), executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
function_argument_results.push_back(
|
function_argument_results.push_back(
|
||||||
check(*expression.get_argument_value(i), sources_manager, state,
|
Run(*expr.get_argument_value(i),
|
||||||
Arguments{}.expect(argument->get_type_proxy().value())));
|
Arguments{}.expect(argument->get_type_proxy().value())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (function_definition->arguments_size() == 0) {
|
if (function_definition->arguments_size() == 0) {
|
||||||
type_check_error(
|
type_check_error(
|
||||||
"Function arguments size is zero. Returned type is not defined",
|
"Function arguments size is zero. Returned type is not defined", expr,
|
||||||
expression, sources_manager);
|
executor);
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -589,31 +560,30 @@ Result check(const nodes::NameExpression &expression,
|
||||||
// TODO: invert modifier ??
|
// TODO: invert modifier ??
|
||||||
if (!returned->get_type().has_value()) {
|
if (!returned->get_type().has_value()) {
|
||||||
type_check_error(
|
type_check_error(
|
||||||
"Function argument type is not defined for returned type", expression,
|
"Function argument type is not defined for returned type", expr,
|
||||||
sources_manager);
|
executor);
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: invert modifier ??
|
// TODO: invert modifier ??
|
||||||
// TODO: generic types should be deduced from arguments
|
// TODO: generic types should be deduced from arguments
|
||||||
return type_check_from_arguments(returned->get_type_proxy().value(),
|
return type_check_from_arguments(returned->get_type_proxy().value(), args,
|
||||||
arguments, expression, sources_manager);
|
expr, executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks for universal call syntax ??
|
// checks for universal call syntax ??
|
||||||
|
|
||||||
// TODO: riturn result
|
// TODO: return result
|
||||||
} // IN PROGRESS
|
} // IN PROGRESS
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
Result check(const nodes::Constructor &expression,
|
Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
|
||||||
SourcesManager &sources_manager, State &state,
|
const Arguments &args) {
|
||||||
const Arguments &arguments) {
|
|
||||||
// TODO: constraints ??
|
// TODO: constraints ??
|
||||||
|
|
||||||
// TODO: use pass type
|
// TODO: use pass type
|
||||||
const auto maybe_type_definition = find_type_definition(
|
const auto maybe_type_definition =
|
||||||
*expression.get_type()->get_name()->get(), expression, sources_manager);
|
find_type_definition(*expr.get_type()->get_name()->get(), expr, executor);
|
||||||
if (!maybe_type_definition.has_value()) {
|
if (!maybe_type_definition.has_value()) {
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
}
|
}
|
||||||
|
|
@ -622,7 +592,7 @@ Result check(const nodes::Constructor &expression,
|
||||||
if (!type_definition->get_type().has_value()) {
|
if (!type_definition->get_type().has_value()) {
|
||||||
type_check_error(
|
type_check_error(
|
||||||
"Type defenition for constructor type not found (declaration only)",
|
"Type defenition for constructor type not found (declaration only)",
|
||||||
expression, sources_manager);
|
expr, executor);
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -634,9 +604,9 @@ Result check(const nodes::Constructor &expression,
|
||||||
|
|
||||||
// TODO: work with different parametric types: tuple, variant, ...
|
// TODO: work with different parametric types: tuple, variant, ...
|
||||||
|
|
||||||
if (expression.arguments_size() == 0) {
|
if (expr.arguments_size() == 0) {
|
||||||
type_check_error("Number of type constructor arguments should be > 0",
|
type_check_error("Number of type constructor arguments should be > 0", expr,
|
||||||
expression, sources_manager);
|
executor);
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
// TODO: try return correct type (constructor's type), when possible (not
|
// TODO: try return correct type (constructor's type), when possible (not
|
||||||
// generic)
|
// generic)
|
||||||
|
|
@ -649,13 +619,13 @@ Result check(const nodes::Constructor &expression,
|
||||||
{ // check arguments size, ets.
|
{ // check arguments size, ets.
|
||||||
switch (builtin_type) {
|
switch (builtin_type) {
|
||||||
case builtin::Type::TUPLE:
|
case builtin::Type::TUPLE:
|
||||||
if (expression.arguments_size() != type.get()->parameters_size()) {
|
if (expr.arguments_size() != type.get()->parameters_size()) {
|
||||||
type_check_error(
|
type_check_error(
|
||||||
"Number of type constructor arguments is different from expected "
|
"Number of type constructor arguments is different from expected "
|
||||||
"(" +
|
"(" +
|
||||||
std::to_string(expression.arguments_size()) + " instead of " +
|
std::to_string(expr.arguments_size()) + " instead of " +
|
||||||
std::to_string(type.get()->parameters_size()) + ")",
|
std::to_string(type.get()->parameters_size()) + ")",
|
||||||
expression, sources_manager);
|
expr, executor);
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
// TODO: try return correct type (constructor's type), when possible
|
// TODO: try return correct type (constructor's type), when possible
|
||||||
// (not generic)
|
// (not generic)
|
||||||
|
|
@ -667,11 +637,11 @@ Result check(const nodes::Constructor &expression,
|
||||||
case builtin::Type::ERROR:
|
case builtin::Type::ERROR:
|
||||||
case builtin::Type::FUNCTION:
|
case builtin::Type::FUNCTION:
|
||||||
case builtin::Type::NONE:
|
case builtin::Type::NONE:
|
||||||
if (expression.arguments_size() != 1) { // TODO: better to_string
|
if (expr.arguments_size() != 1) { // TODO: better to_string
|
||||||
type_check_error("Number of type constructor arguments should be = 1 "
|
type_check_error("Number of type constructor arguments should be = 1 "
|
||||||
"(builtin type " +
|
"(builtin type " +
|
||||||
std::to_string(uint(builtin_type)) + ")",
|
std::to_string(uint(builtin_type)) + ")",
|
||||||
expression, sources_manager);
|
expr, executor);
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
// TODO: try return correct type (constructor's type), when possible
|
// TODO: try return correct type (constructor's type), when possible
|
||||||
// (not generic)
|
// (not generic)
|
||||||
|
|
@ -684,8 +654,8 @@ Result check(const nodes::Constructor &expression,
|
||||||
if (builtin::types::get_parameters_count(builtin_type).has_value() &&
|
if (builtin::types::get_parameters_count(builtin_type).has_value() &&
|
||||||
type.get()->parameters_size() !=
|
type.get()->parameters_size() !=
|
||||||
builtin::types::get_parameters_count(builtin_type).value()) {
|
builtin::types::get_parameters_count(builtin_type).value()) {
|
||||||
type_check_error("Wrong amount of parametars for builtin type",
|
type_check_error("Wrong amount of parametars for builtin type", expr,
|
||||||
expression, sources_manager);
|
executor);
|
||||||
|
|
||||||
return Result::invalid();
|
return Result::invalid();
|
||||||
// TODO: try return correct type (constructor's type), when possible (not
|
// TODO: try return correct type (constructor's type), when possible (not
|
||||||
|
|
@ -697,12 +667,12 @@ Result check(const nodes::Constructor &expression,
|
||||||
|
|
||||||
{ // check annotations
|
{ // check annotations
|
||||||
const auto check_same_annotation =
|
const auto check_same_annotation =
|
||||||
[&expression, &sources_manager](
|
[&expr, &executor = this->executor](
|
||||||
size_t i, std::optional<const std::string *> expected_annotation,
|
size_t i, std::optional<const std::string *> expected_annotation,
|
||||||
bool log_errors) {
|
bool log_errors) {
|
||||||
bool is_same = true;
|
bool is_same = true;
|
||||||
|
|
||||||
const auto annotation = expression.get_argument_annotation(i);
|
const auto annotation = expr.get_argument_annotation(i);
|
||||||
|
|
||||||
if (annotation.has_value() != expected_annotation.has_value()) {
|
if (annotation.has_value() != expected_annotation.has_value()) {
|
||||||
if (log_errors) {
|
if (log_errors) {
|
||||||
|
|
@ -711,7 +681,7 @@ Result check(const nodes::Constructor &expression,
|
||||||
std::string{expected_annotation.has_value()
|
std::string{expected_annotation.has_value()
|
||||||
? *expected_annotation.value()
|
? *expected_annotation.value()
|
||||||
: "[none]"},
|
: "[none]"},
|
||||||
*expression.get_argument_value(i), sources_manager);
|
*expr.get_argument_value(i), executor);
|
||||||
}
|
}
|
||||||
is_same = false;
|
is_same = false;
|
||||||
}
|
}
|
||||||
|
|
@ -722,8 +692,7 @@ Result check(const nodes::Constructor &expression,
|
||||||
type_check_error("Wrong function argument type annotation: " +
|
type_check_error("Wrong function argument type annotation: " +
|
||||||
*annotation.value() + " instead of " +
|
*annotation.value() + " instead of " +
|
||||||
*expected_annotation.value(),
|
*expected_annotation.value(),
|
||||||
*expression.get_argument_value(i),
|
*expr.get_argument_value(i), executor);
|
||||||
sources_manager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is_same = false;
|
is_same = false;
|
||||||
|
|
@ -733,12 +702,12 @@ Result check(const nodes::Constructor &expression,
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto check_no_annotation =
|
const auto check_no_annotation =
|
||||||
[&expression, &sources_manager](size_t i, bool log_errors) {
|
[&expr, &executor = this->executor](size_t i, bool log_errors) {
|
||||||
if (expression.get_argument_annotation(i).has_value()) {
|
if (expr.get_argument_annotation(i).has_value()) {
|
||||||
if (log_errors) {
|
if (log_errors) {
|
||||||
type_check_error(
|
type_check_error(
|
||||||
"Type constructor argument annotation not expected there",
|
"Type constructor argument annotation not expected there",
|
||||||
*expression.get_argument_value(i), sources_manager);
|
*expr.get_argument_value(i), executor);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -747,7 +716,7 @@ Result check(const nodes::Constructor &expression,
|
||||||
|
|
||||||
switch (builtin_type) {
|
switch (builtin_type) {
|
||||||
case builtin::Type::TUPLE:
|
case builtin::Type::TUPLE:
|
||||||
for (size_t i = 0; i < expression.arguments_size(); ++i) {
|
for (size_t i = 0; i < expr.arguments_size(); ++i) {
|
||||||
check_same_annotation(i, type.get()->get_parameter(i)->get_annotation(),
|
check_same_annotation(i, type.get()->get_parameter(i)->get_annotation(),
|
||||||
true /*log errors*/);
|
true /*log errors*/);
|
||||||
}
|
}
|
||||||
|
|
@ -767,7 +736,7 @@ Result check(const nodes::Constructor &expression,
|
||||||
!check_no_annotation(0, false /*do not log errors*/)) {
|
!check_no_annotation(0, false /*do not log errors*/)) {
|
||||||
type_check_error("Wrong type constructor argument annotation in "
|
type_check_error("Wrong type constructor argument annotation in "
|
||||||
"constructor of variant type",
|
"constructor of variant type",
|
||||||
*expression.get_argument_value(0), sources_manager);
|
*expr.get_argument_value(0), executor);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case builtin::Type::ERROR: // no anotations ??
|
case builtin::Type::ERROR: // no anotations ??
|
||||||
|
|
@ -788,89 +757,85 @@ Result check(const nodes::Constructor &expression,
|
||||||
{ // type check arguments
|
{ // type check arguments
|
||||||
switch (builtin_type) {
|
switch (builtin_type) {
|
||||||
case builtin::Type::TUPLE:
|
case builtin::Type::TUPLE:
|
||||||
for (size_t i = 0; i < expression.arguments_size(); ++i) {
|
for (size_t i = 0; i < expr.arguments_size(); ++i) {
|
||||||
check(*expression.get_argument_value(i), sources_manager, state,
|
Run(*expr.get_argument_value(i),
|
||||||
Arguments{}.expect(type.get()->get_parameter_proxy(i)));
|
Arguments{}.expect(type.get()->get_parameter_proxy(i)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case builtin::Type::VARIANT:
|
case builtin::Type::VARIANT:
|
||||||
if (chosen_variant_option.has_value()) {
|
if (chosen_variant_option.has_value()) {
|
||||||
check(*expression.get_argument_value(0), sources_manager, state,
|
Run(*expr.get_argument_value(0),
|
||||||
Arguments{}.expect(type.get()->get_parameter_proxy(
|
Arguments{}.expect(type.get()->get_parameter_proxy(
|
||||||
chosen_variant_option.value())));
|
chosen_variant_option.value())));
|
||||||
} else { // TODO: error, if there is more then one possible variant in
|
} else { // TODO: error, if there is more then one possible variant in
|
||||||
// answer
|
// answer
|
||||||
nodes::TypeProxies possible_options;
|
nodes::TypeProxies possible_options;
|
||||||
for (size_t i = 0; i < type.get()->parameters_size(); ++i) {
|
for (size_t i = 0; i < type.get()->parameters_size(); ++i) {
|
||||||
possible_options.push_back(type.get()->get_parameter_proxy(i));
|
possible_options.push_back(type.get()->get_parameter_proxy(i));
|
||||||
}
|
}
|
||||||
check(*expression.get_argument_value(0), sources_manager, state,
|
Run(*expr.get_argument_value(0), Arguments{}.expect(possible_options));
|
||||||
Arguments{}.expect(possible_options));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case builtin::Type::OPTIONAL:
|
case builtin::Type::OPTIONAL:
|
||||||
// first parameter or NULL
|
// first parameter or NULL
|
||||||
check(*expression.get_argument_value(0), sources_manager, state,
|
Run(*expr.get_argument_value(0),
|
||||||
Arguments{}.expect({type.get()->get_parameter_proxy(0),
|
Arguments{}.expect(
|
||||||
sources_manager.types()->primitive(
|
{type.get()->get_parameter_proxy(0),
|
||||||
builtin::Type::NULL_OPTION)}));
|
state<Types>().primitive(builtin::Type::NULL_OPTION)}));
|
||||||
break;
|
break;
|
||||||
case builtin::Type::RESULT:
|
case builtin::Type::RESULT:
|
||||||
// first parameter or ERROR[second parameter]
|
// first parameter or ERROR[second parameter]
|
||||||
check(*expression.get_argument_value(0), sources_manager, state,
|
Run(*expr.get_argument_value(0),
|
||||||
Arguments{}.expect({type.get()->get_parameter_proxy(0),
|
Arguments{}.expect({type.get()->get_parameter_proxy(0),
|
||||||
sources_manager.types()->add_error_of(
|
state<Types>().add_error_of(
|
||||||
type.get()->get_parameter_proxy(1))}));
|
type.get()->get_parameter_proxy(1))}));
|
||||||
break;
|
break;
|
||||||
case builtin::Type::ERROR:
|
case builtin::Type::ERROR:
|
||||||
// first parameter
|
// first parameter
|
||||||
check(*expression.get_argument_value(0), sources_manager, state,
|
Run(*expr.get_argument_value(0),
|
||||||
Arguments{}.expect(type.get()->get_parameter_proxy(0)));
|
Arguments{}.expect(type.get()->get_parameter_proxy(0)));
|
||||||
break;
|
break;
|
||||||
case builtin::Type::FUNCTION:
|
case builtin::Type::FUNCTION:
|
||||||
case builtin::Type::NONE:
|
case builtin::Type::NONE:
|
||||||
// type itself
|
// type itself
|
||||||
check(*expression.get_argument_value(0), sources_manager, state,
|
Run(*expr.get_argument_value(0), Arguments{}.expect(type));
|
||||||
Arguments{}.expect(type));
|
|
||||||
break;
|
break;
|
||||||
default: // array, basic types
|
default: // array, basic types
|
||||||
type_check_error("Type can't be constructed", expression,
|
type_check_error("Type can't be constructed", expr, executor);
|
||||||
sources_manager);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: deduce generic parts in type
|
// TODO: deduce generic parts in type
|
||||||
return type_check_from_arguments(expression.get_type_proxy(), arguments,
|
return type_check_from_arguments(expr.get_type_proxy(), args, expr, executor);
|
||||||
expression, sources_manager);
|
|
||||||
// TODO: add <- modifiier to type ??
|
// TODO: add <- modifiier to type ??
|
||||||
|
|
||||||
} // IN PROGRESS
|
} // IN PROGRESS
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
Result check(const nodes::Lambda &expression, SourcesManager &sources_manager,
|
Result CheckTask<nodes::Lambda>::operator()(const nodes::Lambda &expr,
|
||||||
State &state, const Arguments &arguments) {
|
const Arguments &args) {
|
||||||
if (arguments.get_expected().empty()) {
|
if (args.get_expected().empty()) {
|
||||||
type_check_error("Can't deduce type of lambda function from context: no "
|
type_check_error("Can't deduce type of lambda function from context: no "
|
||||||
"one type expected",
|
"one type expected",
|
||||||
expression, sources_manager);
|
expr, executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments.get_expected().size() !=
|
if (args.get_expected().size() !=
|
||||||
1) { // TODO: check if only one function argument
|
1) { // TODO: check if only one function argument
|
||||||
type_check_error("Can't deduce type of lambda function from context; too "
|
type_check_error("Can't deduce type of lambda function from context; too "
|
||||||
"much possible types",
|
"much possible types",
|
||||||
expression, sources_manager);
|
expr, executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto expected_type = arguments.get_expected().front();
|
const auto expected_type = args.get_expected().front();
|
||||||
if (!expected_type.get()->is_builtin(builtin::Type::FUNCTION)) {
|
if (!expected_type.get()->is_builtin(builtin::Type::FUNCTION)) {
|
||||||
type_check_error("Type of lambda function should be function", expression,
|
type_check_error("Type of lambda function should be function", expr,
|
||||||
sources_manager);
|
executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: deal with return type (+1 sometimes), etc
|
// TODO: deal with return type (+1 sometimes), etc
|
||||||
const auto arguments_given = expression.arguments_size();
|
const auto arguments_given = expr.arguments_size();
|
||||||
const auto arguments_defined = expected_type.get()->parameters_size();
|
const auto arguments_defined = expected_type.get()->parameters_size();
|
||||||
if (arguments_given != arguments_defined) {
|
if (arguments_given != arguments_defined) {
|
||||||
type_check_error(
|
type_check_error(
|
||||||
|
|
@ -881,43 +846,43 @@ Result check(const nodes::Lambda &expression, SourcesManager &sources_manager,
|
||||||
? (" or " + std::to_string(arguments_defined - 1))
|
? (" or " + std::to_string(arguments_defined - 1))
|
||||||
: ""} +
|
: ""} +
|
||||||
")",
|
")",
|
||||||
expression, sources_manager);
|
expr, executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: set another context (for expression typecheck and vars)
|
// TODO: set another context (for expression typecheck and vars)
|
||||||
|
|
||||||
for (size_t i = 0; i < arguments_given; ++i) {
|
for (size_t i = 0; i < arguments_given; ++i) {
|
||||||
if (!state.insert_variable(*expression.get_argument(i)->get(),
|
if (!state<State>().insert_variable(
|
||||||
expected_type.get()->get_parameter_proxy(i),
|
*expr.get_argument(i)->get(),
|
||||||
nodes::NameDefinition::Modifier::LET)) {
|
expected_type.get()->get_parameter_proxy(i),
|
||||||
|
nodes::NameDefinition::Modifier::LET)) {
|
||||||
// TODO: which modifier ??
|
// TODO: which modifier ??
|
||||||
type_check_error("Variable is already defined in this context",
|
type_check_error("Variable is already defined in this context", expr,
|
||||||
expression, sources_manager);
|
executor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: out type is can be not last
|
// TODO: out type is can be not last
|
||||||
if (arguments_given + 1 == arguments_defined) {
|
if (arguments_given + 1 == arguments_defined) {
|
||||||
check(*expression.get_expression(), sources_manager, state,
|
Run(*expr.get_expression(),
|
||||||
Arguments{}.expect(
|
Arguments{}.expect(
|
||||||
expected_type.get()->get_parameter_proxy(arguments_defined - 1)));
|
expected_type.get()->get_parameter_proxy(arguments_defined - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: needed ?? (only passed type check required ??)
|
// TODO: needed ?? (only passed type check required ??)
|
||||||
return type_check_from_arguments(expected_type, arguments, expression,
|
return type_check_from_arguments(expected_type, args, expr, executor);
|
||||||
sources_manager);
|
|
||||||
} // IN PROGRESS
|
} // IN PROGRESS
|
||||||
|
|
||||||
Result check(const nodes::Extra &, SourcesManager &sources_manager, State &,
|
Result CheckTask<nodes::Extra>::operator()(const nodes::Extra &,
|
||||||
const Arguments &) {
|
const Arguments &) {
|
||||||
|
|
||||||
return Result(sources_manager.types()->primitive(builtin::Type::UNIT));
|
return Result(state<Types>().primitive(builtin::Type::UNIT));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result check(const nodes::EmptyLines &, SourcesManager &sources_manager,
|
Result CheckTask<nodes::EmptyLines>::operator()(const nodes::EmptyLines &,
|
||||||
State &, const Arguments &) {
|
const Arguments &) {
|
||||||
|
|
||||||
return Result(sources_manager.types()->primitive(builtin::Type::UNIT));
|
return Result(state<Types>().primitive(builtin::Type::UNIT));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace type_check
|
} // namespace type_check
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ nodes::TypeProxy check_same_to_pass_type_in_arguments(
|
||||||
logc.Error<Log::kProc>({{message}} /* TODO: node */);
|
logc.Error<Log::kProc>({{message}} /* TODO: node */);
|
||||||
}
|
}
|
||||||
|
|
||||||
return executor.state<nodes::TypeStorage>().primitive(builtin::Type::BOOL);
|
return executor.state<Types>().primitive(builtin::Type::BOOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_no_pass_type_in_arguments(const Arguments &arguments,
|
bool check_no_pass_type_in_arguments(const Arguments &arguments,
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,27 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
template <typename... States> class Task;
|
template <typename Exec, typename Ret, typename Args, typename Node> class Task;
|
||||||
|
|
||||||
template <typename State> class ExecutorState {
|
template <typename State> class ExecutorState {
|
||||||
public:
|
public:
|
||||||
struct Tag {};
|
|
||||||
|
|
||||||
ExecutorState(State &&state) : state_(std::move(state)) {}
|
ExecutorState(State &&state) : state_(std::move(state)) {}
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
// State &state(Tag) { return state; }
|
|
||||||
// const State &state(Tag) const { return state; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
State state_;
|
State state_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... States> class Executor : public ExecutorState<States>... {
|
template <typename... States> class Executor : public ExecutorState<States>... {
|
||||||
friend class Task<States...>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Executor(Log &&log, States &&...states)
|
Executor(Log &&log, States &&...states)
|
||||||
: ExecutorState<States>(std::move(states))..., log_(std::move(log)) {}
|
: ExecutorState<States>(std::move(states))..., log_(std::move(log)) {}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
template <typename T, typename... Args> T New(Args... args) {
|
template <typename T, typename... Args> T Run(Args... args) {
|
||||||
return T(*this, args...);
|
return T(*this, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,17 +39,22 @@ private:
|
||||||
Log log_;
|
Log log_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... States> class Task {
|
template <typename Exec, typename Ret, typename Args, typename Node> class Task {
|
||||||
public:
|
public:
|
||||||
Task(Executor<States...> &executor) : executor(executor) {}
|
Task(Exec &executor) : executor(executor) {}
|
||||||
|
|
||||||
virtual ~Task() {}
|
virtual ~Task() {}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
template <typename T, typename... Args> T New(Args... args) {
|
// template <typename N, typename NArgs> Ret Run(const N& node, NArgs&& args) {
|
||||||
return executor.template New<T>(std::move(args)...);
|
// Task<Exec, Ret, NArgs, N> task(executor);
|
||||||
}
|
// return task(node, std::forward<Args>(args));
|
||||||
|
// }
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual Ret operator()(const Node& node, const Args& args) = 0;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
@ -74,7 +67,7 @@ public:
|
||||||
const Log &log() const { return executor.log_; }
|
const Log &log() const { return executor.log_; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Executor<States...> &executor;
|
Exec &executor;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace error_handling {
|
namespace error_handling {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue