type check minor refactoring, is_scoped fix

This commit is contained in:
ProgramSnail 2024-09-13 15:16:45 +03:00
parent 3445a604f7
commit 0088f2b4e3
10 changed files with 420 additions and 380 deletions

View file

@ -20,18 +20,21 @@ using Exprs = nodes::NodeStorage; // nodes::ExprStorage;
using Types = nodes::TypeStorage; using Types = nodes::TypeStorage;
using Names = names::NameTree; using Names = names::NameTree;
using Positions = core::DependentStorage<utils::Pos>; using Positions = core::DependentStorage<utils::Pos>;
using NodeTypes =
core::DependentStorage<nodes::Type>; // deduce type for each node
using Printer = printers::Printer; using Printer = printers::Printer;
// TODO: partial host ?? (part of params are stored in each executor, use if // TODO: partial host ?? (part of params are stored in each executor, use if
// constexpr requires) (for Printer, State, ...) // constexpr requires) (for Printer, State, ...)
using ExecutorHost = using ExecutorHost =
core::ExecutorHost<Exprs, Types, Names, Positions, core::ExecutorHost<Exprs, Types, Names, Positions, NodeTypes,
builders::State /*, type_check::State*/, Printer>; builders::State /*, type_check::State*/, Printer>;
class SourcesManager { class SourcesManager {
public: public:
SourcesManager(Log &&log, Printer &&printer) SourcesManager(Log &&log, Printer &&printer)
: executor_host_(std::move(log), {}, {}, {}, {}, {}, std::move(printer)), : executor_host_(std::move(log), {}, {}, {}, {}, {}, {},
std::move(printer)),
statements_{} {} statements_{} {}
void AddFile(const std::string &filename) { void AddFile(const std::string &filename) {

View file

@ -55,8 +55,9 @@ template <typename N> struct BuilderTaskUtils : public Task<N> {
return value; return value;
} }
template <typename T> Node Build(T value, utils::Pos pos) { template <typename T> Node Build(T value, bool is_scoped, utils::Pos pos) {
auto id = this->template state<Exprs>().Insert(std::move(value)); auto id =
this->template state<Exprs>().Insert({std::move(value), is_scoped});
this->template state<Positions>().ForceInsert(id, pos); this->template state<Positions>().ForceInsert(id, pos);
return Ext(id); return Ext(id);
} }

View file

@ -96,7 +96,7 @@ struct BuilderTask<nodes::Container, T>
// '{' (expression ';')* '}' // '{' (expression ';')* '}'
// or // or
// '[[' expression+ ']]' // '[[' expression+ ']]'
Node operator()(const ParserNode &parser_node, const Args &) override { Node operator()(const ParserNode &parser_node, const Args &args) override {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
const auto kind = std::is_same_v<T, utils::BlockTag> const auto kind = std::is_same_v<T, utils::BlockTag>
@ -117,7 +117,7 @@ struct BuilderTask<nodes::Container, T>
.kind = kind, .kind = kind,
.exprs = std::move(exprs), .exprs = std::move(exprs),
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
}; };
@ -172,7 +172,7 @@ struct BuilderTask<nodes::ModifierExpression, T>
// _reference_ expression // _reference_ expression
// or // or
// expression ('?' | '!') // expression ('?' | '!')
Node operator()(const ParserNode &parser_node, const Args &) override { Node operator()(const ParserNode &parser_node, const Args &args) override {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
const size_t modifier_pos = const size_t modifier_pos =
@ -184,7 +184,7 @@ struct BuilderTask<nodes::ModifierExpression, T>
RunOther<nodes::Modifier>(parser_node.nth_child(modifier_pos)), RunOther<nodes::Modifier>(parser_node.nth_child(modifier_pos)),
.expr = Run<Node>(parser_node.nth_named_child(0)), .expr = Run<Node>(parser_node.nth_named_child(0)),
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
}; };

View file

@ -91,52 +91,53 @@ Node BuilderTask<Node>::operator()(const ParserNode &parser_node,
nodes::NameExpression{ nodes::NameExpression{
.name = RunOther<nodes::Identifier>(parser_node), .name = RunOther<nodes::Identifier>(parser_node),
}, },
parser_node.get_pos()); // TODO: is_scoped is_scoped, parser_node.get_pos());
case tokens::Type::CONSTRUCTOR: case tokens::Type::CONSTRUCTOR:
return Run<nodes::Constructor>(parser_node); return Run<nodes::Constructor>(parser_node);
case tokens::Type::LAMBDA: case tokens::Type::LAMBDA:
return Run<nodes::Lambda>(parser_node); return Run<nodes::Lambda>(parser_node);
// --- literals // --- literals
case tokens::Type::FLOAT_LITERAL: case tokens::Type::FLOAT_LITERAL:
return Build(RunOther<nodes::Literal, float>(parser_node), return Build(RunOther<nodes::Literal, float>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
case tokens::Type::DOUBLE_LITERAL: case tokens::Type::DOUBLE_LITERAL:
return Build(RunOther<nodes::Literal, double>(parser_node), return Build(RunOther<nodes::Literal, double>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
case tokens::Type::INT_LITERAL: case tokens::Type::INT_LITERAL:
return Build(RunOther<nodes::Literal, int32_t>(parser_node), return Build(RunOther<nodes::Literal, int32_t>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
case tokens::Type::LONG_LITERAL: case tokens::Type::LONG_LITERAL:
return Build(RunOther<nodes::Literal, int64_t>(parser_node), return Build(RunOther<nodes::Literal, int64_t>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
case tokens::Type::INDEX_LITERAL: case tokens::Type::INDEX_LITERAL:
return Build(RunOther<nodes::Literal, size_t>(parser_node), return Build(RunOther<nodes::Literal, size_t>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
case tokens::Type::STRING_LITERAL: case tokens::Type::STRING_LITERAL:
return Build(RunOther<nodes::Literal, std::string>(parser_node), return Build(RunOther<nodes::Literal, std::string>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
case tokens::Type::UNICODE_STRING_LITERAL: case tokens::Type::UNICODE_STRING_LITERAL:
return Build(RunOther<nodes::Literal, nodes::unicode_string>(parser_node), return Build(RunOther<nodes::Literal, nodes::unicode_string>(parser_node),
parser_node.get_pos()); is_scoped, parser_node.get_pos());
case tokens::Type::CHAR_LITERAL: case tokens::Type::CHAR_LITERAL:
return Build(RunOther<nodes::Literal, char>(parser_node), return Build(RunOther<nodes::Literal, char>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
case tokens::Type::UNICODE_LITERAL: case tokens::Type::UNICODE_LITERAL:
return Build(RunOther<nodes::Literal, nodes::unicode>(parser_node), return Build(RunOther<nodes::Literal, nodes::unicode>(parser_node),
parser_node.get_pos()); is_scoped, parser_node.get_pos());
case tokens::Type::BOOL_LITERAL: case tokens::Type::BOOL_LITERAL:
return Build(RunOther<nodes::Literal, bool>(parser_node), return Build(RunOther<nodes::Literal, bool>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
case tokens::Type::UNIT_LITERAL: case tokens::Type::UNIT_LITERAL:
return Build(RunOther<nodes::Literal, nodes::unit>(parser_node), return Build(RunOther<nodes::Literal, nodes::unit>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
case tokens::Type::NULL_LITERAL: case tokens::Type::NULL_LITERAL:
return Build(RunOther<nodes::Literal, nodes::null>(parser_node), return Build(RunOther<nodes::Literal, nodes::null>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
case tokens::Type::EXTRA: case tokens::Type::EXTRA:
return Build(RunOther<nodes::Extra>(parser_node), parser_node.get_pos()); return Build(RunOther<nodes::Extra>(parser_node), is_scoped,
parser_node.get_pos());
case tokens::Type::EMPTY_LINES: case tokens::Type::EMPTY_LINES:
return Build(RunOther<nodes::EmptyLines>(parser_node), return Build(RunOther<nodes::EmptyLines>(parser_node), is_scoped,
parser_node.get_pos()); parser_node.get_pos());
default: default:
break; break;
@ -152,7 +153,7 @@ Node BuilderTask<Node>::operator()(const ParserNode &parser_node,
// (':=' | '=:') expression (('??' | 'if') expression)? (_do_ expression)? // (':=' | '=:') expression (('??' | 'if') expression)? (_do_ expression)?
Node BuilderTask<nodes::Match::Case>::operator()(const ParserNode &parser_node, Node BuilderTask<nodes::Match::Case>::operator()(const ParserNode &parser_node,
const Args &) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
std::string case_kind = parser_node.nth_child(0).get_value(); std::string case_kind = parser_node.nth_child(0).get_value();
@ -186,12 +187,12 @@ Node BuilderTask<nodes::Match::Case>::operator()(const ParserNode &parser_node,
? Run<Node>(expression_node.value()) ? Run<Node>(expression_node.value())
: std::optional<nodes::NodeId>(), : std::optional<nodes::NodeId>(),
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
// expression case+ // expression case+
Node BuilderTask<nodes::Match>::operator()(const ParserNode &parser_node, Node BuilderTask<nodes::Match>::operator()(const ParserNode &parser_node,
const Args &) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
std::vector<nodes::NodeId /*nodes::Match::Case*/> cases; // TODO std::vector<nodes::NodeId /*nodes::Match::Case*/> cases; // TODO
@ -209,13 +210,13 @@ Node BuilderTask<nodes::Match>::operator()(const ParserNode &parser_node,
0)), // TODO: is_scoped info (always false ??) 0)), // TODO: is_scoped info (always false ??)
.cases = std::move(cases), .cases = std::move(cases),
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
// ('??' | 'if') expression _do_ expression (('!!' | 'elif') expression _do_ // ('??' | 'if') expression _do_ expression (('!!' | 'elif') expression _do_
// expression)* (('!!=>', 'else') expression)? // expression)* (('!!=>', 'else') expression)?
Node BuilderTask<nodes::Condition>::operator()(const ParserNode &parser_node, Node BuilderTask<nodes::Condition>::operator()(const ParserNode &parser_node,
const Args &) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
size_t named_child_count = parser_node.named_child_count(); size_t named_child_count = parser_node.named_child_count();
@ -243,31 +244,31 @@ Node BuilderTask<nodes::Condition>::operator()(const ParserNode &parser_node,
named_child_count - 1)) named_child_count - 1))
: std::optional<Node>(), : std::optional<Node>(),
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
// ('@' | 'for') (expression | expression ':' expression)? _do_ expression // ('@' | 'for') (expression | expression ':' expression)? _do_ expression
Node BuilderTask<nodes::Loop>::operator()(const ParserNode &parser_node, Node BuilderTask<nodes::Loop>::operator()(const ParserNode &parser_node,
const Args &) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
size_t named_child_count = parser_node.named_child_count(); size_t named_child_count = parser_node.named_child_count();
if (named_child_count == 1) { // body if (named_child_count == 1) { // body
return Build(nodes::Loop(Run<Node>(parser_node.nth_named_child(0))), return Build(nodes::Loop(Run<Node>(parser_node.nth_named_child(0))),
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} else if (named_child_count == 2) { // condition, } else if (named_child_count == 2) { // condition,
// body // body
return Build(nodes::Loop(Run<Node>(parser_node.nth_named_child(0)), return Build(nodes::Loop(Run<Node>(parser_node.nth_named_child(0)),
Run<Node>(parser_node.nth_named_child(1))), Run<Node>(parser_node.nth_named_child(1))),
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} else if (named_child_count == 3) { // variable, } else if (named_child_count == 3) { // variable,
// interval, // interval,
// body // body
return Build(nodes::Loop(Run<Node>(parser_node.nth_named_child(0)), return Build(nodes::Loop(Run<Node>(parser_node.nth_named_child(0)),
Run<Node>(parser_node.nth_named_child(1)), Run<Node>(parser_node.nth_named_child(1)),
Run<Node>(parser_node.nth_named_child(2))), Run<Node>(parser_node.nth_named_child(2))),
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} else { } else {
logc.Fatal<Log::kProc>({{"Unexpected named expression amount in loop"}}, logc.Fatal<Log::kProc>({{"Unexpected named expression amount in loop"}},
parser_node.get_pos()); parser_node.get_pos());
@ -281,16 +282,16 @@ Node BuilderTask<nodes::Loop>::operator()(const ParserNode &parser_node,
// expression ',' expression // expression ',' expression
Node BuilderTask<nodes::NameExpression, utils::CommaTag>::operator()( Node BuilderTask<nodes::NameExpression, utils::CommaTag>::operator()(
const ParserNode &parser_node, const Args &) { const ParserNode &parser_node, const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
std::vector<std::pair<std::optional<std::string>, nodes::NodeId>> args; std::vector<std::pair<std::optional<std::string>, nodes::NodeId>> args_nodes;
args.emplace_back(std::nullopt, args_nodes.emplace_back(std::nullopt,
Run<nodes::NodeId>(parser_node.nth_named_child(0))); Run<nodes::NodeId>(parser_node.nth_named_child(0)));
args.emplace_back(std::nullopt, args_nodes.emplace_back(std::nullopt,
Run<nodes::NodeId>(parser_node.nth_named_child(1))); Run<nodes::NodeId>(parser_node.nth_named_child(1)));
return Build( return Build(
nodes::NameExpression{ nodes::NameExpression{
@ -300,37 +301,38 @@ Node BuilderTask<nodes::NameExpression, utils::CommaTag>::operator()(
.kind = nodes::Identifier::kSimpleName, .kind = nodes::Identifier::kSimpleName,
.value = ",", .value = ",",
}, },
.args = std::move(args), .args = std::move(args_nodes),
.prefix = {}, .prefix = {},
.is_point_call = false, .is_point_call = false,
.is_operator_call = true, .is_operator_call = true,
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
// expression operator expression // expression operator expression
Node BuilderTask<nodes::NameExpression, utils::OperatorTag>::operator()( Node BuilderTask<nodes::NameExpression, utils::OperatorTag>::operator()(
const ParserNode &parser_node, const Args &) { const ParserNode &parser_node, const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
auto name_node = parser_node.child_by_field_name("name"); auto name_node = parser_node.child_by_field_name("name");
std::vector<std::pair<std::optional<std::string>, nodes::NodeId>> args; std::vector<std::pair<std::optional<std::string>, nodes::NodeId>> args_nodes;
args.emplace_back(std::nullopt, args_nodes.emplace_back(std::nullopt,
Run<Node>(name_node.previous_named_sibling())); Run<Node>(name_node.previous_named_sibling()));
args.emplace_back(std::nullopt, Run<Node>(name_node.next_named_sibling())); args_nodes.emplace_back(std::nullopt,
Run<Node>(name_node.next_named_sibling()));
return Build( return Build(
nodes::NameExpression{ nodes::NameExpression{
.name = RunOther<nodes::Identifier, utils::OperatorIdTag>(name_node), .name = RunOther<nodes::Identifier, utils::OperatorIdTag>(name_node),
.args = std::move(args), .args = std::move(args_nodes),
.prefix = {}, .prefix = {},
.is_point_call = false, .is_point_call = false,
.is_operator_call = true, .is_operator_call = true,
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
// --- continers // --- continers
@ -341,7 +343,7 @@ Node BuilderTask<nodes::NameExpression, utils::OperatorTag>::operator()(
// ('return' | 'bring') expression // ('return' | 'bring') expression
Node BuilderTask<nodes::Return>::operator()(const ParserNode &parser_node, Node BuilderTask<nodes::Return>::operator()(const ParserNode &parser_node,
const Args &) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
std::string modifier = parser_node.nth_child(0).get_value(); std::string modifier = parser_node.nth_child(0).get_value();
@ -352,12 +354,12 @@ Node BuilderTask<nodes::Return>::operator()(const ParserNode &parser_node,
: nodes::Return::BRING, : nodes::Return::BRING,
.expr = Run<Node>(parser_node.nth_named_child(0)), .expr = Run<Node>(parser_node.nth_named_child(0)),
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
// _var_let_ (simple_name_identifier | placeholder) // _var_let_ (simple_name_identifier | placeholder)
Node BuilderTask<nodes::NameDefinition>::operator()( Node BuilderTask<nodes::NameDefinition>::operator()(
const ParserNode &parser_node, const Args &) { const ParserNode &parser_node, const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
std::string modifier = parser_node.nth_child(0).get_value(); std::string modifier = parser_node.nth_child(0).get_value();
@ -371,24 +373,24 @@ Node BuilderTask<nodes::NameDefinition>::operator()(
: nodes::NameDefinition::VAR, : nodes::NameDefinition::VAR,
.name = RunOther<nodes::Identifier>(name_node), .name = RunOther<nodes::Identifier>(name_node),
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} // IN PROGRESS } // IN PROGRESS
// expression '[' expression ']' // expression '[' expression ']'
Node BuilderTask<nodes::Access, utils::ArrayAccessTag>::operator()( Node BuilderTask<nodes::Access, utils::ArrayAccessTag>::operator()(
const ParserNode &parser_node, const Args &) { const ParserNode &parser_node, const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
return Build( return Build(
nodes::Access{.kind = nodes::Access::ARRAY, nodes::Access{.kind = nodes::Access::ARRAY,
.value = Run<Node>(parser_node.nth_named_child(0)), .value = Run<Node>(parser_node.nth_named_child(0)),
.index = Run<Node>(parser_node.nth_named_child(1))}, .index = Run<Node>(parser_node.nth_named_child(1))},
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
// expression '.' number_literal // expression '.' number_literal
Node BuilderTask<nodes::Access, utils::TupleAccessTag>::operator()( Node BuilderTask<nodes::Access, utils::TupleAccessTag>::operator()(
const ParserNode &parser_node, const Args &) { const ParserNode &parser_node, const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
auto const node = Build( auto const node = Build(
@ -400,14 +402,14 @@ Node BuilderTask<nodes::Access, utils::TupleAccessTag>::operator()(
// .index = Build(build_index_literal(parser_node.nth_named_child( // .index = Build(build_index_literal(parser_node.nth_named_child(
// 1)) /*, false}*/, // ?? is_scoped ?? // 1)) /*, false}*/, // ?? is_scoped ??
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
return node; return node;
} }
// 'break' | 'continue' // 'break' | 'continue'
Node BuilderTask<nodes::LoopControl>::operator()(const ParserNode &parser_node, Node BuilderTask<nodes::LoopControl>::operator()(const ParserNode &parser_node,
const Args &) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
return Build( return Build(
@ -416,7 +418,7 @@ Node BuilderTask<nodes::LoopControl>::operator()(const ParserNode &parser_node,
? nodes::LoopControl::BREAK ? nodes::LoopControl::BREAK
: nodes::LoopControl::CONTINUE, : nodes::LoopControl::CONTINUE,
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
// // ModifierExpression -> .hpp // // ModifierExpression -> .hpp
@ -446,10 +448,10 @@ void build_args_until_end(ParserNode first_parse_node, Executor &executor,
// (type '.' simple_name | expression '.' simple_name | name | '(' operator // (type '.' simple_name | expression '.' simple_name | name | '(' operator
// ')') (annotation? expression)* // ')') (annotation? expression)*
Node BuilderTask<nodes::NameExpression, utils::FuncCallTag>::operator()( Node BuilderTask<nodes::NameExpression, utils::FuncCallTag>::operator()(
const ParserNode &parser_node, const Args &) { const ParserNode &parser_node, const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
std::vector<nodes::AnnotatedArgument> args; std::vector<nodes::AnnotatedArgument> args_nodes;
std::optional<nodes::TypeData> prefix; std::optional<nodes::TypeData> prefix;
@ -474,60 +476,60 @@ Node BuilderTask<nodes::NameExpression, utils::FuncCallTag>::operator()(
prefix_node = current_node; prefix_node = current_node;
} else { } else {
is_point_call = true; is_point_call = true;
args.emplace_back(std::nullopt, Run<Node>(current_node)); args_nodes.emplace_back(std::nullopt, Run<Node>(current_node));
} }
} }
build_args_until_end(name_node.next_named_sibling(), executor, args); build_args_until_end(name_node.next_named_sibling(), executor, args_nodes);
return Build( return Build(
nodes::NameExpression{ nodes::NameExpression{
.name = RunOther<nodes::Identifier>(name_node), .name = RunOther<nodes::Identifier>(name_node),
.args = std::move(args), .args = std::move(args_nodes),
.prefix = prefix_node.has_value() .prefix = prefix_node.has_value()
? RunOther<nodes::Type>(prefix_node.value()) ? RunOther<nodes::Type>(prefix_node.value())
: nodes::MaybeType(), : nodes::MaybeType(),
.is_point_call = is_point_call, .is_point_call = is_point_call,
.is_operator_call = false, .is_operator_call = false,
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
// type (annotation? expression)* // type (annotation? expression)*
Node BuilderTask<nodes::Constructor>::operator()(const ParserNode &parser_node, Node BuilderTask<nodes::Constructor>::operator()(const ParserNode &parser_node,
const Args &) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
std::vector<nodes::AnnotatedArgument> args; std::vector<nodes::AnnotatedArgument> args_nodes;
build_args_until_end(parser_node build_args_until_end(parser_node
.child_by_field_name("ty" .child_by_field_name("ty"
"p" "p"
"e") "e")
.next_named_sibling(), .next_named_sibling(),
executor, args); executor, args_nodes);
return Build( return Build(
nodes::Constructor{ nodes::Constructor{
.type = .type =
RunOther<nodes::Type>(parser_node.child_by_field_name("type")), RunOther<nodes::Type>(parser_node.child_by_field_name("type")),
.args = std::move(args), .args = std::move(args_nodes),
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
// '\\' argument_name* _do_ expression // '\\' argument_name* _do_ expression
Node BuilderTask<nodes::Lambda>::operator()(const ParserNode &parser_node, Node BuilderTask<nodes::Lambda>::operator()(const ParserNode &parser_node,
const Args &) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kParse); Log::Context logc(executor.log(), Log::Area::kParse);
std::vector<nodes::Identifier> args; std::vector<nodes::Identifier> args_nodes;
auto current_node = auto current_node =
parser_node.nth_child(1); // next to '\\', not null ('=>' should present) parser_node.nth_child(1); // next to '\\', not null ('=>' should present)
while (current_node.is_named()) { // until _do_ while (current_node.is_named()) { // until _do_
args.emplace_back(RunOther<nodes::Identifier>(current_node)); args_nodes.emplace_back(RunOther<nodes::Identifier>(current_node));
current_node = current_node.next_sibling(); current_node = current_node.next_sibling();
} }
@ -536,10 +538,10 @@ Node BuilderTask<nodes::Lambda>::operator()(const ParserNode &parser_node,
return Build( return Build(
nodes::Lambda{ nodes::Lambda{
.args = std::move(args), .args = std::move(args_nodes),
.expr = Run<Node>(current_node), .expr = Run<Node>(current_node),
}, },
parser_node.get_pos()); args.is_scoped, parser_node.get_pos());
} }
} // namespace builders } // namespace builders

View file

@ -25,8 +25,8 @@ public:
public: public:
State(Log &log) : log_(log) {} State(Log &log) : log_(log) {}
bool insert_variable(const std::string &name, nodes::Type type, bool InsertVariable(const std::string &name, nodes::Type type,
nodes::NameDefinition::Kind modifier) { nodes::NameDefinition::Kind modifier) {
Log::Context logc(log_, Log::Area::kTypeCheck); Log::Context logc(log_, Log::Area::kTypeCheck);
if (contexts_.empty()) { if (contexts_.empty()) {
@ -39,7 +39,7 @@ public:
.second; .second;
} }
std::optional<VariableInfo> find_variable(const std::string &name) { std::optional<VariableInfo> FindVariable(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()) {
@ -50,7 +50,7 @@ public:
return std::nullopt; return std::nullopt;
} }
bool bring_type(nodes::Type type) { bool BringType(nodes::Type type) {
Log::Context logc(log_, Log::Area::kTypeCheck); Log::Context logc(log_, Log::Area::kTypeCheck);
if (contexts_.empty()) { if (contexts_.empty()) {
@ -66,7 +66,7 @@ public:
return true; return true;
} }
bool return_type(nodes::Type type) { bool ReturnType(nodes::Type type) {
Log::Context logc(log_, Log::Area::kTypeCheck); Log::Context logc(log_, Log::Area::kTypeCheck);
if (contexts_.empty()) { if (contexts_.empty()) {
@ -83,7 +83,7 @@ public:
} }
private: private:
void enter_context(const utils::Pos &pos) { void EnterContext(const utils::Pos &pos) {
Log::Context logc(log_, Log::Area::kTypeCheck); Log::Context logc(log_, Log::Area::kTypeCheck);
contexts_.emplace_back(pos); contexts_.emplace_back(pos);
@ -164,10 +164,14 @@ using Exprs = nodes::NodeStorage;
using Types = nodes::TypeStorage; using Types = nodes::TypeStorage;
using Names = names::NameTree; using Names = names::NameTree;
using Positions = core::DependentStorage<utils::Pos>; using Positions = core::DependentStorage<utils::Pos>;
using NodeTypes =
core::DependentStorage<nodes::Type>; // deduce type for each node
using Executor = core::Executor<Exprs, Types, Names, State, Positions>; using Executor =
core::Executor<Exprs, Types, Names, State, Positions, NodeTypes>;
using Node = nodes::Node_<nodes::NodePart<utils::Pos>>; using Node =
nodes::Node_<nodes::NodePart<utils::Pos>, nodes::NodePart<nodes::Type>>;
// //
@ -175,52 +179,52 @@ class Args {
public: public:
Args(storage::Id current_id) : current_id(current_id) {}; Args(storage::Id current_id) : current_id(current_id) {};
Args expect_builtin(builtin::Type type, Executor &executor) const { Args ExpectBuiltin(builtin::Type type, Executor &executor) const {
Args copy(*this); Args copy(*this);
copy.expected_types_ = {executor.state<Types>().primitive(type)}; copy.expected_types_ = {executor.state<Types>().primitive(type)};
return copy; return copy;
} }
Args pass_builtin(builtin::Type type, Executor &executor) const { Args PassBuiltin(builtin::Type type, Executor &executor) const {
Args copy(*this); Args copy(*this);
copy.passed_type_ = executor.state<Types>().primitive(type); copy.passed_type_ = executor.state<Types>().primitive(type);
return copy; return copy;
} }
Args expect(nodes::Types types) const { Args Expect(nodes::Types types) const {
Args copy(*this); Args copy(*this);
copy.expected_types_ = types; copy.expected_types_ = types;
return copy; return copy;
} }
Args expect(nodes::MaybeType type) const { Args Expect(nodes::MaybeType type) const {
Args copy(*this); Args copy(*this);
copy.expected_types_ = copy.expected_types_ =
(type.has_value() ? nodes::Types{type.value()} : nodes::Types{}); (type.has_value() ? nodes::Types{type.value()} : nodes::Types{});
return copy; return copy;
} }
Args pass(nodes::MaybeType type) const { Args Pass(nodes::MaybeType type) const {
Args copy(*this); Args copy(*this);
copy.passed_type_ = type; copy.passed_type_ = type;
return copy; return copy;
} }
Args without_expect() const { Args WithoutExpect() const {
Args copy(*this); Args copy(*this);
copy.expected_types_ = {}; copy.expected_types_ = {};
return copy; return copy;
} }
Args without_pass() const { Args WithoutPass() const {
Args copy(*this); Args copy(*this);
copy.passed_type_ = {}; copy.passed_type_ = {};
return copy; return copy;
} }
nodes::Types get_expected() const { return expected_types_; }; nodes::Types expected() const { return expected_types_; };
nodes::MaybeType get_passed() const { return passed_type_; }; nodes::MaybeType passed() const { return passed_type_; };
// TODO: add check, that there is no passed type for some nodes ?? // TODO: add check, that there is no passed type for some nodes ??
// TODO: args builder ?? // TODO: args builder ??
@ -240,7 +244,7 @@ public:
ContextHolder(State &state, const utils::Pos &pos, ContextHolder(State &state, const utils::Pos &pos,
nodes::MaybeType *context_exit_type) nodes::MaybeType *context_exit_type)
: state_(state), context_exit_type_(context_exit_type) { : state_(state), context_exit_type_(context_exit_type) {
state.enter_context(pos); state.EnterContext(pos);
} }
ContextHolder(const ContextHolder &) = delete; ContextHolder(const ContextHolder &) = delete;
@ -273,14 +277,14 @@ public:
// //
nodes::Type &get() { nodes::Type &Get() {
utils::Assert(type_.has_value(), utils::Assert(type_.has_value(),
"Access to invalid type in TypeCheckResult"); "Access to invalid type in TypeCheckResult");
return type_.value(); return type_.value();
} }
const nodes::Type &get() const { const nodes::Type &Get() const {
utils::Assert(type_.has_value(), utils::Assert(type_.has_value(),
"Access to invalid type in TypeCheckResult"); "Access to invalid type in TypeCheckResult");
@ -288,7 +292,15 @@ public:
return type_.value(); return type_.value();
} }
void set(nodes::Type type) { type_ = type; } //
nodes::MaybeType &MaybeGet() { return type_; }
const nodes::MaybeType &MaybeGet() const { return type_; }
//
void Set(nodes::Type type) { type_ = type; }
// //
@ -305,7 +317,7 @@ using MaybeResult = std::optional<Result>;
// //
nodes::Type check_same_to_pass_type_in_args( nodes::Type CheckSameToPassTypeInArgs(
nodes::Type type, const Args &args, const utils::Pos &pos, nodes::Type type, const Args &args, const utils::Pos &pos,
Executor &executor, Executor &executor,
const std::string &message = "Different type with passed one", const std::string &message = "Different type with passed one",
@ -316,37 +328,31 @@ nodes::Type check_same_to_pass_type_in_args(
// SourcesManager &sources_manager, // SourcesManager &sources_manager,
// const std::string &message = "Type can't be passed to this node"); // const std::string &message = "Type can't be passed to this node");
Result type_same_to_expected( Result CheckTypeSameToExpected(
nodes::Type type, const Args &args, const utils::Pos &pos, nodes::Type type, const Args &args, const utils::Pos &pos,
Executor &executor, Executor &executor,
const std::string &message = "Different type with expected one", const std::string &message = "Different type with expected one",
bool handle_errors = true); bool handle_errors = true);
Result type_check_from_args(nodes::Type type, const Args &args,
const utils::Pos &pos, Executor &executor,
bool handle_errors = true);
std::optional<const nodes::TypeDefinition *> std::optional<const nodes::TypeDefinition *>
find_type_definition(const std::string &name, const utils::Pos &pos, FindTypeDefinition(const std::string &name, const utils::Pos &pos,
Executor &executor, bool handle_errors = true); Executor &executor, bool handle_errors = true);
std::optional<const nodes::FunctionDefinition *> std::optional<const nodes::FunctionDefinition *>
find_name_definition(const std::string &name, const utils::Pos &pos, FindNameDefinition(const std::string &name, const utils::Pos &pos,
Executor &executor, bool handle_errors = true); Executor &executor, bool handle_errors = true);
nodes::MaybeType unfold_user_defined_type(nodes::Type type, nodes::MaybeType UnfoldUserDefinedType(nodes::Type type, const utils::Pos &pos,
const utils::Pos &pos, Executor &executor,
Executor &executor, bool handle_errors = true);
bool handle_errors = true);
nodes::MaybeType get_field_type_by_name(nodes::Type type, nodes::MaybeType FieldTypeByName(nodes::Type type, const std::string &field,
const std::string &field, const utils::Pos &pos, Executor &executor,
const utils::Pos &pos, bool handle_errors = true);
Executor &executor,
bool handle_errors = true);
void type_check_error(const std::string &message, const utils::Pos &pos, inline nodes::MaybeType Curry(MaybeResult result) {
Executor &executor, bool handle_error = true); return result.has_value() ? result->Get() : nodes::MaybeType{};
}
// //
@ -366,12 +372,47 @@ template <typename N> struct CheckTaskBase : public Task<N> {
Node Ext(storage::Id id) { Node Ext(storage::Id id) {
return Node(id, this->template state<Exprs>(), return Node(id, this->template state<Exprs>(),
this->template state<Positions>()); this->template state<Positions>(),
this->template state<NodeTypes>());
} }
utils::Pos PosOf(storage::Id id) { utils::Pos PosOf(storage::Id id) {
return Ext(id).template part<utils::Pos>(); return Ext(id).template part<utils::Pos>();
} }
//
void TypeCheckError(const std::string &message, const utils::Pos &,
bool handle_errors = true) {
Log::Context logc(Task<N>::executor.log(), Log::Area::kTypeCheck);
if (not handle_errors) {
return;
}
logc.Error<Log::kProc>({{message}} /* TODO: use pos */);
}
Result TypeCheckFromArgs(nodes::Type type, const Args &args,
const utils::Pos &pos, bool handle_errors = true) {
Log::Context logc(Task<N>::executor.log(), Log::Area::kTypeCheck);
/* TODO FIXME */
logc.Fatal<Log::kSys>({{"Not implemented yet"}});
throw std::exception(); // unreachable
}
bool CheckNoPassTypeInArgs(const Args &args, const utils::Pos &pos,
const std::string &message, bool handle_errors) {
Log::Context logc(Task<N>::executor.log(), Log::Area::kTypeCheck);
if (args.passed().has_value()) {
TypeCheckError(message, pos, handle_errors);
return false;
}
return true;
}
}; };
} // namespace type_check } // namespace type_check

View file

@ -4,6 +4,8 @@ namespace type_check {
nodes::Type get_literal_type(const nodes::Literal &literal, nodes::Type get_literal_type(const nodes::Literal &literal,
Executor &executor) { Executor &executor) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
switch (literal.value.index()) { switch (literal.value.index()) {
case 0: // float case 0: // float
return executor.state<Types>().primitive(builtin::Type::FLOAT); return executor.state<Types>().primitive(builtin::Type::FLOAT);
@ -39,9 +41,11 @@ nodes::Type get_literal_type(const nodes::Literal &literal,
Result CheckTask<nodes::Literal>::operator()(const nodes::Literal &literal, Result CheckTask<nodes::Literal>::operator()(const nodes::Literal &literal,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
auto const type = get_literal_type(literal, this->executor); auto const type = get_literal_type(literal, this->executor);
return type_same_to_expected(type, args, {}, return CheckTypeSameToExpected(type, args, {},
this->executor); // TODO: add pos ?? this->executor); // TODO: add pos ??
} }
} // namespace type_check } // namespace type_check

View file

@ -35,16 +35,19 @@ Result CheckTask<nodes::NodeData>::operator()(const nodes::NodeData &expr,
Result CheckTask<nodes::Match>::operator()(const nodes::Match &expr, Result CheckTask<nodes::Match>::operator()(const nodes::Match &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
//
Result value_result = Run(expr.value, {expr.value}); Result value_result = Run(expr.value, {expr.value});
// x :=/=: ... // x :=/=: ...
if (value_result.is_invalid()) { if (value_result.is_invalid()) {
type_check_error("Match value is invalid", current_pos, executor); TypeCheckError("Match value is invalid", current_pos);
} }
MaybeResult expression_result; MaybeResult expr_result;
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;
@ -54,95 +57,101 @@ Result CheckTask<nodes::Match>::operator()(const nodes::Match &expr,
Ext(current_case_id).get<nodes::Match::Case>(); Ext(current_case_id).get<nodes::Match::Case>();
// :=/=: x ... // :=/=: x ...
Run(current_case.value, switch (
Args{current_case.value} current_case.kind) { // TODO: FIXME think about passed, brought types
.expect_builtin(builtin::Type::BOOL, executor) case nodes::Match::Case::PATTERN_VALUE:
.pass(value_result.is_invalid() ? nodes::MaybeType{} if (not value_result.is_invalid()) {
: expression_result.value().get())); Run(current_case.value,
// TODO: use type modifiers ?? Args{current_case.value}
.ExpectBuiltin(builtin::Type::BOOL, executor)
.Pass(value_result.Get()));
}
break;
case nodes::Match::Case::VALUE_PATTERN:
Run(current_case.value, Args{current_case.value}
.ExpectBuiltin(builtin::Type::BOOL, executor)
.Pass(value_result.MaybeGet()));
break;
}
// ... ?? x ... // ... ?? x ...
if (current_case.condition.has_value()) { if (current_case.condition.has_value()) {
Run(current_case.condition.value(), const auto &cond = current_case.condition.value();
Args{current_case.condition.value()}.expect_builtin( Run(cond, Args{cond}.ExpectBuiltin(builtin::Type::BOOL, executor));
builtin::Type::BOOL, executor));
} }
// ... -> x // ... -> x
if (current_case.expr.has_value()) { if (current_case.expr.has_value()) {
const auto &expr = current_case.expr.value();
at_least_one_case_with_expression = true; at_least_one_case_with_expression = true;
Result case_result = Run(current_case.expr.value(),
Args{current_case.expr.value()}.expect(
expression_result.has_value()
? expression_result.value().get()
: nodes::MaybeType{}));
if (!expression_result.has_value() && !case_result.is_invalid()) { Result case_result = Run(expr, Args{expr}.Expect(Curry(expr_result)));
expression_result = std::move(case_result);
if (not expr_result.has_value() and not case_result.is_invalid()) {
expr_result = std::move(case_result);
} }
} else { } else {
at_least_one_case_without_expression = true; at_least_one_case_without_expression = true;
} }
} }
if (at_least_one_case_with_expression && if (at_least_one_case_with_expression and
at_least_one_case_without_expression) { at_least_one_case_without_expression) {
type_check_error( TypeCheckError(
"All cases should be with or without expression at the same time", "All cases should be with or without expression at the same time",
current_pos, executor); current_pos);
expression_result = Result::invalid(); expr_result = Result::invalid();
} }
if (!expression_result.has_value()) { if (not expr_result.has_value()) {
expression_result = Result{state<Types>().primitive(builtin::Type::UNIT)}; expr_result = Result{state<Types>().primitive(builtin::Type::UNIT)};
} }
return type_check_from_args( return TypeCheckFromArgs(expr_result.value().Get(), args, current_pos);
state<Types>().add_array_of(expression_result.value().get()), args,
current_pos, executor);
} }
Result CheckTask<nodes::Condition>::operator()(const nodes::Condition &expr, Result CheckTask<nodes::Condition>::operator()(const nodes::Condition &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
MaybeResult expression_result; //
MaybeResult expr_result;
for (const auto &current_case : expr.cases) { for (const auto &current_case : expr.cases) {
// condition
Run(current_case.first, Run(current_case.first,
Args{current_case.first}.expect_builtin(builtin::Type::BOOL, executor)); Args{current_case.first}.ExpectBuiltin(builtin::Type::BOOL, executor));
// expression
Result case_result = Result case_result =
Run(current_case.second, Run(current_case.second,
Args{current_case.second}.expect( Args{current_case.second}.Expect(Curry(expr_result)));
expression_result.has_value() ? expression_result.value().get()
: nodes::MaybeType{}));
if (!expression_result.has_value() && !case_result.is_invalid()) { if (not expr_result.has_value() and not case_result.is_invalid()) {
expression_result = std::move(case_result); expr_result = std::move(case_result);
} }
} }
if (expr.else_case.has_value()) { if (expr.else_case.has_value()) {
Run(expr.else_case.value(), Run(expr.else_case.value(),
Args{expr.else_case.value()}.expect( Args{expr.else_case.value()}.Expect(Curry(expr_result)));
expression_result.has_value() ? expression_result.value().get()
: nodes::MaybeType{}));
} }
if (!expression_result.has_value()) { if (!expr_result.has_value()) {
type_check_error("There should be at least one case in if statement", TypeCheckError("There should be at least one case in if statement",
current_pos, executor); current_pos);
expression_result = Result::invalid(); expr_result = Result::invalid();
} }
return type_check_from_args( return TypeCheckFromArgs(expr_result.value().Get(), args, current_pos);
state<Types>().add_array_of(expression_result.value().get()), args,
current_pos, executor);
} }
Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr, Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
// TODO: ranges ?? // TODO: ranges ??
@ -157,7 +166,7 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
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:
Run(expr.condition.value(), Args{expr.condition.value()}.expect_builtin( Run(expr.condition.value(), Args{expr.condition.value()}.ExpectBuiltin(
builtin::Type::BOOL, executor)); builtin::Type::BOOL, executor));
// --- type check is independent from loop itself --- // --- type check is independent from loop itself ---
@ -169,7 +178,7 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
case nodes::Loop::FOR: case nodes::Loop::FOR:
// TODO: expect range ?? // TODO: expect range ??
interval_result = interval_result =
Run(expr.interval.value(), Args{expr.interval.value()}.expect_builtin( Run(expr.interval.value(), Args{expr.interval.value()}.ExpectBuiltin(
builtin::Type::ARRAY, executor)); builtin::Type::ARRAY, executor));
if (interval_result.value().is_invalid()) { if (interval_result.value().is_invalid()) {
@ -180,8 +189,8 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
variable_result = variable_result =
Run(expr.variable.value(), Run(expr.variable.value(),
Args{expr.variable.value()}.expect( Args{expr.variable.value()}.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()) {
@ -196,15 +205,16 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
// TODO: modifier checks ??, modifiers ?? // TODO: modifier checks ??, modifiers ??
return type_check_from_args( return TypeCheckFromArgs(state<Types>().add_array_of(expression_result.Get()),
state<Types>().add_array_of(expression_result.get()), args, current_pos, args, current_pos);
executor);
} // IN PROGRESS } // IN PROGRESS
// --- containers // --- containers
Result CheckTask<nodes::Container>::CheckArray(const nodes::Container &expr, Result CheckTask<nodes::Container>::CheckArray(const nodes::Container &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
MaybeResult last_expr_result; MaybeResult last_expr_result;
@ -216,9 +226,9 @@ Result CheckTask<nodes::Container>::CheckArray(const nodes::Container &expr,
if (!last_expr_result.has_value()) { if (!last_expr_result.has_value()) {
last_expr_result = expr_result; last_expr_result = expr_result;
} else { } else {
if (last_expr_result.value().get() != expr_result.get()) { if (last_expr_result.value().Get() != expr_result.Get()) {
type_check_error("Elements in array should have same type", TypeCheckError("Elements in array should have same type",
PosOf(args.current_id), executor); PosOf(args.current_id));
// return TypeCheckResult::construct_invalid_result(); // max // return TypeCheckResult::construct_invalid_result(); // max
// possible checks, so no return // possible checks, so no return
} }
@ -226,17 +236,19 @@ Result CheckTask<nodes::Container>::CheckArray(const nodes::Container &expr,
} }
if (!last_expr_result.has_value()) { if (!last_expr_result.has_value()) {
type_check_error("Array with zero elements", current_pos, executor); TypeCheckError("Array with zero elements", current_pos);
return Result::invalid(); return Result::invalid();
} }
return type_check_from_args( return TypeCheckFromArgs(
state<Types>().add_array_of(last_expr_result.value().get()), args, state<Types>().add_array_of(last_expr_result.value().Get()), args,
current_pos, executor); current_pos);
} }
Result CheckTask<nodes::Container>::CheckBlock(const nodes::Container &expr, Result CheckTask<nodes::Container>::CheckBlock(const nodes::Container &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
nodes::MaybeType context_exit_type; nodes::MaybeType context_exit_type;
@ -257,9 +269,8 @@ Result CheckTask<nodes::Container>::CheckBlock(const nodes::Container &expr,
? Result(context_exit_type.value()) ? Result(context_exit_type.value())
: Result(state<Types>().primitive(builtin::Type::UNIT)); : Result(state<Types>().primitive(builtin::Type::UNIT));
return type_check_from_args( return TypeCheckFromArgs(
state<Types>().add_array_of(block_brought_type.get()), args, current_pos, state<Types>().add_array_of(block_brought_type.Get()), args, current_pos);
executor);
} }
Result CheckTask<nodes::Container>::operator()(const nodes::Container &expr, Result CheckTask<nodes::Container>::operator()(const nodes::Container &expr,
@ -276,6 +287,8 @@ Result CheckTask<nodes::Container>::operator()(const nodes::Container &expr,
Result CheckTask<nodes::Return>::operator()(const nodes::Return &expr, Result CheckTask<nodes::Return>::operator()(const nodes::Return &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
auto returned_result = Run(expr.expr, {expr.expr}); auto returned_result = Run(expr.expr, {expr.expr});
@ -286,70 +299,71 @@ Result CheckTask<nodes::Return>::operator()(const nodes::Return &expr,
switch (expr.kind) { switch (expr.kind) {
case nodes::Return::BRING: case nodes::Return::BRING:
if (state<State>().bring_type(returned_result.get())) { if (state<State>().BringType(returned_result.Get())) {
type_check_error("Different brought type to current one", current_pos, TypeCheckError("Different brought type to current one", current_pos);
executor);
return Result::invalid(); return Result::invalid();
} }
break; break;
case nodes::Return::RETURN: case nodes::Return::RETURN:
if (!state<State>().return_type(returned_result.get())) { if (!state<State>().ReturnType(returned_result.Get())) {
type_check_error("Different returned type to current one", current_pos, TypeCheckError("Different returned type to current one", current_pos);
executor);
return Result::invalid(); return Result::invalid();
} }
break; break;
} }
return type_check_from_args(state<Types>().primitive(builtin::Type::UNIT), return TypeCheckFromArgs(state<Types>().primitive(builtin::Type::UNIT), args,
args, current_pos, executor); current_pos);
} }
// 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 Result
CheckTask<nodes::NameDefinition>::operator()(const nodes::NameDefinition &expr, CheckTask<nodes::NameDefinition>::operator()(const nodes::NameDefinition &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
if (!args.get_passed().has_value()) { if (!args.passed().has_value()) {
type_check_error("Can't deduce type of new variable from context", TypeCheckError("Can't deduce type of new variable from context",
current_pos, executor); current_pos);
} }
// assigned type shold be one of <-, <>, -- (can't be ->) // assigned type shold be one of <-, <>, -- (can't be ->)
const auto variable_type = args.get_passed().value(); const auto variable_type = args.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", TypeCheckError("Variable can't be assigned from out (->) value",
current_pos, executor); current_pos);
} }
// variable accessible by reference by default ?? // variable accessible by reference by default ??
state<Types>().add_modification_of(variable_type, nodes::Modifier::REF); state<Types>().add_modification_of(variable_type, nodes::Modifier::REF);
if (!state<State>().insert_variable(expr.name.value, variable_type, if (!state<State>().InsertVariable(expr.name.value, variable_type,
expr.kind)) { expr.kind)) {
type_check_error("Variable is already defined in this context", current_pos, TypeCheckError("Variable is already defined in this context", current_pos);
executor);
} }
// Return BOOL as any := / =: expression // Return BOOL as any := / =: expression
return type_check_from_args(state<Types>().primitive(builtin::Type::BOOL), return TypeCheckFromArgs(state<Types>().primitive(builtin::Type::BOOL), args,
args, current_pos, executor); current_pos);
} }
Result CheckTask<nodes::Access>::CheckArrayAccess(const nodes::Access &expr, Result CheckTask<nodes::Access>::CheckArrayAccess(const nodes::Access &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
auto index_result = auto index_result =
Run(expr.index, Run(expr.index,
Args{expr.index}.expect_builtin(builtin::Type::INDEX, executor)); Args{expr.index}.ExpectBuiltin(builtin::Type::INDEX, executor));
auto value_result = auto value_result =
Run(expr.value, Run(expr.value,
Args{expr.value}.expect_builtin(builtin::Type::ARRAY, executor)); Args{expr.value}.ExpectBuiltin(builtin::Type::ARRAY, executor));
if (index_result.is_invalid()) { if (index_result.is_invalid()) {
return index_result; return index_result;
@ -361,17 +375,19 @@ Result CheckTask<nodes::Access>::CheckArrayAccess(const nodes::Access &expr,
// TODO: modifier checks ?? // TODO: modifier checks ??
return type_check_from_args(value_result.get().get()->get_parameter_proxy(0), return TypeCheckFromArgs(value_result.Get().get()->get_parameter_proxy(0),
args, current_pos, executor); args, current_pos);
} }
Result CheckTask<nodes::Access>::CheckTupleAccess(const nodes::Access &expr, Result CheckTask<nodes::Access>::CheckTupleAccess(const nodes::Access &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
auto value_result = auto value_result =
Run(expr.value, Run(expr.value,
Args{expr.value}.expect_builtin(builtin::Type::TUPLE, executor)); Args{expr.value}.ExpectBuiltin(builtin::Type::TUPLE, executor));
if (value_result.is_invalid()) { if (value_result.is_invalid()) {
return value_result; return value_result;
@ -384,13 +400,14 @@ Result CheckTask<nodes::Access>::CheckTupleAccess(const nodes::Access &expr,
// TODO: modifier checks ?? // TODO: modifier checks ??
return type_check_from_args( return TypeCheckFromArgs(value_result.Get().get()->get_parameter_proxy(index),
value_result.get().get()->get_parameter_proxy(index), args, current_pos, args, current_pos);
executor);
} }
Result CheckTask<nodes::Access>::operator()(const nodes::Access &expr, Result CheckTask<nodes::Access>::operator()(const nodes::Access &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
switch (expr.kind) { switch (expr.kind) {
case nodes::Access::ARRAY: case nodes::Access::ARRAY:
return CheckArrayAccess(expr, args); return CheckArrayAccess(expr, args);
@ -401,14 +418,18 @@ Result CheckTask<nodes::Access>::operator()(const nodes::Access &expr,
Result CheckTask<nodes::LoopControl>::operator()(const nodes::LoopControl &expr, Result CheckTask<nodes::LoopControl>::operator()(const nodes::LoopControl &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
return type_check_from_args(state<Types>().primitive(builtin::Type::UNIT), return TypeCheckFromArgs(state<Types>().primitive(builtin::Type::UNIT), args,
args, current_pos, executor); current_pos);
} }
Result CheckTask<nodes::ModifierExpression>::operator()( Result CheckTask<nodes::ModifierExpression>::operator()(
const nodes::ModifierExpression &expr, const Args &args) { const nodes::ModifierExpression &expr, const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
auto modified_result = Run(expr.expr, {expr.expr}); auto modified_result = Run(expr.expr, {expr.expr});
@ -426,25 +447,23 @@ Result CheckTask<nodes::ModifierExpression>::operator()(
// '!' - open optional / result -> value / panic // '!' - open optional / result -> value / panic
switch (modified_result.get().get()->to_builtin()) { switch (modified_result.Get().get()->to_builtin()) {
case builtin::Type::OPTIONAL: case builtin::Type::OPTIONAL:
case builtin::Type::RESULT: case builtin::Type::RESULT:
// TODO: how to unwrap external modifier ?? // TODO: how to unwrap external modifier ??
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", current_pos, TypeCheckError("Can unwrap only Optional or Result", current_pos);
executor);
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(state<Types>().add_modification_of( modified_result.Set(state<Types>().add_modification_of(
modified_result.get(), expr.modifier)); modified_result.Get(), expr.modifier));
} }
return type_check_from_args(modified_result.get(), args, current_pos, return TypeCheckFromArgs(modified_result.Get(), args, current_pos);
executor);
} // IN PROGRESS } // IN PROGRESS
// --- other // --- other
@ -453,6 +472,8 @@ Result CheckTask<nodes::ModifierExpression>::operator()(
Result Result
CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr, CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
// TODO: constraints ?? // TODO: constraints ??
@ -470,7 +491,7 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
current_prefix.append_after(fragments[i]); current_prefix.append_after(fragments[i]);
} }
maybe_variable = state<State>().find_variable(current_prefix.value); maybe_variable = state<State>().FindVariable(current_prefix.value);
if (maybe_variable.has_value()) { if (maybe_variable.has_value()) {
break; break;
@ -494,8 +515,8 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
// 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].value, current_pos, executor); FieldTypeByName(type, fragments[i].value, current_pos, executor);
if (maybe_field_type.has_value()) { if (maybe_field_type.has_value()) {
type = maybe_field_type.value(); type = maybe_field_type.value();
@ -517,7 +538,7 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
// 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.value, current_pos, executor); FindNameDefinition(name.value, current_pos, executor);
if (!maybe_function_definition.has_value()) { if (!maybe_function_definition.has_value()) {
return Result::invalid(); return Result::invalid();
} }
@ -531,15 +552,13 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
const auto args_defined = function_definition->args.size(); const auto args_defined = function_definition->args.size();
if (args_given + 1 < args_defined || if (args_given + 1 < args_defined ||
args_given > args_defined) { // other, when there is passed type args_given > args_defined) { // other, when there is passed type
type_check_error( TypeCheckError(std::format("Number of function args is different from "
"Number of function args is different from expected (" + "expected ({} instead of {}{})",
std::to_string(args_given) + " instead of " + args_given, args_defined,
std::to_string(args_defined) + args_defined > 0
std::string{args_defined > 0 ? (" or " + std::to_string(args_defined - 1))
? (" or " + std::to_string(args_defined - 1)) : ""),
: ""} + current_pos);
")",
current_pos, 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
} }
@ -553,9 +572,10 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
function_definition->args.at(i); function_definition->args.at(i);
if (!argument.type.has_value()) { if (!argument.type.has_value()) {
type_check_error("Function argument type is not defined for argument " + TypeCheckError(
std::to_string(i), std::format("Function argument type is not defined for argument {}",
current_pos, executor); i),
current_pos);
continue; continue;
} }
@ -563,30 +583,31 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
const auto expected_annotation = argument.annotation; const auto expected_annotation = argument.annotation;
if (annotation.has_value() != expected_annotation.has_value()) { if (annotation.has_value() != expected_annotation.has_value()) {
type_check_error("Wrong function argument annotation: should be " + TypeCheckError("Wrong function argument annotation: should be " +
std::string{expected_annotation.has_value() std::string{expected_annotation.has_value()
? expected_annotation.value() ? expected_annotation.value()
: "[none]"}, : "[none]"},
PosOf(expr.args.at(i).second), executor); PosOf(expr.args.at(i).second));
} }
if (annotation.has_value() && if (annotation.has_value() &&
annotation.value() != expected_annotation.value()) { annotation.value() != expected_annotation.value()) {
type_check_error( TypeCheckError(
"Wrong function argument type annotation: " + annotation.value() + std::format(
" instead of " + expected_annotation.value(), "Wrong function argument type annotation: {} instead of {}",
PosOf(expr.args.at(i).second), executor); annotation.value(), expected_annotation.value()),
PosOf(expr.args.at(i).second));
} }
function_argument_results.push_back( function_argument_results.push_back(
Run(expr.args.at(i).second, Run(expr.args.at(i).second,
Args{expr.args.at(i).second}.expect(argument.type.value()))); Args{expr.args.at(i).second}.Expect(argument.type.value())));
} }
if (function_definition->args.size() == 0) { if (function_definition->args.size() == 0) {
type_check_error( TypeCheckError(
"Function arguments size is zero. Returned type is not defined", "Function arguments size is zero. Returned type is not defined",
current_pos, executor); current_pos);
return Result::invalid(); return Result::invalid();
} }
@ -598,16 +619,14 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
// TODO: invert modifier ?? // TODO: invert modifier ??
if (!returned.type.has_value()) { if (!returned.type.has_value()) {
type_check_error( TypeCheckError("Function argument type is not defined for returned type",
"Function argument type is not defined for returned type", current_pos);
current_pos, executor);
return Result::invalid(); return Result::invalid();
} }
// TODO: invert modifier ?? // TODO: invert modifier ??
// TODO: generic types should be deduced from args // TODO: generic types should be deduced from args
return type_check_from_args(returned.type.value(), args, current_pos, return TypeCheckFromArgs(returned.type.value(), args, current_pos);
executor);
} }
// checks for universal call syntax ?? // checks for universal call syntax ??
@ -618,12 +637,14 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
// TODO // TODO
Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr, Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
// 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 = FindTypeDefinition(
expr.type.get()->get_name()->value, current_pos, executor); expr.type.get()->get_name()->value, current_pos, executor);
if (!maybe_type_definition.has_value()) { if (!maybe_type_definition.has_value()) {
return Result::invalid(); return Result::invalid();
@ -631,9 +652,9 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
const nodes::TypeDefinition *type_definition = maybe_type_definition.value(); const nodes::TypeDefinition *type_definition = maybe_type_definition.value();
if (!type_definition->type.has_value()) { if (!type_definition->type.has_value()) {
type_check_error( TypeCheckError(
"Type defenition for constructor type not found (declaration only)", "Type defenition for constructor type not found (declaration only)",
current_pos, executor); current_pos);
return Result::invalid(); return Result::invalid();
} }
@ -646,8 +667,8 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
// TODO: work with different parametric types: tuple, variant, ... // TODO: work with different parametric types: tuple, variant, ...
if (expr.args.size() == 0) { if (expr.args.size() == 0) {
type_check_error("Number of type constructor arguments should be > 0", TypeCheckError("Number of type constructor arguments should be > 0",
current_pos, executor); current_pos);
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)
@ -661,12 +682,12 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
switch (builtin_type) { switch (builtin_type) {
case builtin::Type::TUPLE: case builtin::Type::TUPLE:
if (expr.args.size() != type.get()->parameters_size()) { if (expr.args.size() != type.get()->parameters_size()) {
type_check_error( TypeCheckError(
"Number of type constructor arguments is different from expected " "Number of type constructor arguments is different from expected "
"(" + "(" +
std::to_string(expr.args.size()) + " instead of " + std::to_string(expr.args.size()) + " instead of " +
std::to_string(type.get()->parameters_size()) + ")", std::to_string(type.get()->parameters_size()) + ")",
current_pos, executor); current_pos);
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)
@ -679,10 +700,10 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
case builtin::Type::FUNCTION: case builtin::Type::FUNCTION:
case builtin::Type::NONE: case builtin::Type::NONE:
if (expr.args.size() != 1) { // TODO: better to_string if (expr.args.size() != 1) { // TODO: better to_string
type_check_error("Number of type constructor arguments should be = 1 " TypeCheckError(std::format("Number of type constructor arguments "
"(builtin type " + "should be = 1 (builtin type {})",
std::to_string(uint(builtin_type)) + ")", uint(builtin_type)),
current_pos, executor); current_pos);
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)
@ -695,8 +716,8 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
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", TypeCheckError("Wrong amount of parametars for builtin type",
current_pos, executor); current_pos);
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
@ -717,12 +738,12 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
if (annotation.has_value() != expected_annotation.has_value()) { if (annotation.has_value() != expected_annotation.has_value()) {
if (log_errors) { if (log_errors) {
type_check_error( TypeCheckError(
"Wrong type constructor argument annotation: should be " + "Wrong type constructor argument annotation: should be " +
std::string{expected_annotation.has_value() std::string{expected_annotation.has_value()
? *expected_annotation.value() ? *expected_annotation.value()
: "[none]"}, : "[none]"},
PosOf(expr.args.at(i).second), executor); PosOf(expr.args.at(i).second));
} }
is_same = false; is_same = false;
} }
@ -730,10 +751,10 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
if (annotation.has_value() && if (annotation.has_value() &&
annotation.value() != *expected_annotation.value()) { annotation.value() != *expected_annotation.value()) {
if (log_errors) { if (log_errors) {
type_check_error("Wrong function argument type annotation: " + TypeCheckError("Wrong function argument type annotation: " +
annotation.value() + " instead of " + annotation.value() + " instead of " +
*expected_annotation.value(), *expected_annotation.value(),
PosOf(expr.args.at(i).second), executor); PosOf(expr.args.at(i).second));
} }
is_same = false; is_same = false;
@ -745,9 +766,9 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
const auto check_no_annotation = [&expr, this](size_t i, bool log_errors) { const auto check_no_annotation = [&expr, this](size_t i, bool log_errors) {
if (expr.args.at(i).first.has_value()) { if (expr.args.at(i).first.has_value()) {
if (log_errors) { if (log_errors) {
type_check_error( TypeCheckError(
"Type constructor argument annotation not expected there", "Type constructor argument annotation not expected there",
PosOf(expr.args.at(i).second), executor); PosOf(expr.args.at(i).second));
} }
return false; return false;
} }
@ -774,9 +795,9 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
if (!chosen_variant_option.has_value() && if (!chosen_variant_option.has_value() &&
!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 " TypeCheckError("Wrong type constructor argument annotation in "
"constructor of variant type", "constructor of variant type",
PosOf(expr.args.front().second), executor); PosOf(expr.args.front().second));
} }
break; break;
case builtin::Type::ERROR: // no anotations ?? case builtin::Type::ERROR: // no anotations ??
@ -798,13 +819,13 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
switch (builtin_type) { switch (builtin_type) {
case builtin::Type::TUPLE: case builtin::Type::TUPLE:
for (size_t i = 0; i < expr.args.size(); ++i) { for (size_t i = 0; i < expr.args.size(); ++i) {
Run(expr.args.at(i).second, Args{expr.args.at(i).second}.expect( Run(expr.args.at(i).second, Args{expr.args.at(i).second}.Expect(
type.get()->get_parameter_proxy(i))); 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()) {
Run(expr.args.front().second, Args{expr.args.front().second}.expect( Run(expr.args.front().second, Args{expr.args.front().second}.Expect(
type.get()->get_parameter_proxy( 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
@ -814,43 +835,43 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
possible_options.push_back(type.get()->get_parameter_proxy(i)); possible_options.push_back(type.get()->get_parameter_proxy(i));
} }
Run(expr.args.front().second, Run(expr.args.front().second,
Args{expr.args.front().second}.expect(possible_options)); Args{expr.args.front().second}.Expect(possible_options));
} }
break; break;
case builtin::Type::OPTIONAL: case builtin::Type::OPTIONAL:
// first parameter or NULL // first parameter or NULL
Run(expr.args.front().second, Run(expr.args.front().second,
Args{expr.args.front().second}.expect( Args{expr.args.front().second}.Expect(
{type.get()->get_parameter_proxy(0), {type.get()->get_parameter_proxy(0),
state<Types>().primitive(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]
Run(expr.args.front().second, Run(expr.args.front().second,
Args{expr.args.front().second}.expect( Args{expr.args.front().second}.Expect(
{type.get()->get_parameter_proxy(0), {type.get()->get_parameter_proxy(0),
state<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
Run(expr.args.front().second, Args{expr.args.front().second}.expect( Run(expr.args.front().second, Args{expr.args.front().second}.Expect(
type.get()->get_parameter_proxy(0))); 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
Run(expr.args.front().second, Run(expr.args.front().second,
Args{expr.args.front().second}.expect(type)); Args{expr.args.front().second}.Expect(type));
break; break;
default: // array, basic types default: // array, basic types
type_check_error("Type can't be constructed", current_pos, executor); TypeCheckError("Type can't be constructed", current_pos);
break; break;
} }
} }
// TODO: deduce generic parts in type // TODO: deduce generic parts in type
return type_check_from_args(expr.type, args, current_pos, executor); return TypeCheckFromArgs(expr.type, args, current_pos);
// TODO: add <- modifiier to type ?? // TODO: add <- modifiier to type ??
} // IN PROGRESS } // IN PROGRESS
@ -858,71 +879,74 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
// TODO // TODO
Result CheckTask<nodes::Lambda>::operator()(const nodes::Lambda &expr, Result CheckTask<nodes::Lambda>::operator()(const nodes::Lambda &expr,
const Args &args) { const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto current_pos = PosOf(args.current_id); const auto current_pos = PosOf(args.current_id);
if (args.get_expected().empty()) { if (args.expected().empty()) {
type_check_error("Can't deduce type of lambda function from context: no " TypeCheckError("Can't deduce type of lambda function from context: no "
"one type expected", "one type expected",
current_pos, executor); current_pos);
} }
if (args.get_expected().size() != if (args.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 " TypeCheckError("Can't deduce type of lambda function from context; too "
"much possible types", "much possible types",
current_pos, executor); current_pos);
} }
const auto expected_type = args.get_expected().front(); const auto expected_type = args.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", current_pos, TypeCheckError("Type of lambda function should be function", current_pos);
executor);
} }
// TODO: deal with return type (+1 sometimes), etc // TODO: deal with return type (+1 sometimes), etc
const auto args_given = expr.args.size(); const auto args_given = expr.args.size();
const auto args_defined = expected_type.get()->parameters_size(); const auto args_defined = expected_type.get()->parameters_size();
if (args_given != args_defined) { if (args_given != args_defined) {
type_check_error( TypeCheckError(std::format("Number of function arguments is different from "
"Number of function arguments is different from expected (" + "expected ({} istead of {}{})",
std::to_string(args_given) + " instead of " + args_given, args_defined,
std::to_string(args_defined) + args_defined > 0
std::string{args_defined > 0 ? (" or " + std::to_string(args_defined - 1))
? (" or " + std::to_string(args_defined - 1)) : ""),
: ""} + current_pos);
")",
current_pos, 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 < args_given; ++i) { for (size_t i = 0; i < args_given; ++i) {
if (!state<State>().insert_variable( if (!state<State>().InsertVariable(
expr.args.at(i).value, expected_type.get()->get_parameter_proxy(i), expr.args.at(i).value, expected_type.get()->get_parameter_proxy(i),
nodes::NameDefinition::Kind::LET)) { nodes::NameDefinition::Kind::LET)) {
// TODO: which modifier ?? // TODO: which modifier ??
type_check_error("Variable is already defined in this context", TypeCheckError("Variable is already defined in this context",
current_pos, executor); current_pos);
} }
} }
// TODO: out type is can be not last // TODO: out type is can be not last
if (args_given + 1 == args_defined) { if (args_given + 1 == args_defined) {
Run(expr.expr, Run(expr.expr,
Args{expr.expr}.expect( Args{expr.expr}.Expect(
expected_type.get()->get_parameter_proxy(args_defined - 1))); expected_type.get()->get_parameter_proxy(args_defined - 1)));
} }
// TODO: needed ?? (only passed type check required ??) // TODO: needed ?? (only passed type check required ??)
return type_check_from_args(expected_type, args, current_pos, executor); return TypeCheckFromArgs(expected_type, args, current_pos);
} // IN PROGRESS } // IN PROGRESS
Result CheckTask<nodes::Extra>::operator()(const nodes::Extra &, const Args &) { Result CheckTask<nodes::Extra>::operator()(const nodes::Extra &, const Args &) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
return Result(state<Types>().primitive(builtin::Type::UNIT)); return Result(state<Types>().primitive(builtin::Type::UNIT));
} }
Result CheckTask<nodes::EmptyLines>::operator()(const nodes::EmptyLines &, Result CheckTask<nodes::EmptyLines>::operator()(const nodes::EmptyLines &,
const Args &) { const Args &) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
return Result(state<Types>().primitive(builtin::Type::UNIT)); return Result(state<Types>().primitive(builtin::Type::UNIT));
} }

View file

@ -6,43 +6,29 @@ namespace type_check {
// pass type -> compare types, return bool // pass type -> compare types, return bool
// no pass type -> return type // no pass type -> return type
nodes::Type check_same_to_pass_type_in_args(nodes::Type type, const Args &args, nodes::Type CheckSameToPassTypeInArgs(nodes::Type type, const Args &args,
const utils::Pos &, const utils::Pos &, Executor &executor,
Executor &executor, const std::string &message,
const std::string &message, bool handle_errors) {
bool handle_errors) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck); Log::Context logc(executor.log(), Log::Area::kTypeCheck);
if (not args.get_passed().has_value()) { if (not args.passed().has_value()) {
return type; return type;
} }
if (type != args.get_passed().value() and handle_errors) { if (type != args.passed().value() and handle_errors) {
logc.Error<Log::kProc>({{message}} /* TODO: node */); logc.Error<Log::kProc>({{message}} /* TODO: node */);
} }
return executor.state<Types>().primitive(builtin::Type::BOOL); return executor.state<Types>().primitive(builtin::Type::BOOL);
} }
bool check_no_pass_type_in_args(const Args &args, const utils::Pos &pos, Result CheckTypeSameToExpected(nodes::Type type, const Args &args,
Executor &executor, const std::string &message, const utils::Pos &, Executor &executor,
bool handle_errors) { const std::string &message, bool handle_errors) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck); Log::Context logc(executor.log(), Log::Area::kTypeCheck);
if (args.get_passed().has_value()) { const auto &expected = args.expected();
type_check_error(message, pos, executor, handle_errors);
return false;
}
return true;
}
Result type_same_to_expected(nodes::Type type, const Args &args,
const utils::Pos &, Executor &executor,
const std::string &message, bool handle_errors) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto &expected = args.get_expected();
if (expected.empty()) { if (expected.empty()) {
return Result{type}; return Result{type};
@ -60,22 +46,12 @@ Result type_same_to_expected(nodes::Type type, const Args &args,
return Result{expected.front()}; // any can be choosen return Result{expected.front()}; // any can be choosen
} }
Result type_check_from_args(nodes::Type /*type*/, const Args & /*args*/,
const utils::Pos &, Executor &executor,
bool /*handle_errors*/) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
/* TODO FIXME */
logc.Fatal<Log::kSys>({{"Not implemented yet"}});
throw std::exception(); // unreachable
}
template <typename T> template <typename T>
std::optional<const T *> std::optional<const T *>
find_statement(const std::string &name, const utils::Pos &, Executor &executor, FindStatement(const std::string &name, const utils::Pos &, Executor &executor,
const std::string &message_not_found, const std::string &message_not_found,
const std::string &message_different_statement, const std::string &message_different_statement,
bool handle_errors) { bool handle_errors) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck); Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto maybe_any_statement = executor.state<names::NameTree>().find(name); const auto maybe_any_statement = executor.state<names::NameTree>().find(name);
@ -98,32 +74,32 @@ find_statement(const std::string &name, const utils::Pos &, Executor &executor,
} }
std::optional<const nodes::TypeDefinition *> std::optional<const nodes::TypeDefinition *>
find_type_definition(const std::string &name, const utils::Pos &pos, FindTypeDefinition(const std::string &name, const utils::Pos &pos,
Executor &executor, bool handle_errors) { Executor &executor, bool handle_errors) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck); Log::Context logc(executor.log(), Log::Area::kTypeCheck);
return find_statement<nodes::TypeDefinition>( return FindStatement<nodes::TypeDefinition>(
name, pos, executor, "No type definition found in name tree", name, pos, executor, "No type definition found in name tree",
"Node in name tree is not type definition", handle_errors); "Node in name tree is not type definition", handle_errors);
} }
std::optional<const nodes::FunctionDefinition *> std::optional<const nodes::FunctionDefinition *>
find_name_definition(const std::string &name, const utils::Pos &pos, FindNameDefinition(const std::string &name, const utils::Pos &pos,
Executor &executor, bool handle_errors) { Executor &executor, bool handle_errors) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck); Log::Context logc(executor.log(), Log::Area::kTypeCheck);
return find_statement<nodes::FunctionDefinition>( return FindStatement<nodes::FunctionDefinition>(
name, pos, executor, "No name definition found in name tree", name, pos, executor, "No name definition found in name tree",
"Node in name tree is not name definition", handle_errors); "Node in name tree is not name definition", handle_errors);
} }
std::optional<nodes::Type> unfold_user_defined_type(nodes::Type type, std::optional<nodes::Type> UnfoldUserDefinedType(nodes::Type type,
const utils::Pos &pos, const utils::Pos &pos,
Executor &executor, Executor &executor,
bool handle_errors) { bool handle_errors) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck); Log::Context logc(executor.log(), Log::Area::kTypeCheck);
const auto maybe_type_definition = find_type_definition( const auto maybe_type_definition = FindTypeDefinition(
type.get()->get_name()->value, pos, executor, handle_errors); type.get()->get_name()->value, pos, executor, handle_errors);
if (!maybe_type_definition.has_value()) { if (!maybe_type_definition.has_value()) {
@ -146,11 +122,9 @@ std::optional<nodes::Type> unfold_user_defined_type(nodes::Type type,
return maybe_type_definition.value()->type.value(); return maybe_type_definition.value()->type.value();
} }
std::optional<nodes::Type> get_field_type_by_name(nodes::Type type, std::optional<nodes::Type>
const std::string &field, FieldTypeByName(nodes::Type type, const std::string &field,
const utils::Pos &pos, const utils::Pos &pos, Executor &executor, bool handle_errors) {
Executor &executor,
bool handle_errors) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck); Log::Context logc(executor.log(), Log::Area::kTypeCheck);
switch (type.get()->to_builtin()) { switch (type.get()->to_builtin()) {
@ -170,13 +144,13 @@ std::optional<nodes::Type> get_field_type_by_name(nodes::Type type,
// remove recursion ?? // remove recursion ??
const auto maybe_internal_type = const auto maybe_internal_type =
unfold_user_defined_type(type, pos, executor, handle_errors); UnfoldUserDefinedType(type, pos, executor, handle_errors);
if (!maybe_internal_type.has_value()) { if (!maybe_internal_type.has_value()) {
return std::nullopt; return std::nullopt;
} }
return get_field_type_by_name(maybe_internal_type.value(), field, pos, return FieldTypeByName(maybe_internal_type.value(), field, pos, executor,
executor, handle_errors); handle_errors);
} }
default: // variant, function, optional, result, error (TODO: add message default: // variant, function, optional, result, error (TODO: add message
// field?), array (TODO: add length field ?), basic types // field?), array (TODO: add length field ?), basic types
@ -191,16 +165,4 @@ std::optional<nodes::Type> get_field_type_by_name(nodes::Type type,
} }
} }
// FIXME: replace with direct log calls
void type_check_error(const std::string &message, const utils::Pos &,
Executor &executor, bool handle_error) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
if (!handle_error) {
return;
}
logc.Error<Log::kProc>({{message}} /* TODO: use pos */);
}
} // namespace type_check } // namespace type_check

View file

@ -3,6 +3,8 @@
#include "core_utils.hpp" #include "core_utils.hpp"
#include "log.hpp" #include "log.hpp"
// TODO: use Counter for Tasks
namespace core { namespace core {
template <typename Tag> template <typename Tag>

View file

@ -7,8 +7,9 @@
namespace utils { namespace utils {
std::string to_string(const std::source_location &source_location) { std::string to_string(const std::source_location &source_location) {
return std::format("{}:{} {}", source_location.file_name(), return std::format(
source_location.line(), source_location.function_name()); "{}:{}" /* {}"*/, source_location.file_name(),
source_location.line() /*, source_location.function_name()*/);
} }
std::string to_string(Pos::Point point) { std::string to_string(Pos::Point point) {