mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-06 15:08:48 +00:00
type check minor refactoring, is_scoped fix
This commit is contained in:
parent
3445a604f7
commit
0088f2b4e3
10 changed files with 420 additions and 380 deletions
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,15 +282,15 @@ 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(
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ 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);
|
||||||
|
|
||||||
|
|
@ -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,
|
|
||||||
Executor &executor,
|
|
||||||
bool handle_errors = true);
|
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
|
||||||
|
|
|
||||||
|
|
@ -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,8 +41,10 @@ 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 ??
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 ...
|
||||||
|
switch (
|
||||||
|
current_case.kind) { // TODO: FIXME think about passed, brought types
|
||||||
|
case nodes::Match::Case::PATTERN_VALUE:
|
||||||
|
if (not value_result.is_invalid()) {
|
||||||
Run(current_case.value,
|
Run(current_case.value,
|
||||||
Args{current_case.value}
|
Args{current_case.value}
|
||||||
.expect_builtin(builtin::Type::BOOL, executor)
|
.ExpectBuiltin(builtin::Type::BOOL, executor)
|
||||||
.pass(value_result.is_invalid() ? nodes::MaybeType{}
|
.Pass(value_result.Get()));
|
||||||
: expression_result.value().get()));
|
}
|
||||||
// TODO: use type modifiers ??
|
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 ¤t_case : expr.cases) {
|
for (const auto ¤t_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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
bool handle_errors) {
|
|
||||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
|
||||||
|
|
||||||
if (args.get_passed().has_value()) {
|
|
||||||
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 utils::Pos &, Executor &executor,
|
||||||
const std::string &message, 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);
|
||||||
|
|
||||||
const auto &expected = args.get_expected();
|
const auto &expected = args.expected();
|
||||||
|
|
||||||
if (expected.empty()) {
|
if (expected.empty()) {
|
||||||
return Result{type};
|
return Result{type};
|
||||||
|
|
@ -60,19 +46,9 @@ 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) {
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue